Пример #1
0
    def get_boundingpolygon(self):
        """
            TODO: Implement ncell bbox

            order of lines creation (assumes 0,0 is x)
            -----3-----
            |         |
            4         2
            |         |
            x----1-----
        """

        if self._ndim == 2: # CGRID
            nx,ny = self._xarray.shape
            one = MultiLineString([((self._xarray[i][0],self._yarray[i][0]),(self._xarray[i+1][0],self._yarray[i+1][0])) for i in range(nx-1)])
            two = MultiLineString([((self._xarray[nx-1][j],self._yarray[nx-1][j]),(self._xarray[nx-1][j+1],self._yarray[nx-1][j+1])) for j in range(ny-1)])
            three = MultiLineString([((self._xarray[i][ny-1],self._yarray[i][ny-1]),(self._xarray[i-1][ny-1],self._yarray[i-1][ny-1])) for i in reversed(list(range(1,nx)))])
            four = MultiLineString([((self._xarray[0][j],self._yarray[0][j]),(self._xarray[0][j-1],self._yarray[0][j-1])) for j in reversed(list(range(1,ny)))])
            m = one.union(two).union(three).union(four)
        else: # RGRID
            nx,ny = self._xarray.shape[0], self._yarray.shape[0]
            one = LineString([(self._xarray[i], self._yarray[0]) for i in range(nx)])
            two = LineString([(self._xarray[-1], self._yarray[i]) for i in range(ny)])
            three = LineString([(self._xarray[i], self._yarray[-1]) for i in reversed(list(range(nx)))])
            four = LineString([(self._xarray[0], self._yarray[i]) for i in reversed(list(range(ny)))])
            m = MultiLineString([one,two,three,four])

        polygons = list(polygonize(m))
        # -- polygonize returns a list of polygons, including interior features, the largest in area "should" be the full feature
        assert len(polygons) > 0, "Could not determine a polygon"
        polygon = sorted(polygons, key=lambda x: x.area)[-1]
        return polygon
 def processAlgorithm(self, progress):
     try:
         from shapely.ops import polygonize
         from shapely.geometry import Point, MultiLineString
     except ImportError:
         raise GeoAlgorithmExecutionException(
             'Polygonize algorithm requires shapely module!')
     vlayer = QGisLayers.getObjectFromUri(self.getParameterValue(
         self.INPUT))
     output = self.getOutputFromName(self.OUTPUT)
     vprovider = vlayer.dataProvider()
     if self.getParameterValue(self.FIELDS):
         fields = vprovider.fields()
     else:
         fields = QgsFields()
     if self.getParameterValue(self.GEOMETRY):
         fieldsCount = fields.count()
         fields.append(QgsField("area", QVariant.Double, "double", 16, 2))
         fields.append(
             QgsField("perimeter", QVariant.Double, "double", 16, 2))
     allLinesList = []
     features = QGisLayers.features(vlayer)
     current = 0
     total = 40.0 / float(len(features))
     for inFeat in features:
         inGeom = inFeat.geometry()
         if inGeom.isMultipart():
             allLinesList.extend(inGeom.asMultiPolyline())
         else:
             allLinesList.append(inGeom.asPolyline())
         current += 1
         progress.setPercentage(int(current * total))
     progress.setPercentage(40)
     allLines = MultiLineString(allLinesList)
     allLines = allLines.union(Point(0, 0))
     progress.setPercentage(45)
     polygons = list(polygonize([allLines]))
     progress.setPercentage(50)
     writer = output.getVectorWriter(fields, QGis.WKBPolygon, vlayer.crs())
     outFeat = QgsFeature()
     current = 0
     total = 50.0 / float(len(polygons))
     for polygon in polygons:
         outFeat.setGeometry(QgsGeometry.fromWkt(polygon.wkt))
         if self.getParameterValue(self.GEOMETRY):
             outFeat.setAttributes(
                 [None] * fieldsCount +
                 [QVariant(polygon.area),
                  QVariant(polygon.length)])
         writer.addFeature(outFeat)
         current += 1
         progress.setPercentage(50 + int(current * total))
     del writer
