Ejemplo n.º 1
0
    def swap_vectors(self, layer, selected=True):
        '''Swap / reverse vector direction for line layers

        Parameters
        ----------
        layer : QgsVectorLayer
            input line vector layer
        selected : boolean
            swap only selected or all features (Default value = True)

        Returns
        -------
        error : boolean
            0/1 - no error/error
        result : str or None
            output or error msg if error == 1

        '''
        features = self.get_features(layer, selected=selected)

        with edit(layer):
            # reverse line direction for each (selected) feature
            for feature in features:
                geom = feature.geometry()
                if geom.isMultipart():
                    mls = QgsMultiLineString()
                    for line in geom.asGeometryCollection():
                        mls.addGeometry(line.constGet().reversed())
                    newgeom = QgsGeometry(mls)
                    layer.changeGeometry(feature.id(), newgeom)
                else:
                    newgeom = QgsGeometry(geom.constGet().reversed())
                    layer.changeGeometry(feature.id(), newgeom)

        return 0, None
Ejemplo n.º 2
0
 def reverseLineDirection(self, line_geom):
     mls1 = line_geom.get()
     mls2 = QgsMultiLineString()
     # For each reversed linestring, visited in reverse order
     for i in [QgsLineString([*i][::-1]) for i in [*mls1][::-1]]:
         _ = mls2.addGeometry(i)  # add it to new geometry
     new_geometry = QgsGeometry(mls2)
     return new_geometry
    def test_except_check_singlepart_lines_more_parts(self):
        mls = QgsMultiLineString()
        mls.addGeometry(QgsLineString([QgsPoint(210, 41), QgsPoint(301, 55)]))
        mls.addGeometry(QgsLineString([QgsPoint(210, 55), QgsPoint(301, 41)]))

        vl = TestGateTransformer.make_single_feature_layer(
            "MultiLineString", mls)
        with self.assertRaises(BadInputError) as e:
            TransformerAnalysis.GateTransformer.check_singlepart_lines(vl)
        self.assertEqual(
            str(e.exception),
            "Feature with id 1 contains more than 1 line, please correct")
Ejemplo n.º 4
0
    def convertToLines(self, geometry):
        rings = self.getRings(geometry.constGet())
        output_wkb = self.convertWkbToLines(geometry.wkbType())
        out_geom = None
        if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString:
            out_geom = QgsMultiLineString()
        else:
            out_geom = QgsMultiCurve()

        for ring in rings:
            out_geom.addGeometry(ring)

        return out_geom
Ejemplo n.º 5
0
    def convertToLines(self, geometry):
        rings = self.getRings(geometry.constGet())
        output_wkb = self.convertWkbToLines(geometry.wkbType())
        out_geom = None
        if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString:
            out_geom = QgsMultiLineString()
        else:
            out_geom = QgsMultiCurve()

        for ring in rings:
            out_geom.addGeometry(ring)

        return out_geom
Ejemplo n.º 6
0
    def segmentizeBoundaries(self, geom):
        """geom: QgsGeometry (polygon or multi-polygon)"""

        xmin, ymax = (self.xmin, self.ymax)
        xres, yres = (self.xres, self.yres)
        z_func = self.valueOnSurface

        polys = []
        for polygon in PolygonGeometry.nestedPointXYList(geom):
            rings = QgsMultiLineString()
            for i, bnd in enumerate(polygon):
                if GeometryUtils.isClockwise(bnd) ^ (i > 0):   # xor
                    bnd.reverse()       # outer boundary should be ccw. inner boundaries should be cw.

                ring = QgsLineString()

                v = bnd[0]     # QgsPointXY
                x0, y0 = (v.x(), v.y())
                nx0 = (x0 - xmin) / xres
                ny0 = (ymax - y0) / yres
                ns0 = abs(ny0 + nx0)

                for v in bnd[1:]:
                    x1, y1 = (v.x(), v.y())
                    nx1 = (x1 - xmin) / xres
                    ny1 = (ymax - y1) / yres
                    ns1 = abs(ny1 + nx1)

                    p = set([0])
                    for v0, v1 in [[nx0, nx1], [ny0, ny1], [ns0, ns1]]:
                        k = ceil(min(v0, v1))
                        n = floor(max(v0, v1))
                        for j in range(k, n + 1):
                            p.add((j - v0) / (v1 - v0))

                    if 1 in p:
                        p.remove(1)

                    for m in sorted(p):
                        x = x0 + (x1 - x0) * m
                        y = y0 + (y1 - y0) * m
                        ring.addVertex(QgsPoint(x, y, z_func(x, y)))

                    x0, y0 = (x1, y1)
                    nx0, ny0, ns0 = (nx1, ny1, ns1)

                ring.addVertex(QgsPoint(x0, y0, z_func(x0, y0)))    # last vertex
                rings.addGeometry(ring)
            polys.append(QgsGeometry(rings))
        return polys
