Ejemplo n.º 1
0
    def test_IntersectionViewVolume(self):
    
        # a viewProjMat corresponding to a persp cam looking down the Y axis,
        # aimed at the origin.
        viewMat = Gf.Matrix4d(1.0, 0.0, 0.0, 0.0,
                            0.0, 0.0, -1.0, 0.0,
                            0.0, 1.0, 0.0, 0.0,
                            0.0, 0.0, -20, 1.0)
        projMat = Gf.Matrix4d(4.241894005673533, 0.0, 0.0, 0.0,
                            0.0, 4.2418940586972074, 0.0, 0.0,
                            0.0, 0.0, -1, -1.0,
                            0.0, 0.0, -20, 0.0)
        viewProjMat = viewMat * projMat

        # a typical box entirely in the view
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) )
        self.assertTrue(Gf.Frustum.IntersectsViewVolume(b,viewProjMat))

        # a typical box entirely out of the view
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 100, 0, 0 ), Gf.Vec3d( 101, 1, 1 ) ) )
        self.assertFalse(Gf.Frustum.IntersectsViewVolume(b,viewProjMat))

        # a large box entirely enclosing the view
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( -1e9, -1e9, -1e9 ),
                    Gf.Vec3d( 1e9, 1e9, 1e9 ) ) )
        self.assertTrue(Gf.Frustum.IntersectsViewVolume(b,viewProjMat))
Ejemplo n.º 2
0
    def test_EmptyFrustumIntersection(self):
        self.assertFalse(Gf.Frustum().Intersects(Gf.BBox3d()))
        self.assertTrue(Gf.Frustum().Intersects(Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1,-1,-1),
                                                Gf.Vec3d(1,1,1)))))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,0,-1)))
        self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0)))

        self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(1,1,1), Gf.Vec3d(0,0,1)))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(-1,-1,-1), Gf.Vec3d(0,0,1)))

        self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0, 100, -100), \
                                        Gf.Vec3d(-100,-100,100), \
                                        Gf.Vec3d(100,-100,100)))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0, 10, 100), \
                                    Gf.Vec3d(-100,-10,-10), \
                                    Gf.Vec3d(100,-10,-10)))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0, 1, 1), \
                                    Gf.Vec3d(50,0,-50), \
                                    Gf.Vec3d(-50,0,-50)))

        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(), Gf.Vec3d(-1,-1,-1), Gf.Vec3d(0,0,1)))

        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,-1)))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(-100,0,-1), Gf.Vec3d(100,0,-1)))
        self.assertTrue(Gf.Frustum().Intersects(Gf.Vec3d(0,100,-1), Gf.Vec3d(0,-100,-1)))
        self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(-100,0,1), Gf.Vec3d(100,0,-1)))
        self.assertFalse(Gf.Frustum().Intersects(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,1)))
Ejemplo n.º 3
0
    def test_Constructors(self):
        # no arg
        self.assertIsInstance( Gf.BBox3d(), Gf.BBox3d )

        # copy constructor
        self.assertIsInstance( Gf.BBox3d( Gf.BBox3d() ), Gf.BBox3d )

        # construct from range.
        self.assertIsInstance( Gf.BBox3d( Gf.Range3d() ), Gf.BBox3d )

        # construct from range and matrix.
        self.assertIsInstance( 
                Gf.BBox3d( Gf.Range3d(), Gf.Matrix4d() ), Gf.BBox3d )
Ejemplo n.º 4
0
    def test_Operators(self):
        # equality
        r1 = Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) )
        b1 = Gf.BBox3d( r1 )
        b2 = Gf.BBox3d( r1 )
        self.assertTrue(b1 == b2)

        # inequality
        r1 = Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) )
        r2 = Gf.Range3d( Gf.Vec3d( 1, 1, 1 ), Gf.Vec3d( 2, 2, 2 ) )
        b1 = Gf.BBox3d( r1 )
        b2 = Gf.BBox3d( r2 )
        self.assertTrue(b1 != b2)

        # string (just checks that it's not empty..)
        self.assertTrue(len(str(Gf.BBox3d())))
