Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps parameters

The first snippet might be a clue to the real problem below. It shows that the rs.ProjectPointToSurface command returns a Rhino.Geometry.Point3d[] object instead of a Python list. This is not difficult to deal with.

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

pointOnSurface = rg.Point3d(415.630,0.000,-263.990)
pointDirection = rg.Vector3d(0.0, 0.0, -1.0)
surface = rs.ObjectsByName(‘lower’)[0]

print(type(pointOnSurface))
print(type(pointDirection))
print(type(surface))

below = rs.ProjectPointToSurface([pointOnSurface], [surface], pointDirection)
print(below)

This code outputs:
<class ‘Rhino.Geometry.Point3d’>
<class ‘Rhino.Geometry.Vector3d’>
<class ‘System.Guid’>
Rhino.Geometry.Point3[]

Here is the code snippet that I am struggling with:

print( type(surface) )
print( type(pointOnSurface) )
print( type(pointDirection) )
print( type(tolerance) )
print(80*‘~’)

above = self.rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps([surface], [pointOnSurface], pointDirection, tolerance)

Here is the output of the code. What RhinoCommon lacks in simplicity it makes up for in error messages :slight_smile:

<class ‘Rhino.Geometry.Brep’>
<class ‘Rhino.Geometry.Point3d’>
<class ‘Rhino.Geometry.Vector3d’>
<class ‘float’>

Python.Runtime.PythonException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep]

The above exception was the direct cause of the following exception:

System.ArgumentException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep] in method Rhino.Geometry.Point3d[] ProjectPointsToBreps(System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep], System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Point3d], Rhino.Geometry.Vector3d, Double) ---> Python.Runtime.PythonException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep]
   --- End of inner exception stack trace ---

The above exception was the direct cause of the following exception:

System.AggregateException: One or more errors occurred. ---> System.ArgumentException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep] in method Rhino.Geometry.Point3d[] ProjectPointsToBreps(System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep], System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Point3d], Rhino.Geometry.Vector3d, Double) ---> Python.Runtime.PythonException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep]
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.ArgumentException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep] in method Rhino.Geometry.Point3d[] ProjectPointsToBreps(System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep], System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Point3d], Rhino.Geometry.Vector3d, Double) ---> Python.Runtime.PythonException: 'list' value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep]
   --- End of inner exception stack trace ---<---


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\mosaic\local\rhinoMemoryServer\adaptToolpath\adaptToolpath.py", line 901, in <module>
    AT.start(iniFilename)
  File "C:\mosaic\local\rhinoMemoryServer\adaptToolpath\adaptToolpath.py", line 703, in start
    result = self.processSingleFile(self.allValues['inputfolder'])
  File "C:\mosaic\local\rhinoMemoryServer\adaptToolpath\adaptToolpath.py", line 848, in processSingleFile
    result = self.pointUtilities.distanceSourceToTarget(self.pointList, sourceSurfaceId, targetSurfaceId)
  File "C:\mosaic\local\rhinoMemoryServer\rhinoUtilities\pointUtilities.py", line 264, in distanceSourceToTarget
    targetInt = self.getClosestIntersection(listofPoints, n, targetSurfaceId)
  File "C:\mosaic\local\rhinoMemoryServer\rhinoUtilities\pointUtilities.py", line 1019, in getClosestIntersection
    above = self.rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps([surface], [pointOnSurface], pointDirection, tolerance)
TypeError: No method matches given arguments for Intersection.ProjectPointsToBreps: (<class 'list'>, <class 'list'>, <class 'Rhino.Geometry.Vector3d'>, <class 'float'>)

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at UnsafeNativeMethods.CRhinoDoc_Delete(UInt32 serialNumber)
   at Rhino.RhinoDoc.Finalize()

Of course, the ScriptSyntax uses several “coerce” methods, but I think that the parameters for Geometry.Intersect.Intersection.ProjectPointsToBreps are correct. The error message seems to be complaining about a list or list value. Is it possible that the same issue about rs.ProjectPointToSurface() not returning a list mean that Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps is also not accepting a list?

