def getIntersection(self, p1, p2): """ Get intersection on segment :param p1: QgsPointV2 :param p2: QgsPointV2 :param inter: QgsPointV2 reference :return: bool """ q1 = self.idxFrom.point() q2 = self.idxTo.point() v = QgsVector(p2.x() - p1.x(), p2.y() - p1.y()) w = QgsVector(q2.x() - q1.x(), q2.y() - q1.y()) vl = v.length() wl = w.length() if self.isclose(vl, 0.) or self.isclose(wl, 0.): return None v = v / vl w = w / wl d = v.y() * w.x() - v.x() * w.y() if d == 0: return None dx = q1.x() - p1.x() dy = q1.y() - p1.y() k = (dy * w.x() - dx * w.y()) / d inter = QgsPointV2(p1.x() + v.x() * k, p1.y() + v.y() * k) lambdav = QgsVector(inter.x() - p1.x(), inter.y() - p1.y()) * v if lambdav < 0. + 1E-8 or lambdav > vl - 1E-8: return None lambdaw = QgsVector(inter.x() - q1.x(), inter.y() - q1.y()) * w if lambdaw < 0. + 1E-8 or lambdaw >= wl - 1E-8: return None return inter
def compute_compatibilty_matrix(self, feedback): """ Compatibility is stored in a matrix (rows = edges, columns = edges). Every coordinate in the matrix tells whether the two edges (r,c)/(c,r) are compatible, or not. The diagonal is always zero, and the other fields are filled with either -1 (not compatible) or 1 (compatible). The matrix is symmetric. """ feedback.setProgressText("Compute compatibility matrix") edges_as_geom = [] edges_as_vect = [] for e_idx, edge in enumerate(self.edges): if feedback.isCanceled(): return geom = edge.geometry() edges_as_geom.append(geom) edges_as_vect.append( QgsVector( geom.vertexAt(1).x() - geom.vertexAt(0).x(), geom.vertexAt(1).y() - geom.vertexAt(0).y())) self.edge_lengths.append(edges_as_vect[e_idx].length()) progress = 0 for i in range(self.E - 1): if feedback.isCanceled(): return feedback.setProgress(100.0 * (i + 1) / (self.E - 1)) for j in range(i + 1, self.E): if feedback.isCanceled(): return # Parameters lavg = (self.edge_lengths[i] + self.edge_lengths[j]) / 2.0 dot = edges_as_vect[i].normalized( ) * edges_as_vect[j].normalized() # Angle compatibility angle_comp = abs(dot) # Scale compatibility scale_comp = 2.0 / ( lavg / min(self.edge_lengths[i], self.edge_lengths[j]) + max(self.edge_lengths[i], self.edge_lengths[j]) / lavg) # Position compatibility i0 = edges_as_geom[i].vertexAt(0) i1 = edges_as_geom[i].vertexAt(1) j0 = edges_as_geom[j].vertexAt(0) j1 = edges_as_geom[j].vertexAt(1) e1_mid = QgsPoint((i0.x() + i1.x()) / 2.0, (i0.y() + i1.y()) / 2.0) e2_mid = QgsPoint((j0.x() + j1.x()) / 2.0, (j0.y() + j1.y()) / 2.0) diff = QgsVector(e2_mid.x() - e1_mid.x(), e2_mid.y() - e1_mid.y()) pos_comp = lavg / (lavg + diff.length()) # Visibility compatibility mid_E1 = edges_as_geom[i].centroid() mid_E2 = edges_as_geom[j].centroid() #dist = mid_E1.distance(mid_E2) I0 = MiscUtils.project_point_on_line(j0, edges_as_geom[i]) I1 = MiscUtils.project_point_on_line(j1, edges_as_geom[i]) mid_I = QgsGeometry.fromPolyline([I0, I1]).centroid() dist_I = I0.distance(I1) if dist_I == 0.0: visibility1 = 0.0 else: visibility1 = max( 0, 1 - ((2 * mid_E1.distance(mid_I)) / dist_I)) J0 = MiscUtils.project_point_on_line(i0, edges_as_geom[j]) J1 = MiscUtils.project_point_on_line(i1, edges_as_geom[j]) mid_J = QgsGeometry.fromPolyline([J0, J1]).centroid() dist_J = J0.distance(J1) if dist_J == 0.0: visibility2 = 0.0 else: visibility2 = max( 0, 1 - ((2 * mid_E2.distance(mid_J)) / dist_J)) visibility_comp = min(visibility1, visibility2) # Compatibility score comp_score = angle_comp * scale_comp * pos_comp * visibility_comp # Fill values into the matrix (1 = yes, -1 = no) and use matrix symmetry (i/j = j/i) if comp_score >= self.compatibility: self.compatibility_matrix[i, j] = 1 self.compatibility_matrix[j, i] = 1 else: self.compatibility_matrix[i, j] = -1 self.compatibility_matrix[j, i] = -1 # Store direction distStart1 = j0.distance(i0) distStart2 = j1.distance(i0) if distStart1 > distStart2: self.direction_matrix[i, j] = -1 self.direction_matrix[j, i] = -1 else: self.direction_matrix[i, j] = 1 self.direction_matrix[j, i] = 1