Ejemplo n.º 7
0
    def processFeature(self, feature, context, feedback):  #pylint: disable=no-self-use,unused-argument,missing-docstring
        def transform(geometry):
            """
            Transform Z into Slope.
            Opposite to mathematical convention,
            slope is oriented in reverse line direction.
            """

            vertices = np.array([(v.x(), v.y(), v.z())
                                 for v in geometry.vertices()])
            slope = np.zeros(len(vertices), dtype=np.float32)

            if len(vertices) > 2:

                # 2D horizontal distance
                distance = np.linalg.norm(vertices[:-1, 0:2] -
                                          vertices[1:, 0:2],
                                          axis=1)

                slope[1:-1] = (vertices[:-2, 2] - vertices[2:, 2]) / (
                    distance[:-1] + distance[1:])
                slope[0] = slope[1]
                slope[-1] = slope[-2]

            points = list()

            for i, vertex in enumerate(geometry.vertices()):
                vertex.setZ(float(slope[i]))
                points.append(vertex)

            return QgsLineString(points)

        geometry = feature.geometry()

        if geometry.isMultipart():

            parts = QgsMultiLineString()

            for part in geometry.asGeometryCollection():
                linestring = transform(part)
                parts.addGeometry(linestring)

            feature.setGeometry(QgsGeometry(parts))

        else:

            feature.setGeometry(QgsGeometry(transform(geometry)))

        return [feature]
Ejemplo n.º 8
0
 def convertToMultiLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return [geom]
         else:
             # line to multiLine
             ml = QgsMultiLineString()
             ml.addGeometry(geom.constGet().clone())
             return [QgsGeometry(ml)]
     else:
         # polygons to multilinestring
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         return [QgsGeometry(geom.constGet().boundary())]
Ejemplo n.º 9
0
 def convertToMultiLineStrings(self, geom):
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
         raise QgsProcessingException(
             self.tr('Cannot convert from {0} to MultiLineStrings').format(QgsWkbTypes.displayString(geom.wkbType())))
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         if QgsWkbTypes.isMultiType(geom.wkbType()):
             return [geom]
         else:
             # line to multiLine
             ml = QgsMultiLineString()
             ml.addGeometry(geom.constGet().clone())
             return [QgsGeometry(ml)]
     else:
         # polygons to multilinestring
         # we just use the boundary here - that consists of all rings in the (multi)polygon
         return [QgsGeometry(geom.constGet().boundary())]
