Select to view content in your preferred language

geoprocessing tool output to geometry object in for loop

3965
3
02-13-2011 08:52 AM
ChristianDevenish
Emerging Contributor
Hi,

I'm new to python (and programming in general), in a script I want to loop through a feature class, use a geoprocessing tool on each row, and access the area of the new (temporary features) created by the tool. 

On the help pages for the geometry object, it states that a blank object can be created for temporary output, for example:

workspace = ".../file.gdb"
testShape = ".../test_graphics"
dBufDis = -10

g = arcpy.Geometry()
geometryList = arcpy.Buffer_analysis(testShape, g, dBufDis)
for geometry in geometryList:
    print geometry.area


The above works on my test shape and I get a list of areas of the new buffers, however, I want to put the geoprocessing tool into a loop something like this:

rows = arcpy.SearchCursor(testShape)

for row in rows:
    g = arcpy.Geometry() 
    rowShape = row.getValue(shapeName)
    arcpy.Buffer_analysis(rowShape, g, dBufDis)


and then access the area for each row, but this is where I can't seem to get to the area property of the temporary geoprocessing output. Why doesn't "g.area" return the area? If .area is a property of the geometry object? Hasn't g been "populated" by the output of the processing tool for each row?

Thanks for any help.
Tags (2)
0 Kudos
3 Replies
KimOllivier
Honored Contributor
You would think that you would extract a geometry object using a cursor, but it doesn't work for some obscure reason. You have to extract out all the vertices, put them in an array and rebuild a geometry object array. Much too hard.

If you copy the entire featureclass into a geometry object and loop through that array of objects then it will work as expected. They are examples in the 10.x help but they skip any advice on the appropriateness of the function for geoprocessing.

You really don't want to "step through a featureclass applying a tool". The tools are designed just like SQL operators to work on a whole featureclass with an implied loop. Besides, a geometry object is stripped of its attributes, it's not a full feature.

Just consider how we might have managed before 10.0 without geometry operators. Think of the tool processing the whole featureclass and then analyse the results with another tool. ModelBuilder is supposed to lead you in this direction. Although ModelBuilder can emit a script, it does not make very readable scripts, but at least it avoids cursors for routine geoprocessing tasks.
0 Kudos
ChristianDevenish
Emerging Contributor
Many thanks for the reply, I'd appreciate a few pointers as to how to do apply this to the feature as a whole. Let me explain what I'm trying to do. I want to translate a VBA script to python (from this post:http://forums.esri.com/Thread.asp?c=...=220690#668542 , script copied below) that allows inner buffers to be drawn to certain percentages of the original polygon's area.

The script iterates through different buffers, changing the buffer distance until the buffer area is within a pre-established tolerance range. I thought that this would be best done by using a search cursor and calculating the buffer per row. From looking at the online help, etc on python, I managed to get the initial buffer distance, minimum and maximum tolerance areas from per row, by looping through the table, but then got stuck with the output of the buffer tool for each row.

However, in light of the reply, it looks like the original script also working on the feature class as a whole, is this correct? For example, in the first part (where the valid area range is calculated), is dMinArea a list of areas for each feature in the feature class? How would I get this from the feature class as a whole, can this be done with the Describe function in arcpy? Some advice on the general way of going about this would be greatly appreciated, so that I can continue trying to work this out.


-----
VBA:
Script:

' ---- You may need to adjust these values ----
Const PCNT_RED As Double = 20
Const PCNT_TOL As Double = 0.001
' ---------------------------------------------
Const NUM_FMT = "0.0##############"
Dim dMinArea As Double
Dim dMaxArea As Double
Dim dMinDis As Double
Dim dMaxDis As Double
Dim dBufDis As Double
Dim pEnv As IEnvelope
Dim pPoly As IPolygon
Dim dPolyArea As Double
Dim pTopOp As ITopologicalOperator
Dim pBuffer As IPolygon
Dim pArea As IArea
Dim dBufArea As Double

' Get a ref to the polygon
Set pPoly = [Shape]
Set pTopOp = pPoly
pTopOp.Simplify

' Calc valid area range
Set pArea = pPoly
dPolyArea = pArea.Area
dMinArea = dPolyArea * (1 - (PCNT_RED + PCNT_TOL) / 100)
dMaxArea = dPolyArea * (1 - (PCNT_RED - PCNT_TOL) / 100)

' Calc min/max/initial bufferdis
Set pEnv = pPoly.Envelope
With pEnv
If .Width > .Height Then
dMaxDis = .Width / 2
Else
dMaxDis = .Height / 2
End If
End With
dMinDis = -dMaxDis
dBufDis = (dMinDis + dMaxDis) / 2

' Get the buffer
Set pBuffer = pTopOp.Buffer(dBufDis)
' Iterate through adjusting the buffer until we get a value
' within our agreed range or until we get as close as possible
Do While Format(dMinDis, NUM_FMT) <> Format(dMaxDis, NUM_FMT)

' Check buffered area is within valid range
Set pArea = pBuffer
dBufArea = pArea.Area
If dBufArea >= dMinArea And dBufArea <= dMaxArea Then Exit Do

' Check if we have a negative area
If dBufArea < 0 Then
' We have, so just use the original polygon
Set pBuffer = pPoly
Exit Do
End If

' Readjust buffer distance
If dBufArea < dMinArea Then
dMinDis = dBufDis
Else
dMaxDis = dBufDis
End If
dBufDis = (dMinDis + dMaxDis) / 2

' Generate the buffer from adjusted distance
Set pBuffer = pTopOp.Buffer(dBufDis)

Loop

' Use pBuffer in box below Advanced Window 
WilliamWhiteford
New Contributor

Hi Christian - did you find a tool or rewrite this VBA script in Python?  I am also interested in creating polygons within polygons based on a percentage reduction.  Please let me know.  Cheers, Bill

0 Kudos