Does the Python list of Point3d objects need to be a System.Array - which is a C# thing and I don’t know how to do that.

Thanks for your suggestions

Hi @Henry_Wede,

This seems to work:

#! python 3
import Rhino
import System;
import scriptcontext as sc

def __GetBreps():
    obj_type = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter
    rc, obj_refs = Rhino.Input.RhinoGet.GetMultipleObjects("Select surface and polysurfaces project onto", False, obj_type)
    if rc != Rhino.Commands.Result.Success:
       return
    breps = []
    for obj_ref in obj_refs:
        brep = obj_ref.Brep()
        if brep is None:
            return None
        breps.append(brep)            
    return breps

def __GetPoints():
    obj_type = Rhino.DocObjects.ObjectType.Point
    rc, obj_refs = Rhino.Input.RhinoGet.GetMultipleObjects("Select points to project", False, obj_type)
    if rc != Rhino.Commands.Result.Success:
       return
    locations = []
    for obj_ref in obj_refs:
        point = obj_ref.Point()
        if point is None:
            return None
        locations.append(point.Location)            
    return locations

def TestProjectPointsToBreps():
    points = __GetPoints()
    if points is None:
        return

    breps = __GetBreps()
    if breps is None:
        return

    direction = -Rhino.Geometry.Vector3d.ZAxis
    tol = sc.doc.ModelAbsoluteTolerance
    out_points = Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(breps, points, direction, tol)
    if out_points:
        print("Points projected: {}".format(len(out_points)))
        for p in out_points:
            sc.doc.Objects.AddPoint(p)
        sc.doc.Views.Redraw()

if __name__=="__main__":     
    TestProjectPointsToBreps()        

TestProjectPointsToBreps.py (1.5 KB)

Maybe this helps?

– Dale

1 Like

Thank you, Dale.

This gives me more information but I still have the same errors. I added a bunch of print statements to your code:

    direction = -Rhino.Geometry.Vector3d.ZAxis
    tol = sc.doc.ModelAbsoluteTolerance
    print(type(breps))
    print(type(breps[0]))
    print(breps[0].IsValid)
    print( len(breps) )
    print('=====================================')
    print(type(points))
    print(type(points[0]))
    print('=====================================')
    print(type(direction))
    print('=====================================')
    print(type(tol))
    out_points = Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(breps, points, direction, tol)

And it printed this:
<class ‘list’>
<class ‘Rhino.Geometry.Brep’>
True
1
=====================================
<class ‘list’>
<class ‘Rhino.Geometry.Point3d’>
=====================================
<class ‘Rhino.Geometry.Vector3d’>
=====================================
<class ‘float’>

I changed my code so that it is assembling the Python lists in the same way that your code does and added the same print statements:

		print( type(surface) )
		print( type(surface[0]) )
		print(surface[0].IsValid)
		print( len(surface) )
		print('=====================================')
		print( type(testPoints) )
		print( type(testPoints[0]) )
		print('=====================================')
		print( type(pointDirection) )
		print('=====================================')
		print( type(tolerance) )
		print(80*'~')

		#            Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(breps,   points,     direction,      tol)
		above = self.rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(surface, testPoints, pointDirection, tolerance)

As far as I can tell, it printed the same thing that your code printed.
<class ‘list’>
<class ‘Rhino.Geometry.Brep’>
True
1
=====================================
<class ‘list’>
<class ‘Rhino.Geometry.Point3d’>
=====================================
<class ‘Rhino.Geometry.Vector3d’>
=====================================
<class ‘float’>

I just don’t understand the error messages. The error below sounds like it is having trouble converting the list value to a Rhino.Geometry.Brep - but that is exactly what is in the list. It is the only object in the list. There must be something wrong with the “System.Collections.Generic.IEnumerable`1” part? What is the backtick doing in there?

Python.Runtime.PythonException: ‘list’ value cannot be converted to System.Collections.Generic.IEnumerable`1[Rhino.Geometry.Brep]