Ejemplo n.º 10
0
    def process(self, name, desc, alt_mode, begin, end, when):
        if self.extDataSize > 0:
            extAttr = [''] * self.extDataSize
        for key in self.extendedData.keys():
            if key in self.extDataMap:
                extAttr[self.extDataMap[key]] = self.extendedData[key]
        # POINTS
        if len(self.ptPts) != 0:
            for x, pt in enumerate(self.ptPts):
                feature = QgsFeature()
                feature.setGeometry(QgsGeometry(pt))
                attr = [
                    name,
                    self.folderString(), desc, self.ptAltitude[x], alt_mode,
                    begin, end, when
                ]
                if self.extDataSize > 0:
                    attr.extend(extAttr)
                feature.setAttributes(attr)
                self.addpoint.emit(feature)

        # LINES - lineStrings is a list of QgsLineString
        if len(self.lineStrings) != 0:
            feature = QgsFeature()
            if len(self.lineStrings) == 1:
                feature.setGeometry(QgsGeometry(self.lineStrings[0]))
            else:
                g = QgsMultiLineString()
                for lineStr in self.lineStrings:
                    g.addGeometry(lineStr)
                feature.setGeometry(QgsGeometry(g))
            attr = [
                name,
                self.folderString(), desc, 0, alt_mode, begin, end, when
            ]
            if self.extDataSize > 0:
                attr.extend(extAttr)
            feature.setAttributes(attr)
            self.addline.emit(feature)

        # POLYGONS
        if len(self.polygons) != 0:
            feature = QgsFeature()
            if len(self.polygons) == 1:
                feature.setGeometry(QgsGeometry(self.polygons[0]))
            else:
                g = QgsMultiPolygon()
                for poly in self.polygons:
                    g.addGeometry(poly)
                feature.setGeometry(QgsGeometry(g))
            attr = [
                name,
                self.folderString(), desc, 0, alt_mode, begin, end, when
            ]
            if self.extDataSize > 0:
                attr.extend(extAttr)
            feature.setAttributes(attr)
            self.addpolygon.emit(feature)
    def test_except_check_singlepart_lines_no_parts(self):
        mls = QgsMultiLineString()

        vl = TestGateTransformer.make_single_feature_layer(
            "MultiLineString", mls)
        with self.assertRaises(BadInputError) as e:
            TransformerAnalysis.GateTransformer.check_singlepart_lines(vl)
        self.assertEqual(
            str(e.exception),
            "Feature with id 1 has no line geometry, please correct")