Пример #3
0
 def processAlgorithm(self, progress):
     try:
         from shapely.ops import polygonize
         from shapely.geometry import Point, MultiLineString
     except ImportError:
         raise GeoAlgorithmExecutionException(
                 'Polygonize algorithm requires shapely module!')
     vlayer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT))
     output = self.getOutputFromName(self.OUTPUT)
     vprovider = vlayer.dataProvider()
     if self.getParameterValue(self.FIELDS):
         fields = vprovider.fields()
     else:
         fields = QgsFields()
     if self.getParameterValue(self.GEOMETRY):
         fieldsCount = fields.count()
         fields.append(QgsField('area', QVariant.Double, 'double', 16, 2))
         fields.append(QgsField('perimeter', QVariant.Double,
                                'double', 16, 2))
     allLinesList = []
     features = vector.features(vlayer)
     current = 0
     total = 40.0 / float(len(features))
     for inFeat in features:
         inGeom = inFeat.geometry()
         if inGeom.isMultipart():
             allLinesList.extend(inGeom.asMultiPolyline())
         else:
             allLinesList.append(inGeom.asPolyline())
         current += 1
         progress.setPercentage(int(current * total))
     progress.setPercentage(40)
     allLines = MultiLineString(allLinesList)
     allLines = allLines.union(Point(0, 0))
     progress.setPercentage(45)
     polygons = list(polygonize([allLines]))
     progress.setPercentage(50)
     writer = output.getVectorWriter(fields, QGis.WKBPolygon, vlayer.crs())
     outFeat = QgsFeature()
     current = 0
     total = 50.0 / float(len(polygons))
     for polygon in polygons:
         outFeat.setGeometry(QgsGeometry.fromWkt(polygon.wkt))
         if self.getParameterValue(self.GEOMETRY):
             outFeat.setAttributes([None] * fieldsCount + [polygon.area,
                                   polygon.length])
         writer.addFeature(outFeat)
         current += 1
         progress.setPercentage(50 + int(current * total))
     del writer
Пример #4
0
 def check_intersections(self):
     checks_done = MultiLineString()
     for subpath, elem in self.get_line_strings():
         line = subpath.as_linestring()
         if not line.is_simple:
             # TODO: find location of self-intersection and introduce some
             # tolerance
             # checks_done = checks_done.union(line)
             yield CheckerResult("self-intersection found", elem)
             # continue
         if checks_done.intersects(line):
             intersection = checks_done.intersection(line)
             yield CheckerResult("intersection found", elem, extra={"intersection": intersection})
         checks_done = checks_done.union(line)
Пример #5
0
 def check_intersections(self):
     checks_done = MultiLineString()
     for subpath, elem in self.get_line_strings():
         line = subpath.as_linestring()
         if not line.is_simple:
             # TODO: find location of self-intersection and introduce some
             # tolerance
             # checks_done = checks_done.union(line)
             yield CheckerResult("self-intersection found", elem)
             # continue
         if checks_done.intersects(line):
             intersection = checks_done.intersection(line)
             yield CheckerResult("intersection found", elem, extra={"intersection": intersection})
         checks_done = checks_done.union(line)
Пример #6
0
  def union(self):
    '''new method using Union function'''
    global polyCount
    inFeat = QgsFeature()

    progress = 0.

    self.emit(SIGNAL('progress'), 0)

    self.parent.layer = getMapLayerByName(self.ui.cmbLayer.currentText())
    provider = self.parent.layer.dataProvider()
    #user can't toggle edit mode of line layer while polygonizing, plugin automatically turn it off 
    QObject.connect(self.parent.layer,SIGNAL("editingStarted()"), self.parent.startEditing)
    allAttrs = provider.attributeIndexes()
    provider.select(allAttrs)

    provider.select()

    step = 45. / self.parent.layer.featureCount()
    allLinesList = []
    allLinesListExtend = allLinesList.extend
    allLinesListAppend = allLinesList.append

    while provider.nextFeature(inFeat):
      geom = inFeat.geometry()
      if geom.isMultipart():
        allLinesListExtend(geom.asMultiPolyline() )
      else:
        allLinesListAppend(geom.asPolyline())

      progress += step
      self.emit(SIGNAL('progress'), progress)

    allLines = MultiLineString(allLinesList)
    allLines = allLines.union(Point(0,0))

    polygons = list(polygonize([allLines]))

    polyCount = len(polygons)
    #if no polygons where created then exit from thread
    if polyCount == 0:
      QObject.disconnect(self.parent.polygonizeThread,SIGNAL("finished()"), self.parent.threadFinished)
      self.emit(SIGNAL('noPolygons'))
      return
    else:
      if self.ui.cbOutput.isChecked():
        self.saveAsFile(polygons, progress)
      else:
        self.saveInMemory(polygons, progress)
