Exemple #1
0
    def test_init(self):
        # Test empty.
        gvar = GeometryVariable()
        self.assertEqual(gvar.dtype, object)

        gvar = self.get_geometryvariable()
        self.assertIsInstance(gvar.get_masked_value(), MaskedArray)
        self.assertEqual(gvar.ndim, 1)

        # Test passing a "crs".
        gvar = self.get_geometryvariable(crs=WGS84(),
                                         name='my_geom',
                                         dimensions='ngeom')
        self.assertEqual(gvar.crs, WGS84())

        # Test using lines.
        line1 = LineString([(0, 0), (1, 1)])
        line2 = LineString([(1, 1), (2, 2)])
        gvar = GeometryVariable(value=[line1, line2], dimensions='two')
        self.assertTrue(gvar.get_value()[1].almost_equals(line2))
        self.assertEqual(gvar.geom_type, line1.geom_type)
        lines = MultiLineString([line1, line2])
        lines2 = [lines, lines]
        for actual in [lines, lines2, lines]:
            gvar2 = GeometryVariable(value=actual, dimensions='ngeom')
            self.assertTrue(gvar2.get_value()[0].almost_equals(lines))
            self.assertEqual(gvar2.geom_type, lines.geom_type)
            self.assertTrue(gvar2.shape[0] > 0)
            self.assertIsNone(gvar2.get_mask())
Exemple #2
0
    def to_python(self, value):
        """
        This assumes the value has been preprocessed into a dictionary of the form:
        {'type': <geometry_type>, 'geometry': <raw_geometry>}
        """

        if not value or isinstance(value, BaseGeometry):
            return value

        geometry_type = value['type']
        geometry = value['geometry']

        try:
            if geometry_type == 'esriGeometryPoint':
                if 'x' in geometry:
                    data = json.loads(geometry)
                    x, y = data['x'], data['y']
                else:
                    x, y = [float(val) for val in geometry.split(',')]
                return Point(x, y)

            elif geometry_type == 'esriGeometryMultipoint':
                data = json.loads(geometry)
                return MultiPoint([(p['0'], p['1']) for p in data['points']])

            elif geometry_type == 'esriGeometryPolyline':
                data = json.loads(geometry)
                return MultiLineString([((l[0][0], l[0][1]), (l[1][0],
                                                              l[1][1]))
                                        for l in data['paths']])

            elif geometry_type == 'esriGeometryPolygon':
                data = json.loads(geometry)
                rings = [
                    LinearRing([(p[0], p[1]) for p in r])
                    for r in data['rings']
                ]
                return Polygon([r for r in rings if not r.is_ccw],
                               interiors=[r for r in rings if r.is_ccw])

            elif geometry_type == 'esriGeometryEnvelope':
                if 'xmin' in geometry:
                    data = json.loads(geometry)
                    xmin, ymin, xmax, ymax = [
                        data[k] for k in ('xmin', 'ymin', 'xmax', 'ymax')
                    ]
                else:
                    xmin, ymin, xmax, ymax = [
                        float(val) for val in geometry.split(',')
                    ]
                return MultiPoint([(xmin, ymin), (xmax, ymax)]).envelope

            else:
                raise ValueError
        except ValueError:
            raise ValidationError('Invalid geometry')
Exemple #3
0
def fix_geom_type(row, expected_geom_type):
    # ESRI mixes geom_types within a given file. GC2 doesn't accept geojson with mixed types.  When expecting multi features this ensures all features in a file are represented as Multi.
    if 'Multi' not in str(
        (row.geometry).geom_type) and expected_geom_type == 'MultiPolygon':
        geom = MultiPolygon([wkt.loads(str(row.geometry))])
    elif 'Multi' not in str(
        (row.geometry).geom_type) and expected_geom_type == 'MultiLineString':
        geom = MultiLineString([wkt.loads(str(row.geometry))])
    elif 'Multi' not in str(
        (row.geometry).geom_type) and expected_geom_type == 'MultiPoint':
        geom = MultiPoint([wkt.loads(str(row.geometry))])
    else:
        geom = row.geometry
    return geom