Ejemplo n.º 5
0
def TestPurposeWithInstancing():
    """ Tests that purpose filtered bounding boxes work correctly with native
        instancing and inherited purpose.
    """

    # Our test stages should all produce the exact same default and render
    # purpose bounding boxes even though they have different permutations of
    # instancing prims.
    defaultBBox = Gf.BBox3d(
        Gf.Range3d(Gf.Vec3d(-1.0, -1.0, -1.0), Gf.Vec3d(1.0, 1.0, 11.0)))
    renderBBox = Gf.BBox3d(
        Gf.Range3d(Gf.Vec3d(-11.0, -1.0, -16.0), Gf.Vec3d(1.0, 1.0, 11.0)))
    defaultCache = UsdGeom.BBoxCache(Usd.TimeCode.Default(), ['default'])
    renderCache = UsdGeom.BBoxCache(Usd.TimeCode.Default(),
                                    ['default', 'render'])

    # Stage with all instancing disabled.
    stage = Usd.Stage.Open("disableAllInstancing.usda")
    assert len(stage.GetMasters()) == 0
    root = stage.GetPrimAtPath("/Root")

    assert defaultCache.ComputeWorldBound(root) == defaultBBox
    assert renderCache.ComputeWorldBound(root) == renderBBox

    # Stage with one set of instances.
    stage = Usd.Stage.Open("disableInnerInstancing.usda")
    assert len(stage.GetMasters()) == 1
    root = stage.GetPrimAtPath("/Root")

    assert defaultCache.ComputeWorldBound(root) == defaultBBox
    assert renderCache.ComputeWorldBound(root) == renderBBox

    # Stage with one different set of instances.
    stage = Usd.Stage.Open("disableOuterInstancing.usda")
    assert len(stage.GetMasters()) == 1
    root = stage.GetPrimAtPath("/Root")

    assert defaultCache.ComputeWorldBound(root) == defaultBBox
    assert renderCache.ComputeWorldBound(root) == renderBBox

    # Stage with both sets of instances which are nested.
    stage = Usd.Stage.Open("nestedInstanceTest.usda")
    assert len(stage.GetMasters()) == 2
    root = stage.GetPrimAtPath("/Root")

    assert defaultCache.ComputeWorldBound(root) == defaultBBox
    assert renderCache.ComputeWorldBound(root) == renderBBox
Ejemplo n.º 6
0
 def _VerifyExtentAndBBox(light, expectedExtent):
     self.assertEqual(
         UsdGeom.Boundable.ComputeExtentFromPlugins(light, time),
         expectedExtent)
     self.assertEqual(
         light.ComputeLocalBound(time, "default"),
         Gf.BBox3d(
             Gf.Range3d(Gf.Vec3d(expectedExtent[0]),
                        Gf.Vec3d(expectedExtent[1])), Gf.Matrix4d(1.0)))
Ejemplo n.º 7
0
 def test_IntersectOrientedBox(self):
     # Rotate (1,0,0) to (1,1,1), and translate by (3,3,3)
     xform = Gf.Matrix4d(Gf.Rotation(Gf.Vec3d(1,0,0), Gf.Vec3d(1,1,1,)), \
                         Gf.Vec3d(3,3,3))
     box = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)),
                     xform)
     r = Gf.Ray(Gf.Vec3d(0, 0, 0), Gf.Vec3d(1, 1, 1))
     (hit, enterDist, exitDist) = r.Intersect(box)
     self.assertTrue(hit and Gf.IsClose(enterDist, 2.42264973081, 0.00001) \
         and Gf.IsClose(exitDist, 3.57735026919, 0.00001))
Ejemplo n.º 8
0
def TestUsd4957():
    """ Tests the case in which a prim has an xform directly on it and its
        bounding box relative to one of its ancestors is computed using
        ComputeRelativeBound().
    """
    s = Usd.Stage.Open("testUSD4957.usda")
    b = s.GetPrimAtPath("/A/B")
    c = s.GetPrimAtPath("/A/B/C")
    bc = UsdGeom.BBoxCache(Usd.TimeCode.Default(), ['default', 'render'])
    
    # Call the function being tested
    relativeBbox = bc.ComputeRelativeBound(c, b)
    
    # Compare the result with the bbox of C in its local space
    cExtent = UsdGeom.Boundable(c).GetExtentAttr().Get()
    cRange = Gf.Range3d(Gf.Vec3d(cExtent[0]), Gf.Vec3d(cExtent[1]))
    cLocalXform = UsdGeom.Xformable(c).GetLocalTransformation()
    cBbox = Gf.BBox3d(cRange, cLocalXform)
    
    AssertBBoxesClose(relativeBbox, cBbox,
                      "ComputeRelativeBound produced a wrong bbox.")
