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