7

I have a polygon feature class. I convert it to a point. Name of field (for example !Number!) in a point feature converted from polygon "A2"(The first point should be in the upper left corner (relative to north) of the polygon.) must match the direction of points in a clockwise. I know "AutoIncrement ()" at using Field Calculator, to change the numerical name of points by OBJECTID, but the point ID identifier sometimes do not match with the clockwise direction. Only one method that I know is to copy the contents of a table in Excel and renumber as I need. Then insert into ArcGIS the modified table in Excel and "display XY data"->"Data"->"Export data to point features". But maybe someone knows how to do it easier?enter image description here

  • 1
    Do you need to create new polygons so the vertex order starts in the Upper-Left or do you want a list of vertices, for each polygon, in the corrected order? – klewis Nov 22 '13 at 0:28
  • Both variants are good. I know how to fix the order of the vertices using Excel, but it is slow and not always convenient method. As a result, I need to make a list of vertices (including coordinates) for each polygon in the correct order. And the correct order of the vertices must be displayed on the map. I need the fastest possible way. – Jannik Nov 26 '13 at 0:08
  • Perhaps it might look like , 1 Use the repair tool geometry and vertex IDs goes clockwise direction . 2 converted polygons to points. 3 in attribute table using python autoIncrement () "expression. cal" 4 From upper left points are numbered with pStart = 1. 5 The rest of the points are numbered with pStart => next number of the last numbered point in paragraph 4 . 6 As a result, the point of going clockwise direction points are numbered as I need to . But they have the wrong ID order. Maybe it's not so important. Do you think there is another way more faster? – Jannik Nov 26 '13 at 5:32
  • Hi Jannik, did you find out a solution to your problem? Also interested if there is a way of doing this. – Slevy Sep 12 '16 at 5:19
5

Use the Repair Geometry tool - the polygon will be reset as clockwise direction.

The Check Geometry documentation says:

Incorrect ring ordering—The polygon is topologically simple, but its rings may not be oriented correctly (outer rings—clockwise, inner rings—counterclockwise).

While the Repair Geometry documentation does not mention clockwise/counterclockwise but says:

Incorrect ring ordering: The geometry will be updated to have correct ring ordering.

| improve this answer | |
  • The first point should be in the upper left corner (relative to north) of the polygon. – Jannik Nov 21 '13 at 9:02
  • There is no topological requirement in GIS software that specifies where the first point should be. What is the rationale for such a need? – blah238 Nov 21 '13 at 9:04
  • 1
    Conditions of numbering for issue of cadastral parcels. – Jannik Nov 21 '13 at 9:31
  • 4
    @Jannik but how do you define the upper left with complex shapes. Like in your exemple 6 is the left poitn, but 9 is the uppr point and 8 could be a "corner" candidate. – radouxju Sep 12 '16 at 5:56
  • Agree with @radouxju starting point requires better definition, e.g. nearest to NW corner of shape extent – FelixIP Sep 18 '16 at 20:25
3

The polygon below was created counterclockwise (not sure if it matters) starting at point 11/15. The point furthest to the left will get objectid 1.

import arcpy
arcpy.env.workspace=r'D:\Arenden_D\Dribbel\flip.gdb'
arcpy.env.overwriteOutput=1
arcpy.env.outputCoordinateSystem = 'D:\Projektionsfiler\SWEREF99TM.prj'

#Create points from polygon vertices
arcpy.FeatureVerticesToPoints_management(in_features='counterclockwise_polygon', out_feature_class='clockwise_points')
#Duplicate points are created at start/stop, removing one
with arcpy.da.UpdateCursor('clockwise_points',['OBJECTID'], 'OBJECTID = 1') as ucursor:
    for row in ucursor:
        ucursor.deleteRow()

#create a list of x, y, and objectid of the clockwise points
coordinates = [f for f in arcpy.da.SearchCursor('clockwise_points',['SHAPE@X','SHAPE@Y','OBJECTID'])]

#find starting point = point furthest to the left
start_point = sorted(coordinates)[0]
#find index of start point in coordinates list
index_of_start_point = [i for i,x in enumerate(coordinates) if x[2]==start_point[2]]

#move start point to first position in list
coordinates.insert(0,coordinates.pop(int(index_of_start_point[0])))

#find index of points with smaller OBJECTID than start point
index_of_lesserpoints = [j for j,z in enumerate(coordinates) if z[2]<start_point[2]]

#create a new list and add coordinate pairs with Objectids in the right order starting with OBJECTID of start_point
coordinates_in_order=[]
coordinates_in_order.extend((coordinates[0],))
coordinates_in_order.extend(coordinates[1+max(index_of_lesserpoints):])
coordinates_in_order.extend(coordinates[min(index_of_lesserpoints):1+max(index_of_lesserpoints)])