I am completely confused because it seems like both programs are sending the same object types to the same method but one of them acts differently.

This also works:

#! python 3
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

pointOnSurface = rg.Point3d(415.630,0.000,-263.990)
pointDirection = rg.Vector3d(0.0, 0.0, -1.0)
surface = rs.ObjectsByName("lower")[0]

print(type(pointOnSurface))
print(type(pointDirection))
print(type(surface))

below = rs.ProjectPointToSurface([pointOnSurface], [surface], pointDirection)
print(below)

brep = rs.coercebrep(surface)
above = rg.Intersect.Intersection.ProjectPointsToBreps([brep], [pointOnSurface], pointDirection, 0.01)
print(above)

– Dale

Yes, unfortunately this is going to run headless using RhinoInside.

If I had the time to do it over again, I would download all of the RhinoScriptSyntax code and somehow make a module so that I could use the same rs.Whatever functions and let it figure stuff out. That way the transition from rs to common would be trivial.

Any other ideas why I am getting different results?

Does that error make any sense to you C# experts?

This should have been the very first thing you said in your first message…

What are you running Rhino in?

– Dale

I’m really sorry about that, Dale - I will be using RhinoCommon from Python.

I expected that the RhinoCommon methods would behave the same way. What difference will there be from using a RhinoCommon method from RhinoInside vs the normal GUI?

I expected that if I am running a script from inside Rhino:

import scriptcontext as sc
import Rhino
theDocument = sc.Doc

And outside of Rhino:

import rhinoinside
rhinoinside.load()
import Rhino
theDocument = Rhino.RhinoDoc.CreateHeadless(None)

From that point on, any code will have access to Rhino + theDocument object and they should not care. Is this completely wrong?

Hi @Henry_Wede,

CPython in Rhino uses Python.NET for interoperability between Python and .NET.

– Dale

This is what I think I understand based on your reply - please tell me if I am wrong.

If we use RhinoCommon methods from the Rhino script editor, there is something behind the curtain that will take a Python list and convert it to a .NET IEnumerable. Life is easy.

If we use the same RhinoCommon method via rhinoInside, there is no mechanism that makes the conversion for us. In this case, all Python objects used for parameters have to be converted to their NET counterparts first.

Is this correct?

If so, then in order have code that will run correctly from both the Rhino script editor AND from rhinoInside we have to do all of the Python → NET conversions. Presumably this will work in the Rhino script editor (even though it is not required if the script would only be run from there).

At first glance, it seems that objects like Python strings and integers might be accepted as NET arguments(?). Not completely sure about that yet.

Cheers.

Seems reasonable.

For example:

import rhinoinside
rhinoinside.load(8, 'net7.0')
import System
import Rhino

points = System.Collections.Generic.List[Rhino.Geometry.Point3d]()
points.Add(Rhino.Geometry.Point3d(0.0, 0.0, 10.0))
points.Add(Rhino.Geometry.Point3d(2.0, 2.0, 10.0))
points.Add(Rhino.Geometry.Point3d(5.0, 5.0, 10.0))

extents = Rhino.Geometry.Interval(-12.0, 12.0)
plane = Rhino.Geometry.Plane.WorldXY
surface = Rhino.Geometry.PlaneSurface(plane, extents, extents)

breps = System.Collections.Generic.List[Rhino.Geometry.Brep]()
breps.Add(surface.ToBrep())

direction = -Rhino.Geometry.Vector3d.ZAxis
out_points = Rhino.Geometry.Intersect.Intersection.ProjectPointsToBreps(breps, points, direction, 0.001)
for pt in out_points:
    print(pt.ToString())

– Dale

1 Like

Hooray! I kind of understand something.

I’ll go through the code and make a couple conversion functions. I don’t there is really that many places where it needs to happen.

Thanks for your help.