Exemple #4
0
    def _get_multigeometry(self, element):
        # MultiTrack
        geoms = []
        if element.tag == ('%sMultiTrack' % self.ns):
            tracks = element.findall("%sTrack" % self.ns)
            for track in tracks:
                self._get_geometry_spec(track)
                geoms.append(LineString(self._get_coordinates(track)))

        geom_types = {geom.geom_type for geom in geoms}
        if len(geom_types) > 1:
            return GeometryCollection(geoms)
        if 'LineString' in geom_types:
            return MultiLineString(geoms)
Exemple #5
0
    def test_init(self):
        # Test empty.
        gvar = GeometryVariable()
        self.assertEqual(gvar.dtype, object)

        gvar = self.get_geometryvariable()
        self.assertIsInstance(gvar.get_masked_value(), MaskedArray)
        self.assertEqual(gvar.ndim, 1)

        # The geometry variable should set itself as the representative geometry on its parent field if that parent does
        # not have a representative geometry set.
        self.assertIsNotNone(gvar.parent.geom)

        # Test with a parent that already has a geometry.
        field = Field()
        field.set_geom(GeometryVariable(name='empty'))
        gvar = self.get_geometryvariable(parent=field)
        self.assertEqual(field.geom.name, 'empty')
        self.assertIn(gvar.name, field)

        # Test passing a "crs".
        gvar = self.get_geometryvariable(crs=WGS84(),
                                         name='my_geom',
                                         dimensions='ngeom')
        self.assertEqual(gvar.crs, WGS84())

        # Test using lines.
        line1 = LineString([(0, 0), (1, 1)])
        line2 = LineString([(1, 1), (2, 2)])
        gvar = GeometryVariable(value=[line1, line2], dimensions='two')
        self.assertTrue(gvar.get_value()[1].almost_equals(line2))
        self.assertEqual(gvar.geom_type, line1.geom_type)
        lines = MultiLineString([line1, line2])
        lines2 = [lines, lines]
        for actual in [lines, lines2, lines]:
            gvar2 = GeometryVariable(value=actual, dimensions='ngeom')
            self.assertTrue(gvar2.get_value()[0].almost_equals(lines))
            self.assertEqual(gvar2.geom_type, lines.geom_type)
            self.assertTrue(gvar2.shape[0] > 0)
            self.assertIsNone(gvar2.get_mask())
Exemple #6
0
def path_to_geos(path):
    """
    """
    import time
    start_time = time.time()
    log = []
    
    DEBUG = False
#    path_verts, path_codes =  zip(*list(path.iter_segments(curves=False)))
    path_verts, path_codes = path_segments(path, curves=False)
    path_verts = np.array(path_verts)
    path_codes = np.array(path_codes)
    
    if DEBUG: print 'codes:', path_codes
    verts_split_inds = np.where(path_codes == Path.MOVETO)[0]
    verts_split = np.split(path_verts, verts_split_inds, 0)
    codes_split = np.split(path_codes, verts_split_inds, 0)
    
    if DEBUG: print 'vs: ', `verts_split`
    if DEBUG: print 'cs: ', `codes_split`
    
    log.append('split done %s' % (time.time() - start_time))
    
    collection = []
    for path_verts, path_codes in zip(verts_split, codes_split):
        if len(path_verts) == 0:
            continue
        # XXX A path can be given which does not end with close poly, in that situation, we have to guess?
        if DEBUG: print 'pv: ', path_verts
        # XXX Implement a point
                
        if path_verts.shape[0] > 2 and (path_codes[-1] == Path.CLOSEPOLY or all(path_verts[0, :] == path_verts[-1, :])):
            if path_codes[-1] == Path.CLOSEPOLY:
                ipath2 = polygon.Polygon(path_verts[:-1, :])
            else:
                ipath2 = polygon.Polygon(path_verts)
        else:
            ipath2 = linestring.LineString(path_verts)
            
        if (len(collection) > 0 and 
                 isinstance(collection[-1][0], polygon.Polygon) and
                 isinstance(ipath2, polygon.Polygon) and
                 collection[-1][0].contains(ipath2.exterior)):
            collection[-1][1].append(ipath2.exterior)
        else:
            # collection is a list of [exernal_poly, list_of_internal_polys]
            collection.append([ipath2, []])
    
    log.append('collection done before while %s.' % (time.time() - start_time))
    
    log.append('Len of collection %s.' % (len(collection)))

    res = []
    
    for external_poly, internal_polys in collection:
