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
