NullReferenceException when using scripted Kangaroo Locator and GH_ObjectWrapper

Hey people,
I have searched the net and the forum for quite some time now and also have found some knowledge regarding the use of GH_ObjectWrapper and the also other problems with the Kangaroo Locator Goal. But still I can’t seem to fix my issue – maybe I’m already blind and just not seeing a simple thing.
Still, I thought maybe some veterans regarding these matters like @AndersDeleuran or @DanielPiker know what’s going on. I would be very grateful :slight_smile:

The Problem occurs when scripting the Kangaroo Locator Goal with python, I have the following code (Polylines is a list of incoming Polylines):

import clr
clr.AddReferenceToFile("KangarooSolver.dll")
import KangarooSolver as ks
import Grasshopper as gh

for i in range(len(Polylines)):
    if i == 0:
        print Polylines[i]
        wrapped_poly = gh.Kernel.Types.GH_ObjectWrapper(Polylines[i])
        print wrapped_poly, wrapped_poly.Value, wrapped_poly.IsValid
        g_show = ks.Goals.Locator(wrapped_poly)
        print g_show

which gives me…

Rhino.Geometry.Polyline object at 0x000000000000009C [Rhino.Geometry.Polyline]>

Rhino.Geometry.Polyline <Rhino.Geometry.Polyline object at 0x000000000000009F [Rhino.Geometry.Polyline]> True

Runtime error (NullReferenceException): Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.

If I understand correctly, the Locator Goal of Kangaroo takes points, lines, polylines wrapped via GH_Objectwrapper. Am I missing something here? I can’t find the reason for the NullReferenceException I’m getting. Maybe I’m instantiating GH_ObjectWrapper wrong?

I would really appreciate any help on this matter as I’m trying to wrap my head around scripting with Kangaroo (side-question: Is there any kind of documentation on KangarooSolver.dll apart from the K2Goals GitHub?)

It is indeed a bit of a walk. As I recall, you have to first wrap a polyline in a GH_Curve, like so (this is old code and things have likely changed since):

"""
Make Kangaroo2 goals for shaping a cable element

    Inputs:
        Polylines: Polylines representing bending beam elements {list,polylinecurve}
        TargetLengths: Values representing the target length of each polyline {list,float,optional}
        SpringStrength: Spring strength i.e. spring/length goal for each edge {item,float}
    Outputs:
        G: Kangaroo2 goals representing behaviours {list,k2Goal}
    Remarks:
        Author: Anders Holden Deleuran
        License: Apache License 2.0
        Version: 160621
"""
ghenv.Component.Name = "ShapingCableGoals"
ghenv.Component.NickName = "SCG"
ghenv.Component.Category = "CM_FAHS"
ghenv.Component.SubCategory = "3 Shaping"

import clr
clr.AddReferenceToFile("KangarooSolver.dll")
import Rhino as rc
import KangarooSolver as ks
import Grasshopper.Kernel.Types as gkt

def makeCableElementGoals(curve,totalLength,strength):
    
    """ Make Kangaroo2 spring/show goals for defining a cable element """
    
    # Return list
    goals = []
    
    # Convert to polyline and get segments
    if type(curve) is not rc.Geometry.Polyline:
        polyline = curve.TryGetPolyline()[1]
    segs = polyline.GetSegments()
    
    # Calculate springs rest lengths
    if totalLength is not None:
        segL = totalLength / len(segs)
        restLengths = [segL for l in segs]
    else:
        restLengths = [l.Length for l in segs]
        
    # Calculate springs strength
    s = strength*len(segs)
    
    # Make spring goals
    for l,rl in zip(segs,restLengths):
        g = ks.Goals.Spring(l.From,l.To,rl,s)
        #g.Name = "cableSpring"
        goals.append(g)
        
    # Make show/locator goal for outputting polyline from solver
    ghCrv = gkt.GH_Curve(curve)
    gow = gkt.GH_ObjectWrapper(ghCrv)
    gl = ks.Goals.Locator(gow)
    goals.append(gl)
    
    return goals


# Make output list and fill it with goals
if Polylines and Polylines[0]:
    G = []
    for i,plc in enumerate(Polylines):
        if len(Polylines) == len(TargetLengths):
            goals = makeCableElementGoals(plc,TargetLengths[i],SpringStrength)
        else:
            goals = makeCableElementGoals(plc,None,SpringStrength)
        G.extend(goals)
else:
    G = []
1 Like

Wow Anders, thank you so much for the fast reply!

Although it’s old code, it works like a charm when first wrapping in a GH_Curve. Thank you for your insight and solution. I’ve been literally “inhaling” all your work regarding bending-active structures over the last few weeks :slight_smile:

1 Like

No worries, glad to hear its useful to someone :wink:

I’ve actually been meaning to update and share the pipelines we developed for the Smart Geometry and Advances in Architectural Geometry workshops back in 2016 (hard to believe it’s been three years!). Let me know if that would be helpful.

1 Like

I started to explore this stuff for my diploma-thesis (started off with research in knitting and somehow I’m here now…).
So I’ve been kind of reverse-engineering from your videos, forum-posts, DMS2015 paper, etc. how it might work and building kind of a rough, similar pipeline myself. Of course it’s still basic and a lot of stuff remains where I can’t wrap my head around at the moment – so I guess it would of course be helpful.

Anyway, I’ll continue fiddling for now. Thanks again for helping with this one, I might bother you again in the future :sweat_smile: