Ejemplo n.º 1
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