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?
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)
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
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.
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?
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?