How to select bottom surfaces

Hello everyone
I’m trying to develop a simple python plugin which draws a sort of “halo” around the bottom surface of a polysurface ( I’ll use that to avoid nesting objects too close to each other )

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

def Halo():
    OBJ = rs.GetObjects("Select objects to nest:", 16, False, True, True, True)
    if not OBJ: return
    
    for ObjId in OBJ:
        Surfaces = rs.ExtractSurface(ObjId, 0, True)
                
        for SrfId in Surfaces:
            Edges = rs.DuplicateEdgeCurves(SrfId)
            rs.DeleteObject(SrfId)
            JoinedEdges = rs.JoinCurves(Edges)
            rs.DeleteObjects(Edges)
            
            for EdgeId in JoinedEdges:
                col = rs.CreateColor(255,0,0)
                Direction = (1000,1000,1000)
                OffsetEdges = rs.OffsetCurve(EdgeId, Direction, 20)
                rs.DeleteObjects(EdgeId)
                
                for OEId in OffsetEdges:
                    rs.ObjectColor(OEId, col)
                    Grp = rs.AddGroup()
                    rs.AddObjectsToGroup([ObjId, OEId], Grp)
                
if __name__=="__main__":
    DoHalo()

This won’t work because the surface “0” is not always the bottom one, as I could have rotated the objects. Question is :

How can I select the surfaces facing down or, at lest, the surfaces laying on the C plane ?
Or even better, is there a way to select the largest one between the top and bottom surface ?

Of course I am open to any better solution

Thank you !

added to Scripting category

emm…About “I’ll use that to avoid nesting objects too close to each other”, I don’t see a code related to transform,about finding the collision range of Breps ,I will try this way:

finding the collision range of Breps.gh (9.1 KB)

This will give you some ideas to work with. Uses RhinoCommon instead of RhinoScriptSyntax.

  • Gets outer trim curves from top and bottom faces of selected polysurfaces.
  • Offsets trim curves.
  • Projects offset curves to WorldXY plane
  • Use projected curves with Curve.CreateBooleanUnion to create outlines
  • Outline curves are assigned red display color and placed in a group (as in your code above)
import Rhino
import Rhino.Geometry as rg
import scriptcontext as sc
import System

def Halo():
    filter = Rhino.DocObjects.ObjectType.PolysrfFilter
    cornerStyle = rg.CurveOffsetCornerStyle.Sharp
    tolerance = sc.doc.ModelAbsoluteTolerance
    crvIds = []
    attrs = Rhino.DocObjects.ObjectAttributes()
    attrs.ObjectColor = System.Drawing.Color.FromArgb(255,255,0,0)
    attrs.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
    
    rc, objRefs = Rhino.Input.RhinoGet.GetMultipleObjects("Select Polysurfaces", False, filter)
    if rc != Rhino.Commands.Result.Success: return rc
    if not objRefs: return Rhino.Commands.Result.Failure
    
    rc, offsetDistance = Rhino.Input.RhinoGet.GetNumber("Offset Distance", False, 1)
    if rc != Rhino.Commands.Result.Success: return rc
    
    for objRef in objRefs:
        brep = objRef.Brep()
        offsetCrvList = []
        for face in brep.Faces:
            faceNormal = face.NormalAt(face.Domain(0).Mid, face.Domain(1).Mid)
            dotProduct = rg.Vector3d.Multiply(faceNormal, rg.Vector3d.ZAxis)
            if Rhino.RhinoMath.EpsilonEquals(abs(dotProduct), 1, tolerance):
                for loop in face.Loops:
                    if loop.LoopType == rg.BrepLoopType.Outer:
                        loopCurve = loop.To3dCurve()
                        rc, plane = loopCurve.TryGetPlane()
                        if rc == False: return Rhino.Commands.Result.Failure
                        offsetCrvs = loopCurve.Offset(plane, offsetDistance, tolerance, cornerStyle)
                        offsetCrvList.extend(offsetCrvs)
        projectedCurves = []
        for offsetCrv in offsetCrvList:
            projectedCurves.append(rg.Curve.ProjectToPlane(offsetCrv, rg.Plane.WorldXY))
        boolUnionCrvs = rg.Curve.CreateBooleanUnion(projectedCurves, tolerance)
        for boolUnionCrv in boolUnionCrvs:
            id = sc.doc.Objects.AddCurve(boolUnionCrv, attrs)
            crvIds.append(id)
    sc.doc.Groups.Add(crvIds)
    sc.doc.Views.Redraw()

if __name__=="__main__":
    Halo()

Halo.py (2.0 KB)

If the offset curves projected from the top and bottom surfaces don’t overlap, 2 separate outline curves will be created as shown here.

-Kevin

Maybe take the Z coordinate of each face area centroid and compare it with your cplane Z

In case that’s undesired another way is creating a meshoutline from top view.

I’m too lazy for that, that’s why I use “Brep Faces by direction” from Wombat.

I’m going something similar in Grasshopper with Mesh Shadow.

Thanks everyone for the help, I ended up using the Meshoutline method with the top view selected.

For some reason it don’t accept polysurfaces as input in a script, so I had to work around it using the Command function and selecting\deselecting things through the loop.

Seems to work pretty well tho

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
import System.Guid

def Halo():
    
    rs.EnableRedraw = False
        
    SelObjects = rs.GetObjects("Seleziona le polisuperfici:", rs.filter.polysurface, False, True, True, True)
    HaloOffset = rs.GetInteger("Valore dell'offset per l'halo:", 10, 0, None)
    
    if not SelObjects: return
    if not HaloOffset: return
    
    rs.UnselectAllObjects()
    
    scriptcontext.doc.Layers.Add("Halo", System.Drawing.Color.Red)
    direzione = (10000, 10000, 10000)
    
    if  rs.MessageBox("Vuoi spostare tutto sul piano C?", 4 | 32)==6:
        #Moves everything on C plane, if needed
            for Obj in SelObjects:
                bb=rs.BoundingBox(Obj)
                if bb: rs.MoveObject(Obj,rs.coerce3dvector([0,0,-bb[0][2]]))
    
    rs.CurrentView('Superiore')
    # Switch view to top
        
    for Obj in SelObjects:
        
        rs.SelectObject(Obj)
                               
        rc = rs.Command("_MeshOutline", False)
        if not rc: return
        
        Crv = rs.FirstObject(True)
        Halo = rs.OffsetCurve(Crv, direzione, HaloOffset, None, 2)
        rs.DeleteObject(Crv)
        
        rs.ObjectLayer(Halo, "Halo")
        
        Group = rs.AddGroup()
        rs.AddObjectsToGroup([Obj, Halo], Group)
                
        rs.UnselectAllObjects()
        
    rs.EnableRedraw = True


Halo()

Halo2.py (1.4 KB)

1 Like