Ejemplo n.º 12
0
    def get_pair_boundary_plot(self,
                               boundary_layer,
                               plot_layer,
                               id_field=ID_FIELD,
                               use_selection=True):
        id_field_idx = plot_layer.fields().indexFromName(id_field)
        request = QgsFeatureRequest().setSubsetOfAttributes([id_field_idx])
        polygons = plot_layer.getSelectedFeatures(
            request) if use_selection else plot_layer.getFeatures(request)
        intersect_more_pairs = list()
        intersect_less_pairs = list()

        if boundary_layer.featureCount() == 0:
            return (intersect_more_pairs, intersect_less_pairs)

        id_field_idx = boundary_layer.fields().indexFromName(id_field)
        request = QgsFeatureRequest().setSubsetOfAttributes([id_field_idx])
        dict_features = {
            feature.id(): feature
            for feature in boundary_layer.getFeatures(request)
        }
        index = QgsSpatialIndex(boundary_layer)
        candidate_features = None

        for polygon in polygons:
            bbox = polygon.geometry().boundingBox()
            bbox.scale(1.001)
            candidates_ids = index.intersects(bbox)

            candidate_features = [
                dict_features[candidate_id] for candidate_id in candidates_ids
            ]

            for candidate_feature in candidate_features:
                polygon_geom = polygon.geometry()
                is_multipart = polygon_geom.isMultipart()
                candidate_geometry = candidate_feature.geometry()

                if polygon_geom.intersects(candidate_geometry):
                    # Does the current multipolygon have inner rings?
                    has_inner_rings = False
                    multi_polygon = None
                    single_polygon = None

                    if is_multipart:
                        multi_polygon = polygon_geom.get()
                        for part in range(multi_polygon.numGeometries()):
                            if multi_polygon.ringCount(part) > 1:
                                has_inner_rings = True
                                break
                    else:
                        single_polygon = polygon_geom.get()
                        if single_polygon.numInteriorRings() > 0:
                            has_inner_rings = True

                    # Now we'll test intersections against borders
                    if has_inner_rings:
                        # In this case we need to identify whether the
                        # intersection is with outer rings (goes to MOREBFS
                        # table) or with inner rings (goes to LESS table)
                        multi_outer_rings = QgsMultiLineString()
                        multi_inner_rings = QgsMultiLineString()

                        if is_multipart and multi_polygon:
                            for i in range(multi_polygon.numGeometries()):
                                temp_polygon = multi_polygon.geometryN(i)
                                multi_outer_rings.addGeometry(
                                    temp_polygon.exteriorRing().clone())
                                for j in range(
                                        temp_polygon.numInteriorRings()):
                                    multi_inner_rings.addGeometry(
                                        temp_polygon.interiorRing(j).clone())

                        elif not is_multipart and single_polygon:
                            multi_outer_rings.addGeometry(
                                single_polygon.exteriorRing().clone())
                            for j in range(single_polygon.numInteriorRings()):
                                multi_inner_rings.addGeometry(
                                    single_polygon.interiorRing(j).clone())

                        intersection_type = QgsGeometry(
                            multi_outer_rings).intersection(
                                candidate_geometry).type()
                        if intersection_type == QgsWkbTypes.LineGeometry:
                            intersect_more_pairs.append(
                                (polygon[id_field],
                                 candidate_feature[id_field]))
                        else:
                            self.log.logMessage(
                                "(MoreBFS) Intersection between plot (t_id={}) and boundary (t_id={}) is a geometry of type: {}"
                                .format(polygon[id_field],
                                        candidate_feature[id_field],
                                        intersection_type), PLUGIN_NAME,
                                Qgis.Warning)

                        intersection_type = QgsGeometry(
                            multi_inner_rings).intersection(
                                candidate_geometry).type()
                        if intersection_type == QgsWkbTypes.LineGeometry:
                            intersect_less_pairs.append(
                                (polygon[id_field],
                                 candidate_feature[id_field]))
                        else:
                            self.log.logMessage(
                                "(Less) Intersection between plot (t_id={}) and boundary (t_id={}) is a geometry of type: {}"
                                .format(polygon[id_field],
                                        candidate_feature[id_field],
                                        intersection_type), PLUGIN_NAME,
                                Qgis.Warning)

                    else:
                        boundary = None
                        if is_multipart and multi_polygon:
                            boundary = multi_polygon.boundary()
                        elif not is_multipart and single_polygon:
                            boundary = single_polygon.boundary()

                        intersection_type = QgsGeometry(boundary).intersection(
                            candidate_geometry).type()
                        if boundary and intersection_type == QgsWkbTypes.LineGeometry:
                            intersect_more_pairs.append(
                                (polygon[id_field],
                                 candidate_feature[id_field]))
                        else:
                            self.log.logMessage(
                                "(MoreBFS) Intersection between plot (t_id={}) and boundary (t_id={}) is a geometry of type: {}"
                                .format(polygon[id_field],
                                        candidate_feature[id_field],
                                        intersection_type), PLUGIN_NAME,
                                Qgis.Warning)
        # free up memory
        del candidate_features
        del dict_features
        gc.collect()
        return (intersect_more_pairs, intersect_less_pairs)
import time

from qgis.core import QgsLineString, QgsMultiLineString, QgsPoint, QgsProject

POLY_LYR = "test_poly"

lyr_polys = QgsProject.instance().mapLayersByName(POLY_LYR)[0]

t0 = time.time()
for counter, poly in enumerate(lyr_polys.getFeatures()):
    centroid = QgsPoint(poly.geometry().centroid().asPoint())
    star = QgsMultiLineString()
    for vertex in poly.geometry().vertices():
        line = QgsLineString(centroid, vertex)
        star.addGeometry(line)

