Point-On-BRep selection

Hi Everyone -
Trying to write a plugin (C#) which performs analysis on a point on a surface selected by the user. I’d like to use all possible surface types - surface (untrimmed=surface, trimmed=brep), polysurface (brep with multiple faces), extrusion (converted to brep with multiple faces), and so on (coming later since they’re so different: mesh (mesh faces), groups, blocks, etc…). Anyways starting with surface and brep.

Here’s where I start: (with a little editing, hopefully nothing is missing)

                 ObjRef initSrf = null;
                 doc.Objects.UnselectAll();
                 GetObject selectObjs = new GetObject();
                 selectObjs.SetCommandPrompt("Select Surface");
             ObjectType geoFilter = ObjectType.Surface | 
                 //ObjectType.PolysrfFilter |
                 ObjectType.Mesh |
                 ObjectType.Brep |
                 ObjectType.Extrusion |
                 ObjectType.SubD;
                 selectObjs.GeometryFilter = geoFilter;
                 selectObjs.Get();
                 if (selectObjs.CommandResult() != Result.Success) return selectObjs.CommandResult();
                 RhinoApp.WriteLine("G " + selectObjs.Object(0).Object().ToString());
                 initSrf = selectObjs.Object(0);
             GetPoint bouncePoint = new GetPoint();
             bouncePoint.SetCommandPrompt("Pick the point on the surface");
             switch (initSrf.Object().ObjectType)
             {
                 case ObjectType.Brep:
                 case ObjectType.Surface:
                     RhinoApp.WriteLine("# of faces: {0}",initSrf.Brep().Faces.Count);
                     bouncePoint.Constrain(initSrf.Brep(), -1, -1, false);
                     break;
                 case ObjectType.Extrusion:
                     Extrusion extru = initSrf.Object().Geometry as Extrusion;
                     newbrep = extru.ToBrep();
                     RhinoApp.WriteLine("# of extrusion faces: {0}", newbrep.Faces.Count);
                     bouncePoint.Constrain(newbrep, -1, -1, false);
                     break;
             }
             bouncePoint.Get();
             if (bouncePoint.CommandResult() != Result.Success) return bouncePoint.CommandResult();
             Point3d srfPoint = bouncePoint.Point();
             double[] firstPoint = new double[2];
             Vector3d firstNormal = new Vector3d();
             switch (initSrf.Object().ObjectType)
             {
                 case ObjectType.Brep:
                     BrepFace face = bouncePoint.PointOnBrep(out firstPoint[0], out firstPoint[1]);
 
                     if (face == null)
                     {
                         RhinoApp.WriteLine("face is null?");
                     }
                     RhinoApp.WriteLine("U = {0}, V = {1}", firstPoint[0], firstPoint[1]);
                     RhinoApp.WriteLine("brep face " + face.ToString());
                     firstNormal = face.NormalAt(firstPoint[0], firstPoint[1]);
                     if (face.OrientationIsReversed) firstNormal.Reverse();
                     firstRotate = Transform.Rotation(Math.PI, firstNormal, srfPoint);
                     doc.Objects.Transform(firstRay, firstRotate, false);
                     doc.Views.Redraw();
                     break;
                 case ObjectType.Mesh:
                     Dialogs.ShowMessage("Mesh not working yet", "no mesh");
                     return Result.Failure;
             }
 
             return Result.Success;
         }
     }

The problem seems to be that bouncePoint.PointOnBrep(out u, out v); always returns null. I get the u and v parameters of the surface I just don’t know which brep face’s parameters are being returned.

I can start the switch another way, which is successful for a single, untrimmed (i.e. pure) surface (which is still shown as a brep, not a surface in the RhinoApp.WriteLine ("G " + selectObjs.Object(0).Object().ToString()); output):

            switch (initSrf.Object().ObjectType)
            {
                case ObjectType.Brep:
                    BrepFace face = initSrf.Face();
                    bouncePoint.PointOnBrep(out firstPoint[0], out firstPoint[1]);

I might be able to boil this down to one item: under what condition does GetPoint.PointOnBrep return the BrepFace? (searching for “PointOnBrep” has precious few returns, maybe no-one is using it?)

If there’s other, better ways to work with polysurface component pieces (and later, meshes), I’m open to suggestions. Thanks.

Hi @Daniel_Beckmann,

From the documentation for PointOnBrep() it looks there is no way to get out which face the point was on.

Maybe try using Brep.ClosestPoint() instead, see: https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Brep_ClosestPoint_1.htm

For the overhead of one additional method call, you get back a ComponentIndex which you can query for the *Face Index, see https://developer.rhino3d.com/api/RhinoCommon/html/P_Rhino_Geometry_ComponentIndex_Index.htm

Thanks, @lando.schumpich.

I thought the documentation for PointOnBrep said that the face was returned, were you looking at a different document?

Parameters

u

Type: System.Double
If the point was on a Brep face, then the u parameter.

v

Type: System.Double
If the point was on a Brep face, then the v parameter.

Return Value

Type: BrepFace
The Brep face or null if the point was not on a Brep face.

I’ve been thinking about ClosestPoint() too, fortunately it returns the normal as you pointed out, saving a couple of method calls; maybe I won’t need the ComponentIndex.

Hi @Daniel_Beckmann,

You are right, i misread the documentation.

I did some small tests and see the same behaviour with PointOnBrep() always returning None for the FaceIndex.

@dale, can you take a look? here is my minimal example, maybe we are both missing something obvious here…:

import Rhino
import scriptcontext as sc

def testGetPointOnBrep():
    
    result, objRef = Rhino.Input.RhinoGet.GetOneObject("Pick polysurface", False, Rhino.DocObjects.ObjectType.Brep)
    if result != Rhino.Commands.Result.Success:
        return result
        
    picked = objRef.Brep()
    if not picked: return
    
    gp = Rhino.Input.Custom.GetPoint()
    gp.SetCommandPrompt("Pick Point")
    gp.Constrain(picked, -1, -1, False)
    
    gp.Get()
    
    if gp.CommandResult() != Rhino.Commands.Result.Success:
        return gp.CommandResult()
        
    print gp.PointOnBrep()
    
if __name__ == "__main__":
    testGetPointOnBrep()

Hi @lando.schumpich,

Yes, I see this. I’ve logged the issue:

https://mcneel.myjetbrains.com/youtrack/issue/RH-57874

As a work around, use the point returned by GetPoint as the argument to Brep.ClosestPoint.

Thanks,

– Dale

Hi @dale - thanks for looking into it
Dan