// Extract component border void MoleculeLayoutGraph::_getBorder (Cycle &border) const { QS_DEF(Array<int>, vertices); QS_DEF(Array<int>, edges); int i, n = 0; for (i = edgeBegin(); i < edgeEnd(); i = edgeNext(i)) if (_layout_edges[i].type == ELEMENT_BOUNDARY) n++; if (n == 0) return; vertices.clear(); edges.clear(); for (i = edgeBegin(); i < edgeEnd(); i = edgeNext(i)) if (_layout_edges[i].type == ELEMENT_BOUNDARY) break; Edge edge = getEdge(i); vertices.push(edge.beg); edges.push(i); while (edge.end != vertices[0]) { const Vertex &vert = getVertex(edge.end); bool found = false; for (int i = vert.neiBegin(); !found && i < vert.neiEnd(); i = vert.neiNext(i)) { int nei_v = vert.neiVertex(i); int nei_e = vert.neiEdge(i); if (getEdgeType(nei_e) == ELEMENT_BOUNDARY && nei_v != edge.beg) { edge.beg = edge.end; edge.end = nei_v; vertices.push(edge.beg); edges.push(nei_e); found = true; } } if (!found || vertices.size() > n) throw Error("corrupted border"); } border.copy(vertices, edges); border.canonize(); }
void MoleculeLayoutGraphSmart::_getSurroundCycle(Cycle &cycle, Vec2f p) const { QS_DEF(Array<int>, vertices); QS_DEF(Array<int>, edges); QS_DEF(Array<Vec2f>, pos); int i, n = 0; float eps = 1e-5; /* for (i = edgeBegin(); i < edgeEnd(); i = edgeNext(i)) if (_layout_edges[i].type == ELEMENT_BOUNDARY) n++; if (n == 0) return;*/ vertices.clear(); edges.clear(); srand(19857615); float sn = 0; float cs = 0; while (sn == 0 && cs == 0) { sn = 2.0*rand() / RAND_MAX - 1; cs = 2.0*rand() / RAND_MAX - 1; } float len = sqrt(sn*sn + cs*cs); sn /= len; cs /= len; pos.resize(vertexEnd()); for (int i = vertexBegin(); i != vertexEnd(); i = vertexNext(i)) if (getVertexType(i) != ELEMENT_NOT_DRAWN) { pos[i].copy(getPos(i) - p); } for (int i = vertexBegin(); i != vertexEnd(); i = vertexNext(i)) if (getVertexType(i) != ELEMENT_NOT_DRAWN) { pos[i].rotate(sn, cs); } int first_edge = -1; float first_edge_x = 1e20; for (int i = edgeBegin(); i != edgeEnd(); i = edgeNext(i)) if (_layout_edges[i].type != ELEMENT_NOT_DRAWN) { Edge e = getEdge(i); if (pos[e.beg].y * pos[e.end].y <= 0) { float mid_x = (pos[e.beg].x * pos[e.end].y - pos[e.end].x * pos[e.beg].y) / (pos[e.end].y - pos[e.beg].y); if (abs(mid_x) < eps) return; if (mid_x > 0 && (first_edge == -1 || mid_x < first_edge_x)) { first_edge = i; first_edge_x = mid_x; } } } int firts_vertex = -1; if (first_edge != -1) if (pos[getEdge(first_edge).beg].y < pos[getEdge(first_edge).end].y) firts_vertex = getEdge(first_edge).beg; else firts_vertex = getEdge(first_edge).end; else { // in this case no edges are intersecs (OX) ray // and so p is outside point // Then we are looking for border // and we can take the lowest vertex as the start vertex for searching of surround cycle float first_vertex_y; for (int i = vertexBegin(); i != vertexEnd(); i = vertexNext(i)) if (_layout_vertices[i].type != ELEMENT_NOT_DRAWN) if (firts_vertex == -1 || pos[i].y < first_vertex_y) { first_vertex_y = pos[i].y; firts_vertex = i; } // and now lets find first edge... int second_vertex = -1; for (int i = getVertex(firts_vertex).neiBegin(); i != getVertex(firts_vertex).neiEnd(); i = getVertex(firts_vertex).neiNext(i)) { int new_vertex = getVertex(firts_vertex).neiVertex(i); if (isVertexDrawn(new_vertex) && (second_vertex == -1 || Vec2f::cross(pos[second_vertex] - pos[firts_vertex], pos[new_vertex] - pos[firts_vertex]) > 0)) { second_vertex = new_vertex; first_edge = getVertex(firts_vertex).neiEdge(i); } } } vertices.push(firts_vertex); edges.push(first_edge); while (true) { int current_vertex = vertices.top(); int current_edge = edges.top(); int next_vertex = getEdge(current_edge).findOtherEnd(current_vertex); int next_edge = -1; int next_vertex2 = current_vertex; for (int i = getVertex(next_vertex).neiBegin(); i != getVertex(next_vertex).neiEnd(); i = getVertex(next_vertex).neiNext(i)) { int try_vertex = getVertex(next_vertex).neiVertex(i); if (isVertexDrawn(try_vertex) && try_vertex != current_vertex) { bool need_to_update = false; if (next_vertex2 == current_vertex) { need_to_update = true; } else { if (Vec2f::cross(pos[next_vertex2] - pos[next_vertex], pos[current_vertex] - pos[next_vertex]) >= 0) { need_to_update = Vec2f::cross(pos[next_vertex2] - pos[next_vertex], pos[try_vertex] - pos[next_vertex]) >= 0 && Vec2f::cross(pos[try_vertex] - pos[next_vertex], pos[current_vertex] - pos[next_vertex]) >= 0; } else { need_to_update = Vec2f::cross(pos[next_vertex2] - pos[next_vertex], pos[try_vertex] - pos[next_vertex]) >= 0 || Vec2f::cross(pos[try_vertex] - pos[next_vertex], pos[current_vertex] - pos[next_vertex]) >= 0; } } if (need_to_update) { next_vertex2 = try_vertex; next_edge = getVertex(next_vertex).neiEdge(i); } } } if (next_vertex == vertices[0] && next_edge == edges[0]) break; else { vertices.push(next_vertex); edges.push(next_edge); if (vertices.size() > vertexCount()) { vertices.clear_resize(0); edges.clear_resize(0); break; } } } cycle.copy(vertices, edges); //cycle.canonize(); }