Problem getting normal mesh rhinocommon

I am doing something wrong. I am trying to get a mesh normal through python.
Do you might know how to do that?

Thank you in advance for your response. :slight_smile:

problem getting normal mesh 00.gh (18.9 KB)

I tried python… failed :sweat_smile:
Go C# .
It might seems more complex but it is much more cleaner and precise, and overall i think is better integrated with C# .
problem getting normal mesh 00_V2.gh (14.5 KB)

private void RunScript(Mesh M, Point3d P, ref object N)
{
Rhino.Geometry.Point3d P2;
Rhino.Geometry.Vector3d vec;
int face_index = M.ClosestPoint(P, out P2, out vec, 9999999);
N = vec;
}

2 Likes

with python.

import Rhino as rc

#rc.Geometry.Mesh.NormalAt

mcp = rc.Geometry.Mesh.ClosestMeshPoint(x, y, 0.01)
print mcp.FaceIndex
print rc.Geometry.Mesh.NormalAt(x, mcp.FaceIndex, mcp.T[0], mcp.T[1],mcp.T[2],mcp.T[3])

https://developer.rhino3d.com/api/RhinoCommon/html/P_Rhino_Geometry_MeshPoint_T.htm
Note: the example I posted does not do any face checking, (quad vs triangle).

1 Like

this is a little simpler…

import Rhino as rc

mcp = rc.Geometry.Mesh.ClosestMeshPoint(x, y, 0.01)
a = rc.Geometry.Mesh.NormalAt(x, mcp)
b = mcp.Point
4 Likes

Just for completeness: You can implement Mesh.ClosestPoint without getting into StrongBox overload territory. The second overload can be implemented like so:

fid,MPt = M.ClosestPoint(Pt,T)
MN = M.FaceNormals[fid]

190921_ProblemGettingNormalMesh_AHD_00.gh (11.4 KB)

In this case it probably does make more sense to implement Mesh.ClosestMeshPoint though, as it returns all the information you’re looking for. If I recall, this is more expensive though (if that’s a parameter).

2 Likes

For complete completeness: I just tried implementing in GHPython the same overload as Riccardo did in C#. And there appears to be a slight difference in the normal that it returns (i.e. that is different from the one returned by Grasshoppers Face Normals component and the method I posted above):

190921_ProblemGettingNormalMesh_AHD_01.gh (19.2 KB)

This is true even for a triangulated mesh, where I would expect the normal returned to be equal to the face normal. Perhaps it operates on vertex normals somehow? Anywho, just something to be aware of.

Update: The third overload (i.e. using StrongBox i.e. the same one as Riccardo used) does indeed appear to return ~the same normal as Mesh Closest Point with Mesh Eval in Grasshopper:

Which is the same normal as with the method Chris posted. So I’ll go have some more coffee now :coffee:

4 Likes

Thank you :smiley:
Thank you :smiley:

Do you might know what I did wrong in these settings (both made with python)?

  1. I am not able to align the plane onto the mesh surface.
  2. Sometimes the points does not project onto the meshes when moving the meshes.

problem project points 01.gh (20.6 KB)


from ghpythonlib import treehelpers
import Rhino as rc

tolerance=sc.doc.ModelAbsoluteTolerance

projected_pts = []
pt_normals = []

for mesh in mshs:
    mesh.FaceNormals.ComputeFaceNormals()
    closest_pts = []
    pt_vecs = []
    for pt in pnts:
        mesh_pt = mesh.ClosestMeshPoint(pt, 0.0)
        vec = mesh.NormalAt(mesh_pt)
        closest_pts.append(mesh_pt.Point)
        pt_vecs.append(vec)
    projected_pts.append(closest_pts)
    pt_normals.append(pt_vecs)

projectedpnts = treehelpers.list_to_tree(projected_pts)
pntsnrmls = treehelpers.list_to_tree(pt_normals)
1 Like

Thank you :smiley:
Thank you :smiley:

rc.Geometry.Intersect.Intersection.ProjectPointsToMeshes(mshs,pnts,rc.Geometry.Vector3d(0,0,10),tolerance)

