# Is that possible to create a polygon from a line feature? like that of thiessen polygon from point data!

971
13
09-28-2018 07:23 AM
New Contributor II

Is that possible to create a polygon from a line feature? like that of thiessen polygon from point data!

I need to have the created polygon edge generated at equal distance from two or more line features, I have tried to make the polygon using modelbuilder by converting the line to point and point to polygon using thiessen polygon tool but the polygons created by the modelbuilder is not what I want, I need to help me someone with python scripts. I need to have the polygon like the red outlined polygon to all classified line feature.

13 Replies
MVP Frequent Contributor

Can you provide a different example?  Or more specific criteria for how far to generate the polygon from the line?

For example, what would one want done in the case where one is generating a polygon from the line you have circled going left and up?  There does not appear to be another line to find the halfway distance to so as to create the polygon, so what would be the goal/criteria desired in that case?

Chris Donohue, GISP

MVP Esteemed Contributor

As Chris mentions, a little more information is needed.  However, what your illustration and description indicate to me is the buffer tool might do the trick for you.  See Buffer—Help | ArcGIS Desktop

That should just about do it....
New Contributor II

The objective is to create cluster area for rail road based on divID, therefore the boundary of the clustering is created at equal distance from any direction of the rail road, if two or three rail road line are meet at a point, we will have two or three polygons based on the divID . the edge or the boundary is created based on the area between the lines which have different divID.

MVP Honored Contributor

This is next to impossible to do, at least without PhD level knowledge of the ArcGIS geometry implementation in ArcObjects,.  I attempted a similar process with road casings, which are easier to do than your problem, because they have less overlap since each line is buffered by only a relatively short distance.  Unfortunately, due to the fact that all of the lines that make up a polygon outline have to follow a right handed alignment I found it extremely difficult to cut the polygons at each junction.  If any lines had angles in them near the junction that created artifacts that dramatically complicated the geometry even more, even if the angles were small.  Most polygons could not be saved without simplifying them (a method Python does not support) and many of the simplified polygons ended up not closing the outline, which created weird behaviors and corruption in the output.  I gave up after many weeks of trying to solve all of the geometry artifacts that cropped up.  Python does not have half of the methods I used to make the code I developed even work half way.  As far I know, no one else has posted any code that came close to doing what my code did.  While I could post my code it would only work using Visual Studio and you would still have to devote many weeks of your life to solving the problems that left me stumped to make it fully work.  I think you are out of luck, and at best will get suggestions for a partial solution that will still require a fair amount of manual intervention to achieve results like you have shown.

MVP Esteemed Contributor

Ahhh...  Now I see what you want:  thiessen  polygons based on a line feature rather than a point feature.

I just googled 'thiessen polygon based on linear feature'; give that a shot.  There are a number of returns you may find useful.

That should just about do it....
MVP Frequent Contributor

This looks like quite a challenge.  I am not going to say its impossible, but if someone with considerable expertise like Richard Fairhurst didn't have much luck with a similar challenge then this one looks to be very hard.

It may come down to having to make a real-world decision as to how important finding the exact location is for the desired polygons.  If an exact polygon is not an ultimate requirement, a more pragmatic solution may be to try some of buffer, Thiessen polygon, or other methods, then mix and match the best parts along with some editing to arrive at the result.

I will toss out an idea here that someone else may be more knowledgeable about and be able to flesh out as a possible solution.  How about using a geostatistical approach like creating a prediction or probability surface based on the lines being total probable and then deriving the surface based on certainty over distance (Note - I am not sure I am using the correct terminology here, so I hope people get the idea).  Then query the resulting high unprobability areas and use them out to create lines.  This could help find the halfway points in many areas, though it is unlikely to do well at junctions.  At that point you would need to do other processes and likely editing to clean things up.  One would need the Geostatistical Analyst Extension and some knowledge of statistics.

Chris Donohue, GISP

MVP Esteemed Contributor

A constrained Delaunay Triangulation (Theissen is the climatology nomenclature for Delaunay)

Haven't check to see if it is supported in PRO, but there are a number of python libraries.

but I haven't done one in years so details are fuzzy, but it is doable.  Do note, that the results may not conform exactly to what you would expect from a Delaunay triangulation since some of the rules are 'bent'

MVP Esteemed Contributor

Of course, converting the vector data to raster opens up the realm of 'spatial allocation' which is easier in raster world than it is in vector.

The example below is a Euclidean Allocation for my attempt to replicate your example of 3 vectors with 2 parts meeting at a point.

In the current incarnation, I used an unbounded allocation, but it can be constrained by distance and other bounds.