#        print external_poly
        if len(internal_polys) > 0:
#            print internal_polys
            # XXX worry about islands within lakes
            poly = polygon.Polygon(external_poly.exterior, internal_polys)
        else:
            poly = external_poly
        res.append(poly)
    collection = res
#    if len(collection) > 1:
#        i = 0
#        while i<len(collection)-1:
#            poly = collection[i]
#            poly2 = collection[i+1]
#                        
#            # TODO Worry about islands within lakes
#            if isinstance(poly, polygon.Polygon) and isinstance(poly2, polygon.Polygon):  
#                if poly.contains(poly2):
#                    # XXX This is the slow bit!
##                    collection[i] = polygon.Polygon(poly.exterior, list(poly.interiors) + [poly2.exterior])                    
#                    collection.pop(i+1)
#                    continue
#            else:
#                res.append([poly])
#            i+=1
#    
#        log.append('Post len of collection %s.' % (len(collection)))
#        log.append('collection done after while %s' % (time.time() - start_time))
        
    if len(collection) == 1:
        result = collection
    else:
        if all([isinstance(geom, linestring.LineString) for geom in collection]):
            result = [MultiLineString(collection)]
        else:
            result = collection
#            if DEBUG: print 'geom: ', collection, type(collection)
#            raise NotImplementedError('The path given was not a collection of line strings, ' 
#                                      'nor a single polygon with interiors.')
    if (time.time() - start_time) > 1:
        print 'geos time %s' % (time.time() - start_time)
        print '\n'.join(log)
    
    # remove any zero area polygons
    result = filter(lambda geom: (isinstance(geom, polygon.Polygon) and geom.area != 0) or \
                    not isinstance(geom, polygon.Polygon), result) 
    
    return result
Exemple #7
0
def path_to_geos(path, force_ccw=False):
    """
    Creates a list of Shapely geometric objects from a
    :class:`matplotlib.path.Path`.

    Args:

    * path
        A :class:`matplotlib.path.Path` instance.

    Kwargs:

    * force_ccw
        Boolean flag determining whether the path can be inverted to enforce
        ccw.

    Returns:
        A list of :class:`shapely.geometry.polygon.Polygon`,
        :class:`shapely.geometry.linestring.LineString` and/or
        :class:`shapely.geometry.multilinestring.MultiLineString` instances.

    """
    # Convert path into numpy array of vertices (and associated codes)
    path_verts, path_codes = path_segments(path, curves=False)

    # Split into subarrays such that each subarray consists of connected
    # line segments based on the start of each one being marked by a
    # matplotlib MOVETO code.
    verts_split_inds = np.where(path_codes == Path.MOVETO)[0]
    verts_split = np.split(path_verts, verts_split_inds)
    codes_split = np.split(path_codes, verts_split_inds)

    # Iterate through the vertices generating a list of
    # (external_geom, [internal_polygons]) tuples.
    collection = []
    for path_verts, path_codes in zip(verts_split, codes_split):
        if len(path_verts) == 0:
            continue

        # XXX A path can be given which does not end with close poly, in that
        # situation, we have to guess?
        # XXX Implement a point
        if (path_verts.shape[0] > 2
                and (path_codes[-1] == Path.CLOSEPOLY
                     or all(path_verts[0, :] == path_verts[-1, :]))):
            if path_codes[-1] == Path.CLOSEPOLY:
                geom = Polygon(path_verts[:-1, :])
            else:
                geom = Polygon(path_verts)
        else:
            geom = LineString(path_verts)

        # If geom is a Polygon and is contained within the last geom in
        # collection, add it to its list of internal polygons, otherwise
        # simple append it as a  new external geom.
        if (len(collection) > 0 and isinstance(collection[-1][0], Polygon)
                and isinstance(geom, Polygon)
                and collection[-1][0].contains(geom.exterior)):
            collection[-1][1].append(geom.exterior)
        else:
            collection.append((geom, []))

    # Convert each (external_geom, [internal_polygons]) pair into a
    # a shapely Polygon that encapsulates the internal polygons, if the
    # external geom is a LineSting leave it alone.
    geom_collection = []
    for external_geom, internal_polys in collection:
        if internal_polys:
            # XXX worry about islands within lakes
            geom = Polygon(external_geom.exterior, internal_polys)
        else:
            geom = external_geom

        # Correctly orientate the polygon (ccw)
        if force_ccw and not geom.exterior.is_ccw:
            geom = shapely.geometry.polygon.orient(geom)

        geom_collection.append(geom)

    # If the geom_collection only contains LineStrings combine them
    # into a single MultiLinestring.
    if geom_collection and all(
            isinstance(geom, LineString) for geom in geom_collection):
        geom_collection = [MultiLineString(geom_collection)]

    # Remove any zero area Polygons
    not_zero_poly = lambda geom: (
        (isinstance(geom, Polygon) and not geom._is_empty and geom.area != 0
         ) or not isinstance(geom, Polygon))
    result = filter(not_zero_poly, geom_collection)

    return result