#create a new point fc and insert points
arcpy.CreateFeatureclass_management(out_path=arcpy.env.workspace, out_name='new_clockwise_points', geometry_type='POINT')
with arcpy.da.InsertCursor('new_clockwise_points',['SHAPE@XY']) as icursor:
    for pair in coordinates_in_order:
        icursor.insertRow((pair[0:2],))

enter image description here

| improve this answer | |
  • Great, Will give this a shot. Would you know how this would handle donuts? – Slevy Sep 19 '16 at 3:40
2
+50

INPUTS:

enter image description here enter image description here

SCRIPT:

import arcpy

##  input parameters
mxd = arcpy.mapping.MapDocument("CURRENT")
polygons = arcpy.mapping.ListLayers(mxd,"PGONS")[0]
points = arcpy.mapping.ListLayers(mxd,"POINTS")[0]

##truncated coordinate as string
def truncate(f, n):
    s = '{}'.format(f)
    i, p, d = s.partition('.')
    return '.'.join([i, (d+'0'*n)[:n]])        

with arcpy.da.SearchCursor(polygons,["SHAPE@","MB2013"]) as cursor:
    for shp,idL in cursor:
##      get extent NW corner
        ext=shp.extent
        UL=arcpy.PointGeometry(ext.upperLeft)
        Q='"MB2013" = %s'%("'"+idL+"'")
        points.definitionQuery=Q
        aList=[];pLine=shp.boundary()
##      order points along boundary at new start
        dMin=1e6
        with arcpy.da.SearchCursor(points,"SHAPE@") as pCur:
            for line in pCur:
                pnt=line[0].firstPoint
                L=pLine.measureOnLine(pnt)
                d=UL.distanceTo(pnt)
                if d<dMin: dMin=d;lMin=L
                aList.append([L,pnt])
        for i,(L,pnt) in enumerate(aList):
            if L>=lMin: aList[i][0]=L-lMin
            else:aList[i][0]=L+pLine.length-lMin
##     dictionary of points signatures and chainage
        newList=sorted(aList)
        aDict={}
        for i,(L,pnt) in enumerate(newList):
            aKey=truncate(pnt.X,2)+truncate(pnt.Y,2)
            aDict[aKey]=i+1
##      transfer new order to points table
        with arcpy.da.UpdateCursor(points,("SHAPE@","GroupNo")) as pCur:
            for pnt,no in pCur:
                aKey=truncate(pnt.firstPoint.X,2)+truncate(pnt.firstPoint.Y,2)
                pCur.updateRow((pnt,aDict[aKey]))

RESULT:

enter image description here

I hope there are enough comments in the script to understand a method I applied. It is tested on shapefiles and of course field names are to be changed

| improve this answer | |
  • This great, would you know how this would handle with donuts in the shape? – Slevy Sep 19 '16 at 3:39
  • 1
    It most likely will, providing points are sitting on the outer ring only, multipart - unlikely. Just test it, no harm expected – FelixIP Sep 19 '16 at 3:54
1

The Production Mapping extension includes a Set Origin Vertex tool that may suit your purposes:

A polygon is a collection of rings. Rings contain collections of points, or vertices, which describe a closed path. The first vertex, number 0, in the outermost ring of a polygon is the origin vertex. Vertices are oriented in a clockwise direction from the origin vertex. The origin vertex is the from-point (and to-point) of the ring that encloses a polygon.

The Set Origin Vertex tool allows you to change the origin vertex of a polygon feature. The following workflows may require you to use this tool:

  • Grid and graticules layers—Set an origin location for an area of interest.
  • Suppress outline geometry effect—Control where line suppression starts.
| improve this answer | |
  • Ow its look like very simple but we dont have "Production Mapping extension". Maybe you know another way? – Jannik Nov 22 '13 at 8:43
0

Solving a portion of the problem, I recommend that the starting vertex is the vertex closest to the NW corner of the polygon's minimum bounding box (MBR).

An efficient processing function for the entire problem would:

  1. Create a temporary array of vertex, old and new vertex order
  2. Create a temporary point geometry variable and store the MBR NW cnr in it
  3. Read in a geometry into the temp array
  4. Measure each vertex distance to the NW corner of the MBR
  5. Find the minimum distance of all measures in step 4
  6. Assign that vertex as the start point (new order = 1)
  7. Assign the remaining vertex orders as +1 from the new start point, proceeding in the old order
  8. Update the geometry by recreating the vertex array in the new order
  9. Return the updated geometry

Examples of how to implement such ordinate array processing, temporary variable assignment, etc. can be found here for the case of SDO geometry storage in Oracle.

Not strictly an easier solution than manipulation in Excel, but it scales well to lots of polygons.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.