The example below was for a bounding area about 1 km^2 in size.  The cell size I used was 1 m^2, so the rasters are fairly small and the processing is fast.  If you have to scale up your study area, then you may have to experiment with cell size relative to file size and processing time.

Food for thought anyway... if you have the Spatial Analyst extension (for arcmap or ArcGIS Pro )

MVP Esteemed Contributor

Then there is the requisite numpy/scipy solution... it looks the same as the above picture.

It takes a *.tif (exported raster if it is in another format), does the fill and returns a tif as output

def num_121():  # --- just one of my demo def's
""" Fill an array's zeros in with their nearest value
simple sample data
a = np.random.randint(0, 3, size=(20, 20))
"""
from scipy import ndimage as nd
import arcpy
r = r"C:\path\to\thefile\poly.tif"
a = arcpy.RasterToNumPyArray(r)
m = np.where(a==0,1, 0)
ind = nd.distance_transform_edt(m, return_distances=False, return_indices=True)
b = a[tuple(ind)]
r0 = arcpy.NumPyArrayToRaster(b, arcpy.Point(300000, 5025000), 1)
r0.save(r"C:\path\to\thefile\polyfilled.tif")
return a, b‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

For a simple random sample you can explore the result if you don't have and image.

'a' is the raster who's zeros need to be filled … 'b' is the result

from scipy import ndimage as nd
a = np.random.randint(0, 3, size=(20, 20))
m = np.where(a==0,1, 0)
ind = nd.distance_transform_edt(m, return_distances=False, return_indices=True)
b = a[tuple(ind)]

a
Out[74]:
array([[1, 1, 0, 2, 2, 2, 0, 1, 1, 2, 2, 2, 2, 2, 0, 1, 0, 2, 1, 0],
[1, 1, 2, 1, 0, 2, 0, 0, 0, 2, 2, 2, 0, 1, 2, 0, 2, 2, 0, 1],
[2, 0, 2, 1, 1, 2, 0, 0, 0, 2, 2, 1, 1, 0, 2, 1, 0, 0, 0, 0],
[2, 0, 1, 1, 0, 2, 0, 0, 2, 1, 0, 0, 0, 1, 2, 0, 2, 2, 2, 2],
[2, 1, 1, 0, 0, 0, 2, 1, 0, 1, 1, 1, 0, 0, 2, 2, 0, 2, 1, 1],
[2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 0, 1, 1, 0, 2, 2, 2],
[0, 2, 1, 0, 2, 0, 1, 1, 1, 0, 1, 2, 1, 2, 2, 2, 1, 2, 0, 2],
[1, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 0, 0, 1, 2, 2, 0, 2, 1],
[0, 2, 2, 2, 2, 2, 2, 0, 2, 0, 1, 0, 1, 2, 1, 2, 0, 2, 0, 2],
[0, 2, 2, 2, 2, 2, 0, 1, 0, 1, 2, 2, 1, 2, 0, 1, 1, 1, 1, 2],
[1, 2, 0, 2, 0, 1, 0, 2, 0, 0, 0, 2, 2, 2, 0, 1, 0, 2, 1, 1],
[1, 1, 0, 2, 2, 1, 1, 2, 2, 1, 0, 1, 0, 1, 2, 2, 2, 0, 2, 0],
[2, 0, 2, 2, 1, 2, 2, 2, 1, 0, 0, 1, 2, 0, 0, 2, 0, 2, 0, 0],
[1, 0, 1, 1, 1, 0, 0, 0, 1, 2, 0, 1, 1, 2, 1, 0, 2, 1, 0, 1],
[2, 2, 1, 1, 1, 2, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 2, 1, 0],
[1, 1, 0, 1, 1, 2, 0, 2, 0, 1, 1, 1, 1, 2, 0, 2, 1, 1, 1, 0],
[0, 1, 0, 1, 2, 2, 0, 2, 0, 1, 1, 1, 2, 1, 0, 1, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 1, 0, 1, 2, 1, 0, 0, 2, 1, 1, 1, 1, 1, 0, 0],
[2, 0, 0, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 0, 2],
[1, 1, 2, 1, 1, 2, 2, 1, 0, 2, 1, 2, 0, 2, 0, 0, 2, 1, 0, 2]])

b
Out[75]:
array([[1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1],
[1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1],
[2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1],
[2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1],
[2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2],
[2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2],
[1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1],
[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2],
[1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2],
[1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1],
[1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1],
[2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1],
[1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1],
[1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1],
[2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2],
[1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2]])‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