Example #1
0
def snapToPrecision(geom, precision):
    snapped = QgsGeometry(geom)
    if precision == 0.0:
        return snapped

    i = 0
    p = snapped.vertexAt(i)
    while p.x() != 0.0 and p.y() != 0.0:
        x = round(p.x() / precision, 0) * precision
        y = round(p.y() / precision, 0) * precision
        snapped.moveVertex(x, y, i)
        i = i + 1
        p = snapped.vertexAt(i)
    return snapped
Example #2
0
def snapToPrecision(geom, precision):
    snapped = QgsGeometry(geom)
    if precision == 0.0:
        return snapped

    i = 0
    p = snapped.vertexAt(i)
    while p.x() != 0.0 and p.y() != 0.0:
        x = round(p.x() / precision, 0) * precision
        y = round(p.y() / precision, 0) * precision
        snapped.moveVertex(x, y, i)
        i = i + 1
        p = snapped.vertexAt(i)
    return snapped
Example #3
0
    def processFeatures(self, reaches, reach_layer, wastewater_node_layer, distance_threshold):
        ids = list()
        to_ids = list()
        # Gather ids of connected networkelements
        # to_ids are also gathered separately, because they can be either
        # reaches or nodes
        for reach in reaches:
            if reach['rp_from_fk_wastewater_networkelement']:
                ids.append(reach['rp_from_fk_wastewater_networkelement'])

            if reach['rp_to_fk_wastewater_networkelement']:
                ids.append(reach['rp_to_fk_wastewater_networkelement'])
                to_ids.append(reach['rp_to_fk_wastewater_networkelement'])

        # Get all nodes on which to snap
        quoted_ids = [QgsExpression.quotedValue(objid) for objid in ids]
        node_request = QgsFeatureRequest()
        filter_expression = '"obj_id" IN ({ids})'.format(
            ids=','.join(quoted_ids))
        node_request.setFilterExpression(filter_expression)
        node_request.setSubsetOfAttributes([])

        nodes = dict()
        for node in wastewater_node_layer.getFeatures(node_request):
            nodes[node['obj_id']] = node

        # Get all reaches on which to snap
        quoted_to_ids = [QgsExpression.quotedValue(objid) for objid in to_ids]
        reach_request = QgsFeatureRequest()
        filter_expression = '"obj_id" IN ({ids})'.format(
            ids=','.join(quoted_to_ids))
        reach_request.setFilterExpression(filter_expression)
        reach_request.setSubsetOfAttributes([])

        target_reaches = dict()
        for target_reach in reach_layer.getFeatures(reach_request):
            target_reaches[target_reach['obj_id']] = target_reach

        for reach in reaches:
            reach_geometry = QgsGeometry(reach.geometry())
            from_id = reach['rp_from_fk_wastewater_networkelement']
            if from_id in list(nodes.keys()):
                if distance_threshold == 0 or reach_geometry.sqrDistToVertexAt(nodes[from_id].geometry().asPoint(), 0) < distance_threshold:
                    reach_geometry.moveVertex(
                        nodes[from_id].geometry().constGet(), 0)

            to_id = reach['rp_to_fk_wastewater_networkelement']
            if to_id in list(nodes.keys()):
                last_vertex = reach_geometry.constGet().nCoordinates() - 1
                if distance_threshold == 0 or reach_geometry.sqrDistToVertexAt(nodes[to_id].geometry().asPoint(), last_vertex) < distance_threshold:
                    reach_geometry.moveVertex(
                        nodes[to_id].geometry().constGet(), last_vertex)

            if to_id in list(target_reaches.keys()):
                last_vertex = reach_geometry.constGet().nCoordinates() - 1
                target_reach = target_reaches[to_id]
                distance, point, min_distance_point, after_vertex = target_reach.geometry(
                ).closestSegmentWithContext(QgsPointXY(reach_geometry.vertexAt(last_vertex)))
                if distance_threshold == 0 or distance < distance_threshold:
                    reach_geometry.moveVertex(
                        point.x(), point.y(), last_vertex)

            reach.setGeometry(reach_geometry)
            reach_layer.updateFeature(reach)