I want to do project? Do you know why this code does not work in my script?

EDIT: I now tried this, but, unfortunately,
It does not project the points along the z-axis nor does it ‘only project the points along the z-axis.’
Do you know what I am doing wrong?

problem project points 03.gh (25.5 KB)

When projecting points, the points do not appear to be projected in a straight line. Do you might know what I am doing wrong?
problem project points 04.gh (22.1 KB)

Does curve mesh intersection exists in rhinocommon or rhinosyntax? I cannot find it.

Good morning,

Hm, I have no clue, but here’s an alternative using mesh ray intersections and Bowie:

from ghpythonlib import treehelpers
import Rhino as rc


projpnts = []
projnmls=[]
projdirs = []

# Ground control to Major Tom...

for mesh in mshs:
    # ... take your protein pills and put your helmet on!
    mesh.FaceNormals.ComputeFaceNormals()
    # Commencing coundown... engines on...
    # Check ignition and may GH gods love be with you.
    # 6, 5, 4, ...
    dir_vec = rc.Geometry.Vector3d.ZAxis
    # ... and I think my spaceship knows which way to go-o-o-o...
    
    proj_pts = []
    ppts_nmls = []
    proj_dirs = []
    
    for pt in pnts:
        # 3, 2, 1, lift off!
        ray = rc.Geometry.Ray3d(pt, dir_vec)
        t = rc.Geometry.Intersect.Intersection.MeshRay(mesh, ray)
        
        # Ground control, to Major Tom! 
        # Your circuits dead!! There's something wrong...
        
        if t < 0: 
            dir_vec.Reverse()
            ray = rc.Geometry.Ray3d(pt, dir_vec)
            t = rc.Geometry.Intersect.Intersection.MeshRay(mesh, ray)
        
        # Can you hear me, Major Tom? Can you hear me, Major Tom?
        
        if t >= 0:
            proj_pt = ray.PointAt(t)
            mesh_pt = mesh.ClosestMeshPoint(proj_pt, 0.0)
            normal = mesh.NormalAt(mesh_pt)
            normal.Unitize() 
            proj_pts.append(proj_pt)
            ppts_nmls.append(normal)
            proj_dirs.append(dir_vec)
        
        # Here I am floating in my tin can, far above the moon!
        # And there's nothing I can do...
        else: 
            proj_pts.append(None)
            ppts_nmls.append(None)
            proj_dirs.append(None)
         
    projpnts.append(proj_pts)
    projnmls.append(ppts_nmls)
    projdirs.append(proj_dirs)


a = treehelpers.list_to_tree(projpnts)
b = treehelpers.list_to_tree(projnmls)
c = treehelpers.list_to_tree(projdirs)

problem project points 05 space oddity remix.gh (16.8 KB)

2 Likes

2 Likes

Here you can investigate which geometries can be intersected in rhinocommon. Make sure to dive into the reference for Intersection under Classes. Nothing more will be available in rhinoscriptsyntax, since it’s based on the API in the first place, but it might be more straightforward to use for beginners.

For meshes specifically, there’s MeshLine, MeshMeshAccurate, MeshMeshFast, MeshPlane, MeshPolyline, and the above used MeshRay. So to answer your question, mesh-curve-intersections don’t seem to be available, if the curve is not a line or polyline object.

When you use mesh-curve-intersection in rhinoscriptsyntax (i.e. rs.CurveMeshIntersection()) or Grasshopper (i.e. Mesh | Curve), what probably happens behind the scenes is that first your input curve gets converted to a polyline, before being intersected with the mesh, on success.

Example:

import Rhino.Geometry as rg

tolerance = 0.01
polyline_curve = curve.ToPolyline(0, 0, 0, 0, 0.0, tolerance, 0.0, 0.0, True)
pts, face_ids = rg.Intersect.Intersection.MeshPolyline(mesh, polyline_curve)

if not pts:
    print "No intersection!"

pts = list(pts) # array to list
face_ids = list(face_ids) # array to list
2 Likes