Пример #7
0
def overlay(df1, df2, how, use_sindex=True):
    """Perform spatial overlay between two polygons.

    Currently only supports data GeoDataFrames with polygons.
    Implements several methods that are all effectively subsets of
    the union.

    Parameters
    ----------
    df1 : GeoDataFrame with MultiPolygon or Polygon geometry column
    df2 : GeoDataFrame with MultiPolygon or Polygon geometry column
    how : string
        Method of spatial overlay: 'intersection', 'union',
        'identity', 'symmetric_difference' or 'difference'.
    use_sindex : boolean, default True
        Use the spatial index to speed up operation if available.

    Returns
    -------
    df : GeoDataFrame
        GeoDataFrame with new set of polygons and attributes
        resulting from the overlay

    """
    allowed_hows = [
        'intersection',
        'union',
        'identity',
        'symmetric_difference',
        'difference',  # aka erase
    ]

    if how not in allowed_hows:
        raise ValueError("`how` was \"%s\" but is expected to be in %s" % \
            (how, allowed_hows))

    if isinstance(df1, GeoSeries) or isinstance(df2, GeoSeries):
        raise NotImplementedError("overlay currently only implemented for GeoDataFrames")

    # Collect the interior and exterior rings
    rings1 = _extract_rings(df1)
    rings2 = _extract_rings(df2)
    mls1 = MultiLineString(rings1)
    mls2 = MultiLineString(rings2)

    # Union and polygonize
    try:
        # calculating union (try the fast unary_union)
        mm = unary_union([mls1, mls2])
    except:
        # unary_union FAILED
        # see https://github.com/Toblerity/Shapely/issues/47#issuecomment-18506767
        # calculating union again (using the slow a.union(b))
        mm = mls1.union(mls2)
    newpolys = polygonize(mm)

    # determine spatial relationship
    collection = []
    for fid, newpoly in enumerate(newpolys):
        cent = newpoly.representative_point()

        # Test intersection with original polys
        # FIXME there should be a higher-level abstraction to search by bounds
        # and fall back in the case of no index?
        if use_sindex and df1.sindex is not None:
            candidates1 = [x.object for x in
                           df1.sindex.intersection(newpoly.bounds, objects=True)]
        else:
            candidates1 = [i for i, x in df1.iterrows()]

        if use_sindex and df2.sindex is not None:
            candidates2 = [x.object for x in
                           df2.sindex.intersection(newpoly.bounds, objects=True)]
        else:
            candidates2 = [i for i, x in df2.iterrows()]

        df1_hit = False
        df2_hit = False
        prop1 = None
        prop2 = None
        for cand_id in candidates1:
            cand = df1.loc[cand_id]
            if cent.intersects(cand[df1.geometry.name]):
                df1_hit = True
                prop1 = cand
                break  # Take the first hit
        for cand_id in candidates2:
            cand = df2.loc[cand_id]
            if cent.intersects(cand[df2.geometry.name]):
                df2_hit = True
                prop2 = cand
                break  # Take the first hit

        # determine spatial relationship based on type of overlay
        hit = False
        if how == "intersection" and (df1_hit and df2_hit):
            hit = True
        elif how == "union" and (df1_hit or df2_hit):
            hit = True
        elif how == "identity" and df1_hit:
            hit = True
        elif how == "symmetric_difference" and not (df1_hit and df2_hit):
            hit = True
        elif how == "difference" and (df1_hit and not df2_hit):
            hit = True

        if not hit:
            continue

        # gather properties
        if prop1 is None:
            prop1 = pd.Series(dict.fromkeys(df1.columns, None))
        if prop2 is None:
            prop2 = pd.Series(dict.fromkeys(df2.columns, None))

        # Concat but don't retain the original geometries
        out_series = pd.concat([prop1.drop(df1._geometry_column_name),
                                prop2.drop(df2._geometry_column_name)])

        out_series.index = _uniquify(out_series.index)

        # Create a geoseries and add it to the collection
        out_series['geometry'] = newpoly
        collection.append(out_series)

    # Return geodataframe with new indicies
    return GeoDataFrame(collection, index=range(len(collection)))