def calc_gz(GL_FILE='', WIDTH_FILE='', BASIN_FILE='', region='', N=0):
    #-- read the grounding lines and widths
    df_gl = gpd.read_file(GL_FILE)
    df_w = gpd.read_file(WIDTH_FILE)
    #-- read the basin file
    basins = gpd.read_file(BASIN_FILE)
    idx = basins.index[basins['NAME'] == region]
    #-- get polygon
    poly = basins['geometry'][idx[0]]

    #-- add a 5km buffer to find the corresponding GLs
    region_poly = poly.buffer(5e3)

    lines = []
    dates = []
    for i in range(len(df_gl)):
        #-- extract geometry to see if it's in region of interest
        ll = df_gl['geometry'][i]
        if ll.intersects(region_poly):
            lines.append(ll)
            dates.append(df_gl['FILENAME'][i].split("_")[2])

    #-- get width lines
    ws = []
    for i in range(len(df_w)):
        ws.append(df_w['geometry'][i])
    widths = MultiLineString(ws)

    #-- get middle coordinates
    xlist = np.zeros(N)
    ylist = np.zeros(N)
    gz = np.zeros(N)
    date1_list = [None] * N
    date2_list = [None] * N
    ind_list = np.zeros(N, dtype=int)
    random.seed(11)
    for i in range(N):
        ind_list[i] = random.randrange(0, len(widths))
        mid_pt = widths[ind_list[i]].interpolate(0.5, normalized=True)
        xx, yy = mid_pt.coords.xy
        xlist[i] = float(xx[0])
        ylist[i] = float(yy[0])
        gz[i] = widths[ind_list[i]].length
        #-- also get teh corresponding dates
        pt0 = widths[ind_list[i]].interpolate(0, normalized=True)
        pt1 = widths[ind_list[i]].interpolate(1, normalized=True)
        for l in range(len(lines)):
            if lines[l].distance(pt1) < 0.2:
                date1_list[i] = dates[l]
            elif lines[l].distance(pt0) < 0.2:
                date2_list[i] = dates[l]

    #-- write grounding zone widths to file
    outfile = os.path.join(os.path.dirname(GL_FILE),
                           'GZ_retreived-widths_{0}.csv'.format(region))
    outfid = open(outfile, 'w')
    outfid.write('X (m),Y (m),width (km),date1,date2\n')
    for i in range(N):
        outfid.write('{0:.6f},{1:.6f},{2:.3f},{3},{4}\n'.\
        format(xlist[i],ylist[i],gz[i]/1e3,date1_list[i],date2_list[i]))
    outfid.close()

    #-- plot a sample of points to check the grounding zones
    fig = plt.figure(1, figsize=(10, 8))
    ax = fig.add_subplot(111)
    pp = PolygonPatch(poly,
                      alpha=0.3,
                      fc='lawngreen',
                      ec='lawngreen',
                      zorder=1)
    ax.add_patch(pp)
    for il in lines:
        xs, ys = il.coords.xy
        ax.plot(xs, ys, linewidth=0.4, alpha=0.8, color='k', zorder=2)
    for i in range(35):
        ip = random.randrange(0, N)
        #-- while distance to any of the previous points is less than 20km,
        #-- keep trying new indices (doesn't apply to 1st point)
        if i == 0:
            plot_pts = [Point(xlist[ip], ylist[ip])]
        else:
            pt = Point(xlist[ip], ylist[ip])
            while (pt.distance(MultiPoint(plot_pts)) < 10e3):
                ip = random.randrange(0, N)
                pt = Point(xlist[ip], ylist[ip])
            #-- now we can ensure the points aren't overlapping
            print("minimum distance to previous points: ",
                  pt.distance(MultiPoint(plot_pts)))
            plot_pts.append(pt)
        #-- Now plot the transect for the given index
        lx, ly = widths[ind_list[ip]].coords.xy
        ax.plot(lx, ly, linewidth=2.0, alpha=1.0, color='red', zorder=3)
        ax.text(xlist[ip]+5e3,ylist[ip]+5e3,'{0:.1f}km'.format(gz[ip]/1e3),color='darkred',\
         fontsize=6,fontweight='bold',bbox=dict(facecolor='mistyrose', alpha=0.5))
    ax.get_xaxis().set_ticks([])
    ax.get_yaxis().set_ticks([])
    ax.set_title("Grounding Zone Width for {0}".format(region))
    plt.tight_layout()
    plt.savefig(outfile.replace('.csv', '.pdf'), format='PDF')
    plt.close(fig)
