Using the PolygonArea ICE attribute to select similar polygons


After seeing this select similar post on xsibase, I wrote this Python example that uses the PolygonArea ICE attribute to find polygons with similar areas. I didn’t want to use a custom preference or any ppg, so this script looks for [more-or-less] equal areas rather than for a value range. It’d probably be more useful to look for areas within a certain range (but that would require user input).

To use this script, select a polygon and then run the script. It’ll select all polygons with the “same” area.

This ss_SelectSimilarPolys add-on uses a threshold to define an area range (and it uses PolygonArea too). RCTools also lets you specify an area range, along with a number of other things like number of edges and poly orientation, in its custom Polygon selection filter.

from siutils import si		# Application
from siutils import sidict	# Dictionary
from siutils import sisel	# Selection
from siutils import log		# LogMessage
from siutils import C		# win32com.client.constants

# Number of decimal places
# For example, do I match .776 or .78 ?
# With 2 decimal places, anything in the range (7.75, 7.85) will be caught by .78
gPrecision = 2

# Need this for .Polygons later...
def dispFix( badDispatch ):
	import win32com.client.dynamic
	# Re-Wraps a bad dispatch into a working one:
	return win32com.client.dynamic.Dispatch(badDispatch)


# Get selected polygons
polys = sisel(0).SubComponent.ComponentCollection

# Get index of first selected polygon
ix = polys(0).Index

# Get primitive of parent 3D object
prim = sisel(0).SubComponent.Parent3DObject.ActivePrimitive
prim = dispFix(prim)

# Get PolygonArea DataArray (which is a tuple)
attr = prim.GetICEAttributeFromName( "PolygonArea" )
areaData = attr.DataArray

# Round PolygonArea to the specified precision
roundedAreas = [round(x,gPrecision) for x in areaData]

# Get the area that you want to match
areaToMatch = roundedAreas[ ix ]

# Get all polys with a similar PolygonArea and select them
#
# Function findall from http://effbot.org/zone/python-list.htm
def findall(L, value, start=0):
        # generator version
        i = start - 1
        try:
			while 1:
				i = L.index(value, i+1)
				yield i
        except ValueError:
            pass
			
for ix in findall(roundedAreas, areaToMatch ):
	sisel.Add( prim.Geometry.Polygons( ix ) )