Example #4
0
    def addZtoPointFeatures(self,
                            inputPoints,
                            inputCrs,
                            fieldIdWithZVals=-1,
                            override=True):
        #pointsListZ=[] #list of QgsFeature()
        featuresWithZ = []
        try:

            #check if pointsLayer is emty
            #if inputPoints.featureCount!=0:
            for feat in inputPoints:
                #if geom.hasZ==False or geom.hasZ==True and override==True:
                # get Raster Values for each point feature
                featZ = QgsFeature(feat.fields())  #Copy of the Feature
                geom = feat.geometry()
                #create a copy of the geometry for temporary transform to the project.crs()
                wkb = feat.geometry().asWkb()
                #self.feedback.pushInfo("addZtoPointFeatures1 " + geom.asWkt())
                geom2CRS = QgsGeometry()
                geom2CRS.fromWkb(wkb)
                #transform geom to rasterLayer.crs() if crs a different
                if not inputCrs.authid() == self.rasterLayer.crs().authid():
                    trafo = QgsCoordinateTransform(inputCrs,
                                                   self.rasterLayer.crs(),
                                                   QgsProject.instance())
                    #transform clip Geom to SrcLayer.crs Reverse
                    geom2CRS.transform(trafo,
                                       QgsCoordinateTransform.ForwardTransform,
                                       False)

                pinPoint = None
                if geom.isMultipart():
                    pinPoint = geom.vertexAt(
                        0)  #nimm den ersten Punkt, wenn es ein MultiPoint ist
                    pin2Crs = geom2CRS.vertexAt(0)

                else:
                    pinPoint = geom.asPoint()
                    pin2Crs = geom2CRS.asPoint()

                rastVal = None
                if fieldIdWithZVals > -1:
                    rastVal = feat[fieldIdWithZVals]
                    if rastVal is None or str(rastVal) == 'NULL':
                        felder = feat.fields()
                        feld = felder.field(fieldIdWithZVals)
                        self.feedback.reportError('Error on Feature ' +
                                                  str(feat.id()))
                        self.feedback.reportError('Feature Attributes :' +
                                                  str(feat.attributes()))
                        raise QgsProcessingException('Z value on field   ' +
                                                     feld.name() +
                                                     ' is empty!')
                else:  #hole Z-Wert von DGM
                    rastVal = self.interpolator.linear(
                        pin2Crs)  #QgsPointXY(4459566.0, 5613959.0))
                #self.feedback.pushInfo("addZtoPointFeatures2 " + geom.asWkt() + " 2Crs: " + geom2CRS.asWkt())
                #self.feedback.pushInfo("rastVal " + str(pinPoint)+ " = in RasterCrs:"+ str(pin2Crs)+ " = "+ str(rastVal))
                #rastSample = rasterLayer.dataProvider().identify(pin2Crs, QgsRaster.IdentifyFormatValue).results()
                if not rastVal is None or str(
                        rastVal
                ) != 'NULL':  # ToDo der Leerwert muss noch beruecksichtigt werden
                    wkt = "PointZ(" + str(pinPoint.x()) + " " + str(
                        pinPoint.y()) + " " + str(rastVal) + ")"
                    #self.feedback.reportError(wkt)

                    #construct new Feature in source Crs
                    ptZ = QgsPoint(pinPoint.x(), pinPoint.y())
                    ptZ.addZValue(rastVal)
                    geomZ = QgsGeometry.fromWkt(wkt)
                    featZ.setGeometry(geomZ)
                    featZ.setAttributes(feat.attributes())
                    featuresWithZ.append(featZ)
                else:
                    self.feedback.reportError('Point Feature: ' + feat.id() +
                                              '  ' + wkt + ' ' +
                                              feat.attributes())
                    raise QgsProcessingException(
                        "No valid RasterValue for this position: " +
                        str(round(pinPoint.x(), 1)) + " " +
                        str(round(pinPoint.y(), 1)) + ' raster value: ' +
                        str(rastVal))
            #self.feedback.pushInfo("addZtoPointFeatures " + str(len(featuresWithZ))+ " Objekte")
        except Exception as err:
            msg = "Error: add Z to Point Features {0} \n {1}".format(
                err.args, repr(err))
            self.feedback.reportError(msg)
            featuresWithZ = []
            raise QgsProcessingException(msg)
            #print("Error addZtoPointFeatures")#,str(err.args) + ";" + str(repr(err)))
            #raise QgsProcessingException("Error addZtoPointFeatures " + str(err.args))# + ";" + str(repr(err)))
        return featuresWithZ
