Add support for elementTypes "tetrahedron" and "face" to
authordiyajoy <diyajoy@users.noreply.github.com>
Sat, 3 Feb 2024 03:58:47 +0000 (19:58 -0800)
committerpixar-oss <pixar-oss@users.noreply.github.com>
Sat, 3 Feb 2024 04:09:40 +0000 (20:09 -0800)
UsdGeomSubset for use with UsdGeomTetMesh.

(Internal change: 2313837)

pxr/usd/usdGeom/generatedSchema.usda
pxr/usd/usdGeom/schema.usda
pxr/usd/usdGeom/subset.cpp
pxr/usd/usdGeom/subset.h
pxr/usd/usdGeom/testenv/testUsdGeomSubset.py
pxr/usd/usdGeom/testenv/testUsdGeomSubset/Sphere.usda
pxr/usd/usdGeom/tokens.cpp
pxr/usd/usdGeom/tokens.h
pxr/usd/usdGeom/wrapTokens.cpp

index 4e02114d34f83328870f34512f29001701577f92..bcc12e740096668584281f0e0898e512deea1b93 100644 (file)
@@ -2415,16 +2415,15 @@ class TetMesh "TetMesh" (
 
 class GeomSubset "GeomSubset" (
     doc = """Encodes a subset of a piece of geometry (i.e. a UsdGeomImageable) 
-    as a set of indices. Currently only supports encoding of face-subsets and
-    point-subsets, but could be extended in the future to support subsets 
-    representing edges, segments, tetrahedrons, etc.
+    as a set of indices. Currently supports encoding subsets of faces, 
+    points, edges, and tetrahedrons.
 
     To apply to a geometric prim, a GeomSubset prim must be the prim's direct 
     child in namespace, and possess a concrete defining specifier (i.e. def). 
     This restriction makes it easy and efficient to discover subsets of a prim. 
     We might want to relax this restriction if it's common to have multiple 
     <b>families</b> of subsets on a gprim and if it's useful to be able to 
-    organize subsets belonging to a </b>family</b> under a common scope. See 
+    organize subsets belonging to a <b>family</b> under a common scope. See 
     'familyName' attribute for more info on defining a family of subsets.
 
     Note that a GeomSubset isn't an imageable (i.e. doesn't derive from
@@ -2437,20 +2436,27 @@ class GeomSubset "GeomSubset" (
 )
 {
     uniform token elementType = "face" (
-        allowedTokens = ["face", "point", "edge"]
+        allowedTokens = ["face", "point", "edge", "tetrahedron"]
         doc = """The type of element that the indices target. \"elementType\" can
         have one of the following values:
-        <ul><li><b>face</b>: for a UsdGeomMesh, each element of the indices 
-        attribute would refer to an element of the Mesh's faceCounts 
-        attribute</li>
+        <ul><li><b>face</b>: Identifies faces on a Gprim's surface. For a 
+        UsdGeomMesh, each element of the _indices_ attribute would refer to 
+        an element of the Mesh's _faceCounts_ attribute. For a UsdGeomTetMesh,
+        each element of the _indices_ attribute would refer to an element of
+        the Mesh's _surfaceFaceVertexIndices_ attribute.</li>
         <li><b>point</b>: for any UsdGeomPointBased, each 
-        element of the indices attribute would refer to an element of the 
-        Mesh's points attribute</li>
+        element of the _indices_ attribute would refer to an element of the 
+        Mesh's _points_ attribute</li>
         <li><b>edge</b>: for any UsdGeomMesh, each pair of elements
-        in the indices attribute would refer to a pair of points of the 
-        Mesh's points attribute that are connected as an implicit edge on the 
-        Mesh. These edges are derived from the Mesh's faceVertexIndices 
-        attribute.
+        in the _indices_ attribute would refer to a pair of points of the 
+        Mesh's _points_ attribute that are connected as an implicit edge on the 
+        Mesh. These edges are derived from the Mesh's _faceVertexIndices_ 
+        attribute. Edges are not currently defined for a UsdGeomTetMesh, but
+        could be derived from all tetrahedron edges or surface face edges only 
+        if a specific use-case arises.</li>
+        <li><b>tetrahedron</b>: for any UsdGeomTetMesh, each element of the 
+        _indices_ attribute would refer to an element of the TetMesh's 
+        _tetVertexIndices_ attribute.
         </li></ul>"""
     )
     uniform token familyName = "" (
index 435ac074b75755685153e6c0fb801c1291740a89..6994ef3a2d8d96789b591d2276d1a1b107d9c8d1 100644 (file)
@@ -1269,16 +1269,15 @@ class TetMesh "TetMesh" (
 class GeomSubset "GeomSubset" (
     inherits = </Typed>
     doc = """Encodes a subset of a piece of geometry (i.e. a UsdGeomImageable) 
-    as a set of indices. Currently only supports encoding of face-subsets and
-    point-subsets, but could be extended in the future to support subsets 
-    representing edges, segments, tetrahedrons, etc.
+    as a set of indices. Currently supports encoding subsets of faces, 
+    points, edges, and tetrahedrons.
 
     To apply to a geometric prim, a GeomSubset prim must be the prim's direct 
     child in namespace, and possess a concrete defining specifier (i.e. def). 
     This restriction makes it easy and efficient to discover subsets of a prim. 
     We might want to relax this restriction if it's common to have multiple 
     <b>families</b> of subsets on a gprim and if it's useful to be able to 
-    organize subsets belonging to a </b>family</b> under a common scope. See 
+    organize subsets belonging to a <b>family</b> under a common scope. See 
     'familyName' attribute for more info on defining a family of subsets.
 
     Note that a GeomSubset isn't an imageable (i.e. doesn't derive from
@@ -1293,25 +1292,34 @@ class GeomSubset "GeomSubset" (
         string extraIncludes = """
 #include "pxr/base/tf/token.h"
 #include "pxr/usd/usdGeom/imageable.h"
+#include "pxr/usd/usdGeom/mesh.h"
+#include "pxr/usd/usdGeom/tetMesh.h"
 """
     }
 )
 {
     uniform token elementType = "face" (
-        allowedTokens = ["face", "point", "edge"]
+        allowedTokens = ["face", "point", "edge", "tetrahedron"]
         doc = """The type of element that the indices target. "elementType" can
         have one of the following values:
-        <ul><li><b>face</b>: for a UsdGeomMesh, each element of the indices 
-        attribute would refer to an element of the Mesh's faceCounts 
-        attribute</li>
+        <ul><li><b>face</b>: Identifies faces on a Gprim's surface. For a 
+        UsdGeomMesh, each element of the _indices_ attribute would refer to 
+        an element of the Mesh's _faceCounts_ attribute. For a UsdGeomTetMesh,
+        each element of the _indices_ attribute would refer to an element of
+        the Mesh's _surfaceFaceVertexIndices_ attribute.</li>
         <li><b>point</b>: for any UsdGeomPointBased, each 
-        element of the indices attribute would refer to an element of the 
-        Mesh's points attribute</li>
+        element of the _indices_ attribute would refer to an element of the 
+        Mesh's _points_ attribute</li>
         <li><b>edge</b>: for any UsdGeomMesh, each pair of elements
-        in the indices attribute would refer to a pair of points of the 
-        Mesh's points attribute that are connected as an implicit edge on the 
-        Mesh. These edges are derived from the Mesh's faceVertexIndices \
-        attribute.
+        in the _indices_ attribute would refer to a pair of points of the 
+        Mesh's _points_ attribute that are connected as an implicit edge on the 
+        Mesh. These edges are derived from the Mesh's _faceVertexIndices_ 
+        attribute. Edges are not currently defined for a UsdGeomTetMesh, but
+        could be derived from all tetrahedron edges or surface face edges only 
+        if a specific use-case arises.</li>
+        <li><b>tetrahedron</b>: for any UsdGeomTetMesh, each element of the 
+        _indices_ attribute would refer to an element of the TetMesh's 
+        _tetVertexIndices_ attribute.
         </li></ul>"""
     )
     int[] indices = [] (
index 4359b1197bd013202f85eddb6464ae11edc59a36..4155ade1e904c70a247f6844de21807d6e2e50b4 100644 (file)
@@ -461,15 +461,31 @@ _GetElementCountAtTime(
 
     if (elementType == UsdGeomTokens->face) {
         // XXX: Use UsdGeomMesh schema to get the face count.
-        const UsdAttribute fvcAttr = geom.GetPrim().GetAttribute(
-            UsdGeomTokens->faceVertexCounts);
-        if (fvcAttr) {
-            VtIntArray faceVertexCounts;
-            if (fvcAttr.Get(&faceVertexCounts, time)) {
-                elementCount = faceVertexCounts.size();
+        const UsdPrim prim = geom.GetPrim();
+        if (prim.IsA<UsdGeomMesh>()) {
+            const UsdAttribute fvcAttr = prim.GetAttribute(
+                UsdGeomTokens->faceVertexCounts);
+            if (fvcAttr) {
+                VtIntArray faceVertexCounts;
+                if (fvcAttr.Get(&faceVertexCounts, time)) {
+                    elementCount = faceVertexCounts.size();
+                }
+                if (isCountTimeVarying) {
+                    *isCountTimeVarying = fvcAttr.ValueMightBeTimeVarying();
+                }
             }
-            if (isCountTimeVarying) {
-                *isCountTimeVarying = fvcAttr.ValueMightBeTimeVarying();
+        } else if (prim.IsA<UsdGeomTetMesh>()) {
+            const UsdAttribute sfviAttr = prim.GetAttribute(
+                UsdGeomTokens->surfaceFaceVertexIndices);
+            
+            if (sfviAttr) {
+                VtVec3iArray surfaceFaceVertexIndices;
+                if (sfviAttr.Get(&surfaceFaceVertexIndices, time)) {
+                    elementCount = surfaceFaceVertexIndices.size();
+                }
+                if (isCountTimeVarying) {
+                    *isCountTimeVarying = sfviAttr.ValueMightBeTimeVarying();
+                }
             }
         }
     } else if (elementType == UsdGeomTokens->point) {
@@ -498,6 +514,18 @@ _GetElementCountAtTime(
                                         fviAttr.ValueMightBeTimeVarying();
             }
         }
+    } else if (elementType == UsdGeomTokens->tetrahedron) {
+        const UsdAttribute tviAttr = geom.GetPrim().GetAttribute(
+            UsdGeomTokens->tetVertexIndices);
+        if (tviAttr) {
+            VtVec4iArray tetVertexIndices;
+            if (tviAttr.Get(&tetVertexIndices, time)) {
+                elementCount = tetVertexIndices.size();
+            }
+            if (isCountTimeVarying) {
+                *isCountTimeVarying = tviAttr.ValueMightBeTimeVarying();
+            }
+        }
     } else {
         TF_CODING_ERROR("Unsupported element type '%s'.",
                         elementType.GetText());
@@ -506,6 +534,29 @@ _GetElementCountAtTime(
     return elementCount;
 }
 
+static bool _ValidateGeomType(const UsdGeomImageable &geom, const TfToken &elementType) {
+    const UsdPrim prim = geom.GetPrim();
+    if (prim.IsA<UsdGeomMesh>()) {
+        if (elementType != UsdGeomTokens->face && elementType != UsdGeomTokens->point 
+            && elementType != UsdGeomTokens->edge) {
+            TF_CODING_ERROR("Unsupported element type '%s' for prim type Mesh.",
+                            elementType.GetText());
+            return false;
+        }
+    } else if (prim.IsA<UsdGeomTetMesh>()) {
+        if (elementType != UsdGeomTokens->face && elementType != UsdGeomTokens->tetrahedron) {
+            TF_CODING_ERROR("Unsupported element type '%s' for prim type TetMesh.",
+                            elementType.GetText());
+            return false;
+        }
+    } else {
+        TF_CODING_ERROR("Unsupported prim type '%s'.",
+                        elementType.GetText());
+        return false;
+    }
+    return true;
+}
+
 /* static */
 VtIntArray
 UsdGeomSubset::GetUnassignedIndices(
@@ -514,6 +565,11 @@ UsdGeomSubset::GetUnassignedIndices(
     const TfToken &familyName,
     const UsdTimeCode &time /* UsdTimeCode::EarliestTime() */)
 {
+    VtIntArray result;
+    if (!_ValidateGeomType(geom, elementType)) {
+        return result;
+    }
+
     std::vector<UsdGeomSubset> subsets = UsdGeomSubset::GetGeomSubsets(
             geom, elementType, familyName);
     
@@ -538,7 +594,6 @@ UsdGeomSubset::GetUnassignedIndices(
 
     const size_t elementCount = _GetElementCountAtTime(geom, elementType, time);
 
-    VtIntArray result;
     if (assignedIndices.empty()) {
         result.reserve(elementCount);
         for (size_t idx = 0 ; idx < elementCount ; ++idx) 
@@ -719,10 +774,9 @@ UsdGeomSubset::ValidateFamily(
     const TfToken &familyName,
     std::string * const reason)
 {
-    if (elementType != UsdGeomTokens->face && elementType != UsdGeomTokens->point 
-            && elementType != UsdGeomTokens->edge) {
-        TF_CODING_ERROR("Unsupported element type '%s'.",
-                        elementType.GetText());
+    if (!_ValidateGeomType(geom, elementType)) {
+        *reason += TfStringPrintf("Invalid geom type for elementType %s.\n", 
+                elementType.GetText());
         return false;
     }
 
index cefa53be7d452749443034b00eb5c42f8afccd4d..a6d119b60c017d3f15f1d822e5d7d241af85b2b3 100644 (file)
@@ -35,6 +35,8 @@
 
 #include "pxr/base/tf/token.h"
 #include "pxr/usd/usdGeom/imageable.h"
+#include "pxr/usd/usdGeom/mesh.h"
+#include "pxr/usd/usdGeom/tetMesh.h"
 
 
 #include "pxr/base/vt/value.h"
@@ -57,16 +59,15 @@ class SdfAssetPath;
 /// \class UsdGeomSubset
 ///
 /// Encodes a subset of a piece of geometry (i.e. a UsdGeomImageable) 
-/// as a set of indices. Currently only supports encoding of face-subsets and
-/// point-subsets, but could be extended in the future to support subsets 
-/// representing edges, segments, tetrahedrons, etc.
+/// as a set of indices. Currently supports encoding subsets of faces, 
+/// points, edges, and tetrahedrons.
 /// 
 /// To apply to a geometric prim, a GeomSubset prim must be the prim's direct 
 /// child in namespace, and possess a concrete defining specifier (i.e. def). 
 /// This restriction makes it easy and efficient to discover subsets of a prim. 
 /// We might want to relax this restriction if it's common to have multiple 
 /// <b>families</b> of subsets on a gprim and if it's useful to be able to 
-/// organize subsets belonging to a </b>family</b> under a common scope. See 
+/// organize subsets belonging to a <b>family</b> under a common scope. See 
 /// 'familyName' attribute for more info on defining a family of subsets.
 /// 
 /// Note that a GeomSubset isn't an imageable (i.e. doesn't derive from
@@ -182,17 +183,24 @@ public:
     // --------------------------------------------------------------------- //
     /// The type of element that the indices target. "elementType" can
     /// have one of the following values:
-    /// <ul><li><b>face</b>: for a UsdGeomMesh, each element of the indices 
-    /// attribute would refer to an element of the Mesh's faceCounts 
-    /// attribute</li>
+    /// <ul><li><b>face</b>: Identifies faces on a Gprim's surface. For a 
+    /// UsdGeomMesh, each element of the _indices_ attribute would refer to 
+    /// an element of the Mesh's _faceCounts_ attribute. For a UsdGeomTetMesh,
+    /// each element of the _indices_ attribute would refer to an element of
+    /// the Mesh's _surfaceFaceVertexIndices_ attribute.</li>
     /// <li><b>point</b>: for any UsdGeomPointBased, each 
-    /// element of the indices attribute would refer to an element of the 
-    /// Mesh's points attribute</li>
+    /// element of the _indices_ attribute would refer to an element of the 
+    /// Mesh's _points_ attribute</li>
     /// <li><b>edge</b>: for any UsdGeomMesh, each pair of elements
-    /// in the indices attribute would refer to a pair of points of the 
-    /// Mesh's points attribute that are connected as an implicit edge on the 
-    /// Mesh. These edges are derived from the Mesh's faceVertexIndices 
-    /// attribute.
+    /// in the _indices_ attribute would refer to a pair of points of the 
+    /// Mesh's _points_ attribute that are connected as an implicit edge on the 
+    /// Mesh. These edges are derived from the Mesh's _faceVertexIndices_ 
+    /// attribute. Edges are not currently defined for a UsdGeomTetMesh, but
+    /// could be derived from all tetrahedron edges or surface face edges only 
+    /// if a specific use-case arises.</li>
+    /// <li><b>tetrahedron</b>: for any UsdGeomTetMesh, each element of the 
+    /// _indices_ attribute would refer to an element of the TetMesh's 
+    /// _tetVertexIndices_ attribute.
     /// </li></ul>
     ///
     /// | ||
@@ -201,7 +209,7 @@ public:
     /// | C++ Type | TfToken |
     /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Token |
     /// | \ref SdfVariability "Variability" | SdfVariabilityUniform |
-    /// | \ref UsdGeomTokens "Allowed Values" | face, point, edge |
+    /// | \ref UsdGeomTokens "Allowed Values" | face, point, edge, tetrahedron |
     USDGEOM_API
     UsdAttribute GetElementTypeAttr() const;
 
@@ -394,6 +402,9 @@ public:
     /// the GeomSubsets in the \p familyName family on the given \p geom at the 
     /// timeCode, \p time, given the element count (total number of indices in 
     /// the array being subdivided), \p elementCount.
+    ///
+    /// If the \p elementType is not applicable to the given \p geom, an empty
+    /// array is returned and a coding error is issued.
     USDGEOM_API
     static VtIntArray GetUnassignedIndices(
         const UsdGeomImageable &geom, 
index 209c2ea4ac72e9e614ca1e1d4131d8fc1c542c8d..f87bfea575af6c2c25c5e5354a1c0db80afdea85 100644 (file)
@@ -43,60 +43,89 @@ class testUsdGeomSubset(unittest.TestCase):
             self.assertFalse(valid)
             self.assertTrue(len(reason) > 0)
 
+    def _TestSubsetValidity(self, geom, varyingGeom, nullGeom, elementType):
+        prefix = elementType + "_"
+
+        validFamilies = ['validPartition', 
+                         'validNonOverlapping', 'validUnrestricted',
+                         'emptyIndicesSomeTimes']
+        for familyName in validFamilies:
+            self._ValidateFamily(geom, elementType, prefix+familyName, True)
+
+        invalidFamilies = ['invalidIndices', 'badPartition1', 'badPartition2',
+                           'badPartition3', 'invalidNonOverlapping',
+                           'invalidUnrestricted', 'onlyNegativeIndices',
+                           'emptyIndicesAtAllTimes']
+        for familyName in invalidFamilies:
+            self._ValidateFamily(geom, elementType, prefix+familyName, False)
+
+        validFamilies = ['validPartition']
+        for familyName in validFamilies:
+            self._ValidateFamily(varyingGeom, elementType, prefix+familyName, True)
+
+        invalidFamilies = ['invalidNoDefaultTimeElements']
+        for familyName in invalidFamilies:
+            self._ValidateFamily(varyingGeom, elementType, prefix+familyName, False)
+
+        invalidFamilies = ['emptyIndicesAtAllTimes', 'invalidPartition']
+        for familyName in invalidFamilies:
+            self._ValidateFamily(nullGeom, elementType, prefix+familyName, False)
+
+    def _TestSubsetRetrieval(self, geom, elementType, familyName):
+        prefix = elementType + "_"
+
+        materialBindSubsets = UsdGeom.Subset.GetGeomSubsets(geom, 
+            elementType=elementType,
+            familyName=prefix+familyName)
+        self.assertEqual(len(materialBindSubsets), 3)
+        
+        self.assertEqual(UsdGeom.Tokens.partition, 
+            UsdGeom.Subset.GetFamilyType(geom, prefix+familyName))
+
+        self._ValidateFamily(geom, elementType, prefix+familyName, True)
+
     def test_SubsetRetrievalAndValidity(self):
         testFile = "Sphere.usda"
         stage = Usd.Stage.Open(testFile)
         sphere = stage.GetPrimAtPath("/Sphere/pSphere1")
         geom = UsdGeom.Imageable(sphere)
         self.assertTrue(geom)
-    
-        materialBindSubsets = UsdGeom.Subset.GetGeomSubsets(geom, 
-            elementType=UsdGeom.Tokens.face,
-            familyName='face_materialBind')
-        self.assertEqual(len(materialBindSubsets), 3)
-        
-        self.assertEqual(UsdGeom.Tokens.partition, 
-            UsdGeom.Subset.GetFamilyType(geom, 'face_materialBind'))
 
-        (valid, reason) = UsdGeom.Subset.ValidateFamily(geom, 
-                UsdGeom.Tokens.face, familyName='face_materialBind')
-        self.assertTrue(valid)
-        
+        varyingMesh = stage.GetPrimAtPath("/Sphere/VaryingMesh")
+        varyingGeom = UsdGeom.Imageable(varyingMesh)
+        self.assertTrue(varyingGeom)
 
-        validFamilies = ['face_materialBind', 'face_validPartition', 
-                         'face_validNonOverlapping', 'face_validUnrestricted',
-                         'face_emptyIndicesSomeTimes']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.face, familyName, True)
-
-        invalidFamilies = ['face_invalidIndices', 'face_badPartition1', 
-                           'face_badPartition2', 'face_badPartition3', 
-                           'face_invalidNonOverlapping',
-                           'face_invalidUnrestricted', 
-                           'face_onlyNegativeIndices',
-                           'face_emptyIndicesAtAllTimes']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.face, familyName, False)
+        nullMesh = stage.GetPrimAtPath("/Sphere/NullMesh")
+        nullGeom = UsdGeom.Imageable(nullMesh)
+        self.assertTrue(nullGeom)
 
-        varyingMesh = stage.GetPrimAtPath("/Sphere/VaryingMesh")
-        geom = UsdGeom.Imageable(varyingMesh)
-        self.assertTrue(geom)
+        self._TestSubsetRetrieval(geom, UsdGeom.Tokens.face, "materialBind")
+        self._TestSubsetValidity(geom, varyingGeom, nullGeom, UsdGeom.Tokens.face)
 
-        validFamilies = ['face_validPartition']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.face, familyName, True)
+        self._TestSubsetRetrieval(geom, UsdGeom.Tokens.point, "physicsAttachment")
+        self._TestSubsetValidity(geom, varyingGeom, nullGeom, UsdGeom.Tokens.point)
 
-        invalidFamilies = ['face_invalidNoDefaultTimeElements']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.face, familyName, False)
+        self._TestSubsetRetrieval(geom, UsdGeom.Tokens.edge, "physicsAttachment")
+        self._TestSubsetValidity(geom, varyingGeom, nullGeom, UsdGeom.Tokens.edge)
 
-        nullMesh = stage.GetPrimAtPath("/Sphere/NullMesh")
-        geom = UsdGeom.Imageable(nullMesh)
+        sphere = stage.GetPrimAtPath("/Sphere/TetMesh")
+        geom = UsdGeom.Imageable(sphere)
         self.assertTrue(geom)
 
-        invalidFamilies = ['face_emptyIndicesAtAllTimes', 'face_invalidPartition']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.face, familyName, False)
+        varyingMesh = stage.GetPrimAtPath("/Sphere/VaryingTetMesh")
+        varyingGeom = UsdGeom.Imageable(varyingMesh)
+        self.assertTrue(varyingGeom)
+
+        nullMesh = stage.GetPrimAtPath("/Sphere/NullTetMesh")
+        nullGeom = UsdGeom.Imageable(nullMesh)
+        self.assertTrue(nullGeom)
+
+        self._TestSubsetRetrieval(geom, UsdGeom.Tokens.tetrahedron, "materialBind")
+        self._TestSubsetValidity(geom, varyingGeom, nullGeom, UsdGeom.Tokens.tetrahedron)
+
+        self._TestSubsetRetrieval(geom, UsdGeom.Tokens.face, "materialBind")
+        self._TestSubsetValidity(geom, varyingGeom, nullGeom, UsdGeom.Tokens.face)
+
 
     def test_CreateGeomSubset(self):
         testFile = "Sphere.usda"
@@ -233,110 +262,6 @@ class testUsdGeomSubset(unittest.TestCase):
         (valid, reason) = UsdGeom.Subset.ValidateFamily(geom, 
             UsdGeom.Tokens.face, familyName='materialBind')
         self.assertTrue(valid)
-    
-    def test_PointSubsetRetrievalAndValidity(self):
-        testFile = "Sphere.usda"
-        stage = Usd.Stage.Open(testFile)
-        sphere = stage.GetPrimAtPath("/Sphere/pSphere1")
-        geom = UsdGeom.Imageable(sphere)
-        self.assertTrue(geom)
-
-        pointSubsets = UsdGeom.Subset.GetGeomSubsets(geom, 
-            elementType=UsdGeom.Tokens.point,
-            familyName='point_physicsAttachment')
-        self.assertEqual(len(pointSubsets), 3)
-        
-        self.assertEqual(UsdGeom.Tokens.partition, 
-            UsdGeom.Subset.GetFamilyType(geom, 'point_physicsAttachment'))
-
-        (valid, reason) = UsdGeom.Subset.ValidateFamily(geom, 
-                UsdGeom.Tokens.point, familyName='point_physicsAttachment')
-        self.assertTrue(valid)
-        
-        validFamilies = ['point_physicsAttachment', 'point_validPartition', 
-                         'point_validNonOverlapping', 'point_validUnrestricted',
-                         'point_emptyIndicesSomeTimes']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.point, familyName, True)
-
-        invalidFamilies = ['point_invalidIndices', 'point_badPartition1', 'point_badPartition2',
-                           'point_badPartition3', 'point_invalidNonOverlapping',
-                           'point_invalidUnrestricted', 'point_onlyNegativeIndices',
-                           'point_emptyIndicesAtAllTimes']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.point, familyName, False)
-        
-        varyingMesh = stage.GetPrimAtPath("/Sphere/VaryingMesh")
-        geom = UsdGeom.Imageable(varyingMesh)
-        self.assertTrue(geom)
-
-        validFamilies = ['point_validPartition']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.point, familyName, True)
-
-        invalidFamilies = ['point_invalidNoDefaultTimeElements']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.point, familyName, False)
-
-        nullMesh = stage.GetPrimAtPath("/Sphere/NullMesh")
-        geom = UsdGeom.Imageable(nullMesh)
-        self.assertTrue(geom)
-
-        invalidFamilies = ['point_emptyIndicesAtAllTimes', 'point_invalidPartition']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.point, familyName, False)
-
-    def test_EdgeSubsetRetrievalAndValidity(self):
-        testFile = "Sphere.usda"
-        stage = Usd.Stage.Open(testFile)
-        sphere = stage.GetPrimAtPath("/Sphere/pSphere1")
-        geom = UsdGeom.Imageable(sphere)
-        self.assertTrue(geom)
-
-        edgeSubsets = UsdGeom.Subset.GetGeomSubsets(geom, 
-            elementType=UsdGeom.Tokens.edge,
-            familyName='edge_physicsAttachment')
-        self.assertEqual(len(edgeSubsets), 3)
-        
-        self.assertEqual(UsdGeom.Tokens.partition, 
-            UsdGeom.Subset.GetFamilyType(geom, 'edge_physicsAttachment'))
-
-        (valid, reason) = UsdGeom.Subset.ValidateFamily(geom, 
-                UsdGeom.Tokens.edge, familyName='edge_physicsAttachment')
-        self.assertTrue(valid)
-        
-        validFamilies = ['edge_physicsAttachment', 'edge_validPartition', 
-                         'edge_validNonOverlapping', 'edge_validUnrestricted',
-                         'edge_emptyIndicesSomeTimes']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.edge, familyName, True)
-
-        invalidFamilies = ['edge_invalidIndices', 'edge_badPartition1', 'edge_badPartition2',
-                           'edge_badPartition3', 'edge_invalidNonOverlapping',
-                           'edge_invalidUnrestricted', 'edge_onlyNegativeIndices',
-                           'edge_emptyIndicesAtAllTimes']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.edge, familyName, False)
-        
-        varyingMesh = stage.GetPrimAtPath("/Sphere/VaryingMesh")
-        geom = UsdGeom.Imageable(varyingMesh)
-        self.assertTrue(geom)
-
-        validFamilies = ['edge_validPartition']
-        for familyName in validFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.edge, familyName, True)
-
-        invalidFamilies = ['edge_invalidNoDefaultTimeElements']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.edge, familyName, False)
-
-        nullMesh = stage.GetPrimAtPath("/Sphere/NullMesh")
-        geom = UsdGeom.Imageable(nullMesh)
-        self.assertTrue(geom)
-
-        invalidFamilies = ['edge_emptyIndicesAtAllTimes', 'edge_invalidPartition']
-        for familyName in invalidFamilies:
-            self._ValidateFamily(geom, UsdGeom.Tokens.edge, familyName, False)
 
 if __name__ == "__main__":
     unittest.main()
