How to repair this NURBS surfaces?

Hi,

after I imported a FBX model I got a lot of buggy NURBS surfaces. Is there a quick way to repair them? My current workflow: _UntrimBorder → set _KeepTrimObjects=yes, choose surface and untrim. Now trim the clean surface with the border curve again.

I tried _RebuildEdges, but it doesn’t help. Is there an other command to do it in one step?

-Micha


BuggySurface.3dm (78.3 KB)

IIRC @pascal had a script for that.

In general, something like this;
Duplicate boundary curves.
Untrim surface.
Retrim surface using the boundary curves.

2 Likes

Here’s a quick py version…

RetrimSrf.py (1.4 KB)

To use the Python script use RunPythonScript, or a macro:

_-RunPythonScript "Full path to py file inside double-quotes"

-Pascal

2 Likes

Sorry, I should have read your entire post…

No problem, thanks for trying to help. :slight_smile:

1 Like

Hi @pascal,

today I run in the situation again and try to repair the attached surface per script, but nothing happens. I have a lot of this surfaces in my model. Do you know a solution?

Best -
Micha

! _-RunPythonScript (

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import System.Collections.Generic.IEnumerable as IEnumerable 
import System.Double as sd

"""
Get the 3d edge curves that you will be splitting with. 
Reverse any that come from reversed trims.  
Split with those curves.  
Now the face that you want to keep will 
not have any reversed trims.

"""
def RetrimSrf():
    tol = sc.doc.ModelAbsoluteTolerance
    
    id = rs.GetObject(filter = 8, preselect=True)
    if not id: return
    
    brep = rs.coercebrep(id)
    bb = brep.GetBoundingBox(True)
    
    face = brep.Faces[0]
    edges = brep.Edges
    trims = brep.Trims

    crvs =[]
    for i in range(edges.Count):
        crv = edges[i].ToNurbsCurve()
        if trims[i].IsReversed():
            crv.Flip()
        crvs.append(crv)
        pass
    x = trims[0].IsReversed()
    srf = face.UnderlyingSurface()

    temp = srf.ToBrep()
    tFace = temp.Faces[0]

    newBrep  = tFace.Split(crvs, tol)

    for brepFace in newBrep.Faces:
        rev = False
        
        for trim in brepFace.OuterLoop.Trims:
            if trim.IsReversed():
                rev = True
                break
        if rev:
            continue
        else:
            sc.doc.Objects.Replace(id, brepFace.DuplicateFace(False))
        
    sc.doc.Views.Redraw()
    
    
if __name__== '__main__':RetrimSrf()

)

InvisibleSurface.3dm (70.5 KB)

Hi Micha - it works here - here is the version of the script that I am using -
RetrimSrf.py (2.6 KB)

-Pascal

1 Like

Hi Pascal,

thank you very much for your help. :slight_smile:

I started your latest script per
_-RunPythonScript "Full path to py file inside double-quotes"
and it works fine.

General I try to keep scripts within toolbar buttons (for easier update and transportation to new Rhino versions) and I wonder why your script doesn’t work if I copy the py code within () of this code. Do you see an aspect I have overseen - complete copy at the end of the post. This version makes nothing, no retrim, no messages and no errors.

Often only some surfaces of a polysurface needs a retrim. Could you modify the script for cleaning polysurfaces too please?

-Micha

! _-RunPythonScript (
import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs

def BBCompare(BB1,BB2):
    #BB2 = original
    tol = sc.doc.ModelAbsoluteTolerance
    x = BB1.Min.DistanceTo(BB2.Min)
    #rs.AddPoints([BB1.Min,BB2.Min])
    y = BB1.Max.DistanceTo(BB2.Max) 
    if BB1.Min.DistanceTo(BB2.Min)< tol:
        if BB1.Max.DistanceTo(BB2.Max)< tol:
            #print "BBTrue"
            return True  
    return False
    
def MaxEdgeTol(brep):
    eTol = 0
    
    for edge in brep.Edges:
        if edge.Tolerance > eTol: eTol=edge.Tolerance
    return eTol
    
def MaxVerTol(brep):
    vTol = 0
    
    for v in brep.Vertices:
        if v.Tolerance > vTol: vTol=v.Tolerance
    return vTol


def RetrimSrf():
    tol = sc.doc.ModelAbsoluteTolerance
    
    id = rs.GetObject("Select a surface to retrim.", 8, preselect=True, select=True)
    
    if not id: return
    
    brep = sc.doc.Objects.Find(id).Geometry
    if isinstance( brep,Rhino.Geometry.Extrusion): brep = brep.ToBrep()
    
    tolStr = None
    outTol= False
    
    if not brep.IsValid:
        eTol = MaxEdgeTol(brep)
        
        #vTol = MaxVerTol(brep)
        
        tolStr = " Object is not valid."
        outTol= False
        if eTol >= tol:
            tolStr = tolStr + " Edge tolerances = " + str(round(eTol, 6)) + " This is larger then the file tolerance."
            outTol=True
    #        if vTol >= tol: 
    #            tolStr = tolStr + "Vertex tolerances = " + str(vTol)
    #            outTol=True
        

    
    bb = brep.GetBoundingBox(True)
    #sc.doc.Objects.AddBrep(bb.ToBrep())
    trims = brep.Trims
    
    crvs = brep.DuplicateEdgeCurves()

    face = brep.Faces[0]
    
    srf = face.UnderlyingSurface()
    
    brep2 = srf.ToBrep()
    
    face2 = brep2.Faces[0]
    
    brep2 = face2.Split(crvs, tol)

    #sc.doc.Objects.AddBrep(brep2)
    
    newBrep=None
    #brep2.Faces.ShrinkFaces() 
    for face in brep2.Faces:
        temp = face.DuplicateFace(False)
        tempBB = temp.GetBoundingBox(True)
        #sc.doc.Objects.AddBrep(tempBB.ToBrep())
        if BBCompare(tempBB, bb):
            newBrep = face.DuplicateFace(False)
            break
    
    
    failStr = "Failed to retrim the surface."
    if outTol:
        failStr = failStr + tolStr
    if newBrep is not None:
         sc.doc.Objects.Replace(id, newBrep)
         print "The surface was successfully retrimmed."
         return
    print failStr
    pass
    
if __name__ == "__main__":
    RetrimSrf()
)

