To filter selections of subcomponents (edges, points, or polygons), Softimage prefers the Subset callback to the Match callback. That is, Softimage calls Subset instead of the Match callback when a user selects some subcomponents. You should always provide a Subset callback for a subcomponent filter.
When Softimage calls Subset, it puts an XSICollection in the Input attribute of the callback context. This collection contains one CollectionItem for each 3D object with selected subcomponents. In the callback function, you get the selected subcomponents from the CollectionItem.SubComponent.ComponentCollection property.
The following example shows the typical structure of a Subset callback for subcomponent filter. First, the callback creates a new XSICollection, which will be used to hold the output of the callback. Then for each 3D object, Subset finds the matching polygons and creates a new SubComponent object with them. The new SubComponent objects are added to the output collection, and the collection is put in the Output attribute of the callback context.
function MyPolygonFilter_Subset( oContext ) { var oFilter = oContext.Source; logmessage( oFilter.Name + "_Subset"); // Create a new XSICollection to hold the output var cloSubset = new ActiveXObject( "XSI.Collection" ); // Get the XSI.Collection from the context // The collection contains one CollectionItem for each object with selected polygons var cloObjects = oContext.GetAttribute( "Input" ); for (var objEnumerator = new Enumerator(cloObjects) ; !objEnumerator.atEnd(); objEnumerator.moveNext()) { // Get the CollectionItem var oItem = objEnumerator.item(); // Get the SubComponent object var oPolySubComponent = oItem.SubComponent; if ( !( (classname(oPolySubComponent) == "SubComponent") && ( oPolySubComponent.type == "polySubComponent" ) ) ) continue; // This array will hold the indices of the polygons that match the filter conditions var aIndices = new Array(); // Enumerate the selected polygons; if a polygon matches, put its index in the array for (var polyEnumerator = new Enumerator(oPolySubComponent.ComponentCollection) ; !polyEnumerator.atEnd(); polyEnumerator.moveNext()) { var oPoly = polyEnumerator.item(); if ( polygon_isamatch( oPoly ) ) { aIndices.push( oPoly.index ); } } // Create a SubComponent from the subset of polygons that match, and add the SubComponent to the output if ( aIndices.length > 0 ) { var oSubComponent = oPolySubComponent.Parent3DObject.ActivePrimitive.Geometry.CreateSubComponent(siPolygonCluster, aIndices ); cloSubset.Add( oSubComponent ); } } // You always set the Output attribute, even if the subset is empty oContext.SetAttribute( "Output", cloSubset ); // Return True if the subset is non-empty return (cloSubset.Count > 0); } // Select only polygons with more than 3 points function polygon_isamatch( oPoly ) { return ( oPoly.NbPoints != 3 ) }
Another way to implement a Subset callback is to work directly with the SubComponent objects passed in by Softimage. In this approach, you use SubComponent.RemoveElement to remove the polygons that don't match, and put the modified SubComponent in the output collection.
function MyPolygonFilter_Subset( oContext ) { var cloSubset = new ActiveXObject( "XSI.Collection" ); var cloObjects = oContext.GetAttribute( "Input" ); for (var objEnumerator = new Enumerator(cloObjects) ; !objEnumerator.atEnd(); objEnumerator.moveNext()) { var oItem = objEnumerator.item(); var oPolySubComponent = oItem.SubComponent; if ( !( (classname(oPolySubComponent) == "SubComponent") && ( oPolySubComponent.type == "polySubComponent" ) ) ) continue; // Get a copy of the PolygonFaceCollection; // We'll enumerate cloTmpCopy, and modify oPolySubComponent.ComponentCollection var cloTmpCopy = oPolySubComponent.ComponentCollection; // Enumerate the selected polygons; if a polygon doesn't match, remove it from oPolySubComponent for (var polyEnumerator = new Enumerator(cloTmpCopy) ; !polyEnumerator.atEnd(); polyEnumerator.moveNext()) { var oPoly = polyEnumerator.item(); if ( !polygon_isamatch( oPoly ) ) { oPolySubComponent.RemoveElement( oPoly.index ); } } // Add the modified SubComponent the output collection if ( aIndices.length > 0 ) { cloSubset.Add( oPolySubComponent ); } } oContext.SetAttribute( "Output", cloSubset ); return (cloSubset.Count > 0); }
For subcomponent filters, Subset is the most important callback. Softimage won't call Match unless a filter doesn't have a Subset callback. However, Match is required, so you must provide an implementation. Typically, Match returns false as soon as it finds a subcomponent that doesn't match the filter conditions.
When Softimage calls Match for a subcomponent filter, it puts a SubComponent object in the callback context. The following example shows a typical structure for a Match callback.
function MyPolygonFilter_Match( oContext ) { // Get the SubComponent object from the context var oPolySubComponent = oContext.GetAttribute( "Input" ); // Return false if we don't have a SubComponent, or we don't have polygons if ( !( (classname(oPolySubComponent) == "SubComponent") && ( oPolySubComponent.type == "polySubComponent" ) ) ) { return false; } // Enumerate the selected polygons; Return false as soon as we find a polygon that doesn't match for (var polyEnumerator = new Enumerator(oPolySubComponent.ComponentCollection) ; !polyEnumerator.atEnd(); polyEnumerator.moveNext()) { var oPoly = polyEnumerator.item(); if ( !polygon_isamatch( oPoly ) ) { return false; } } // If we make it here, all the polygons match return true; }