Ejemplo n.º 9
0
    def test_BBoxCache(self):
        """
        Tests that a UsdGeomPointInstancer with multiple instances of multiple
        cube prototypes has the correct bboxes computed with UsdGeomBBoxCache.
        """
        stage = Usd.Stage.CreateInMemory()

        world = UsdGeom.Xform.Define(stage, '/World')
        parent = UsdGeom.Xform.Define(
            stage, world.GetPath().AppendChild('parent'))
        instancer = UsdGeom.PointInstancer.Define(
            stage, parent.GetPath().AppendChild('MyPointInstancer'))
        prototypesPrim = self.stage.DefinePrim(
            instancer.GetPath().AppendChild('prototypes'))
        prototypesPrimPath = prototypesPrim.GetPath()

        # A unit cube at the origin.
        originCube = self._AddCubeModel(
            stage, prototypesPrimPath.AppendChild('OriginCube'))

        # A cube at the origin with a scale xformOp that makes it of length 5
        # in each dimension.
        originScaledCube = self._AddCubeModel(
            stage, prototypesPrimPath.AppendChild('OriginScaledCube'))
        xformable = UsdGeom.Xformable(originScaledCube)
        xformable.AddScaleOp().Set(Gf.Vec3f(5.0))

        # A unit cube with a translate xformOp.
        translatedCube = self._AddCubeModel(
            stage, prototypesPrimPath.AppendChild('TranslatedCube'))
        xformable = UsdGeom.Xformable(translatedCube)
        xformable.AddTranslateOp().Set(Gf.Vec3d(3.0, 6.0, 9.0))

        # A unit cube with a rotateZ xformOp.
        rotatedCube = self._AddCubeModel(
            stage, prototypesPrimPath.AppendChild('RotatedCube'))
        xformable = UsdGeom.Xformable(rotatedCube)
        xformable.AddRotateZOp().Set(45.0)

        instancer.CreatePrototypesRel().SetTargets([
            originCube.GetPath(),
            originScaledCube.GetPath(),
            translatedCube.GetPath(),
            rotatedCube.GetPath()
        ])

        # Add transformations on the parent and the instancer itself.
        UsdGeom.Xformable(world).AddTranslateOp().Set((2,2,2))
        UsdGeom.Xformable(parent).AddTranslateOp().Set((7,7,7))
        UsdGeom.Xformable(instancer).AddTranslateOp().Set((11,11,11))

        positions = [Gf.Vec3f(0,0,0)]*4
        indices = range(4)
        self._SetTransformComponentsAndIndices(
            instancer, positions=positions, indices=indices)
        
        bboxCache = UsdGeom.BBoxCache(
            Usd.TimeCode.Default(), includedPurposes=[UsdGeom.Tokens.default_])
        
        unitBox = Gf.Range3d((-0.5,)*3, (0.5,)*3)

        worldxf = Gf.Matrix4d().SetTranslate((2,)*3)
        parentxf = Gf.Matrix4d().SetTranslate((7,)*3)
        instancerxf = Gf.Matrix4d().SetTranslate((11,)*3)

        cubescale = Gf.Matrix4d().SetScale((5,)*3)
        cubexlat = Gf.Matrix4d().SetTranslate((3,6,9))
        cuberot = Gf.Matrix4d().SetRotate(Gf.Rotation((0,0,1), 45))

        cases = [
            (0, Gf.Matrix4d()), # originCube
            (1, cubescale),     # originScaledCube
            (2, cubexlat),      # translatedCube
            (3, cuberot),       # rotatedCube
            ]

        # scalar
        for iid, cubexf in cases:
            self.assertEqual(
                bboxCache.ComputePointInstanceWorldBound(instancer, iid),
                Gf.BBox3d(unitBox, cubexf*instancerxf*parentxf*worldxf))
            self.assertEqual(
                bboxCache.ComputePointInstanceRelativeBound(
                    instancer, iid, world.GetPrim()),
                Gf.BBox3d(unitBox, cubexf*instancerxf*parentxf))
            self.assertEqual(
                bboxCache.ComputePointInstanceLocalBound(instancer, iid),
                Gf.BBox3d(unitBox, cubexf*instancerxf))
            self.assertEqual(
                bboxCache.ComputePointInstanceUntransformedBound(
                    instancer, iid), Gf.BBox3d(unitBox, cubexf))

        # vectorized
        for i, wbox in enumerate(bboxCache.ComputePointInstanceWorldBounds(
                instancer, range(4))):
            self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]*
                                             instancerxf*parentxf*worldxf))
        for i, wbox in enumerate(bboxCache.ComputePointInstanceRelativeBounds(
                instancer, range(4), world.GetPrim())):
            self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]*
                                             instancerxf*parentxf)) 
        for i, wbox in enumerate(bboxCache.ComputePointInstanceLocalBounds(
                instancer, range(4))):
            self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]*
                                             instancerxf))
        for i, wbox in enumerate(
                bboxCache.ComputePointInstanceUntransformedBounds(
                    instancer, range(4))):
            self.assertEqual(wbox, Gf.BBox3d(unitBox, cases[i][1]))