Пример #8
0
def overlay(df1, df2, how, use_sindex=True):
    """Perform spatial overlay between two polygons.

    Currently only supports data GeoDataFrames with polygons.
    Implements several methods that are all effectively subsets of
    the union.

    Parameters
    ----------
    df1 : GeoDataFrame with MultiPolygon or Polygon geometry column
    df2 : GeoDataFrame with MultiPolygon or Polygon geometry column
    how : string
        Method of spatial overlay: 'intersection', 'union',
        'identity', 'symmetric_difference' or 'difference'.
    use_sindex : boolean, default True
        Use the spatial index to speed up operation if available.

    Returns
    -------
    df : GeoDataFrame
        GeoDataFrame with new set of polygons and attributes
        resulting from the overlay

    """
    allowed_hows = [
        'intersection',
        'union',
        'identity',
        'symmetric_difference',
        'difference',  # aka erase
    ]

    if how not in allowed_hows:
        raise ValueError("`how` was \"%s\" but is expected to be in %s" % \
            (how, allowed_hows))

    if isinstance(df1, GeoSeries) or isinstance(df2, GeoSeries):
        raise NotImplementedError("overlay currently only implemented for GeoDataFrames")

    # Collect the interior and exterior rings
    rings1 = _extract_rings(df1)
    rings2 = _extract_rings(df2)
    mls1 = MultiLineString(rings1)
    mls2 = MultiLineString(rings2)

    # Union and polygonize
    try:
        # calculating union (try the fast unary_union)
        mm = unary_union([mls1, mls2])
    except:
        # unary_union FAILED
        # see https://github.com/Toblerity/Shapely/issues/47#issuecomment-18506767
        # calculating union again (using the slow a.union(b))
        mm = mls1.union(mls2)
    newpolys = polygonize(mm)

    # determine spatial relationship
    collection = []
    for fid, newpoly in enumerate(newpolys):
        cent = newpoly.representative_point()

        # Test intersection with original polys
        # FIXME there should be a higher-level abstraction to search by bounds
        # and fall back in the case of no index?
        if use_sindex and df1.sindex is not None:
            candidates1 = [x.object for x in
                           df1.sindex.intersection(newpoly.bounds, objects=True)]
        else:
            candidates1 = [i for i, x in df1.iterrows()]

        if use_sindex and df2.sindex is not None:
            candidates2 = [x.object for x in
                           df2.sindex.intersection(newpoly.bounds, objects=True)]
        else:
            candidates2 = [i for i, x in df2.iterrows()]

        df1_hit = False
        df2_hit = False
        prop1 = None
        prop2 = None
        for cand_id in candidates1:
            cand = df1.ix[cand_id]
            if cent.intersects(cand[df1.geometry.name]):
                df1_hit = True
                prop1 = cand
                break  # Take the first hit
        for cand_id in candidates2:
            cand = df2.ix[cand_id]
            if cent.intersects(cand[df2.geometry.name]):
                df2_hit = True
                prop2 = cand
                break  # Take the first hit

        # determine spatial relationship based on type of overlay
        hit = False
        if how == "intersection" and (df1_hit and df2_hit):
            hit = True
        elif how == "union" and (df1_hit or df2_hit):
            hit = True
        elif how == "identity" and df1_hit:
            hit = True
        elif how == "symmetric_difference" and not (df1_hit and df2_hit):
            hit = True
        elif how == "difference" and (df1_hit and not df2_hit):
            hit = True

        if not hit:
            continue

        # gather properties
        if prop1 is None:
            prop1 = pd.Series(dict.fromkeys(df1.columns, None))
        if prop2 is None:
            prop2 = pd.Series(dict.fromkeys(df2.columns, None))

        # Concat but don't retain the original geometries
        out_series = pd.concat([prop1.drop(df1._geometry_column_name),
                                prop2.drop(df2._geometry_column_name)])

        out_series.index = _uniquify(out_series.index)

        # Create a geoseries and add it to the collection
        out_series['geometry'] = newpoly
        collection.append(out_series)

    # Return geodataframe with new indicies
    return GeoDataFrame(collection, index=range(len(collection)))
