I am trying to reproduce the function of rs.BoundingBox, but have it take RhinoCommon Geometry instead of object ids, and output a RhinoCommon box instead of just the corner points. Specifically I want to duplicate the function when a non-world plane is input.
Basically i copied the rhinoscriptsyntax definition and just eliminated the various conversions from object id to geometry. That is fine, it is at the end, where the rhinoscriptsyntax function gets the bounding box corners - which I assume are in plane coordinates at this point - transforms them back to world and returns them. That works fine, but I tried transforming the box from which the corners came with the same transform as used for the points and it does not return the same result.
I assume I’m missing something in how the box is transformed. Using the reverse transform or no transform on the box doesn’t work either.
Here is my test code:
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
def MyBoundingBox(objs,plane=None,w_coords=True):
def __objectbbox(obj, xform):
geom=rs.coercegeometry(obj, False)
if not geom:
pt = rs.coerce3dpoint(obj, True)
if xform: pt = xform * pt
return Rhino.Geometry.BoundingBox(pt,pt)
if xform: return geom.GetBoundingBox(xform)
return geom.GetBoundingBox(True)
xform=None
wxy=Rhino.Geometry.Plane.WorldXY
if plane:
xform=Rhino.Geometry.Transform.ChangeBasis(wxy,plane)
bbox = Rhino.Geometry.BoundingBox.Empty
if type(objs) is list or type(objs) is tuple:
for obj in objs:
objectbbox = __objectbbox(obj,xform)
bbox = Rhino.Geometry.BoundingBox.Union(bbox,objectbbox)
else:
objectbbox = __objectbbox(objs, xform)
bbox = Rhino.Geometry.BoundingBox.Union(bbox,objectbbox)
if bbox.IsValid:
if w_coords and plane is not None:
plane_to_world=Rhino.Geometry.Transform.ChangeBasis(plane,wxy)
box_pts=list(bbox.GetCorners())
#transform points from input plane back to world (works)
for pt in box_pts: pt.Transform(plane_to_world)
#try to transform box the same way (doesn't work)
bbox.Transform(plane_to_world)
return box_pts,bbox
obj_ids=rs.GetObjects(preselect=True)
objs=[rs.coercegeometry(obj_id) for obj_id in obj_ids]
pts,box=MyBoundingBox(objs, rs.ViewCPlane(), True)
rs.AddPolyline([pts[0],pts[1],pts[2],pts[3],pts[0]])
box_pts=box.GetCorners()
rs.AddPolyline([box_pts[0],box_pts[1],box_pts[2],box_pts[3],box_pts[0]])
Here is a simple file to test - just a 45° rotated CPlane in the perspective view with a rectangle aligned to it. Run the script with the Perspective view active. Connecting the returned points with a polyline gives the correct rectangle, connecting the returned box’s bottom corner points does not.
Plane-45.3dm (2.8 MB)