Using the Python ExtractSurface method on a specific face


#1

I’m working on a project where I would like to extract the “top” surface exclusively. By top, I mean the face that is always visible looking down the Z axis. The objects that this will apply to will always be very “boxy” in nature, actually plates, usually full of holes.

Here is my question: How do I know which face indices I will need? Is there a way of knowing which of the many possible indices this will be? Can I manipulate it to be constant?

Thanks,

Dan


(Willem Derks) #2

Hi Dan,

I’m short in time right now so I just throw this at you:

Get the Objects
Itterate through each Brep’s faces and check:
If the face is planar.
If so get it’s frame(= plane)
check if the normal (z-axis)of that plane is equal to the vector 0,0,1
for this you can use the vector dot product

fwiw
here is a function i have for a script that does something similar.

def FindBrepPlane(Obj):
    Brep = rs.coercebrep(Obj)
    # if no Brtep passed
    if not Brep: return
    blnFound = False
    # get Brep Surfaces
    arrFaces = Brep.Faces
    arrSrfResult = []
    arrSrfArea = []
    for Face in arrFaces:
        # test face planarity
        if Face.IsPlanar(rs.UnitAbsoluteTolerance()):
            a,b = Face.Domain(0)
            u = (a+b)/2
            a,b  = Face.Domain(1)
            v = (a+b)/2
            # evaluate at domain center
            # point and Frame
            ptE= Face.Evaluate(u,v,0)[1]
            #Dan the plane for the face is below
            # if the plane passed the test, you can directly add this Face to the document from within RhinoCommon
            # I'm not sure yet how exactly I used to do that before
            arrPlane = Face.FrameAt(u,v)
                        
            
            if arrPlane[0] :
                blnFound = True
                #Area from face
                arrSrfArea.append (Rhino.Geometry.AreaMassProperties.Compute(Face).Area)
                arrSrfResult.append(arrPlane[1])
            else:
                arrSrfArea.append (None)
                arrSrfResult.append(None)
        else:
            arrSrfArea.append (None)
            arrSrfResult.append(None)

HTH
-Willem

In Addition here is -as a reference- a script to do what you maybe are trying to do in VBS:
instaal_ExtractUpFacingSubSurfaces_01.rvb (6.6 KB)


#3

Awesome @Willem! This is really going to help.

Thanks,

Dan


#4

Hi Dan,

I think the index depends on the way that solid was created (you had a planar drilled surface and then extruded it to create a solid; or you had a non-drilled solid - and then you drilled it…).
So the top face may not always have the same index.
If those drilled plates are always closed polysurfaces, then the top face normal will always point towards up (0,0,1).

If the drilled surface is not made of closed polysurface, that could mean that Rhino may not set the top face normal direction to (0,0,1) - meaning it could be (0,0,-1) as well.
In that case you could check the Z coordinate of of each surface. The largest one would belong to the top face:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

brep_id = rs.GetObject("pick your drilled solid")
brep_obj = rs.coercebrep(brep_id)
faces = brep_obj.Faces

mdlPts = []
domain0 = Rhino.Geometry.Interval(0,1)
domain1 = Rhino.Geometry.Interval(0,1)
for f in faces:
    duplF = f.DuplicateFace(False)
    f.SetDomain(0, domain0)
    f.SetDomain(1, domain1)
    mdlPts.append(f.PointAt(0.5, 0.5))

topZ = mdlPts[0][2]
faceI = 0
for i,pt in enumerate(mdlPts):
    if pt[2] > topZ:
        topZ = pt[2]
        faceI = i

sc.doc.Objects.AddBrep(brep_obj.Faces[faceI].DuplicateFace(False))
print faceI

#5

Hi @djordje

The drilled plates are always a closed polysurface, but they are imported from Solidworks. We bring them into Rhino for feature recognition and to create g-code for drilling.

Thank you for this script. This too, will prove very useful.

Take care,

Dan