Пример #9
0
#print "\t", len([x for x in rings if not x.is_valid]), "invalid rings"
#rings = [x for x in rings if x.is_valid]

from shapely.geometry import MultiLineString

mls1 = MultiLineString(rings1)
mls2 = MultiLineString(rings2)

try:
    print "calculating union (try the fast unary_union)"
    mm = unary_union([mls1, mls2])
except:
    print "FAILED"
    print "calculating union again (using the slow a.union(b))"
    mm = mls1.union(mls2)

print "polygonize rings"
newpolys = polygonize(mm)

print "determine spatial relationship and plot new polys"
for newpoly in newpolys:
    cent = newpoly.representative_point()

    # Test intersection with original polys
    layer1_hit = False
    layer2_hit = False
    candidates1 = list(idx1.intersection(cent.bounds))
    candidates2 = list(idx2.intersection(cent.bounds))

    for cand in candidates1:
Пример #10
0
    def _overlay(self, layer2, method):
        assert method in ['union', 'intersection', 'identity']

        idx1 = index.Index()
        idx2 = index.Index()

        # for fast lookup of geometry and properties after spatial index
        # advantage: don't have to reopen ds and seek on disk
        # disadvantage: have to keep everything in memory
        #  {id: (shapely geom, properties dict) }
        # TODO just use the index as the id and just copy the fiona records?
        features1 = {}
        features2 = {}
        rings1 = []
        rings2 = []

        log.debug("gathering LinearRings")
        log.debug("\tself")
        for rec in self.collection():
            geom = shape(rec['geometry'])
            rid = int(rec['id'])
            features1[rid] = (geom, rec['properties'])
            idx1.insert(rid, geom.bounds)
            if hasattr(geom, 'geoms'):
                for poly in geom.geoms:  # if it's a multipolygon
                    if not poly.is_valid:
                        log.debug("\tgeom from self layer is not valid," +
                                  " attempting fix by buffer 0")
                        poly = poly.buffer(0)
                    rings1.append(poly.exterior)
                    rings1.extend(poly.interiors)
            else:
                if not geom.is_valid:
                    log.debug("\tgeom from self layer is not valid," +
                              " attempting fix by buffer 0")
                    geom = geom.buffer(0)
                rings1.append(geom.exterior)
                rings1.extend(geom.interiors)

        log.debug("\tlayer2")
        for rec in layer2.collection():
            geom = shape(rec['geometry'])

            rid = int(rec['id'])
            features2[rid] = (geom, rec['properties'])
            idx2.insert(rid, geom.bounds)

            if hasattr(geom, 'geoms'):
                for poly in geom.geoms:  # multipolygon
                    if not poly.is_valid:
                        log.debug("\t geom from layer2 is not valid," +
                                  " attempting fix by buffer 0")
                        poly = poly.buffer(0)
                    rings2.append(poly.exterior)
                    rings2.extend(poly.interiors)
            else:
                if not geom.is_valid:
                    log.debug("\t geom from layer2 is not valid," +
                              " attempting fix by buffer 0")
                    geom = geom.buffer(0)
                rings2.append(geom.exterior)
                rings2.extend(geom.interiors)

        #rings = [x for x in rings if x.is_valid]
        mls1 = MultiLineString(rings1)
        mls2 = MultiLineString(rings2)

        try:
            log.debug("calculating union (try the fast unary_union)")
            mm = unary_union([mls1, mls2])
        except:
            log.exception("unary_union FAILED")
            log.debug("calculating union again (using the slow a.union(b))")
            mm = mls1.union(mls2)

        log.debug("polygonize rings")
        newpolys = polygonize(mm)

        log.debug("constructing new schema")
        out_schema = self.collection().schema.copy()
        # TODO polygon geomtype

        layer2_schema_map = {}  # {old: new}
        for key, value in layer2.collection().schema['properties'].items():
            if key not in out_schema['properties']:
                out_schema['properties'][key] = value
                layer2_schema_map[key] = key
            else:
                # try to rename it
                i = 2
                while True:
                    newkey = "%s_%d" % (key, i)
                    if newkey not in out_schema['properties']:
                        out_schema['properties'][newkey] = value
                        layer2_schema_map[key] = newkey
                        break
                    i += 1

        tempds = self.tempds(method)
        out_collection = fiona.collection(tempds, "w", "ESRI Shapefile",
                                          out_schema)

        log.debug("determine spatial relationship")
        for fid, newpoly in enumerate(newpolys):
            cent = newpoly.representative_point()

            # Test intersection with original polys
            layer1_hit = False
            layer2_hit = False
            prop1 = None
            prop2 = None
            candidates1 = list(idx1.intersection(cent.bounds))
            candidates2 = list(idx2.intersection(cent.bounds))

            for cand in candidates1:
                if cent.intersects(features1[cand][0]):
                    layer1_hit = True
                    prop1 = features1[cand][1]  # properties
                    break

            for cand in candidates2:
                if cent.intersects(features2[cand][0]):
                    layer2_hit = True
                    prop2 = features2[cand][1]  # properties
                    break

            # determine whether to output based on type of overlay
            hit = False
            if method == "intersection" and (layer1_hit and layer2_hit):
                hit = True
            elif method == "union" and (layer1_hit or layer2_hit):
                hit = True
            elif method == "identity" and ((layer1_hit and layer2_hit) or
                                           (layer1_hit and not layer2_hit)):
                hit = True

            if not hit:
                continue

            log.debug("write newpoly with attrs gathered from prop1 & prop2")
            if not prop1:
                prop1 = dict.fromkeys(
                    self.collection().schema['properties'].keys(), None)

            if not prop2:
                prop2 = dict.fromkeys(layer2_schema_map.keys(), None)

            newprop = prop1
            for key, value in prop2.items():
                newkey = layer2_schema_map[key]
                newprop[newkey] = value

            out_feature = {
                'id': fid,
                'properties': newprop,
                'geometry': mapping(newpoly)
            }

            out_collection.write(out_feature)

        out_collection.close()
        return Layer(tempds)
