Using the Python ExtractSurface method on a specific face

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

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)

Awesome @Willem! This is really going to help.

Thanks,

Dan

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

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

It looks like this syntax is getting the max z value of these points. Is that correct? Could someone point me to a resource that explains how this works?

Thanks,

Dan

Not sure what you are wanting to do in this case (this is a 9 year old thread), but yes, it’s looking for the max Z value of the points collected for each face to be able to determine which is the “topmost” face in a brep.

Maybe you could post some more details about what information you are looking for?

Hello,

Yes, I recognize this is an old post, and should have been more clear.

With a list of Point3d if you declare:

topZ = mdlPts[0][2] 

What are the [0] and [2] doing?

I understand that if you just have

topZ = mdlPts[0] it will get the first item on the list. But what does adding the [2] do?

Thanks,

Dan

Accessing the Z coordinate of the Point3d instance.
More readable would be to write:

topZ = mdlPts[0].Z