Example #5
0
    def simplify(self):
        """
        Reduce the number of vertices in a polygon layer.

        * Delete vertex if the angle with its adjacents is near of the straight
          angle for less than 'straight_thr' degrees in all its parents.

        * Delete vertex if the distance to the segment formed by its parents is
          less than 'cath_thr' meters.
        """
        if log.app_level <= logging.DEBUG:
            debshp = DebugWriter("debug_simplify.shp", self)
        killed = 0
        to_change = {}
        # Clean non corners
        (parents_per_vertex,
         geometries) = self.get_parents_per_vertex_and_geometries()
        pbar = self.get_progressbar(_("Simplify"), len(parents_per_vertex))
        for wkt, parents in parents_per_vertex.items():
            point = Point(wkt)
            # Test if this vertex is a 'corner' in any of its parent polygons
            for fid in parents:
                geom = geometries[fid]
                (angle, is_acute, is_corner,
                 cath) = point.get_corner_context(geom)
                debmsg = "angle=%.1f, is_acute=%s, is_corner=%s, cath=%.4f" % (
                    angle,
                    is_acute,
                    is_corner,
                    cath,
                )
                if is_corner:
                    break
            msg = "Keep"
            if not is_corner:
                killed += 1  # delete the vertex from all its parents.
                for fid in frozenset(parents):
                    g = QgsGeometry(geometries[fid])
                    (__, ndx, __, __, __) = g.closestVertex(point)
                    (ndxa, ndxb) = g.adjacentVertices(ndx)
                    v = g.vertexAt(ndx)
                    va = g.vertexAt(ndxa)
                    vb = g.vertexAt(ndxb)
                    invalid_ring = v == va or v == vb or va == vb
                    g.deleteVertex(ndx)
                    msg = "Refused"
                    if Geometry.is_valid(g) and not invalid_ring:
                        parents.remove(fid)
                        geometries[fid] = g
                        to_change[fid] = g
                        msg = "Deleted"
            if log.app_level <= logging.DEBUG:
                debshp.add_point(point, msg + " " + debmsg)
            if len(to_change) > BUFFER_SIZE:
                self.writer.changeGeometryValues(to_change)
                to_change = {}
            pbar.update()
        pbar.close()
        if len(to_change) > 0:
            self.writer.changeGeometryValues(to_change)
        if killed > 0:
            log.debug(_("Simplified %d vertices in the '%s' layer"), killed,
                      self.name())
            report.values["vertex_simplify_" + self.name()] = killed
