Problem transforming box

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)

I’m not really understanding what you are trying to do, but are you aware that the GetBoundingBox method has 4 different versions? Would perhaps just using the version that does what you want eliminate the need for much of your code?

Also your code crashes if the cplane is not world top. I think that is because the polyline the script creates is not valid when the cplane is a side or front view.

Yes, there was no error checking involved, the code was just designed to run on the file provided when chosen in Perspective view - as stated above.

Yes I am. However, GetBoundingBox() only operates on one object. In order to get the bounding box of multiple objects, one needs to get the bounding box of each and union them, as this part of the code does:

It’s very simple, as already stated in the first post, to recreate the functionality of rs.BoundingBox() but accept RhinoCommon virtual geometry instead of object ids and return the box as a RhinoCommon box object and not just the corners.

Why not use RhinoObject.GetTightBoundingBox Method (IEnumerable(RhinoObject), Plane, BoundingBox) and then Box Constructor (Plane, BoundingBox) ?

#! python3

import scriptcontext as sc
import Rhino

p = sc.doc.Views.ActiveView.ActiveViewport.ConstructionPlane()

obs = list(sc.doc.Objects)

(ok, bb) = Rhino.DocObjects.RhinoObject.GetTightBoundingBox(obs, p)

bx = Rhino.Geometry.Box(p, bb)

sc.doc.Objects.AddBox(bx)