Hi everyone. I’m trying to write some scripts operating only on “box-like” objects – which I currently define as right-angled cuboids, sometimes rotated so that they are not grid-aligned.
RhinoScript has a test method “IsBox”, which is useful (whether or not the definition exactly matches the above). If an object passes that, then BoxPoints will provide the array (inevitably size 8) of corner coordinates. So I have something like this:
arrSelected = Rhino.SelectedObjects
If IsArray(arrSelected) Then
For Each objo In arrSelected
If rhino.IsBox(objo) Then
arrPoints = Rhino.BoxPoints(objo)
' ... and now deal with arrPoints ...
My main question is: how could I achieve something similar to the above using PythonScript?
(I see that IsBox was added for breps: Rhino 7 Service Release Available - #14 by brian – but I have no idea what breps are. The initial discussion that prompted that is linked – and in that discussion, the initial answers suggested roll-your-own methods in Grasshopper. I was hoping that there would be PythonScript equivalents to all RhinoScript commands, but perhaps that is overoptimistic.)
Two more detailed questions:
• What does IsBox test for? (For example, does it matter whether a polysurface was originally created using a Box command, or extruding a rectangular surface or curve? Is a sheared box still a box?)
• Is there a list of indexes for the BoxPoints array that is guaranteed to create a right-handed coordinate system for the edges? Something like “From index 0 as the origin, to indexes 1, 3 and 4 in that order”. The in-app PythonScript help files (but not the online ones) specify “Points are returned in counter-clockwise order starting with the bottom rectangle of the box.” – but what is the bottom rectangle of a rotated box? I’ve tried a few experiments, but the results confused me.
Rhino represents surfaces in polysurfaces a Breps.
For Brep.IsBox to return true, the Brep must be:
Solid
Contain six planar faces
The normals of apposing faces should point in opposite directions
RhinoScript’s BoxPoints method returns points in this order:
This Python script will do the same:
import Rhino
import scriptcontext as sc
def __boxpoints(brep, tol):
if brep and brep.IsBox():
verts = brep.DuplicateVertices()
if len(verts) == 8:
# Since the vertices can be in any order,
# cook up their bounding box and return
# them in some logical order
face = brep.Faces[0]
u = face.Domain(0).Min
v = face.Domain(1).Min
rc, plane = face.FrameAt(u, v)
points = Rhino.Geometry.PointCloud(verts)
w2p = Rhino.Geometry.Transform.ChangeBasis(Rhino.Geometry.Plane.WorldXY, plane)
bbox = points.GetBoundingBox(w2p)
corners = Rhino.Geometry.PointCloud(bbox.GetCorners())
p2w = Rhino.Geometry.Transform.ChangeBasis(plane, Rhino.Geometry.Plane.WorldXY)
corners.Transform(p2w)
return corners.GetPoints()
return None
def test_boxpoints():
filter = Rhino.DocObjects.ObjectType.PolysrfFilter
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select polysurface", False, filter)
if not objref or rc != Rhino.Commands.Result.Success:
return
brep = objref.Brep()
if not brep:
return
points = __boxpoints(brep, sc.doc.ModelAbsoluteTolerance)
if points:
i = 0
for pt in points:
sc.doc.Objects.AddTextDot(str(i), pt)
i = i + 1
sc.doc.Views.Redraw();
if __name__ == "__main__":
test_boxpoints()
Thanks, Dale – that works. At first I thought that the GetBoundingBox stuff would be invalid for a rotated box – but once it’s in a customised basis, then the bounding box is the box.
I can’t imagine reaching a stage where I could write something like that, so I think my follow-up question belongs in a separate thread.