replace that by:

RetrimSrf()

so without the check if the function is called as main function

1 Like

Hi @Gijs, thank you for the hint, it works now. :slight_smile:

Do you or @pascal see a way to fix polysurfaces?

depends on what’s wrong with them

It’s the same problem like above which can be fixed per the script from Pascal. Only it’s not so easy to explode the polysurface, start the script and look for the critical surface. Or would the script be to slow for a polysurface, if all surfaces would be retrimmed?

Attached an example polysurface.

InvisibleSurfaceOfPolysurface.3dm (938.6 KB)

if I run _ExtractBadSrf I get a lot of flagged ones:
So I think it is worthwhile to see if you can ask your customer to try different exporting options and see if that gives you better surfaces.

Also I noticed that your file has a very rough tolerance setting of 0.1mm, is this your setting or the result of opening the file you got from your customer in Rhino? In what program was the file made?

You can use this after extracting the bad surfaces, so that you can apply the script on multiple surfaces at once:

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs

def BBCompare(BB1,BB2):
    #BB2 = original
    tol = sc.doc.ModelAbsoluteTolerance
    x = BB1.Min.DistanceTo(BB2.Min)
    #rs.AddPoints([BB1.Min,BB2.Min])
    y = BB1.Max.DistanceTo(BB2.Max) 
    if BB1.Min.DistanceTo(BB2.Min)< tol:
        if BB1.Max.DistanceTo(BB2.Max)< tol:
            #print "BBTrue"
            return True  
    return False
    
def MaxEdgeTol(brep):
    eTol = 0
    
    for edge in brep.Edges:
        if edge.Tolerance > eTol: eTol=edge.Tolerance
    return eTol
    
def MaxVerTol(brep):
    vTol = 0
    
    for v in brep.Vertices:
        if v.Tolerance > vTol: vTol=v.Tolerance
    return vTol


def RetrimSrf():
    tol = sc.doc.ModelAbsoluteTolerance
    
    ids = rs.GetObjects("Select surfaces to retrim.", 8, preselect=True, select=True)
    
    if not ids: return
    for id in ids:
        brep = sc.doc.Objects.Find(id).Geometry
        if isinstance( brep,Rhino.Geometry.Extrusion): brep = brep.ToBrep()
    
        tolStr = None
        outTol= False
        
        if not brep.IsValid:
            eTol = MaxEdgeTol(brep)
            
            #vTol = MaxVerTol(brep)
            
            tolStr = " Object is not valid."
            outTol= False
            if eTol >= tol:
                tolStr = tolStr + " Edge tolerances = " + str(round(eTol, 6)) + " This is larger then the file tolerance."
                outTol=True
        #        if vTol >= tol: 
        #            tolStr = tolStr + "Vertex tolerances = " + str(vTol)
        #            outTol=True
        

    
        bb = brep.GetBoundingBox(True)
        #sc.doc.Objects.AddBrep(bb.ToBrep())
        trims = brep.Trims
        
        crvs = brep.DuplicateEdgeCurves()

        face = brep.Faces[0]
        
        srf = face.UnderlyingSurface()
        
        brep2 = srf.ToBrep()
        
        face2 = brep2.Faces[0]
        
        brep2 = face2.Split(crvs, tol)
    
        #sc.doc.Objects.AddBrep(brep2)
        
        newBrep=None
        #brep2.Faces.ShrinkFaces() 
        for face in brep2.Faces:
            temp = face.DuplicateFace(False)
            tempBB = temp.GetBoundingBox(True)
            #sc.doc.Objects.AddBrep(tempBB.ToBrep())
            if BBCompare(tempBB, bb):
                newBrep = face.DuplicateFace(False)
                continue
    
    
        failStr = "Failed to retrim the surface."
        if outTol:
            failStr = failStr + tolStr
        if newBrep is not None:
             sc.doc.Objects.Replace(id, newBrep)
             print "The surface was successfully retrimmed."
             continue
        print failStr
        pass
    
RetrimSrf()

Thank you very much Gijs, the script is a big helper now. :smiley:

Also thank you for the background info so I can try to get better models in the future. My client isn’t creating the model, he got the model by his client, so I don’t have a direct contact to the model creator. But your information are very detailed and I hope to get them to them to the source creator.

Have a nice day,
Micha

1 Like