I was skimming through Guillaume’s posts on polygon islands and arrays, and in particular I was looking at the Get Lowest Point Index by Islands compound. That’s a pretty neat technique for sure, but I had to think about it a bit before I really understood what was going on…
So as an exercise I took a different approach. I used scripting to find the polygon islands and generate an array of island indices for the polygons, and then plugged that into ICE:
For the script, I adapted a script posted by Alan Fregtman to return a list of lists (a list of islands, and for each island, a list of poly indices).
Here’s the code:
from siutils import si # Application from siutils import log # LogMessage from siutils import disp # win32com.client.Dispatch from siutils import C # win32com.client.constants def getPolygonIslands( o ): if not o or o.type != "polymsh" : log( "Cannot work without an object" ) return selFilter = si.Filters("Polygon_Island") thisPoly = XSIFactory.CreateActiveXObject("XSI.Collection") # List of lists islands = [] # List of polygons that have already been checked usedArr = [] for poly in o.ActivePrimitive.Geometry.Polygons: if poly.Index not in usedArr: thisPoly.Add(poly) island = selFilter.Subset(thisPoly) island = si.Dictionary.GetObject(island).SubComponent.ComponentCollection.IndexArray usedArr.extend(island) islands.append( island ) thisPoly.RemoveAll() return islands islands = getPolygonIslands( si.Selection(0) ) log( islands ) # INFO : [(0, 6, 7, 10, 11), (1, 2, 3, 4, 5, 18, 20, 22), (8, 9, 12, 13, 14, 15, 16, 17, 19, 21, 23, 24)] # I use a dict instead or pre-initializing a list of the required size dict = {} for i in range(len(islands)): for j in range(len(islands[i])): dict[islands[i][j]] = str(i) log( ",".join( dict.itervalues()) ) # INFO : 0,1,1,1,1,1,0,0,2,2,0,0,2,2,2,2,2,2,1,2,1,2,1,2,2
To get that into an ICE Tree, I put together a little plugin that adds a menu command to the ICE Tree > User Tools menu.
By using a menu item callback, I can get the ICE Tree view from the callback context, and then from the view, the ICE Tree operator via the container view attribute.
I scripted the creation of the little ICE tree, and that’s pretty tedious work. If I was going to distribute something like this, I think I’d include a pre-built compound in an addon.
# GetPolygonIslandsPlugin # Initial code generated by Softimage SDK Wizard # Executed Wed Mar 21 06:36:33 EDT 2012 by blairs # from siutils import si # Application from siutils import log # LogMessage from siutils import disp # win32com.client.Dispatch from siutils import C # win32com.client.C null = None false = 0 true = 1 def XSILoadPlugin( in_reg ): in_reg.Author = "blairs" in_reg.Name = "GetPolygonIslandsPlugin" in_reg.Major = 1 in_reg.Minor = 0 in_reg.RegisterCommand("GetPolygonIslands","GetPolygonIslands") in_reg.RegisterMenu(C.siMenuICEViewToolsID,"GetPolygonIslands_Menu",false,false) #RegistrationInsertionPoint - do not remove this line return true def XSIUnloadPlugin( in_reg ): strPluginName = in_reg.Name Application.LogMessage(str(strPluginName) + str(" has been unloaded."),C.siVerbose) return true def GetPolygonIslands_Init( in_ctxt ): oCmd = in_ctxt.Source oCmd.Description = "" oCmd.ReturnValue = true oArgs = oCmd.Arguments oArgs.AddWithHandler("object","SingleObj") return true def GetPolygonIslands_Execute( object ): Application.LogMessage("GetPolygonIslands_Execute called",C.siVerbose) if not object or object.type != "polymsh" : log( "GetPolygonIslands: Cannot work without an object" ) return selFilter = si.Filters("Polygon_Island") thisPoly = XSIFactory.CreateActiveXObject("XSI.Collection") # List of lists islands = [] # List of polygons that have already been checked usedArr = [] for poly in object.ActivePrimitive.Geometry.Polygons: if poly.Index not in usedArr: log( poly.Index ) thisPoly.Add(poly) island = selFilter.Subset(thisPoly) island = si.Dictionary.GetObject(island).SubComponent.ComponentCollection.IndexArray usedArr.extend(island) islands.append( island ) thisPoly.RemoveAll() return islands def GetPolygonIslands_Menu_Init( in_ctxt ): oMenu = in_ctxt.Source oMenu.AddCallbackItem( "Get Polygon Islands Index Array", "OnGetPolygonIslands" ) return true def OnGetPolygonIslands( in_ctxt ): Application.LogMessage("OnGetPolygonIslands called",C.siVerbose) view = in_ctxt.GetAttribute( "Target" ) op = si.Dictionary.GetObject( view.GetAttributeValue( "container" ) ) log( "Getting polygon islands. This may take a few seconds..." ) islands = si.GetPolygonIslands( op.Parent3DObject ) log( "Building polygon island index list" ) dict = {} for i in range(len(islands)): for j in range(len(islands[i])): dict[islands[i][j]] = str(i) s = ",".join( dict.itervalues() ) # Temporarily disable command logging bLog = si.Preferences.GetPreferenceValue( "scripting.cmdlog" ) if bLog == True: si.Preferences.SetPreferenceValue( "scripting.cmdlog", False ) # Add String node to ICE tree oStringNode = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\StringNode.Preset", op.FullName ) oStringNode.Parameters( "value_string" ).Value = s # # Set up ICE branch to set the attributes: # self._polyPolygonIslandIndex # self._vertPolygonIslandIndex attributes # oStringToArray = si.AddICENode("StringToArray", op.FullName) si.ConnectICENodes( oStringToArray.InputPorts("Value"), oStringNode.OutputPorts("result") ) oSelectInArrayNode = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\SelectInArrayNode.Preset", op.FullName) oIntegerNode = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\IntegerNode.Preset", op.FullName) si.ConnectICENodes( oSelectInArrayNode.InputPorts("array"), oIntegerNode.OutputPorts("result") ) si.ConnectICENodes( oSelectInArrayNode.InputPorts("array"), oStringToArray.OutputPorts("result") ) si.DeleteObj( oIntegerNode ) oGet_Polygon_Index = si.AddICECompoundNode("Get Polygon Index", op.FullName) si.ConnectICENodes(oSelectInArrayNode.InputPorts("index"), oGet_Polygon_Index.OutputPorts("Polygon_Index")) oSetDataNode = si.AddICECompoundNode("Set Data", op.FullName ) si.SetValue( oSetDataNode.FullName + ".Reference", "self._polyPolygonIslandIndex", "") si.AddPortToICENode(oSetDataNode.FullName + ".Value", "siNodePortDataInsertionLocationAfter") si.SetValue(oSetDataNode.FullName + ".Reference1", "self._vertPolygonIslandIndex", "") si.ConnectICENodes( oSetDataNode.InputPorts("Value"), oSelectInArrayNode.OutputPorts("value") ) oSelectInArrayNode = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\SelectInArrayNode.Preset", op.FullName) oSelectInArrayNode1 = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\SelectInArrayNode.Preset", op.FullName) oGetDataNode = si.AddICENode("$XSI_DSPRESETS\\ICENodes\\GetDataNode.Preset", op.FullName) si.SetValue( oGetDataNode.FullName + ".reference", "this.VertexToPolygons", "") si.ConnectICENodes(oSelectInArrayNode.InputPorts("array"), oGetDataNode.OutputPorts("value") ) si.ConnectICENodes( oSelectInArrayNode1.InputPorts("index"), oSelectInArrayNode.OutputPorts("value") ) si.ConnectICENodes( oSelectInArrayNode1.InputPorts("array"), oStringToArray.OutputPorts("result") ) si.ConnectICENodes( oSetDataNode.InputPorts("Value1"), oSelectInArrayNode1.OutputPorts("value") ) # Put back original pref value for command logging si.Preferences.SetPreferenceValue( "scripting.cmdlog", bLog ) return true
Nice post. I love PolygonIslandTransform as well, and wondered if you would take on a bigger challenge in reproducing that effect? Guill is running a script to create the polygon islands, you think you could wire up an ICE tree that could create polygon islands?
That’s the part I’m stuck on.