Divide a polygon from a fix point in edge of polygon

921
4
10-21-2021 03:44 AM
Labels (2)
VassilisTrigkas1974
New Contributor III

I try to divide a polygon into two straight polygons using a fixed point on one side.
The fixed point is where the dividing line will start and end at the opposite side of the polygon. The only condition is that the two new polygons should be the same in area.

 

0 Kudos
4 Replies
DanPatterson
MVP Esteemed Contributor

In Pro (so I hope in arcmap), you can subdivide by area, but there is no mention of specifying a starting point

Subdivide Polygon (Data Management)—ArcGIS Pro | Documentation

 


... sort of retired...
0 Kudos
Scott_Harris
Esri Regular Contributor

Hi@VassilisTrigkas1974 

I'm not clear on the requirement, but did you try the Divide tool found on the modify features pane?

https://pro.arcgis.com/en/pro-app/latest/help/editing/divide-a-polygon-by-a-value.htm

If you already know where the start and endpoints of the splitting line need to be, why won't Split work (also found on the modify features pane)?

https://pro.arcgis.com/en/pro-app/latest/help/editing/split-a-feature.htm

-Scott

0 Kudos
JohannesLindner
MVP Frequent Contributor

So one point of the cutting line is defined and it should cut the polygon into equal areas. I doubt there's a tool for that (though I could be wrong).

This seems like a job for Python, so I took a stab at it. I can get it to work with very small relative differences between the polygon parts, but the computation time is still quite high...

import datetime
def cut_equally(polygon, point, max_increment=1, rel_err=0.01):
    """Cuts a polygon into equal parts, with one point of the cutting line predefined.

    Returns a list of arcpy.PolygonGeometry, or an empty list if the target error
    is too small or the maximum increment too big.
    
    How it works:
    1.) Create a buffer around the point, create a 1-dimensional intersection
    of that buffer with the polygon.
    1.a) If there is no such intersection, the buffer is too big, return an empty list.
    2.) For each of the intersection of polygon and buffer, create a line between
    that intersection and the point and cut the polygon.
    3.) Calculate the relative error with
    rel_err = abs(1 - area_1/area_2)
    3.a) If rel_err is smaller than the target error, return the cut polygons.
    4.) Increase the buffer distance. Small target errors need a very small
    increment, which affects computing time massively. To alleviate that, the
    increment is dynamic: it is the maximum of the current relative error and
    a specified value.
    5.) Repeat.
    
    polygon: arcpy.PolygonGeometry, the polygon to be cut
    point: arcpy.Point or arcpy.PointGeometry, the start point of the cutting line, must be on the polygon's edge
    max_increment: the maximum increment to the buffer distance (see step 4)
    rel_err: the target relative error (see step 3)

    """
    # change point to point geometry
    if not isinstance(point, arcpy.PointGeometry):
        point = arcpy.PointGeometry(point)
    # set start values for dist and curr_rel_err
    dist = max_increment
    curr_rel_err = max_increment
    # loop
    start_time = datetime.datetime.now()
    while True:
        # create a buffer and intersect with the polygon
        point_buffer = point.buffer(dist)
        intersect_points = polygon.intersect(point_buffer, 1)
        # no intersection means the buffer is too big, return an empty list
        if len(intersect_points) == 0:
            print("Could not cut the polygon with the specified parameters.")
            return []
        for ip in intersect_points:
            # create the cutting line
            cut_line = arcpy.Polyline(arcpy.Array([point.firstPoint, ip]))
            try:
                # cut
                poly_cuts = polygon.cut(cut_line)
                # get the relative error
                curr_rel_err = abs(1 - poly_cuts[0].area/poly_cuts[1].area)
                # return if target error is met
                if curr_rel_err <= rel_err:
                    print("area_1: {}, area_2: {}, rel_err: {}, time: {} seconds".format(int(poly_cuts[0].area), int(poly_cuts[1].area), curr_rel_err, (datetime.datetime.now() - start_time).seconds))
                    return poly_cuts
            # these errors occur when the buffer is too small, ignore them
            except (RuntimeError, ZeroDivisionError):
                pass
        # increase the buffer distance
        dist += min(curr_rel_err, max_increment)

 

JohannesLindner_0-1634829219838.pngJohannesLindner_1-1634829316596.png

 


Have a great day!
Johannes
VassilisTrigkas1974
New Contributor III

@DanPatterson & @Scott_Harris Yes, exactly, that’s the problem. Divide is excellent tool but I cannot add a point. I know is something very special that I ask.

And I think the Python is the answer.

@JohannesLindner I will give a try and I will come again back if works or not.

Thank you so much for your response guys

0 Kudos