Polygon Islands, arrays, and indices


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

One thought on “Polygon Islands, arrays, and indices

  1. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s