Example #6
0
 def topology(self):
     """Add to nearest segments each vertex in a polygon layer."""
     threshold = self.dist_thr  # Distance threshold to create nodes
     dup_thr = self.dup_thr
     straight_thr = self.straight_thr
     tp = 0
     td = 0
     if log.app_level <= logging.DEBUG:
         debshp = DebugWriter("debug_topology.shp", self)
     geometries = {
         f.id(): QgsGeometry(f.geometry())
         for f in self.getFeatures()
     }
     index = self.get_index()
     to_change = {}
     nodes = set()
     pbar = self.get_progressbar(_("Topology"), len(geometries))
     for (gid, geom) in geometries.items():
         if geom.area() < config.min_area:
             continue
         for point in frozenset(Geometry.get_outer_vertices(geom)):
             if point not in nodes:
                 area_of_candidates = Point(point).boundingBox(threshold)
                 fids = index.intersects(area_of_candidates)
                 for fid in fids:
                     g = QgsGeometry(geometries[fid])
                     (p, ndx, ndxa, ndxb, dist_v) = g.closestVertex(point)
                     (dist_s, closest,
                      vertex) = g.closestSegmentWithContext(point)[:3]
                     va = Point(g.vertexAt(ndxa))
                     vb = Point(g.vertexAt(ndxb))
                     note = ""
                     if dist_v == 0:
                         dist_a = va.sqrDist(point)
                         dist_b = vb.sqrDist(point)
                         if dist_a < dup_thr**2:
                             g.deleteVertex(ndxa)
                             note = "dupe refused by isGeosValid"
                             if Geometry.is_valid(g):
                                 note = "Merge dup. %.10f %.5f,%.5f->%.5f,%.5f" % (
                                     dist_a,
                                     va.x(),
                                     va.y(),
                                     point.x(),
                                     point.y(),
                                 )
                                 nodes.add(p)
                                 nodes.add(va)
                                 td += 1
                         if dist_b < dup_thr**2:
                             g.deleteVertex(ndxb)
                             note = "dupe refused by isGeosValid"
                             if Geometry.is_valid(g):
                                 note = "Merge dup. %.10f %.5f,%.5f->%.5f,%.5f" % (
                                     dist_b,
                                     vb.x(),
                                     vb.y(),
                                     point.x(),
                                     point.y(),
                                 )
                                 nodes.add(p)
                                 nodes.add(vb)
                                 td += 1
                     elif dist_v < dup_thr**2:
                         g.moveVertex(point.x(), point.y(), ndx)
                         note = "dupe refused by isGeosValid"
                         if Geometry.is_valid(g):
                             note = "Merge dup. %.10f %.5f,%.5f->%.5f,%.5f" % (
                                 dist_v,
                                 p.x(),
                                 p.y(),
                                 point.x(),
                                 point.y(),
                             )
                             nodes.add(p)
                             td += 1
                     elif (dist_s < threshold**2 and closest != va
                           and closest != vb):
                         va = Point(g.vertexAt(vertex))
                         vb = Point(g.vertexAt(vertex - 1))
                         angle = abs(point.azimuth(va) - point.azimuth(vb))
                         note = "Topo refused by angle: %.2f" % angle
                         if abs(180 - angle) <= straight_thr:
                             note = "Topo refused by insertVertex"
                             if g.insertVertex(point.x(), point.y(),
                                               vertex):
                                 note = "Topo refused by isGeosValid"
                                 if Geometry.is_valid(g):
                                     note = "Add topo %.6f %.5f,%.5f" % (
                                         dist_s,
                                         point.x(),
                                         point.y(),
                                     )
                                     tp += 1
                     if note.startswith("Merge") or note.startswith("Add"):
                         to_change[fid] = g
                         geometries[fid] = g
                     if note and log.app_level <= logging.DEBUG:
                         debshp.add_point(point, note)
         if len(to_change) > BUFFER_SIZE:
             self.writer.changeGeometryValues(to_change)
             to_change = {}
         pbar.update()
     pbar.close()
     if len(to_change) > 0:
         self.writer.changeGeometryValues(to_change)
     if td:
         log.debug(_("Merged %d close vertices in the '%s' layer"), td,
                   self.name())
         report.values["vertex_close_" + self.name()] = td
     if tp:
         log.debug(_("Created %d topological points in the '%s' layer"), tp,
                   self.name())
         report.values["vertex_topo_" + self.name()] = tp