Пример #11
0
    def _overlay(self, layer2, method):
        assert method in ['union', 'intersection', 'identity']

        idx1 = index.Index()
        idx2 = index.Index()

        # for fast lookup of geometry and properties after spatial index
        # advantage: don't have to reopen ds and seek on disk
        # disadvantage: have to keep everything in memory
        #  {id: (shapely geom, properties dict) }
        # TODO just use the index as the id and just copy the fiona records?
        features1 = {}
        features2 = {}
        rings1 = []
        rings2 = []

        log.debug("gathering LinearRings")
        log.debug("\tself")
        for rec in self.collection():
            geom = shape(rec['geometry'])
            rid = int(rec['id'])
            features1[rid] = (geom, rec['properties'])
            idx1.insert(rid, geom.bounds)
            if hasattr(geom, 'geoms'):
                for poly in geom.geoms:  # if it's a multipolygon
                    if not poly.is_valid:
                        log.debug("\tgeom from self layer is not valid," +
                                  " attempting fix by buffer 0")
                        poly = poly.buffer(0)
                    rings1.append(poly.exterior)
                    rings1.extend(poly.interiors)
            else:
                if not geom.is_valid:
                    log.debug("\tgeom from self layer is not valid," +
                              " attempting fix by buffer 0")
                    geom = geom.buffer(0)
                rings1.append(geom.exterior)
                rings1.extend(geom.interiors)

        log.debug("\tlayer2")
        for rec in layer2.collection():
            geom = shape(rec['geometry'])

            rid = int(rec['id'])
            features2[rid] = (geom, rec['properties'])
            idx2.insert(rid, geom.bounds)

            if hasattr(geom, 'geoms'):
                for poly in geom.geoms:  # multipolygon
                    if not poly.is_valid:
                        log.debug("\t geom from layer2 is not valid," +
                                  " attempting fix by buffer 0")
                        poly = poly.buffer(0)
                    rings2.append(poly.exterior)
                    rings2.extend(poly.interiors)
            else:
                if not geom.is_valid:
                    log.debug("\t geom from layer2 is not valid," +
                              " attempting fix by buffer 0")
                    geom = geom.buffer(0)
                rings2.append(geom.exterior)
                rings2.extend(geom.interiors)

        #rings = [x for x in rings if x.is_valid]
        mls1 = MultiLineString(rings1)
        mls2 = MultiLineString(rings2)

        try:
            log.debug("calculating union (try the fast unary_union)")
            mm = unary_union([mls1, mls2])
        except:
            log.exception("unary_union FAILED")
            log.debug("calculating union again (using the slow a.union(b))")
            mm = mls1.union(mls2)

        log.debug("polygonize rings")
        newpolys = polygonize(mm)

        log.debug("constructing new schema")
        out_schema = self.collection().schema.copy()
        # TODO polygon geomtype

        layer2_schema_map = {}  # {old: new}
        for key, value in layer2.collection().schema['properties'].items():
            if key not in out_schema['properties']:
                out_schema['properties'][key] = value
                layer2_schema_map[key] = key
            else:
                # try to rename it
                i = 2
                while True:
                    newkey = "%s_%d" % (key, i)
                    if newkey not in out_schema['properties']:
                        out_schema['properties'][newkey] = value
                        layer2_schema_map[key] = newkey 
                        break
                    i += 1 

        tempds = self.tempds(method)
        out_collection = fiona.collection(
            tempds, "w", "ESRI Shapefile", out_schema)

        log.debug("determine spatial relationship")
        for fid, newpoly in enumerate(newpolys):
            cent = newpoly.representative_point()

            # Test intersection with original polys
            layer1_hit = False
            layer2_hit = False
            prop1 = None
            prop2 = None
            candidates1 = list(idx1.intersection(cent.bounds))
            candidates2 = list(idx2.intersection(cent.bounds))

            for cand in candidates1:
                if cent.intersects(features1[cand][0]):
                    layer1_hit = True
                    prop1 = features1[cand][1]  # properties
                    break

            for cand in candidates2:
                if cent.intersects(features2[cand][0]):
                    layer2_hit = True
                    prop2 = features2[cand][1]  # properties
                    break

            # determine whether to output based on type of overlay
            hit = False
            if method == "intersection" and (layer1_hit and layer2_hit):
                hit = True
            elif method == "union" and (layer1_hit or layer2_hit):
                hit = True
            elif method == "identity" and ((layer1_hit and layer2_hit) or
                           (layer1_hit and not layer2_hit)):
                hit = True

            if not hit:
                continue

            log.debug("write newpoly with attrs gathered from prop1 & prop2")
            if not prop1:
                prop1 = dict.fromkeys(
                    self.collection().schema['properties'].keys(), None)

            if not prop2:
                prop2 = dict.fromkeys(layer2_schema_map.keys(), None)

            newprop = prop1
            for key, value in prop2.items():
                newkey = layer2_schema_map[key]
                newprop[newkey] = value

            out_feature = {
                'id': fid,
                'properties': newprop,
                'geometry': mapping(newpoly)}

            out_collection.write(out_feature)

        out_collection.close()
        return Layer(tempds)