Ejemplo n.º 10
0
    def test_LightExtentAndBBox(self):
        # Test extent and bbox computations for the boundable lights.

        time = Usd.TimeCode.Default()

        # Helper for computing the extent and bounding boxes for a light and
        # comparing against an expect extent pair.
        def _VerifyExtentAndBBox(light, expectedExtent):
            self.assertEqual(
                UsdGeom.Boundable.ComputeExtentFromPlugins(light, time),
                expectedExtent)
            self.assertEqual(
                light.ComputeLocalBound(time, "default"),
                Gf.BBox3d(
                    Gf.Range3d(
                        Gf.Vec3d(expectedExtent[0]), 
                        Gf.Vec3d(expectedExtent[1])), 
                    Gf.Matrix4d(1.0)))

        # Create a prim of each boundable light type.
        stage = Usd.Stage.CreateInMemory()
        rectLight = UsdLux.RectLight.Define(stage, "/RectLight")
        self.assertTrue(rectLight)
        diskLight = UsdLux.DiskLight.Define(stage, "/DiskLight")
        self.assertTrue(diskLight)
        cylLight = UsdLux.CylinderLight.Define(stage, "/CylLight")
        self.assertTrue(cylLight)
        sphereLight = UsdLux.SphereLight.Define(stage, "/SphereLight")
        self.assertTrue(sphereLight)

        # Verify the extent and bbox computations for each light given its
        # fallback attribute values.
        _VerifyExtentAndBBox(rectLight, [(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)])
        _VerifyExtentAndBBox(diskLight, [(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)])
        _VerifyExtentAndBBox(cylLight, [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)])
        _VerifyExtentAndBBox(sphereLight, [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)])

        # Change the size related attribute of each light and verify the extents
        # and bounding boxes are updated.
        rectLight.CreateWidthAttr(4.0)
        rectLight.CreateHeightAttr(6.0)
        _VerifyExtentAndBBox(rectLight, [(-2.0, -3.0, 0.0), (2.0, 3.0, 0.0)])

        diskLight.CreateRadiusAttr(5.0)
        _VerifyExtentAndBBox(diskLight, [(-5.0, -5.0, 0.0), (5.0, 5.0, 0.0)])

        cylLight.CreateRadiusAttr(4.0)
        cylLight.CreateLengthAttr(10.0)
        _VerifyExtentAndBBox(cylLight, [(-4.0, -4.0, -5.0), (4.0, 4.0, 5.0)])

        sphereLight.CreateRadiusAttr(3.0)
        _VerifyExtentAndBBox(sphereLight, [(-3.0, -3.0, -3.0), (3.0, 3.0, 3.0)])

        # Special case for portal light. Portal lights don't have any attributes
        # that affect their extent, but they do have a constant extent defined
        # for a unit rectangle in the XY plane.
        portalLight = UsdLux.PortalLight.Define(stage, "/PortalLight")
        self.assertTrue(portalLight)
        self.assertIsNone(
            UsdGeom.Boundable.ComputeExtentFromPlugins(portalLight, time))
        self.assertEqual(
            portalLight.ComputeLocalBound(time, "default"),
            Gf.BBox3d(
                Gf.Range3d(Gf.Vec3d(-0.5, -0.5, 0.0), Gf.Vec3d(0.5, 0.5, 0.0)), 
                Gf.Matrix4d(1.0)))

        # For completeness verify that distant and dome lights are not 
        # boundable.
        domeLight = UsdLux.DomeLight.Define(stage, "/DomeLight")
        self.assertTrue(domeLight)
        self.assertFalse(UsdGeom.Boundable(domeLight))
        distLight = UsdLux.DistantLight.Define(stage, "/DistLight")
        self.assertTrue(distLight)
        self.assertFalse(UsdGeom.Boundable(distLight))