index 95cb175d48549b6b8d3d0777bc747b071c6bd861..6cfa9aba76433b54ea889fa9a630c821230e8ec1 100644 (file)
@@ -9,6 +9,670 @@ def Xform "Sphere" (
     kind = "component"
 )
 {
+
+    def TetMesh "TetMesh"
+    {
+        # Tetrahedron subsets
+
+        uniform token subsetFamily:tetrahedron_materialBind:familyType = "partition"
+        uniform token subsetFamily:tetrahedron_validPartition:familyType = "partition"
+
+        uniform token subsetFamily:tetrahedron_badPartition1:familyType = "partition"
+        uniform token subsetFamily:tetrahedron_badPartition2:familyType = "partition"
+        uniform token subsetFamily:tetrahedron_badPartition3:familyType = "partition"
+
+        uniform token subsetFamily:tetrahedron_validNonOverlapping:familyType = "nonOverlapping"
+        uniform token subsetFamily:tetrahedron_invalidNonOverlapping:familyType = "nonOverlapping"
+
+        uniform token subsetFamily:tetrahedron_validUnrestricted:familyType = "unrestricted"
+        uniform token subsetFamily:tetrahedron_invalidUnrestricted:familyType = "unrestricted"
+
+        # Face subsets
+
+        uniform token subsetFamily:face_materialBind:familyType = "partition"
+        uniform token subsetFamily:face_validPartition:familyType = "partition"
+
+        uniform token subsetFamily:face_badPartition1:familyType = "partition"
+        uniform token subsetFamily:face_badPartition2:familyType = "partition"
+        uniform token subsetFamily:face_badPartition3:familyType = "partition"
+
+        uniform token subsetFamily:face_validNonOverlapping:familyType = "nonOverlapping"
+        uniform token subsetFamily:face_invalidNonOverlapping:familyType = "nonOverlapping"
+
+        uniform token subsetFamily:face_validUnrestricted:familyType = "unrestricted"
+        uniform token subsetFamily:face_invalidUnrestricted:familyType = "unrestricted"
+        
+        int4[] tetVertexIndices = [(0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (3, 0, 4, 7), (4, 5, 9, 8), (5, 6, 10, 9), (6, 7, 11, 10), (7, 4, 8, 11), (1, 0, 12, 2), (1, 12, 3, 2), (12, 0, 3, 13), (8, 9, 13, 10), (10, 13, 12, 11), (13, 11, 8, 10)]
+        int3[] surfaceFaceVertexIndices = [(0, 4, 5), (7, 4, 11), (2, 3, 6), (3, 4, 0), (2, 7, 3), (8, 10, 13), (13, 12, 11), (4, 8, 11), (10, 12, 13), (0, 1, 4), (3, 7, 4), (10, 13, 11), (0, 5, 1), (1, 2, 12)]
+        PointFloat[] points = [(6.59105e-07, 5.02619, -5.02619), (-5.02619, 4.39403e-07, -5.02619), (-2.19702e-07, -5.02619, -5.02619), (5.02619, -1.11604e-15, -5.02619), (9.32115e-07, 7.10811, -1.57832e-15), (-7.10811, 6.2141e-07, -1.37981e-22), (-3.10705e-07, -7.10811, 1.57832e-15), (7.10811, 0, 0), (6.59105e-07, 5.02619, 5.02619), (-5.02619, 4.39403e-07, 5.02619), (-2.19702e-07, -5.02619, 5.02619), (5.02619, 1.11604e-15, 5.02619), (0, -1.57832e-15, -7.10811), (0, 1.57832e-15, 7.10811)]
+
+        def GeomSubset "tetrahedron_green" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_materialBind"
+            int[] indices = [12, 13]
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3],
+                2: [12, 13],
+                3: [0, 1, 2, 3]
+            }
+            rel material:binding =  </Sphere/Looks/initialShadingGroup>
+        }
+
+
+        def GeomSubset "tetrahedron_blue" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_materialBind"
+            int[] indices = [0, 1, 2, 3, 8, 9, 10, 11]
+            rel material:binding =  </Sphere/Looks/lambert2SG>
+            int[] indices.timeSamples = {
+                1: [4, 5, 6, 7, 8, 9, 10, 11],
+                2: [0, 1, 2, 3, 8, 9, 10, 11],
+                3: [4, 5, 6, 7, 8, 9, 10, 11]
+            }
+        }
+
+
+        def GeomSubset "tetrahedron_red" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_materialBind"
+            int[] indices = [4, 5, 6, 7]
+            rel material:binding =  </Sphere/Looks/lambert3SG>
+            int[] indices.timeSamples = {
+                1: [12, 13],
+                2: [4, 5, 6, 7],
+                3: [12, 13]
+            }
+        }
+
+
+        def GeomSubset "tetrahedron_invalidIndices" 
+        # Indices 16 at frame 2 and -1 at frame 3 are invalid.
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidIndices"
+            int[] indices = [4, 5, 6, 7]
+            int[] indices.timeSamples = {
+                1: [12, 13],
+                2: [4, 5, 6, 7, 16],
+                3: [-1, 12, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validNonOverlapping_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validNonOverlapping"
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]            
+            int[] indices.timeSamples = {
+                1: [1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validNonOverlapping_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validNonOverlapping"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "tetrahedron_invalidNonOverlapping_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidNonOverlapping"
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]            
+            int[] indices.timeSamples = {
+                1: [1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_invalidNonOverlapping_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidNonOverlapping"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validUnrestricted_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validUnrestricted"
+            # index 0 is overlapping
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]
+            int[] indices.timeSamples = {
+                # index 13 is not included in timeSamples.
+                1: [0, 1, 3, 5, 7, 9, 11]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validUnrestricted_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validUnrestricted"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "tetrahedron_invalidUnrestricted_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidUnrestricted"
+            # out of bound index - 14
+            int[] indices = [0, 2, 4, 6, 8, 10, 12, 14]            
+            int[] indices.timeSamples = {
+                # negative index
+                1: [-1, 1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_invalidUnrestricted_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidUnrestricted"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "tetrahedron_badPartition1_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_badPartition1"
+            int[] indices = [4, 5, 6, 7]            
+            int[] indices.timeSamples = {
+                1: [12, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_badPartition1_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_badPartition1"
+            int[] indices = [0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
+            }
+        }
+
+        def GeomSubset "tetrahedron_badPartition2_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_badPartition2"
+            # mising indices 8-13
+            int[] indices = [0, 1, 2, 3, 4, 5, 6, 7]
+        }
+
+        def GeomSubset "tetrahedron_badPartition3_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_badPartition3"
+            # duplicate indices 0 and 5
+            int[] indices = [0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 5]
+        }
+
+
+        def GeomSubset "tetrahedron_validPartition_1"
+        {       
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices = [0, 1, 2, 3, 4, 5]
+            int[] indices.timeSamples = {
+                1: [11, 12, 13],
+                3: [0, 1, 2, 3, 4, 5]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validPartition_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices = [6, 7, 8, 9, 10]
+            int[] indices.timeSamples = {
+                1: [6, 7, 8, 9, 10],
+                2: [0, 1, 2, 3, 4, 5],
+                3: [11, 12, 13]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validPartition_3"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices = [11, 12, 13]
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3, 4, 5],
+                2: [6, 7, 8, 9, 10]
+            }
+        }
+
+        def GeomSubset "tetrahedron_onlyNegativeIndices"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_onlyNegativeIndices"
+            int[] indices = [-1, -2, -3, -4, -5]
+        }
+
+        def GeomSubset "tetrahedron_emptyIndicesSomeTimes"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_emptyIndicesSomeTimes"
+            int[] indices.timeSamples = {
+                0: [],
+                1: [0, 1, 2, 3],
+                2: []
+            }
+        }
+
+        def GeomSubset "tetrahedron_emptyIndicesAtAllTimes"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_emptyIndicesAtAllTimes"
+        }
+
+        def GeomSubset "face_green" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_materialBind"
+            int[] indices = [12, 13]
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3],
+                2: [12, 13],
+                3: [0, 1, 2, 3]
+            }
+            rel material:binding =  </Sphere/Looks/initialShadingGroup>
+        }
+
+
+        def GeomSubset "face_blue" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_materialBind"
+            int[] indices = [0, 1, 2, 3, 8, 9, 10, 11]
+            rel material:binding =  </Sphere/Looks/lambert2SG>
+            int[] indices.timeSamples = {
+                1: [4, 5, 6, 7, 8, 9, 10, 11],
+                2: [0, 1, 2, 3, 8, 9, 10, 11],
+                3: [4, 5, 6, 7, 8, 9, 10, 11]
+            }
+        }
+
+
+        def GeomSubset "face_red" (
+            prepend apiSchemas = ["MaterialBindingAPI"]
+        )
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_materialBind"
+            int[] indices = [4, 5, 6, 7]
+            rel material:binding =  </Sphere/Looks/lambert3SG>
+            int[] indices.timeSamples = {
+                1: [12, 13],
+                2: [4, 5, 6, 7],
+                3: [12, 13]
+            }
+        }
+
+
+        def GeomSubset "face_invalidIndices" 
+        # Indices 16 at frame 2 and -1 at frame 3 are invalid.
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidIndices"
+            int[] indices = [4, 5, 6, 7]
+            int[] indices.timeSamples = {
+                1: [12, 13],
+                2: [4, 5, 6, 7, 16],
+                3: [-1, 12, 13]
+            }
+        }
+
+        def GeomSubset "face_validNonOverlapping_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validNonOverlapping"
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]            
+            int[] indices.timeSamples = {
+                1: [1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "face_validNonOverlapping_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validNonOverlapping"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "face_invalidNonOverlapping_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidNonOverlapping"
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]            
+            int[] indices.timeSamples = {
+                1: [1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "face_invalidNonOverlapping_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidNonOverlapping"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "face_validUnrestricted_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validUnrestricted"
+            # index 0 is overlapping
+            int[] indices = [0, 2, 4, 6, 8, 10, 12]
+            int[] indices.timeSamples = {
+                # index 13 is not included in timeSamples.
+                1: [0, 1, 3, 5, 7, 9, 11]
+            }
+        }
+
+        def GeomSubset "face_validUnrestricted_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validUnrestricted"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "face_invalidUnrestricted_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidUnrestricted"
+            # out of bound index - 14
+            int[] indices = [0, 2, 4, 6, 8, 10, 12, 14]            
+            int[] indices.timeSamples = {
+                # negative index
+                1: [-1, 1, 3, 5, 7, 9, 11, 13]
+            }
+        }
+
+        def GeomSubset "face_invalidUnrestricted_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidUnrestricted"
+            int[] indices = [1, 3, 5, 7, 9, 11, 13]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 4, 6, 8, 10, 12]
+            }
+        }
+
+        def GeomSubset "face_badPartition1_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_badPartition1"
+            int[] indices = [4, 5, 6, 7]            
+            int[] indices.timeSamples = {
+                1: [12, 13]
+            }
+        }
+
+        def GeomSubset "face_badPartition1_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_badPartition1"
+            int[] indices = [0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14]
+            int[] indices.timeSamples = {
+                2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
+            }
+        }
+
+        def GeomSubset "face_badPartition2_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_badPartition2"
+            # mising indices 8-13
+            int[] indices = [0, 1, 2, 3, 4, 5, 6, 7]
+        }
+
+        def GeomSubset "face_badPartition3_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_badPartition3"
+            # duplicate indices 0 and 5
+            int[] indices = [0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 5]
+        }
+
+
+        def GeomSubset "face_validPartition_1"
+        {       
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices = [0, 1, 2, 3, 4, 5]
+            int[] indices.timeSamples = {
+                1: [11, 12, 13],
+                3: [0, 1, 2, 3, 4, 5]
+            }
+        }
+
+        def GeomSubset "face_validPartition_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices = [6, 7, 8, 9, 10]
+            int[] indices.timeSamples = {
+                1: [6, 7, 8, 9, 10],
+                2: [0, 1, 2, 3, 4, 5],
+                3: [11, 12, 13]
+            }
+        }
+
+        def GeomSubset "face_validPartition_3"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices = [11, 12, 13]
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3, 4, 5],
+                2: [6, 7, 8, 9, 10]
+            }
+        }
+
+        def GeomSubset "face_onlyNegativeIndices"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_onlyNegativeIndices"
+            int[] indices = [-1, -2, -3, -4, -5]
+        }
+
+        def GeomSubset "face_emptyIndicesSomeTimes"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_emptyIndicesSomeTimes"
+            int[] indices.timeSamples = {
+                0: [],
+                1: [0, 1, 2, 3],
+                2: []
+            }
+        }
+
+        def GeomSubset "face_emptyIndicesAtAllTimes"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_emptyIndicesAtAllTimes"
+        }
+    }
+
+    def TetMesh "VaryingTetMesh"
+    {
+        uniform token subsetFamily:tetrahedron_validPartition:familyType = "partition"
+        uniform token subsetFamily:face_validPartition:familyType = "partition"
+
+        int4[] tetVertexIndices.timeSamples = {
+            1: [(0, 1, 2, 3)],
+            2: [(0, 1, 2, 3), (4, 5, 6, 7)],
+            3: [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
+        }
+
+        int3[] surfaceFaceVertexIndices.timeSamples = {
+            1: [(1, 2, 3), (0, 3, 2), (0, 1, 3), (0, 2, 1)],
+            2: [(1, 2, 3), (0, 3, 2), (0, 1, 3), (0, 2, 1), (5, 6, 7), (4, 7, 6), (4, 5, 7), (4, 6, 5)],
+            3: [(1, 2, 3), (0, 3, 2), (0, 1, 3), (0, 2, 1), (5, 6, 7), (4, 7, 6), (4, 5, 7), (4, 6, 5), (9, 10, 11), (8, 11, 10), (8, 9, 11), (8, 10, 9)]
+        }
+
+        PointFloat[] points.timeSamples = {
+            1: [(6.59105e-07, 5.02619, -5.02619), (-5.02619, 4.39403e-07, -5.02619), (-2.19702e-07, -5.02619, -5.02619), (5.02619, -1.11604e-15, -5.02619)],
+            2: [(6.59105e-07, 5.02619, -5.02619), (-5.02619, 4.39403e-07, -5.02619), (-2.19702e-07, -5.02619, -5.02619), (5.02619, -1.11604e-15, -5.02619), (9.32115e-07, 7.10811, -1.57832e-15), (-7.10811, 6.2141e-07, -1.37981e-22), (-3.10705e-07, -7.10811, 1.57832e-15), (7.10811, 0, 0)],
+            3: [(6.59105e-07, 5.02619, -5.02619), (-5.02619, 4.39403e-07, -5.02619), (-2.19702e-07, -5.02619, -5.02619), (5.02619, -1.11604e-15, -5.02619), (9.32115e-07, 7.10811, -1.57832e-15), (-7.10811, 6.2141e-07, -1.37981e-22), (-3.10705e-07, -7.10811, 1.57832e-15), (7.10811, 0, 0), (6.59105e-07, 5.02619, 5.02619), (-5.02619, 4.39403e-07, 5.02619), (-2.19702e-07, -5.02619, 5.02619), (5.02619, 1.11604e-15, 5.02619)]
+        }
+
+        def GeomSubset "tetrahedron_validPartition_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices.timeSamples = {
+                1: [0],
+                2: [],
+                3: [0]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validPartition_2"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices.timeSamples = {
+                1: [],
+                2: [0, 1],
+                3: [1]
+            }
+        }
+
+        def GeomSubset "tetrahedron_validPartition_3"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_validPartition"
+            int[] indices.timeSamples = {
+                1: [],
+                2: [],
+                3: [2]
+            }
+        }
+
+        def GeomSubset "tetrahedron_invalidNoDefaultTimeElements"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidNoDefaultTimeElements"
+            int[] indices = [0]
+            int[] indices.timeSamples = {
+                1: [0],
+                2: [1],
+                3: [2]
+            }
+        }
+
+        def GeomSubset "face_validPartition_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3],
+                2: [],
+                3: [0, 1, 2, 3]
+            }
+        }
+
+        def GeomSubset "face_validPartition_2"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices.timeSamples = {
+                1: [],
+                2: [0, 1, 2, 3, 4, 5, 6, 7],
+                3: [4, 5, 6, 7]
+            }
+        }
+
+        def GeomSubset "face_validPartition_3"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_validPartition"
+            int[] indices.timeSamples = {
+                1: [],
+                2: [],
+                3: [8, 9, 10, 11]
+            }
+        }
+
+        def GeomSubset "face_invalidNoDefaultTimeElements"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidNoDefaultTimeElements"
+            int[] indices = [0, 1, 2, 3]
+            int[] indices.timeSamples = {
+                1: [0, 1, 2, 3],
+                2: [4, 5, 6, 7],
+                3: [8, 9, 10, 11]
+            }
+        }
+    }
+
+    def TetMesh "NullTetMesh"
+    {
+        uniform token subsetFamily:tetrahedron_invalidPartition:familyType = "partition"
+        uniform token subsetFamily:face_invalidPartition:familyType = "partition"
+
+        def GeomSubset "tetrahedron_emptyIndicesAtAllTimes"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_emptyIndicesAtAllTimes"
+        }
+
+        def GeomSubset "tetrahedron_invalidPartition_1"
+        {
+            uniform token elementType = "tetrahedron"
+            uniform token familyName = "tetrahedron_invalidPartition"
+            int[] indices = [0, 1, 2, 3]
+        }
+
+        def GeomSubset "face_emptyIndicesAtAllTimes"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_emptyIndicesAtAllTimes"
+        }
+
+        def GeomSubset "face_invalidPartition_1"
+        {
+            uniform token elementType = "face"
+            uniform token familyName = "face_invalidPartition"
+            int[] indices = [0, 1, 2, 3]
+        }
+    }
+    
     def Mesh "pSphere1" 
     {
         Vec3f[] extent = [(-7.10811, -7.10811, -7.10811), (7.10811, 7.10811, 7.10811)]
index 091ea140bdf631a3f6a4c9e4352eff9450ee886b..343a05b2b63e2eb2681d5d24d195d9fdc5a85345 100644 (file)
@@ -158,6 +158,7 @@ UsdGeomTokensType::UsdGeomTokensType() :
     subdivisionScheme("subdivisionScheme", TfToken::Immortal),
     surfaceFaceVertexIndices("surfaceFaceVertexIndices", TfToken::Immortal),
     tangents("tangents", TfToken::Immortal),
+    tetrahedron("tetrahedron", TfToken::Immortal),
     tetVertexIndices("tetVertexIndices", TfToken::Immortal),
     triangleSubdivisionRule("triangleSubdivisionRule", TfToken::Immortal),
     trimCurveCounts("trimCurve:counts", TfToken::Immortal),
@@ -359,6 +360,7 @@ UsdGeomTokensType::UsdGeomTokensType() :
         subdivisionScheme,
         surfaceFaceVertexIndices,
         tangents,
+        tetrahedron,
         tetVertexIndices,
         triangleSubdivisionRule,
         trimCurveCounts,
index cfd9fb86dd14bb700ad58e6032dd405c23ccf155..6f90a61dce5b6e1371bb920e8d8360857fd724fa 100644 (file)
@@ -590,6 +590,10 @@ struct UsdGeomTokensType {
     /// 
     /// UsdGeomHermiteCurves
     const TfToken tangents;
+    /// \brief "tetrahedron"
+    /// 
+    /// Possible value for UsdGeomSubset::GetElementTypeAttr()
+    const TfToken tetrahedron;
     /// \brief "tetVertexIndices"
     /// 
     /// UsdGeomTetMesh
index 91a574e9445cd3a7367f96b476e0e8f942e87018..b07f9a429bca17db8c45d35ba073dfa18a916818 100644 (file)
@@ -196,6 +196,7 @@ void wrapUsdGeomTokens()
     _AddToken(cls, "subdivisionScheme", UsdGeomTokens->subdivisionScheme);
     _AddToken(cls, "surfaceFaceVertexIndices", UsdGeomTokens->surfaceFaceVertexIndices);
     _AddToken(cls, "tangents", UsdGeomTokens->tangents);
+    _AddToken(cls, "tetrahedron", UsdGeomTokens->tetrahedron);
     _AddToken(cls, "tetVertexIndices", UsdGeomTokens->tetVertexIndices);
     _AddToken(cls, "triangleSubdivisionRule", UsdGeomTokens->triangleSubdivisionRule);
     _AddToken(cls, "trimCurveCounts", UsdGeomTokens->trimCurveCounts);