Example #7
0
    def in_mask(self, feature, srid=None):
        if feature is None:  # expression overview
            return False

        if self.layer is None:
            return False

        try:
            # layer is not None but destroyed ?
            self.layer.id()
        except:
            self.reset_mask_layer()
            return False

        # mask layer empty due to unloaded memlayersaver plugin > no filtering
        if self.layer.featureCount() == 0:
            return True

        mask_geom, bbox = self.mask_geometry()
        geom = QgsGeometry(feature.geometry())
        if not geom.isGeosValid():
            geom = geom.buffer(0.0, 1)

        if geom is None:
            return False

        if srid is not None and self.layer.crs().postgisSrid() != srid:
            src_crs = QgsCoordinateReferenceSystem(srid)
            dest_crs = self.layer.crs()
            xform = QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance())
            try:
                geom.transform(xform)
            except:
                # transformation error. Check layer projection.
                pass

        if geom.type() == QgsWkbTypes.PolygonGeometry:
            if self.parameters.polygon_mask_method == 2 and not self.has_point_on_surface:
                self.parameters.polygon_mask_method = 1

            if self.parameters.polygon_mask_method == 0:
                # this method can only work when no geometry simplification is involved
                return (mask_geom.overlaps(geom) or mask_geom.contains(geom))
            elif self.parameters.polygon_mask_method == 1:
                # the fastest method, but with possible inaccuracies
                pt = geom.vertexAt(0)
                return bbox.contains(QgsPointXY(pt)) and mask_geom.contains(geom.centroid())
            elif self.parameters.polygon_mask_method == 2:
                # will always work
                pt = geom.vertexAt(0)
                return bbox.contains(QgsPointXY(pt)) and mask_geom.contains(geom.pointOnSurface())
            else:
                return False
        elif geom.type() == QgsWkbTypes.LineGeometry:
            if self.parameters.line_mask_method == 0:
                return mask_geom.intersects(geom)
            elif self.parameters.line_mask_method == 1:
                return mask_geom.contains(geom)
            else:
                return False
        elif geom.type() == QgsWkbTypes.PointGeometry:
            return mask_geom.intersects(geom)
        else:
            return False
Example #8
0
    def in_mask(self, feature, srid=None):
        if feature is None:  # expression overview
            return False

        if self.layer is None:
            return False

        try:
            # layer is not None but destroyed ?
            self.layer.id()
        except:
            self.reset_mask_layer()
            return False

        # mask layer empty due to unloaded memlayersaver plugin > no filtering
        if self.layer.featureCount() == 0:
            return True

        mask_geom, bbox = self.mask_geometry()
        geom = QgsGeometry(feature.geometry())
        if not geom.isGeosValid():
            geom = geom.buffer(0.0, 1)

        if geom is None:
            return False

        if srid is not None and self.layer.crs().postgisSrid() != srid:
            src_crs = QgsCoordinateReferenceSystem(srid)
            dest_crs = self.layer.crs()
            xform = QgsCoordinateTransform(src_crs, dest_crs,
                                           QgsProject.instance())
            try:
                geom.transform(xform)

            except Exception as e:
                for m in e.args:
                    QgsMessageLog.logMessage("in_mask - {}".format(m),
                                             "Extensions")
                    # transformation error. Check layer projection.
                    pass

        if geom.type() == QgsWkbTypes.PolygonGeometry:
            if (self.parameters.polygon_mask_method == 2
                    and not self.has_point_on_surface):
                self.parameters.polygon_mask_method = 1

            if self.parameters.polygon_mask_method == 0:
                # this method can only work when no geometry simplification is involved
                return mask_geom.overlaps(geom) or mask_geom.contains(geom)
            elif self.parameters.polygon_mask_method == 1:
                # the fastest method, but with possible inaccuracies
                pt = geom.vertexAt(0)
                return bbox.contains(QgsPointXY(pt)) and mask_geom.contains(
                    geom.centroid())
            elif self.parameters.polygon_mask_method == 2:
                # will always work
                pt = geom.vertexAt(0)
                return bbox.contains(QgsPointXY(pt)) and mask_geom.contains(
                    geom.pointOnSurface())
            else:
                return False
        elif geom.type() == QgsWkbTypes.LineGeometry:
            if self.parameters.line_mask_method == 0:
                return mask_geom.intersects(geom)
            elif self.parameters.line_mask_method == 1:
                return mask_geom.contains(geom)
            else:
                return False
        elif geom.type() == QgsWkbTypes.PointGeometry:
            return mask_geom.intersects(geom)
        else:
            return False