// Increase minimal distance between vertices void MoleculeLayoutGraph::_refineCoordinates (const BiconnectedDecomposer &bc_decomposer, const ObjArray<MoleculeLayoutGraph> &bc_components, const Array<int> &bc_tree) { RefinementState beg_state(*this); RefinementState best_state(*this); RefinementState new_state(*this); QS_DEF(Array<int>, branch); int v1, v2; int v1c, v2c; int i, j, n; v1c = v1 = vertexBegin(); v2c = v2 = vertexNext(v1); // Calculate initial energy beg_state.copyFromGraph(); beg_state.calcEnergy(); beg_state.calcDistance(v1, v2); best_state.copy(beg_state); new_state.copy(beg_state); // Look through all vertex pairs which are closer than 0.6 bool improved = true; QS_DEF(RedBlackSet<int>, edges); QS_DEF(Array<int>, components1); QS_DEF(Array<int>, components2); EnumContext context; context.edges = &edges; context.graph = this; context.maxIterationNumber = max_iterations; int max_improvements = max_iterations * max_iterations; int n_improvements = 0; while (improved) { if (max_improvements > 0 && n_improvements > max_improvements) break; n_improvements++; improved = false; edges.clear(); int n_edges = 0; int n_enumerations = 0; bool to_break = false; for (v1 = vertexBegin(); v1 < vertexEnd() && !to_break; v1 = vertexNext(v1)) for (v2 = vertexNext(v1); v2 < vertexEnd(); v2 = vertexNext(v2)) { new_state.calcDistance(v1, v2); if (new_state.dist > 0.36f) continue; // Check if they are from the same component bool next_pair = false; bc_decomposer.getVertexComponents(v1, components1); bc_decomposer.getVertexComponents(v2, components2); for (i = 0; i < components1.size() && !next_pair; i++) for (j = 0; j < components2.size(); j++) { int comp1 = components1[i]; int comp2 = components2[j]; if (comp1 == comp2 && !bc_components[comp1].isSingleEdge() && !bc_components[comp2].isSingleEdge()) { next_pair = true; break; } } if (next_pair) continue; // check iterations limit if (max_iterations > 0 && n_enumerations > max_iterations) { to_break = true; break; } n_enumerations++; // Find acyclic edges on the all paths between v1 and v2 PathEnumerator path_enum(*this, v1, v2); path_enum.cb_check_edge = _edge_check; path_enum.cb_handle_path = _path_handle; path_enum.context = &context; context.iterationNumber = 0; try { path_enum.process(); } catch (Error) { // iterations limit reached } if (edges.size() == n_edges) continue; n_edges = edges.size(); if (beg_state.dist - 0.00001 > new_state.dist) { beg_state.dist = new_state.dist; v1c = v1; v2c = v2; } } if (edges.size() == 0) { //beg_state.applyToGraph(); break; } // Flipping // Look through found edges for (i = edges.begin(); i < edges.end(); i = edges.next(i)) { if (max_improvements > 0 && n_improvements > max_improvements) break; n_improvements++; // Try to flip branch const Edge &edge = getEdge(edges.key(i)); if (_molecule != 0 && _molecule->cis_trans.getParity(_molecule_edge_mapping[_layout_edges[edges.key(i)].ext_idx]) != 0) continue; if (getVertex(edge.beg).degree() == 1 || getVertex(edge.end).degree() == 1) continue; Filter filter; _makeBranches(branch, edges.key(i), filter); new_state.flipBranch(filter, beg_state, edge.beg, edge.end); new_state.calcEnergy(); if (new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } } if (improved) { beg_state.copy(best_state); continue; } // Rotations // Look through found edges for (i = edges.begin(); i < edges.end(); i = edges.next(i)) { if (max_improvements > 0 && n_improvements > max_improvements) break; n_improvements += 3; // Try to rotate one branch by 10 degrees in both directions around both vertices const Edge &edge = getEdge(edges.key(i)); if (_molecule != 0 && _molecule->cis_trans.getParity(_molecule_edge_mapping[_layout_edges[edges.key(i)].ext_idx]) != 0) continue; Filter filter; _makeBranches(branch, edges.key(i), filter); bool around_beg = _allowRotateAroundVertex(edge.beg); bool around_end = _allowRotateAroundVertex(edge.end); if (around_beg) { new_state.rotateBranch(filter, beg_state, edge.beg, 10); new_state.calcDistance(v1c, v2c); new_state.calcEnergy(); if (new_state.dist > beg_state.dist && new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } new_state.rotateBranch(filter, beg_state, edge.beg, -10); new_state.calcDistance(v1c, v2c); new_state.calcEnergy(); if (new_state.dist > beg_state.dist && new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } } if (around_end) { new_state.rotateBranch(filter, beg_state, edge.end, 10); new_state.calcDistance(v1c, v2c); new_state.calcEnergy(); if (new_state.dist > beg_state.dist && new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } new_state.rotateBranch(filter, beg_state, edge.end, -10); new_state.calcDistance(v1c, v2c); new_state.calcEnergy(); if (new_state.dist > beg_state.dist && new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } } // Stretching // Try to stretch each edge with 1.6 ratio if ((n = filter.count(*this)) != 1 && n != vertexCount() - 1) { new_state.stretchBranch(filter, beg_state, edge.beg, edge.end, 6); new_state.calcDistance(v1c, v2c); new_state.calcEnergy(); if (new_state.dist > beg_state.dist && new_state.energy + 20 < beg_state.energy && new_state.energy < best_state.energy - 0.00001) { improved = true; best_state.copy(new_state); } } } if (improved) beg_state.copy(best_state); } if (_n_fixed == 0) { int center = -1; long max_code = 0; for (i = vertexBegin(); i < vertexEnd(); i = vertexNext(i)) if (getLayoutVertex(i).morgan_code > max_code) { center = i; max_code = getLayoutVertex(i).morgan_code; } beg_state.calcHeight(); for (float angle = -90.f; angle < 90.f + EPSILON; angle += 30.f) { new_state.rotateLayout(beg_state, center, angle); new_state.calcHeight(); if (new_state.height < beg_state.height - EPSILON) beg_state.copy(new_state); } } beg_state.applyToGraph(); _excludeDandlingIntersections(); }
void MoleculeLayoutGraph::_findFixedComponents (BiconnectedDecomposer &bc_decom, Array<int> &fixed_components, ObjArray<MoleculeLayoutGraph> & bc_components ) { // 1. Find biconnected components forming connected subgraph from fixed vertices if (_n_fixed == 0) return; int n_comp = bc_decom.componentsCount(); QS_DEF(Array<int>, fixed_count); fixed_count.clear_resize(n_comp); fixed_count.zerofill(); // calculate number of fixed vertices in each component for (int i = 0; i < n_comp; i++) { Filter filter; bc_decom.getComponent(i, filter); for (int j = vertexBegin(); j < vertexEnd(); j = vertexNext(j)) if (filter.valid(j) && _fixed_vertices[j]) fixed_count[i]++; } // keep only with fixed number greater than a half for (int i = 0; i < n_comp; i++) { Filter filter; bc_decom.getComponent(i, filter); if (fixed_count[i] > filter.count(*this) / 2) fixed_components[i] = 1; } _fixed_vertices.zerofill(); // update fixed vertices for (int i = 0; i < n_comp; i++) { if (!fixed_components[i]) continue; MoleculeLayoutGraph &component = bc_components[i]; for (int j = component.vertexBegin(); j < component.vertexEnd(); j = component.vertexNext(j)) _fixed_vertices[component.getVertexExtIdx(j)] = 1; } Filter fixed_filter(_fixed_vertices.ptr(), Filter::EQ, 1); Graph fixed_graph; QS_DEF(Array<int>, fixed_mapping); fixed_graph.makeSubgraph(*this, fixed_filter, &fixed_mapping, 0); if (Graph::isConnected(fixed_graph)) _n_fixed = fixed_filter.count(*this); else { // fixed subgraph is not connected - choose its greatest component int n = fixed_graph.countComponents(); const Array<int> &decomposition = fixed_graph.getDecomposition(); fixed_count.clear_resize(n); fixed_count.zerofill(); for (int i = fixed_graph.vertexBegin(); i < fixed_graph.vertexEnd(); i = fixed_graph.vertexNext(i)) fixed_count[decomposition[i]]++; int j = 0; for (int i = 1; i < n; i++) if (fixed_count[i] > fixed_count[j]) j = i; Filter max_filter(decomposition.ptr(), Filter::EQ, j); // update fixed vertices _fixed_vertices.zerofill(); _n_fixed = 0; for (int i = fixed_graph.vertexBegin(); i < fixed_graph.vertexEnd(); i = fixed_graph.vertexNext(i)) { if (max_filter.valid(i)) { _fixed_vertices[fixed_mapping[i]] = 1; _n_fixed++; } } for (int i = 0; i < n_comp; i++) { if (!fixed_components[i]) continue; MoleculeLayoutGraph &component = bc_components[i]; if (!max_filter.valid(component.getVertexExtIdx(component.vertexBegin()))) fixed_components[i] = 0; } } }