Normal vector problem in Python, Help Please

I am trying to write a Python script to iteratively calculate the normal vector at a specific point on a polysurface selected by the user.

I have written the code as follows, but it’s producing an error.

rs.SurfaceNormal used

import rhinoscriptsyntax as rs
def calculate_normal_at_points(polysurface_id):
    while True:
        # Prompt the user to select a point on the polysurface. Exit the loop if canceled.
        point = rs.GetPointOnSurface(polysurface_id, "Select a point to calculate the normal (Press Esc to cancel)")
        if not point:
            break
        # Calculate the normal vector at the selected point on the polysurface.
        normal = rs.SurfaceNormal(polysurface_id, point[2])
        if normal:
            print("Normal vector at the selected point:", normal)
        else:
            print("Unable to calculate the normal vector.")
#- Prompt the user to select a polysurface.
polysurface_id = rs.GetObject("Select a polysurface", rs.filter.polysurface)
if polysurface_id:
    calculate_normal_at_points(polysurface_id)

error Message

Message: unable to convert 16c2377c-91b6-4c7b-9661-86b5ebaa6002 into Surface geometry

Traceback:
  line 1026, in coercesurface, "C:\Users\jiny0\AppData\Roaming\McNeel\Rhinoceros\6.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\utility.py"
  line 2912, in SurfaceNormal, "C:\Users\jiny0\AppData\Roaming\McNeel\Rhinoceros\6.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\rhinoscript\surface.py"
  line 11, in calculate_normal_at_points, "C:\Users\jiny0\AppData\Local\Temp\TempScript.py"
  line 20, in <module>, "C:\Users\jiny0\AppData\Local\Temp\TempScript.py"

So, I changed the code from PolySurface to blep as follows.
But there’s another problem. Please help

Brep

import rhinoscriptsyntax as rs

def calculate_polysurface_normal(polysurface_id, point):
    brep = rs.coercebrep(polysurface_id)
    if brep:
        cp_result = brep.ClosestPoint(point)
        if cp_result[0]:
            face_index = cp_result[1].FaceIndex
            u, v = cp_result[2], cp_result[3]
            face = brep.Faces[face_index]
            normal = face.NormalAt(u, v)
            return normal
    return None

polysurface_id = rs.GetObject("select polysurface", rs.filter.polysurface)
if polysurface_id:
    point = rs.GetPointOnSurface(polysurface_id, "point for noraml")
    if point:
        normal = calculate_polysurface_normal(polysurface_id, point)
        if normal:
            print("normalvector:", normal)
        else:
            print("can't")
print(normal)
Message: 'float' object has no attribute 'FaceIndex'

Traceback:
  line 9, in calculate_polysurface_normal, "C:\Users\jiny0\AppData\Roaming\McNeel\Rhinoceros\6.0\scripts\LeoGem\brep .py"
  line 20, in <module>, "C:\Users\jiny0\AppData\Roaming\McNeel\Rhinoceros\6.0\scripts\LeoGem\brep .py"

What should I fix

I’d appreciate it if you could tell me a better way than this

You’re using the overload of Brep.ClosestPoint() that takes a single Point3d parameter and returns a single Point3d value.

To get the overload you want you’ll need to supply a second parameter (Double) for
maximumDistance.

This should get you close to what you want.

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

def calculate_polysurface_normal(polysurface_id, point):
    brep = rs.coercebrep(polysurface_id)
    if brep:
        cp_result = brep.ClosestPoint(point,maximumDistance=0)
    if cp_result[0]:
        normal = cp_result[5]
        if cp_result[2].ComponentIndexType == rg.ComponentIndexType.BrepFace:
            print(str.format("BrepFace (u,v) = {0}, {1}", cp_result[3], cp_result[4]))
        elif cp_result[2].ComponentIndexType == rg.ComponentIndexType.BrepEdge:
            print(str.format("BrepEdge (t) = {0}", cp_result[3]))
        return normal
    else:
        return None

polysurface_id = rs.GetObject("select polysurface", rs.filter.polysurface)
if polysurface_id:
    point = rs.GetPointOnSurface(polysurface_id, "point for noraml")
if point:
    normal = calculate_polysurface_normal(polysurface_id, point)
if normal:
    print("normalvector:", normal)
else:
    print("can't")

If you want to post python code in the future, please format your code by placing 3 backticks (```) on their own line above and below your code.

Like this:

-Kevin

2 Likes

"Hello, kevin
I’m so happy that thanks to you, my concern has been resolved.
Thank you for the quick and kind explanation.
Have a great day