t1 = time.time()
print(f"PYTHON: run {counter + 1} times for {t1-t0:.2f} secs")
Ejemplo n.º 14
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.PrmInputLayer,
                                        context)
        outer_col = self.parameterAsString(parameters,
                                           self.PrmOuterRadiusField, context)
        inner_col = self.parameterAsString(parameters,
                                           self.PrmInnerRadiusField, context)
        lines_col = self.parameterAsString(parameters,
                                           self.PrmNumberOfLinesField, context)
        def_outer_radius = self.parameterAsDouble(parameters,
                                                  self.PrmDefaultOuterRadius,
                                                  context)
        def_inner_radius = self.parameterAsDouble(parameters,
                                                  self.PrmDefaultInnerRadius,
                                                  context)
        def_lines = self.parameterAsDouble(parameters,
                                           self.PrmDefaultNumberOfLines,
                                           context)
        units = self.parameterAsInt(parameters, self.PrmUnitsOfMeasure,
                                    context)
        export_geom = self.parameterAsBool(parameters,
                                           self.PrmExportInputGeometry,
                                           context)

        measure_factor = conversionToMeters(units)

        def_inner_radius *= measure_factor
        def_outer_radius *= measure_factor

        src_crs = source.sourceCrs()
        fields = source.fields()
        if export_geom:
            names = fields.names()
            name_x, name_y = settings.getGeomNames(names)
            fields.append(QgsField(name_x, QVariant.Double))
            fields.append(QgsField(name_y, QVariant.Double))
        (sink, dest_id) = self.parameterAsSink(parameters, self.PrmOutputLayer,
                                               context, fields,
                                               QgsWkbTypes.MultiLineString,
                                               src_crs)

        if src_crs != epsg4326:
            geom_to_4326 = QgsCoordinateTransform(src_crs, epsg4326,
                                                  QgsProject.instance())
            to_sink_crs = QgsCoordinateTransform(epsg4326, src_crs,
                                                 QgsProject.instance())

        feature_count = source.featureCount()
        total = 100.0 / feature_count if feature_count else 0

        iterator = source.getFeatures()
        num_bad = 0
        for cnt, feature in enumerate(iterator):
            if feedback.isCanceled():
                break
            try:
                line_strings = []
                pt = feature.geometry().asPoint()
                pt_orig = QgsPoint(pt)
                # make sure the coordinates are in EPSG:4326
                if src_crs != epsg4326:
                    pt = geom_to_4326.transform(pt.x(), pt.y())
                lat = pt.y()
                lon = pt.x()
                if inner_col:
                    inner_radius = float(feature[inner_col]) * measure_factor
                else:
                    inner_radius = def_inner_radius
                if outer_col:
                    outer_radius = float(feature[outer_col]) * measure_factor
                else:
                    outer_radius = def_outer_radius
                if lines_col:
                    num_lines = int(feature[lines_col])
                else:
                    num_lines = def_lines
                if num_lines <= 0:
                    num_bad += 1
                    continue
                angle = 0
                angle_step = 360.0 / num_lines
                while angle < 360:
                    if inner_radius == 0:
                        pt_start = pt_orig
                    else:
                        g = geod.Direct(lat, lon, angle, inner_radius,
                                        Geodesic.LATITUDE | Geodesic.LONGITUDE)
                        pt_start = QgsPoint(g['lon2'], g['lat2'])
                        if src_crs != epsg4326:
                            pt_start = to_sink_crs.transform(pt_start)
                    g = geod.Direct(lat, lon, angle, outer_radius,
                                    Geodesic.LATITUDE | Geodesic.LONGITUDE)
                    pt_end = QgsPoint(g['lon2'], g['lat2'])
                    if src_crs != epsg4326:
                        pt_end = to_sink_crs.transform(pt_end)

                    line_str = QgsLineString([pt_start, pt_end])
                    line_strings.append(line_str)
                    angle += angle_step

                f = QgsFeature()
                if len(line_strings) == 1:
                    f.setGeometry(QgsGeometry(line_strings[0]))
                else:
                    g = QgsMultiLineString()
                    for line_str in line_strings:
                        g.addGeometry(line_str)
                    f.setGeometry(QgsGeometry(g))
                attr = feature.attributes()
                if export_geom:
                    attr.append(pt_orig.x())
                    attr.append(pt_orig.y())
                f.setAttributes(attr)
                sink.addFeature(f)
            except Exception:
                s = traceback.format_exc()
                feedback.pushInfo(s)
                num_bad += 1

            feedback.setProgress(int(cnt * total))

        if num_bad > 0:
            feedback.pushInfo(
                tr("{} out of {} features had invalid parameters and were ignored."
                   .format(num_bad, feature_count)))

        return {self.PrmOutputLayer: dest_id}
    def createGeom(self, coords):

        crsDest = self.__layer.crs()

        rc = ReprojectCoordinates(self.crsId, crsDest.srsid(), self.__hasZ, self.__hasM)
        if self.crsId != crsDest.srsid():
            coordsPoint = list(rc.reproject(coords, True))
        else:
            coordsPoint = list(rc.copyCoordstoPoints(coords))

        # Point and multipoint Geometry
        # Always 1 part, 0 element of matrix
        if self.__layergeometryType == QgsWkbTypes.PointGeometry:
            if self.__isMultiType:
                multipoint = QgsMultiPoint()
                for coords_item in coordsPoint[0][1]:
                    multipoint.addGeometry(coords_item)

                geom = QgsGeometry(multipoint)
                self.createFeature(geom)
            else:
                geom = QgsGeometry(coordsPoint[0][1][0])
                self.createFeature(geom)

        elif self.__layergeometryType == QgsWkbTypes.LineGeometry:
            if self.__isMultiType:
                multiline = QgsGeometry(QgsMultiLineString())
                for j in range(len(coordsPoint)):
                    line = QgsLineString(coordsPoint[j][1])
                    multiline.addPart(line)
                self.createFeature(multiline)
            else:
                line = QgsGeometry(QgsLineString(coordsPoint[0][1]))
                self.createFeature(line)

        elif self.__layergeometryType == QgsWkbTypes.PolygonGeometry:
            if self.__isMultiType:
                multipoly = QgsGeometry(QgsMultiPolygon())

                for i in range(len(coordsPoint)):
                    if int(coordsPoint[i][0]) > 0:
                        mycurve = QgsLineString(coordsPoint[i][1])
                        poly = QgsPolygon()
                        poly.setExteriorRing(mycurve)

                        polyGeometry = QgsGeometry(QgsPolygon(poly))
                        for j in range(len(coordsPoint)):
                            if int(coordsPoint[j][0]) < 0:
                                containsAllPoints = True
                                for k in range(len(coordsPoint[j][1])):
                                    containsAllPoints = True
                                    curPoint = coordsPoint[j][1][k].clone()
                                    containsAllPoints = containsAllPoints \
                                                    and polyGeometry.contains(QgsPointXY(curPoint.x(), curPoint.y()))
                                if containsAllPoints:
                                    mycurve = QgsLineString(coordsPoint[j][1])
                                    poly.addInteriorRing(mycurve)

                        multipoly.addPart(poly)
                self.createFeature(multipoly)
            else:
                extRing = 0
                for i in range(len(coordsPoint)):
                    if int(coordsPoint[i][0]) > 0:
                       extRing = i

                mycurve = QgsLineString(coordsPoint[extRing][1])
                poly = QgsPolygon()
                poly.setExteriorRing(mycurve)

                polyGeometry = QgsGeometry(QgsPolygon(poly))

                for i in range(len(coordsPoint)):
                    if int(coordsPoint[i][0]) < 0:
                        containsAllPoints = True
                        for j in range(len(coordsPoint[i][1])):
                            containsAllPoints = True
                            curPoint = coordsPoint[i][1][j].clone()
                            containsAllPoints = containsAllPoints \
                                                and polyGeometry.contains(QgsPointXY(curPoint.x(), curPoint.y()))
                        if containsAllPoints:
                            mycurve = QgsLineString(coordsPoint[i][1])
                            poly.addInteriorRing(mycurve)
                        else:
                            QMessageBox.question(self.iface.mainWindow(),
                                                 self.translate_str("Ring not in exterior contour"),
                                                 self.translate_str("The new geometry of the feature"
                                                                    " isn't valid. Do you want to use it anyway?"),
                                                 QMessageBox.Yes, QMessageBox.No)

                self.createFeature(QgsGeometry(poly))