PythonScript equivalent of IsBox and BoxPoints?

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.

Thanks.
Ed

Hi @e.wynn,

Rhino represents surfaces in polysurfaces a Breps.

For Brep.IsBox to return true, the Brep must be:

  1. Solid
  2. Contain six planar faces
  3. The normals of apposing faces should point in opposite directions

RhinoScript’s BoxPoints method returns points in this order:

image

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()

– Dale

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.