Ejemplo n.º 11
0
    def test_MethodsAndProperties(self):
        # set
        m = Gf.Matrix4d()
        r = Gf.Range3d()
        b = Gf.BBox3d()
        self.assertEqual(b.Set( r, m ), Gf.BBox3d( r, m ))

        # matrix prop
        b = Gf.BBox3d()
        b.matrix = Gf.Matrix4d(5)
        self.assertEqual(b.matrix, Gf.Matrix4d(5))

        # box property
        b = Gf.BBox3d()
        self.assertTrue(b.box.IsEmpty())
        b.box = Gf.Range3d( Gf.Vec3d(1,2,3), Gf.Vec3d(4,5,6) )
        self.assertEqual(b.box, Gf.Range3d( Gf.Vec3d(1,2,3), Gf.Vec3d(4,5,6) ))
        self.assertFalse(b.box.IsEmpty())

        # GetInverseGf.Matrix
        b = Gf.BBox3d()
        b.matrix = Gf.Matrix4d(5)
        m = Gf.Matrix4d(5).GetInverse()
        self.assertEqual(b.GetInverseMatrix(), Gf.Matrix4d(5).GetInverse())

        # hasZeroAreaPrimitives
        b = Gf.BBox3d()
        b.hasZeroAreaPrimitives = True
        b.hasZeroAreaPrimitives = not b.hasZeroAreaPrimitives
        self.assertFalse(b.hasZeroAreaPrimitives)

        # GetVolume
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 2, 2, 2 ) ) )
        self.assertEqual(b.GetVolume(), 8)
        b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1),Gf.Vec3d()))
        self.assertEqual(b.GetVolume(), 0)

        # Transform
        m1 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30))
        m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60))
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m1 )
        b.Transform(m2)
        self.assertEqual(b.matrix, (m1 * m2))

        # ComputeAlignedRange
        m = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30))
        b = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m )
        r1 = b.ComputeAlignedRange()
        b = Gf.BBox3d( r1 )
        r2 = b.ComputeAlignedRange()
        self.assertEqual(r1, r2)
        m = Gf.Matrix4d().SetScale(3)
        b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)), m)
        r = b.ComputeAlignedRange()
        self.assertEqual(r.GetSize(), Gf.Vec3d(6.0, 6.0, 6.0))
        m = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30))
        b = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(-1, -1, -1), Gf.Vec3d(1, 1, 1)), m)
        angle = math.pi / 6 # 30 degrees
        width = 2 * (math.cos(angle) + math.sin(angle))
        size = Gf.Vec3d(2.0, width, width)
        r = b.ComputeAlignedRange()
        self.assertFalse((r.GetSize() - size).GetLength() > 0.000001)
        b = Gf.BBox3d()
        r = b.ComputeAlignedRange()
        self.assertTrue(r.IsEmpty())
        
        # static combine method
        m1 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.XAxis(), 30))
        m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60))
        b1 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ), m1 )
        b2 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 1, 1, 1 ), Gf.Vec3d( 2, 2, 2 ) ), m2 )
        b3 = Gf.BBox3d.Combine( b1, b2 )
        b4 = Gf.BBox3d.Combine( b2, b1 )
        self.assertEqual(b3, b4)

        # centroid
        b1 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( 0, 0, 0 ), Gf.Vec3d( 1, 1, 1 ) ) )

        m2 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60))
        b2 = Gf.BBox3d( Gf.Range3d( Gf.Vec3d( -1, -1, -1 ), Gf.Vec3d( 1, 1, 1 ) ), m2)
        self.assertEqual(b1.ComputeCentroid(), Gf.Vec3d( .5, .5, .5 ))
        self.assertEqual(b2.ComputeCentroid(), Gf.Vec3d( 0, 0, 0 ))
        
        b3 = Gf.BBox3d()
        self.assertEqual(b3.ComputeCentroid(), Gf.Vec3d( 0, 0, 0 ))

        # other cases to hit code coverage.
        m1 = Gf.Matrix4d(Gf.Vec4d(1,0,0,0))
        m2 = Gf.Matrix4d(Gf.Vec4d(0,1,0,0))
        b1 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d()), m1)
        b2 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d(2,2,2)), m2)
        b3 = Gf.BBox3d.Combine(b1, b2)
        self.assertEqual(b3, b2)
        b3 = Gf.BBox3d.Combine(b2, b1)
        self.assertEqual(b3, b2)

        m1 = Gf.Matrix4d(Gf.Vec4d(1,0,0,0))
        m2 = Gf.Matrix4d(Gf.Vec4d(0,1,0,0))
        m3 = Gf.Matrix4d(1).SetRotate(Gf.Rotation(Gf.Vec3d.YAxis(), 60))
        b1 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(0,0,0), Gf.Vec3d(0,1,1)), m1)
        b2 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(0,0,0), Gf.Vec3d(1,1,0)), m2)
        b3 = Gf.BBox3d(Gf.Range3d(Gf.Vec3d(1,1,1), Gf.Vec3d(2,2,2)), m3)
        b4 = Gf.BBox3d.Combine(b1,b2)
        b4 = Gf.BBox3d.Combine(b1,b2)
        b4 = Gf.BBox3d.Combine(b2,b3)
        b4 = Gf.BBox3d.Combine(b3,b2)

        self.assertEqual(b4, eval(repr(b4)))