Пример #12
0
#print "\t", len([x for x in rings if not x.is_valid]), "invalid rings"
#rings = [x for x in rings if x.is_valid]

from shapely.geometry import MultiLineString

mls1 = MultiLineString(rings1)
mls2 = MultiLineString(rings2)

try:
    print "calculating union (try the fast unary_union)"
    mm = unary_union([mls1, mls2])
except:
    print "FAILED"
    print "calculating union again (using the slow a.union(b))"
    mm = mls1.union(mls2)

print "polygonize rings"
newpolys = polygonize(mm)

print "determine spatial relationship and plot new polys"
for newpoly in newpolys:
    cent = newpoly.representative_point()

    # Test intersection with original polys
    layer1_hit = False
    layer2_hit = False
    candidates1 = list(idx1.intersection(cent.bounds))
    candidates2 = list(idx2.intersection(cent.bounds))

    for cand in candidates1:
Пример #13
0
 def polygonize(self, outputLayer, append):
     try:
         from shapely.ops import polygonize
         from shapely.geometry import Point, MultiLineString
     except ImportError:
         self.messageBarUtils.showMessage("Polygonize", "Polygonize requires the Shapely Python module. Please contact your administrator.", QgsMessageBar.CRITICAL, 5)
         return
     
     self.outputLayer = outputLayer
     self.append = append
     
     outputEditable = False
     if self.outputLayer.isEditable():
         outputEditable = True
         self.outputLayer.beginEditCommand("Polygonize")
     else:
         self.outputLayer.startEditing()    
     
     grassOutputLayer=None
     tempDir = None
     try:
         
         selected = self.layer.selectedFeatureCount() > 0
         
         tempDir = tempfile.mkdtemp()
         shpPath = os.path.join(tempDir, "temp.shp")
         QgsVectorFileWriter.writeAsVectorFormat(self.layer, shpPath, self.layer.dataProvider().encoding(), 
                                                 self.layer.crs(), onlySelected=selected)
         grassOutputLayer = self.cleanupGRASS(shpPath)
         
         
         self.iface.mainWindow().statusBar().showMessage("Cleanup duplicate and degenerate lines")
         allLinesList = self.cleanupDuplicateAndDegenerateLines(grassOutputLayer)
         
         _, progress = self.messageBarUtils.showProgress("Polygonize", "Running...", QgsMessageBar.INFO)
             
         
         self.iface.mainWindow().statusBar().showMessage("Shapely polygonize")
             
         progress.setValue(10)
         allLines = MultiLineString(allLinesList)
         allLines = allLines.union(Point(0, 0))
         progress.setValue(25)
         polygons = list(polygonize([allLines]))
         progress.setValue(35)
         
         outFeat = QgsFeature()
         
         outputFields = self.outputLayer.dataProvider().fields()
         
         
         self.iface.mainWindow().statusBar().showMessage("Freeze canvas before update")
         
         self.iface.mapCanvas().freeze(True)
         
         if not append:
             # delete all features in outputlayer
             for feature in self.outputLayer.getFeatures():
                 self.outputLayer.deleteFeature(feature.id())
         
         progress.setValue(50)
         
         
         self.iface.mainWindow().statusBar().showMessage("add to output")
         
         current = 0
         if len(polygons) > 0:
             total = 50.0 / float(len(polygons))
             for polygon in polygons:
                 geom = QgsGeometry.fromWkt(polygon.wkt)
                 outFeat.setGeometry(geom)
                 outFeat.initAttributes(outputFields.count())
                 self.outputLayer.addFeature(outFeat)
                 current += 1
                 progress.setValue(50 + int(current * total))
             
             self.messageBarUtils.showMessage("Polygonize", "Success: %d polygons created in %s" %(current, self.outputLayer.name()), QgsMessageBar.INFO, 2)
         else:
             self.messageBarUtils.showMessage("Polygonize", "No polygon was created", QgsMessageBar.WARNING, 2)
             
     except Exception as e:
         QgsMessageLog.logMessage(repr(e))
         self.messageBarUtils.removeAllMessages()
         self.messageBarUtils.showMessage("Polygonize", "There was an error performing this command. See QGIS Message log for details.", QgsMessageBar.CRITICAL, duration=5)
         
         if outputEditable:
             self.outputLayer.destroyEditCommand()
         else:
             self.outputLayer.rollBack()
         return
     finally:
         if tempDir:
             shutil.rmtree(tempDir, True)
         if grassOutputLayer:
             del grassOutputLayer
         self.iface.mapCanvas().freeze(False)
         self.iface.mapCanvas().refresh()
     
     if outputEditable:
         self.outputLayer.endEditCommand()
     else:
         self.outputLayer.commitChanges()