Exemple #9
0
def quarter(polygon):
    """Split the polygon into 4 line strings, classify the lines by their direction to determine
    cardinality.  For each of the 4 lines split at the midpoint while preserving the original coordinates.
    Generate 4 polygons based on the diagram below.

    Eg, the NW polygon is the convex_hull of the following lines
        - first half of the north line
        - first half of the center vertical line
        - first half of the center horizontal line
        - second half of the west line


             1            2
      ---------------------------
      |            |            |
    8 |     NW     |     NE     | 3
      |            |9           |
      |     11     |      12    |
      ---------------------------
      |            |            |
      |            |10          |
    7 |     SW     |     SE     | 4
      |            |            |
      ---------------------------
             6            5

    :param polygon:
    :type polygon: LabeledPolygon
    :return: list of LabeledPolygons
    :rtype: []LabeledPolygon
    """
    label, polygon = polygon.label, polygon.polygon
    try:
        if polygon.type == 'MultiPolygon':
            logging.debug(
                "Multipolygon found, attemping to convert to polygon...")
            polygon = unary_union(polygon)
            if polygon.type == 'MultiPolygon':
                raise Exception(
                    "Unable to convert multipolygon to polygon (disjoint)")

        polygon = orient(polygon, sign=-1.0)  # set orientation to clockwise

        lines = split_to_lines(polygon)
        labeled_lines = classify_lines(lines)

        north_lines = split_line(
            linemerge(
                MultiLineString(
                    [l.line for l in labeled_lines if l.label == "N"])))
        east_lines = split_line(
            linemerge(
                MultiLineString(
                    [l.line for l in labeled_lines if l.label == "E"])))
        south_lines = split_line(
            linemerge(
                MultiLineString(
                    [l.line for l in labeled_lines if l.label == "S"])))
        west_lines = split_line(
            linemerge(
                MultiLineString(
                    [l.line for l in labeled_lines if l.label == "W"])))

        # split the inner lines at their intersection
        center_vertical = LineString(
            (north_lines[0].coords[-1], south_lines[0].coords[-1])
        )  # straight line between midpoint of north line and midpoint of south line
        center_horizontal = LineString(
            (west_lines[0].coords[-1], east_lines[0].coords[-1])
        )  # straight line between midpoint of west line and midpoint of east line
        center_verticals, center_horizontals = split_intersection(
            center_vertical, center_horizontal)

        nw_polygon = LabeledPolygon(label="NW" + label,
                                    polygon=MultiLineString(
                                        (north_lines[0], center_verticals[0],
                                         center_horizontals[0],
                                         west_lines[1])).convex_hull)
        ne_polygon = LabeledPolygon(label="NE" + label,
                                    polygon=MultiLineString(
                                        (north_lines[1], center_verticals[0],
                                         center_horizontals[1],
                                         east_lines[0])).convex_hull)
        sw_polygon = LabeledPolygon(label="SW" + label,
                                    polygon=MultiLineString(
                                        (south_lines[1], center_verticals[1],
                                         center_horizontals[0],
                                         west_lines[0])).convex_hull)
        se_polygon = LabeledPolygon(label="SE" + label,
                                    polygon=MultiLineString(
                                        (south_lines[0], center_verticals[1],
                                         center_horizontals[1],
                                         east_lines[1])).convex_hull)

        return [nw_polygon, ne_polygon, sw_polygon, se_polygon]
    except Exception as e:
        logging.error("Unable to process polygon! {}; {}".format(polygon, e))
