How to ensure consistency of normal direction while using Network curves in RhinoPython?Scr

Hi everyone,

I am trying to figure use of NetworkSurface in Rhino using RhinoPython. Before moving to non-straight edge geometries, I am working on creating just a single rectangular surface. Please give your feedback on the issue.

While creating the surface, I am facing a trouble that the normal direction of the surface created does not remain consistent. I am also implementig a flag to flip the normal using the FlipNormal function if necessary but I would really like the normal direction to be consistent for a given NetworkSurface function call for a given order of curves/lines created.

See the code below. This if you run once will have normal in one direction. But delete that surface and say run again then it might end up having a flipped normal.

import rhinoscriptsyntax as rs

def srfCreate(P1=None,P2=None,P3=None,P4=None):
Line1 = rs.AddLine(P1,P2)
Line2 = rs.AddLine(P2,P3)
Line3 = rs.AddLine(P3,P4)
Line4 = rs.AddLine(P4,P1)
curves = {Line1,Line2,Line3,Line4}
Rectangle_obj = rs.AddNetworkSrf(curves,edge_tolerance=1e-5, interior_tolerance=1e-4,angle_tolerance=0)

if name == ‘main’:
P1=(0,0,0)
P2=(0,1,0)
P3=(1,1,0)
P4=(1,0,0)
normal_flag=‘FALSE’
srf1=srfCreate(P1,P2,P3,P4)
if(normal_flag):
rs.FlipSurface(srf1, normal_flag)

Hello - it looks like if your points are set in an order going around a rectangle, making the lines in opposite pairs allows you to control the normal by picking the points either clockwise or counter-clockwise.

import rhinoscriptsyntax as rs


def srfCreate():
    pts = rs.GetPoints(max_points=4)
    if not pts: return
    Line1 = rs.AddLine(pts[0],pts[1])
    Line2 = rs.AddLine(pts[3],pts[2])
    Line3 = rs.AddLine(pts[1],pts[2])
    Line4 = rs.AddLine(pts[0],pts[3])
    curves = [Line1,Line2,Line3,Line4]
    Rectangle_obj = rs.AddNetworkSrf(curves,edge_tolerance=1e-5, interior_tolerance=1e-4,angle_tolerance=0)
    
srfCreate()

But in general, there is not a good way to predict the normal direction of a surface - it probably makes sense to make a function that checks against some standard that you want and rearranges the surface U and V to get the normal headed in the right direction… why do you need this, btw?

-Pascal

1 Like

Hi Pascal,

Thank you for your prompt reply!

The code that you gave seems to work well. Thanks a lot!

Do you mind elaborating the part where one re-arranges the surface U and V? I didn’t quite understand the implementation you meant.

I am trying to automate surface creation if I have the points that I read from a text file using RhinoPython so that I can just change a line in text file and generate the geometry in Rhino.

Hello - something like this is what I was suggesting - if it works you don’t need to worry about how the surface is made, you can re-orient it as long as you have a direction vector that you can compare the normal to. This compares the World Z (0,0,1) with the normal at the middle of the surface domain - just by way of example.


import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import math

def NormalCheck(id, testVec):
    """
    Checks to see if a vector is more parallel or anti-parallel to another
    
    """
    pi = math.pi
    
    #get the surface domain and find the middle of U and V domains
    # as a 'useful' location to check the normal 
    domU = rs.SurfaceDomain(id, 0)
    domU = Rhino.Geometry.Interval(domU[0], domU[1])
    domV = rs.SurfaceDomain(id, 1)
    domV = Rhino.Geometry.Interval(domV[0], domV[1])
    parU = domU.Mid
    parV = domV.Mid
    
    # get the normal
    vecNorm = rs.SurfaceNormal(id,[parU, parV])
    print Rhino.Geometry.Vector3d.VectorAngle(testVec, vecNorm)
    
    #Check the angle against the test normal and return the result
    #for parallel-ness
    if Rhino.Geometry.Vector3d.VectorAngle(testVec, vecNorm) > pi/2:
        print False
        return False
    print True
    return True
    pass
    
    
def srfCreate():
    pts = rs.GetPoints(max_points=4)
    if not pts: return
    Line1 = rs.AddLine(pts[0],pts[1])
    Line2 = rs.AddLine(pts[3],pts[2])
    Line3 = rs.AddLine(pts[1],pts[2])
    Line4 = rs.AddLine(pts[0],pts[3])
    curves = {Line1,Line2,Line3,Line4}
    id = rs.AddNetworkSrf(curves,edge_tolerance=1e-5, interior_tolerance=1e-4,angle_tolerance=0)
    
    
    
    if not id: return
    rs.DeleteObjects(curves)
    
    # Check the angle of World Z with a surface normal
    if not NormalCheck(id, Rhino.Geometry.Vector3d(0,0,1)):
        #if it's not pointing more or less the same way, reverse U and V
        rs.ReverseSurface(id,4)
        srf = sc.doc.Objects.Find(id).Geometry.Faces[0]
        # make sure the flip flag is off
        rs.FlipSurface(id, False)
    pass
    
srfCreate()

Shifted to the scripting forum…

-Pascal

1 Like

Hi Pascal,

Thanks a lot. This is great!

The whole code as a whole makes sense (i.e. to flip the normal if the angle between Global Z and the normal vector is >pi/2, I hope. Please correct me otherwise) although I have some trouble understanding parts of the code.

For example,here:

rs.ReverseSurface(id,4) changes both U and V direction so am I correct in understanding the normal is also reversed?

If so, what role does rs.FlipSurface(id, False) play here?
and how about, srf = sc.doc.Objects.Find(id).Geometry.Faces[0] ?

Hello -

That makes sure that there is no flipped flag set - so the normal will follow the surface UV. The normal comparison (if I did it right) compares the natural normal, ignoring any flippedness.

That is bogus - I had it in there earlier, testing, but decided to stick with rs functions as much as possible - just take that out, looks like it’s not being used any more.

-Pascal

1 Like

Hi Pascal,

Thanks a lot!

:slight_smile:

Hi Pascal,

If you select multiple surfaces and opened polysurfaces, can you automatically convert the uniform normal direction?

Now I can only select the inverse object to perform the Flip command flipping it, if I can select all the objects to automatically switch to the same normal direction. This will be very quick.

Thanks

Hello -the script above will flip individual surfaces to match some known direction - in my example, the World Z direction, but if there is no direction to compare with, or if the surfaces are have inconsistent normals in 3d space at different locations on the surface - say on a half cylinder - then I do not see how to reliably set normal directions to what the user expects.

-Pascal

What is your suggestion?
Does this impossible?

Hello -

Well, my question is what is “this”? If this is making sure that some open planar objects that are not parallel to the test vector are facing either more with, or more away, compared to that direction, then yes, that is certainly possible. But as soon as you allow arbitrary shapes, I would say it becomes difficult to decide what direction you’re working with:

image

What can ‘uniform normal direction’ mean for a collection of surfaces like this?

-Pascal

Yes.
In addition to this special situation?