Depicting Uneven Tree Crowns

819
6
03-11-2022 08:31 AM
Labels (2)
WennyiDing
New Contributor II

I'm trying to create polygon features depicting the crowns of trees based on a CSV of tree measurements that were collected in the field.

Each tree record includes the co-ordinates of the trunk in X and Y fields, and the crown dimensions are stored as 4 measurements (in metres) that record the distance from the trunk to the edge of the crown at each cardinal direction (north, south, east and west). I need to show crowns that accord with these measurements (i.e. a tree with a 'Crown East' field of 4m and a 'Crown West' field of 2m will need to produce a crown polygon that is suitably asymmetrical).

Is there any way to use Geoprocessing tools to draw ellipses / polygons to represent the crowns based on this information?

I'm using ArcGIS Pro 2.7 with a Basic licence.

0 Kudos
6 Replies
BryndaHatch
Esri Contributor

My first thought was the Extrude Features to 3D Symbology feature: https://pro.arcgis.com/en/pro-app/latest/help/mapping/layer-properties/extrude-features-to-3d-symbol...

But this would just make your trees the right height.  I'll keep thinking about your actual question.

0 Kudos
BryndaHatch
Esri Contributor

This tool would create ellipses using your attributes, but it assumes a major and a minor axis.  (symmetrical, not asymmetrical); https://pro.arcgis.com/en/pro-app/latest/help/data/distance-direction/create-ellipses.htm

And my last idea is to use Arcade Expressions, but I don't have a specific suggestion to help.

0 Kudos
WennyiDing
New Contributor II

Thanks for this. I did have a look at the Create Ellipses tool, but as you say, it seems to only produce symmetrical ellipses. I'll investigate Arcade Expressions and see if I can work anything out.

0 Kudos
RhettZufelt
MVP Frequent Contributor

Not sure about a geoprocessing tool, but with arcpy this is pretty simple.

Though, with 4 measures from the point, it will create rectangles oriented N/S/E/W.

Basically, would add new columns for 4 coordinate pairs (X1,Y1,  X2, Y2,........Y4).

then you would add/subtract the measures from the coordinates giving you the corner points of the polygon.

Dump those points to a polygon, and you have your rectangles.

RhettZufelt_0-1647367006737.png

Could even subtract a certain amount from the difference, then buffer with that amount to make them rounded corner rectangles (same point as above, but minus 10 from polygon, then 10 on buffer).

RhettZufelt_1-1647367058676.png

If arcpy is an option for you, I can share the code that did the above.  would just need some tweaking to fit your dataset.

R_

 

With GeoTools, you could massage the spreadsheet then use one of these methods to generate the polygons.

0 Kudos
WennyiDing
New Contributor II

Thanks for this!

If you're happy to share the code, I'll have a look and see if I can get to the buffered rectangles as above. Unfortunately, I'll probably have to keep going from there to see if I can get them a little closer to real crown shapes / ellipses after that, but this is definitely a step in the right direction.

0 Kudos
RhettZufelt
MVP Frequent Contributor

This is the code I used to do the above.

import arcpy

# Overwrite pre-existing files
arcpy.env.overwriteOutput = True

#####  set input point feature class and output FC for polygons and buffers

infc = r'Database Connections\pathToInputFeatureClass\testpoints'
outfc = r'Database Connections\pathToOutputPolygonFeatureClass\polygons' 
bufffc = r'Database Connections\pathToOutputBufferPolygonFeatureClass\buffers' 

## set the size of the buffer (in map units) for the buffered polygons

buff = 10

##  this line caluclates the x,y values of the points in fields named "x" and "y".
## can omit if you already have these columns with x,y coordinates of the point

arcpy.management.CalculateGeometryAttributes(infc, "x POINT_X;y POINT_Y", '', '', None, "SAME_AS_INPUT")

###  Expects these fields in the input FC.  "x" and "y" are the coordinates
###  the rest I added manually to the FC to hold the new corner coordsinates
###  and the distance measured in each cardinal direction from the tree

#        Index numbers to make it easier to tell what row[#] refers to.
#         [0]   [1]   [2]   [3]   [4]  [5]   [6]   [7]  [8] [9] [10]  [11] [12] [13]
fields = ['X1', 'Y1', 'X2', 'Y2', 'X3','Y3', 'X4', 'Y4','x', 'y', 'n', 's', 'e', 'w']

###  This updatecursor adds/updates the new corner coordinate columns
###   the "- buff" subtracts the buffer value from each new coordinate
###  set to buff=0 above to have straight output without buffer

with arcpy.da.UpdateCursor(infc, fields) as ucursor:
  for row in ucursor: 
      row[0] = row[8] - row[13] - buff
      row[1] = row[9] + row[10] - buff
      row[2] = row[8] + row[12] - buff
      row[3] = row[9] + row[10] - buff
      row[4] = row[8] + row[12] - buff
      row[5] = row[9] - row[11] - buff
      row[6] = row[8] - row[13] - buff
      row[7] = row[9] - row[11] - buff
      ucursor.updateRow(row)  
      
## Fields to establish the search curson on the newly populated input FC.

fields = ['X1', 'Y1', 'X2', 'Y2', 'X3','Y3', 'X4', 'Y4', 'Id','SHAPE@']

## fields for the insert cursor to insert polygons and Id into output FC
##      "SHAPE@" is the geometry column that we insert the polygon into
##       "Id" is the Id column of the input point
##       this way, there is an Id from the respective point in the Polygon
##       you may need to update/add to this if you want other fields copied over

ifields = ['SHAPE@','Id']

## Search cursor inside insert cursor
## Search cursor extracts the new coordinate pairs
## insert cursor inserts the geometry and name ('Id') into the polygon FC

with arcpy.da.InsertCursor(outfc, ifields) as icursor:
    with arcpy.da.SearchCursor(infc,fields) as cursor:
        for s in cursor:
            coords = [(s[0],s[1]),
                      (s[2],s[3]),
                      (s[4],s[5]),
                      (s[6],s[7]),
                      (s[0],s[1])]
            name = s[8]
            icursor.insertRow((coords,name))
            
###  If you set a buffer distance, this will create the buffer to round the corners
            
if buff > 0:
    arcpy.analysis.Buffer(outfc, bufffc, buff, "FULL", "ROUND", "NONE", None, "PLANAR")

 

R_

 

 

0 Kudos