Create closed polygon from boundary points

后端 未结 3 1983
盖世英雄少女心
盖世英雄少女心 2021-01-13 02:45

I have an array of longitude-latitude points that defines the boundaries of an area. I would like to create a polygon based on these points and plot the polygon on a map and

相关标签:
3条回答
  • 2021-01-13 03:31

    Having an array of points is not enough. You need to know the order of the points. Normally the points of a polygon are given sequentially. So you draw a line from the first point to the second, then from the second to the third et cetera.

    If your list is not in sequential order, you need extra information to be able to make a sequential list.

    A shapefile (see the documentation) contains a list of shapes, like a Null shape, Point, PolyLine, Polygon, with variants containing also the Z and M (measure) coordinates. So just dumping the points will not do. You have to divide them up in the different shapes and render the ones you are interested in. In this case probably a PolyLine or Polygon. See the link above for the data format for these shapes. Keep in mind that some parts of the file are big-endian, while others are little-endian. What a mess.

    I would suggest using the struct module to parse the binary .shp file, because again according to the documentation, the points of a single Polygon are in order, and they form a closed chain (the last point is the same as the first).

    Another thing you could try with your current list of coordinates is to start with a point, and then look for the same point furtheron in the list. Everything between those identical points should be one polygon. This is probably not foolproof, but see how far it gets you.

    0 讨论(0)
  • 2021-01-13 03:35

    I recommend using the original Shapefile, which is in a format appropriate for storing polygons. As an alternative to OGR you could use Shapely, or export the polygon to Wkt etc.

    import ogr
    import matplotlib.path as mpath
    import matplotlib.patches as patches
    import matplotlib.pyplot as plt
    
    ds = ogr.Open('lmes_64.shp')
    lyr = ds.GetLayer(0)
    ft = lyr.GetFeature(38)
    geom = ft.GetGeometryRef()
    ds = None
    
    codes = []
    all_x = []
    all_y = []
    
    if (geom.GetGeometryType() == ogr.wkbPolygon):
      for i in range(geom.GetGeometryCount()):
    
        r = geom.GetGeometryRef(i)
        x = [r.GetX(j) for j in range(r.GetPointCount())]
        y = [r.GetY(j) for j in range(r.GetPointCount())]
    
        codes += [mpath.Path.MOVETO] + (len(x)-1)*[mpath.Path.LINETO]
        all_x += x
        all_y += y
    
    if (geom.GetGeometryType() == ogr.wkbMultiPolygon):
      codes = []
      for i in range(geom.GetGeometryCount()):
        # Read ring geometry and create path
        r = geom.GetGeometryRef(i)
        for part in r:
          x = [part.GetX(j) for j in range(part.GetPointCount())]
          y = [part.GetY(j) for j in range(part.GetPointCount())]
          # skip boundary between individual rings
          codes += [mpath.Path.MOVETO] + (len(x)-1)*[mpath.Path.LINETO]
          all_x += x
          all_y += y
    
    carib_path = mpath.Path(np.column_stack((all_x,all_y)), codes)    
    carib_patch = patches.PathPatch(carib_path, facecolor='orange', lw=2)
    
    poly1 = patches.Polygon([[-80,20],[-75,20],[-75,15],[-80,15],[-80,20]], zorder=5, fc='none', lw=3)
    poly2 = patches.Polygon([[-65,25],[-60,25],[-60,20],[-65,20],[-65,25]], zorder=5, fc='none', lw=3)
    
    
    fig, ax = plt.subplots(1,1)
    
    for poly in [poly1, poly2]:
        if carib_path.intersects_path(poly.get_path()):
            poly.set_edgecolor('g')
        else:
            poly.set_edgecolor('r')
    
        ax.add_patch(poly)
    
    ax.add_patch(carib_patch)
    ax.autoscale_view()
    

    enter image description here

    Also checkout Fiona (wrapper for OGR) if you want really easy Shapefile handling.

    0 讨论(0)
  • 2021-01-13 03:35

    There is a blog post here which talks about shapefiles and basemap: http://www.geophysique.be/2013/02/12/matplotlib-basemap-tutorial-10-shapefiles-unleached-continued/

    If you're keen to try it out, cartopy might also be an option. Plotting data from a shapefile is designed to be fairly easy:

    import matplotlib.pyplot as plt
    
    import cartopy.crs as ccrs
    import cartopy.io.shapereader as shpreader
    
    # pick a shapefile - Cartopy makes it easy to access Natural Earth
    # shapefiles, but it could be anything
    shapename = 'admin_1_states_provinces_lakes_shp'
    states_shp = shpreader.natural_earth(resolution='110m',
                                          category='cultural', name=shapename)
    

    .

    # states_shp is just a filename to a shapefile
    >>> print states_shp
    /Users/pelson/.local/share/cartopy/shapefiles/natural_earth/cultural/110m_admin_1_states_provinces_lakes_shp.shp
    

    .

    # Create the mpl axes of a PlateCarree map
    ax = plt.axes(projection=ccrs.PlateCarree())
    
    # Read the shapes from the shapefile into a list of shapely geometries.
    geoms = shpreader.Reader(states_shp).geometries()
    
    # Add the shapes in the shapefile to the axes
    ax.add_geometries(geoms, ccrs.PlateCarree(),
                      facecolor='coral', edgecolor='black')
    
    plt.show()
    

    output

    0 讨论(0)
提交回复
热议问题