Dictionaries returned instead of geometry

Have found a couple of calls that don’t return the geometry the docs say they will, they return dictionaries instead.

NurbsSurface.CreateNetworkSurface(…) and Curve.CreateFillet(…) are the two I’m aware of.

CreateFillet can be worked around by using Util.DecodeToPoint3d afterwards to recreate the arc, but I can’t find a way to do something similar for CreateNetworkSurface - does anyone have any ideas?

Based on here https://compute-rhino3d.readthedocs.io/en/latest/NurbsSurface.html a (list of) NurbsSurface is expected:

But what is actually returned is this (list of) dictionary:

[{‘version’: 10000,
‘archive3dm’: 60,
‘opennurbs’: -1912309747,
‘data’: ‘+n8CAPEQAAAAAAAA+/8CABQAAAAAAAAAF8hgR+ML1BG//gAQgwEi8Ksojr78/wIAuRAAAAAAAAAQAwAAAAAAAAAEAAAABAAAAAYAAAAbAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9HSBclX…
< snipped >
…Xrm4PiDOZQHCDGe7d5uVAHwG6/01EZEB9WFAQ47yZQAAAAAAAduZAAAAAAAAAAAAAAAAAAPCZQE2T/9L/fwKAAAAAAAAAAAA=’},
0]

Does anyone have any suggestions? Is there a way I can get a surface from the data value in the dictionary above?

HI @fergus.hudson,

You need to post at least a relevant example of your code (and geometry)! How can anybody help you otherwise? At this point, it’s pretty much just guessing what your issue is, which - when I’m wrong - was a waste of my time and yours.

Have you already tried something like this?

import rhino3dm
import compute_rhino3d

compute_rhino3d.Util.authToken = ""
#compute_rhino2d.Util.url = ""

model = rhino3dm.File3dm()

# ...
# Your mysterious code 
# ...

srf = compute_rhino3d.NurbsSurface.CreateNetworkSurface(…)
if srf is not None:
    model.Objects.AddSurface(srf)

model.Write("test.3dm", 5)

Hi diff, here’s a piece of code I’m running to test this:

import os
import compute_rhino3d.NurbsSurface
import rhino3dm

if os.environ.get('userdomain') == "":
    internal_proxy_address = ""
    os.environ["HTTP_PROXY"] = f"{internal_proxy_address}:x"
    os.environ["HTTPS_PROXY"] = f"{internal_proxy_address}:x"

compute_rhino3d.Util.apiKey = ""
compute_rhino3d.Util.url = ""   

pt0 = rhino3dm.Point3d(0,0,0)
pt1 = rhino3dm.Point3d(10,0,0)
pt2 = rhino3dm.Point3d(0,10,0)
pt3 = rhino3dm.Point3d(10,10,0)
pt4 = rhino3dm.Point3d(5,0,0)
pt5 = rhino3dm.Point3d(5,10,0)

l1 = rhino3dm.LineCurve(pt0, pt1)
l2 = rhino3dm.LineCurve(pt0, pt2)
l3 = rhino3dm.LineCurve(pt3, pt1)
l4 = rhino3dm.LineCurve(pt3, pt2)
l5 = rhino3dm.LineCurve(pt4, pt5)


crvs = [ l1, l2, l3, l4, l5 ]

surfs = compute_rhino3d.NurbsSurface.CreateNetworkSurface1( crvs, 0, 1, 1, 1, False )               

print(surfs)

and the output:
[{'version': 10000, 'archive3dm': 60, 'opennurbs': -1912047459, 'data': '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'}, 0]

Look at my example above! You need to specify a model, add the network surface to it and at the end write it out.

I realise that, the issue is that CreateNetworkSurface1 doesn’t return a NurbsSurface, it returns the dictionary in the list shown in my post above. It can’t be added to the model, because it isn’t a rhino3dm.Surface, nor rhino3dm.GeometryBase.

CreateNetworkSurface1 returns the wrong type. I’m wondering if anyone has a workaround to use until this is fixed. There’s a similar situation with Curve.CreateFillet, and for that there is a workaround, which is using Util.DecodeToPoint with the coordinates that are returned in the dictionary there.

You are getting a list. The data in the list you are getting is in JSON format, which looks like a dictionary.

See this post SQLite in RhinoPython with a snippet by @efestwin how to deserialize this in Python.

1 Like

The return type should be NurbsSurface according to the docs. I had tried to deserialise this using compute_rhino3d.Util.DecodeToCommonObject before creating this thread but, somehow, I must have been doing it wrong, because just now when doing it again so I could post my results here - it works.

The code including deserialisation:

import os
import compute_rhino3d.NurbsSurface
import rhino3dm
import compute_rhino3d.Util

if os.environ.get('userdomain') == "":
    internal_proxy_address = ""
    os.environ["HTTP_PROXY"] = f"{internal_proxy_address}:x"
    os.environ["HTTPS_PROXY"] = f"{internal_proxy_address}:x"

compute_rhino3d.Util.apiKey = ""
compute_rhino3d.Util.url = ""   

pt0 = rhino3dm.Point3d(0,0,0)
pt1 = rhino3dm.Point3d(10,0,0)
pt2 = rhino3dm.Point3d(0,10,0)
pt3 = rhino3dm.Point3d(10,10,0)
pt4 = rhino3dm.Point3d(5,0,0)
pt5 = rhino3dm.Point3d(5,10,0)

l1 = rhino3dm.LineCurve(pt0, pt1)
l2 = rhino3dm.LineCurve(pt0, pt2)
l3 = rhino3dm.LineCurve(pt3, pt1)
l4 = rhino3dm.LineCurve(pt3, pt2)
l5 = rhino3dm.LineCurve(pt4, pt5)


crvs = [ l1, l2, l3, l4, l5 ]

surfs = compute_rhino3d.NurbsSurface.CreateNetworkSurface1( crvs, 0, 1, 1, 1, False )               

print( compute_rhino3d.Util.DecodeToCommonObject( surfs[0] ) )

Ouput:

<rhino3dm._rhino3dm.NurbsSurface object at 0x00000184D3A32030>
1 Like

I can appreciate how this could be confusing given that the docs say that the function simply returns a NurbsSurface. The reason you get a list instead is that the RhinoCommon method, CreateNetworkSurface(), that is being called behind the scenes also has an out param – an integer representing the error “code”. Since out params are a .NET thing, the python client returns them along with the actual return value, as a list.

A good way to handle this clearly in your python code might be to use multiple assignment (a.k.a. destructuring assignment) to decompose the returned list into separate variables.

surf_obj, e = compute_rhino3d.NurbsSurface.CreateNetworkSurface1(crvs, 0, 1, 1, 1, False)
# TODO: check the value of e
surf = compute_rhino3d.Util.DecodeToCommonObject(surf_obj)
print(srf)
1 Like

Thanks Will. It was having to decode the json that had been the sticking point (and that’s what I meant by “incorrect”).

Anyway, all is good on this now, thanks!

Well, we should be decoding the data to geometry in the python client library…

You’re right! I guess the client generator needs to be updated to handle cases like this. Logged as mcneel/compute.rhino3d#151