Exemple #10
0
def intersectionsGridFrontiere(P, X, Y):
    """Calcule la trace de la grille cartésienne définie par X, Y sur le Polyligne P
     autrement dit les intersections de P  avec les droites
        - x = X[i] verticales et
        - y = Y[j] horizontales
        qui représentent la grille.
    :param P : un polyligne np.ndarray de shape (n,3) ou (n,2). La 3-eme dimension est ignorée.
    :param X, Y : la grille cartésienne.
        X et Y sont des np.ndarray de shape (nx,1) et (ny,1) qui représentent
        les abscisses et les ordonnées de la grille
        - On suppose que X et Y sont croissants (i)
        - On suppose également que la grille recouvre entièrement P, et déborde, i.e.
            min(X) < xmin(P) <= xmax(P) < max(X)
            min(Y) < ymin(P) <= ymax(P) < max(Y)
    :return PD: np.ndarray((npd,2)) contenant les points
    """
    #     nx, ny = len(X), len(Y)
    #     for x in X : plt.plot(ny*[x], Y, 'y-', linewidth=0.3,)
    #     for y in Y : plt.plot(X, nx*[y], 'y-', linewidth=0.3)
    #     plt.plot(P[:,0],P[:,1], 'r.')
    #     P = LineString(P)
    P = LinearRing(P)
    #     x,y = P.xy
    #     plt.plot(x,y,'g-')
    #     plt.axes().set_aspect('equal')
    #     debug(P)
    (minx, miny, maxx, maxy) = P.bounds
    #     debug(P.bounds)
    #Les numeros de droites verticales intersectant P
    iX = np.where(np.logical_and(minx < X, X < maxx))[0]
    #     px = X[iX]#une croix pour marquer les droite concernées (graphique)
    #     plt.plot(px, len(px)*[min(Y)], 'rx')
    #les droites verticales
    ms = [((X[i], Y[0]), (X[i], Y[-1])) for i in iX]

    #Les numeros de droites horizontales intersectant P
    iY = np.where(np.logical_and(miny < Y, Y < maxy))[0]
    #     px = Y[iY]#une croix pour marquer les droite concernées
    #     plt.plot(len(px)*[max(X)], px, 'rx')

    #     plt.legend()
    #     plt.show()
    #Les droites horizontales concernées par P
    ms.extend([((X[0], Y[i]), (X[-1], Y[i])) for i in iY])

    D = MultiLineString(ms)  #La famille des droites de la grille
    #     debug(len(D))

    #convex_hull pour réordonner les points, en faire un polygone
    #array_interface pour recuperer les data pures numpy
    PD = P.intersection(D)  #.array_interface()
    #     debug(type(PD))
    D = [P.project(pd)
         for pd in PD]  #abscisse curviligne des points d'intersection
    D.sort()
    PD = [P.interpolate(d).xy for d in D]  #Les points dans l'ordre
    #     PD = PD.array_interface()
    #     exit()
    #.convex_hull.exterior

    #     shape = PD['shape']
    #PD.reshape(...) : si le tableau PD doit être recopié => en silence
    #PD = array(PD['data']).reshape(shape)
    #     PD = array(PD['data'])
    PD = array(PD)
    #PD.shape=... : si le tableau PD doit être recopié => erreur
    #     PD.shape = shape
    return PD