From 36a43a5d8ce3a5644fa6a9fce0a75c97dd175db8 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 30 Dec 2024 12:01:05 +0100 Subject: [PATCH 01/27] step 1 --- core/indigo-core/common/math/algebra.h | 28 ++- core/indigo-core/common/math/vec2f.cpp | 5 + core/indigo-core/molecule/base_molecule.h | 7 + .../molecule/src/base_molecule.cpp | 84 ++++++++ .../reaction/reaction_multistep_detector.h | 37 +++- .../src/reaction_multistep_detector.cpp | 197 ++++++++++++++++++ 6 files changed, 355 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 9ec0be286b..3defa4dff4 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -23,14 +23,15 @@ #include #include #include +#include #include "base_c/defs.h" #include "base_cpp/exception.h" #define SQR(x) ((x) * (x)) -#define DEG2RAD(x) ((x)*M_PI / 180) -#define RAD2DEG(x) ((x)*180 / M_PI) +#define DEG2RAD(x) ((x) * M_PI / 180) +#define RAD2DEG(x) ((x) * 180 / M_PI) #define HYPOT(a, b) (sqrt((a) * (a) + (b) * (b))) namespace indigo @@ -279,6 +280,7 @@ namespace indigo DLLEXPORT void rotateL(float si, float co); DLLEXPORT void rotateL(Vec2f vec); DLLEXPORT void rotateAroundSegmentEnd(const Vec2f& a, const Vec2f& b, float angle); + DLLEXPORT float relativeCross(const Vec2f& a, const Vec2f& b); DLLEXPORT static float distSqr(const Vec2f& a, const Vec2f& b); DLLEXPORT static float dist(const Vec2f& a, const Vec2f& b); @@ -822,5 +824,27 @@ namespace indigo float _d; }; + inline bool isPointInPolygon(const Vec2f& p, const std::vector& poly) + { + bool in = false; + for (size_t i = 0, n = poly.size(); i < n; ++i) + { + size_t j = (i + 1) % n; + bool intersect = + ((poly[i].y > p.y) != (poly[j].y > p.y)) && (p.x < (poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x); + if (intersect) + in = !in; + } + return in; + } + + inline std::vector getPointsInsidePolygon(const std::vector& polygon1, const std::vector& polygon2) + { + std::vector result; + result.reserve(polygon1.size()); + std::copy_if(polygon1.begin(), polygon1.end(), std::back_inserter(result), [&](auto& p) { return isPointInPolygon(p, polygon2); }); + return result; + } + } // namespace indigo #endif diff --git a/core/indigo-core/common/math/vec2f.cpp b/core/indigo-core/common/math/vec2f.cpp index d8c2d9c7f7..559490bfba 100644 --- a/core/indigo-core/common/math/vec2f.cpp +++ b/core/indigo-core/common/math/vec2f.cpp @@ -189,6 +189,11 @@ float Vec2f::cross(const Vec2f& a, const Vec2f& b) return a.x * b.y - a.y * b.x; } +float Vec2f::relativeCross(const Vec2f& a, const Vec2f& b) +{ + return (a.x - x) * (b.y - y) - (a.y - y) * (b.x - x); +} + void Vec2f::projectZ(Vec2f& v2, const Vec3f& v3) { v2.x = v3.x; diff --git a/core/indigo-core/molecule/base_molecule.h b/core/indigo-core/molecule/base_molecule.h index 04def60ddd..48d5119aee 100644 --- a/core/indigo-core/molecule/base_molecule.h +++ b/core/indigo-core/molecule/base_molecule.h @@ -589,6 +589,13 @@ namespace indigo void getBoundingBox(float font_size, LABEL_MODE label_mode, Vec2f& bottom_left, Vec2f& top_right); void getBoundingBox(float font_size, LABEL_MODE label_mode, Rect2f& bbox); + // calc convex hull + std::vector getConvexHull(const Vec2f& min_box) const; + + // calc distance between molecules + float distance(BaseMolecule& other); + float distance1(const BaseMolecule& other); + // aliases bool isAlias(int atom_idx) const; const char* getAlias(int atom_idx) const; diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index 3e52f0d8e8..127fc53219 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -4775,6 +4775,90 @@ void BaseMolecule::getBoundingBox(float font_size, LABEL_MODE label_mode, Rect2f bbox = Rect2f(a, b); } +std::vector BaseMolecule::getConvexHull(const Vec2f& min_box) const +{ + std::vector vertices; + std::transform(_xyz.ptr(), _xyz.ptr() + _xyz.size(), std::back_inserter(vertices), [](const Vec3f& v) -> Vec2f { return Vec2f(v.x, v.y); }); + if (vertices.size() < 3) + { + Rect2f bbox; + getBoundingBox(bbox, min_box); + vertices.clear(); + vertices.emplace_back(bbox.leftTop()); + vertices.emplace_back(bbox.rightTop()); + vertices.emplace_back(bbox.rightBottom()); + vertices.emplace_back(bbox.leftBottom()); + return vertices; + } + std::sort(vertices.begin(), vertices.end()); + std::vector hull; + for (const auto& p : vertices) + { + while (hull.size() >= 2 && hull[hull.size() - 2].relativeCross(hull.back(), p) <= 0) + hull.pop_back(); + hull.push_back(p); + } + size_t lower_size = hull.size(); + for (auto it = vertices.rbegin(); it != vertices.rend(); ++it) + { + while (hull.size() > lower_size && hull[hull.size() - 2].relativeCross(hull.back(), *it) <= 0) + hull.pop_back(); + hull.push_back(*it); + } + hull.pop_back(); + return hull; +} + +float BaseMolecule::distance(BaseMolecule& other) +{ + float min_dist = -1; + for (int atom_idx = 0; atom_idx < vertexCount(); ++atom_idx) + { + const auto& vec3d = _xyz[atom_idx]; + for (int j = 0; j < other.vertexCount(); ++j) + { + float dist = std::hypot(vec3d.x - other._xyz[j].x, vec3d.y - other._xyz[j].y, vec3d.z - other._xyz[j].z); + if (atom_idx == 0 && j == 0) + min_dist = dist; + else + min_dist = std::min(min_dist, dist); + } + } + return min_dist; +} + + + +float BaseMolecule::distance1(const BaseMolecule& other) +{ + auto build_kd_tree = [](const Array& points) -> std::vector { + std::vector sorted_points(points.ptr(), points.ptr() + points.size()); + std::sort(sorted_points.begin(), sorted_points.end(), [](const Vec3f& a, const Vec3f& b) { return a.x < b.x; }); + return sorted_points; + }; + + auto nearest_neighbor = [](const std::vector& tree, const Vec3f& target) -> float { + float best_dist = std::numeric_limits::infinity(); + for (const auto& point : tree) + { + float dist = std::hypot(point.x - target.x, point.y - target.y, point.z - target.z); + best_dist = std::min(best_dist, dist); + } + return best_dist; + }; + + if (_xyz.size() == 0 || other._xyz.size() == 0) + return std::numeric_limits::infinity(); + + auto kd_tree = build_kd_tree(other._xyz); + float min_dist = std::numeric_limits::infinity(); + + for (const auto& atom : _xyz) + min_dist = std::min(min_dist, nearest_neighbor(kd_tree, atom)); + + return min_dist; +} + void BaseMolecule::getBoundingBox(Vec2f& a, Vec2f& b) const { for (int atom_idx = 0; atom_idx < vertexCount(); ++atom_idx) diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index b93ccc1f5c..9b7bde3fb4 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -30,6 +30,7 @@ #include "base_cpp/exception.h" #include "molecule/meta_commons.h" +#include "layout/metalayout.h" namespace indigo { @@ -41,6 +42,15 @@ namespace indigo class ReactionMultistepDetector { public: + using MOL_DISTANCES = std::vector>; + using MOL_DISTANCES_MAP = std::unordered_map; + + struct MOL_DISTANCES_DESC + { + MOL_DISTANCES sorted_distances; + MOL_DISTANCES_MAP distances_map; + }; + enum class ReactionType { ESimpleReaction, @@ -48,6 +58,19 @@ namespace indigo EPathwayReaction }; + enum class ZoneType + { + EPlus, + EArrow, + EPathPay + }; + + struct SPECIAL_ZONE_DESC + { + ZoneType zone_type; + std::vector> zone_sections; + }; + ReactionMultistepDetector(BaseMolecule& mol); ~ReactionMultistepDetector(); ReactionType detectReaction(); @@ -62,11 +85,21 @@ namespace indigo typedef std::vector FLOAT_INT_PAIRS; const Vec2f PLUS_BBOX_SHIFT = {0.9f, 0.9f}; const Vec2f ARROW_BBOX_SHIFT = {0.0f, 0.9f}; + const float PLUS_DETECTION_DISTANCE = LayoutOptions::DEFAULT_BOND_LENGTH * 5; DECL_ERROR; private: void createSummBlocks(); + // collect molecules' distances + void collectSortedDistances(); + void createSpecialZones(); + void addPlusZones(const Vec2f& pos); + void addArrowZones(const Vec2f& tale, const Vec2f& head); + std::unordered_map> findSpecialZones(int mol_idx); + void mergeCloseComponents(); + bool isMergeable(size_t mol_idx1, size_t mol_idx2); + std::unique_ptr extractComponent(int index); void sortSummblocks(); bool mapReactionComponents(); @@ -79,7 +112,9 @@ namespace indigo std::vector _reaction_components; std::vector _component_summ_blocks; std::list _component_summ_blocks_list; - + std::vector> _components; + std::vector _mol_distances; + std::vector _zones; int _moleculeCount; }; diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index bf6b7d41a1..2ef30ab6ba 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -16,6 +16,7 @@ * limitations under the License. ***************************************************************************/ #include +#include #include "layout/pathway_layout.h" #include "reaction/pathway_reaction.h" @@ -238,6 +239,190 @@ void ReactionMultistepDetector::createSummBlocks() } } +std::unique_ptr ReactionMultistepDetector::extractComponent(int index) +{ + Filter filter(_bmol.getDecomposition().ptr(), Filter::EQ, index); + std::unique_ptr component; + if (_bmol.isQueryMolecule()) + component = std::make_unique(); + else + component = std::make_unique(); + component->makeSubmolecule(_bmol, filter, 0, 0); + return component; +} + +void ReactionMultistepDetector::collectSortedDistances() +{ + _mol_distances.resize(_moleculeCount); + for (int i = 0; i < _moleculeCount; ++i) + { + for (int j = i + 1; j < _moleculeCount; ++j) + { + float dist = _components[i]->distance(*_components[j]); + + auto& mdi = _mol_distances[i]; + auto it = std::lower_bound(mdi.sorted_distances.begin(), mdi.sorted_distances.end(), std::make_pair(j, dist), + [](auto& lhs, auto& rhs) { return lhs.second < rhs.second; }); + + mdi.sorted_distances.insert(it, {j, dist}); + mdi.distances_map[j] = dist; + + auto& mdj = _mol_distances[j]; + it = std::lower_bound(mdj.sorted_distances.begin(), mdj.sorted_distances.end(), std::make_pair(i, dist), + [](auto& lhs, auto& rhs) { return lhs.second < rhs.second; }); + + mdj.sorted_distances.insert(it, {i, dist}); + mdj.distances_map[i] = dist; + } + } +} + +void ReactionMultistepDetector::createSpecialZones() +{ + for (int i = 0; i < _bmol.meta().getMetaCount(ReactionPlusObject::CID); ++i) + { + auto& plus = (const ReactionPlusObject&)_bmol.meta().getMetaObject(ReactionPlusObject::CID, i); + const auto& plus_pos = plus.getPos(); + addPlusZones(plus_pos); + } + + for (int i = 0; i < _bmol.meta().getMetaCount(ReactionArrowObject::CID); ++i) + { + auto& arrow = (const ReactionArrowObject&)_bmol.meta().getMetaObject(ReactionArrowObject::CID, i); + addArrowZones(arrow.getTail(), arrow.getHead()); + } + + for (int i = 0; i < _bmol.meta().getMetaCount(ReactionMultitailArrowObject::CID); ++i) + { + auto& multi = (const ReactionMultitailArrowObject&)_bmol.meta().getMetaObject(ReactionMultitailArrowObject::CID, i); + auto& tails = multi.getTails(); + + // TODO: add zones for multitail arrows + } +} + +void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) +{ + Rect2f bbox(pos - PLUS_BBOX_SHIFT, pos + PLUS_BBOX_SHIFT); + SPECIAL_ZONE_DESC szd; + szd.zone_type = ZoneType::EPlus; + std::vector left, right, bottom, top; + + left.push_back(pos); + left.push_back(bbox.leftBottom()); + left.push_back(Vec2f(left.back().x - PLUS_DETECTION_DISTANCE, left.back().y)); + left.push_back(Vec2f(left.back().x, left.back().y + bbox.height())); + left.push_back(bbox.leftTop()); + left.push_back(pos); + + right.push_back(pos); + right.push_back(bbox.rightTop()); + right.push_back(Vec2f(right.back().x + PLUS_DETECTION_DISTANCE, right.back().y)); + right.push_back(Vec2f(right.back().x, right.back().y - bbox.height())); + right.push_back(bbox.rightBottom()); + right.push_back(pos); + + bottom.push_back(pos); + bottom.push_back(bbox.rightBottom()); + bottom.push_back(Vec2f(bottom.back().x, bottom.back().y - PLUS_DETECTION_DISTANCE)); + bottom.push_back(Vec2f(bottom.back().x - bbox.width(), bottom.back().y)); + bottom.push_back(bbox.leftBottom()); + bottom.push_back(pos); + + top.push_back(pos); + top.push_back(bbox.leftTop()); + top.push_back(Vec2f(top.back().x, top.back().y + PLUS_DETECTION_DISTANCE)); + top.push_back(Vec2f(top.back().x + bbox.width(), top.back().y)); + top.push_back(bbox.rightTop()); + top.push_back(pos); + szd.zone_sections.push_back(left); + szd.zone_sections.push_back(right); + szd.zone_sections.push_back(bottom); + szd.zone_sections.push_back(top); + _zones.push_back(szd); +} + +void ReactionMultistepDetector::addArrowZones(const Vec2f& tale, const Vec2f& head) +{ + float dx = head.x - tale.x, dy = head.y - tale.y; + float length = std::hypot(dx, dy), half = length * 0.5f; + float inv = 1.0f / length; + Vec2f nTop = {-dy * inv * half, dx * inv * half}; + Vec2f nBottom = {dy * inv * half, -dx * inv * half}; + + std::vector top{{head.x, head.y}, {tale.x, tale.y}, {tale.x + nTop.x, tale.y + nTop.y}, {head.x + nTop.x, head.y + nTop.y}}; + std::vector bottom{{tale.x, tale.y}, {head.x, head.y}, {head.x + nBottom.x, head.y + nBottom.y}, {tale.x + nBottom.x, tale.y + nBottom.y}}; + SPECIAL_ZONE_DESC szd; + szd.zone_type = ZoneType::EArrow; + szd.zone_sections.push_back(top); + szd.zone_sections.push_back(bottom); + _zones.push_back(szd); +} + +std::unordered_map> ReactionMultistepDetector::findSpecialZones(int mol_idx) +{ + std::unordered_map> result; + for (int i = 0; i < static_cast(_zones.size()); ++i) + { + auto& zone = _zones[i]; + for (int j = 0; j < static_cast(zone.zone_sections.size()); ++j) + { + auto& section = zone.zone_sections[j]; + } + } + return result; +} + +void ReactionMultistepDetector::mergeCloseComponents() +{ + for (std::size_t i = 0; i < _components.size(); ++i) + { + if (!_components[i]) + continue; + std::queue bfs_queue; + std::vector cluster; + bfs_queue.push(i); + cluster.push_back(i); + while (!bfs_queue.empty()) + { + auto idx = bfs_queue.front(); + bfs_queue.pop(); + for (std::size_t j = 0; j < _components.size(); ++j) + { + if (!_components[j] || j == idx) + continue; + if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) + continue; + if (isMergeable(idx, j)) + { + cluster.push_back(j); + bfs_queue.push(j); + } + } + } + for (std::size_t k = 1; k < cluster.size(); ++k) + { + QS_DEF(Array, mapping); + _components[i]->mergeWithMolecule(*_components[cluster[k]], &mapping, 0); + _components[cluster[k]].reset(); + } + } + _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p; }), _components.end()); +} + +bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) +{ + auto& mdi1 = _mol_distances[mol_idx1]; + auto& mdi2 = _mol_distances[mol_idx2]; + auto dist_it = mdi1.distances_map.find(mol_idx2); + if (dist_it != mdi1.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) + { + // TODO: add merge conditions + return true; + } + return false; +} + void ReactionMultistepDetector::sortSummblocks() { // Create a list of original indices @@ -275,6 +460,14 @@ void ReactionMultistepDetector::sortSummblocks() ReactionMultistepDetector::ReactionType ReactionMultistepDetector::detectReaction() { + std::list> s_neighbors; + getSGroupAtoms(_bmol, s_neighbors); + _moleculeCount = _bmol.countComponents(s_neighbors); + for (int i = 0; i < _moleculeCount; ++i) + _components.push_back(std::move(extractComponent(i))); + + collectSortedDistances(); + mergeCloseComponents(); createSummBlocks(); bool has_multistep = mapReactionComponents(); bool has_multitail = mapMultitailReactionComponents(); @@ -456,6 +649,7 @@ bool ReactionMultistepDetector::mapMultitailReactionComponents() bool ReactionMultistepDetector::findPlusNeighbours(const Vec2f& plus_pos, const FLOAT_INT_PAIRS& mol_tops, const FLOAT_INT_PAIRS& mol_bottoms, const FLOAT_INT_PAIRS& mol_lefts, const FLOAT_INT_PAIRS& mol_rights, std::pair& connection) { + // TODO: add bounding box for plus auto plus_pos_y = std::make_pair(plus_pos.y, 0); auto plus_pos_x = std::make_pair(plus_pos.x, 0); @@ -512,6 +706,7 @@ bool ReactionMultistepDetector::findPlusNeighbours(const Vec2f& plus_pos, const bottoms_col.emplace_back(lr_box.bottom(), kvp.second); } + // sort to find the closest to the plus std::sort(lefts_row.begin(), lefts_row.end(), pair_comp_asc); std::sort(rights_row.begin(), rights_row.end(), pair_comp_des); std::sort(tops_col.begin(), tops_col.end(), pair_comp_asc); @@ -528,6 +723,7 @@ bool ReactionMultistepDetector::findPlusNeighbours(const Vec2f& plus_pos, const if (rights_row_it != rights_row.end() && lefts_row_it != lefts_row.end()) { + // TODO: distances limit min_distance_h = std::min(std::fabs(rights_row_it->first - plus_pos_x.first), std::fabs(plus_pos_x.first - lefts_row_it->first)); connection.second = lefts_row_it->second; connection.first = rights_row_it->second; @@ -537,6 +733,7 @@ bool ReactionMultistepDetector::findPlusNeighbours(const Vec2f& plus_pos, const if (tops_col_it != tops_col.end() && bottoms_col_it != bottoms_col.end()) { + // TODO: distances limit min_distance_v = std::min(std::fabs(tops_col_it->first - plus_pos_y.first), std::fabs(bottoms_col_it->first - plus_pos_y.first)); if (!result || min_distance_v < min_distance_h) { From 0250bf96d36659add464b56af3f7f3b5f4e39d8a Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 30 Dec 2024 12:52:54 +0100 Subject: [PATCH 02/27] step 1 --- core/indigo-core/reaction/src/reaction_json_loader.cpp | 2 +- core/indigo-core/reaction/src/reaction_multistep_detector.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 4a630ec30c..35a0ec7867 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -72,7 +72,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) if (arrow_count == 0 && multi_count == 0) throw Error("No arrow in the reaction"); - if (arrow_count > 1 || multi_count > 0) + if (arrow_count > 0 || multi_count > 0) { ReactionMultistepDetector md(*_pmol); switch (md.detectReaction()) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 2ef30ab6ba..3cb95a4c39 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -258,7 +258,7 @@ void ReactionMultistepDetector::collectSortedDistances() { for (int j = i + 1; j < _moleculeCount; ++j) { - float dist = _components[i]->distance(*_components[j]); + float dist = _components[i]->distance1(*_components[j]); auto& mdi = _mol_distances[i]; auto it = std::lower_bound(mdi.sorted_distances.begin(), mdi.sorted_distances.end(), std::make_pair(j, dist), From fae6434c6ce858211099e15d3edc6b6d62b00ae4 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 30 Dec 2024 13:05:36 +0100 Subject: [PATCH 03/27] step 1 --- core/indigo-core/common/math/algebra.h | 4 ++-- core/indigo-core/reaction/reaction_multistep_detector.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 3defa4dff4..7f11faab0e 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -30,8 +30,8 @@ #define SQR(x) ((x) * (x)) -#define DEG2RAD(x) ((x) * M_PI / 180) -#define RAD2DEG(x) ((x) * 180 / M_PI) +#define DEG2RAD(x) ((x)*M_PI / 180) +#define RAD2DEG(x) ((x)*180 / M_PI) #define HYPOT(a, b) (sqrt((a) * (a) + (b) * (b))) namespace indigo diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 9b7bde3fb4..1895e6c1c0 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -29,8 +29,8 @@ #include #include "base_cpp/exception.h" -#include "molecule/meta_commons.h" #include "layout/metalayout.h" +#include "molecule/meta_commons.h" namespace indigo { From 5119605167d4ac995c22f68c5435c72d0341ea39 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 30 Dec 2024 13:18:11 +0100 Subject: [PATCH 04/27] step 1 --- core/indigo-core/molecule/src/base_molecule.cpp | 2 -- .../reaction/reaction_multistep_detector.h | 2 +- .../src/reaction_multistep_detector.cpp | 17 +++-------------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index 127fc53219..f1b256a526 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -4827,8 +4827,6 @@ float BaseMolecule::distance(BaseMolecule& other) return min_dist; } - - float BaseMolecule::distance1(const BaseMolecule& other) { auto build_kd_tree = [](const Array& points) -> std::vector { diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 1895e6c1c0..7c54031d7e 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -115,7 +115,7 @@ namespace indigo std::vector> _components; std::vector _mol_distances; std::vector _zones; - int _moleculeCount; + size_t _moleculeCount; }; } // namespace indigo diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 3cb95a4c39..fee06f2380 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -50,32 +50,20 @@ void ReactionMultistepDetector::createSummBlocks() auto pair_comp_asc = [](const FLOAT_INT_PAIR& a, const FLOAT_INT_PAIR& b) { return b.first > a.first; }; auto pair_comp_des = [](const FLOAT_INT_PAIR& a, const FLOAT_INT_PAIR& b) { return b.first < a.first; }; auto pair_comp_mol_asc = [](const FLOAT_INT_PAIR& a, const FLOAT_INT_PAIR& b) { return b.second > a.second; }; - std::list> s_neighbors; - getSGroupAtoms(_bmol, s_neighbors); - _moleculeCount = _bmol.countComponents(s_neighbors); _reaction_components.reserve(_moleculeCount); FLOAT_INT_PAIRS mol_tops, mol_bottoms, mol_lefts, mol_rights; // collect components for (int i = 0; i < _moleculeCount; ++i) { - Filter filter(_bmol.getDecomposition().ptr(), Filter::EQ, i); - std::unique_ptr component; - if (_bmol.isQueryMolecule()) - component = std::make_unique(); - else - component = std::make_unique(); - - BaseMolecule& mol = *component; - mol.makeSubmolecule(_bmol, filter, 0, 0); Rect2f bbox; - mol.getBoundingBox(bbox, MIN_MOL_SIZE); + _components[i]->getBoundingBox(bbox, MIN_MOL_SIZE); mol_tops.emplace_back(bbox.top(), i); mol_bottoms.emplace_back(bbox.bottom(), i); mol_lefts.emplace_back(bbox.left(), i); mol_rights.emplace_back(bbox.right(), i); - _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(component)); + _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(_components[i])); } for (int i = 0; i < _bmol.meta().getMetaCount(ReactionPlusObject::CID); ++i) @@ -408,6 +396,7 @@ void ReactionMultistepDetector::mergeCloseComponents() } } _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p; }), _components.end()); + _moleculeCount = _components.size(); } bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) From abdef6a326ef42a677931213fb0581c02c11a049 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 30 Dec 2024 13:33:27 +0100 Subject: [PATCH 05/27] step 1 --- core/indigo-core/reaction/reaction_multistep_detector.h | 2 +- core/indigo-core/reaction/src/reaction_multistep_detector.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 7c54031d7e..1895e6c1c0 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -115,7 +115,7 @@ namespace indigo std::vector> _components; std::vector _mol_distances; std::vector _zones; - size_t _moleculeCount; + int _moleculeCount; }; } // namespace indigo diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index fee06f2380..3f95a86e12 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -396,7 +396,7 @@ void ReactionMultistepDetector::mergeCloseComponents() } } _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p; }), _components.end()); - _moleculeCount = _components.size(); + _moleculeCount = (int)_components.size(); } bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) From 65cdf25d0a9fafb6a1512b2b95d67038652ad17b Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 31 Dec 2024 11:42:03 +0100 Subject: [PATCH 06/27] step 1 --- core/indigo-core/common/math/algebra.h | 141 ++++++++++++++++++ .../reaction/reaction_multistep_detector.h | 4 +- .../src/reaction_multistep_detector.cpp | 30 ++-- 3 files changed, 160 insertions(+), 15 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 7f11faab0e..f2f3f51d77 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -846,5 +846,146 @@ namespace indigo return result; } + inline bool isPointInConvexPolygon(const Vec2f& p, const std::vector& poly) + { + auto cross = [](const Vec2f& a, const Vec2f& b, const Vec2f& c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); }; + bool sign = cross(poly.back(), poly[0], p) < 0; + for (size_t i = 0, n = poly.size(); i < n; ++i) + if ((cross(poly[i], poly[(i + 1) % n], p) < 0) != sign) + return false; + return true; + } + + inline std::vector getPointsInsideConvexPolygon(const std::vector& polygon1, const std::vector& polygon2) + { + std::vector result; + result.reserve(polygon1.size()); + std::copy_if(polygon1.begin(), polygon1.end(), std::back_inserter(result), [&](auto& p) { return isPointInConvexPolygon(p, polygon2); }); + return result; + } + + inline float convexPolygonArea(const std::vector& poly) + { + float area = 0.0f; + size_t n = poly.size(); + for (size_t i = 0; i < n; ++i) + { + const Vec2f& p1 = poly[i]; + const Vec2f& p2 = poly[(i + 1) % n]; + area += Vec2f::cross(p1, p2); + } + return std::abs(area) * 0.5f; + } + + inline bool isCCW(const Vec2f& edgeStart, const Vec2f& edgeEnd, const Vec2f& point) + { + return Vec2f::cross(edgeEnd - edgeStart, point - edgeStart) >= 0.0f; + } + + inline Vec2f computeIntersection(const Vec2f& p1, const Vec2f& p2, const Vec2f& p3, const Vec2f& p4) + { + Vec2f res; + Vec2f d1 = p2 - p1; + Vec2f d2 = p4 - p3; + float denom = Vec2f::cross(d1, d2); + if(denom != 0.0f) + { + float t = Vec2f::cross((p3 - p1), d2) / denom; + res = Vec2f(p1.x + d1.x * t, p1.y + d1.y * t); + } + return res; + } + + inline std::vector convexClip(const std::vector& subject, const std::vector& clip) + { + std::vector output = subject; + size_t clipCount = clip.size(); + for (size_t i = 0; i < clipCount; ++i) + { + std::vector input = std::move(output); + output.clear(); + Vec2f A = clip[i]; + Vec2f B = clip[(i + 1) % clipCount]; + size_t inputCount = input.size(); + if (inputCount == 0) + break; + Vec2f S = input[inputCount - 1]; + for (size_t j = 0; j < inputCount; ++j) + { + Vec2f E = input[j]; + if (isCCW(A, B, E)) + { + if (!isCCW(A, B, S)) + { + output.emplace_back(computeIntersection(S, E, A, B)); + } + output.emplace_back(E); + } + else if (isCCW(A, B, S)) + { + output.emplace_back(computeIntersection(S, E, A, B)); + } + S = E; + } + } + return output; + } + + inline float computeConvexContainment(const std::vector& poly1, const std::vector& poly2) + { + float area = convexPolygonArea(poly1); + if (area == 0.0f) + return 0.0f; + std::vector intersection = convexClip(poly1, poly2); + if (intersection.empty()) + return 0.0f; + float intersectionArea = convexPolygonArea(intersection); + if (std::abs(intersectionArea - area) < 1e-6f) + return 1.0f; + return intersectionArea / area; + } + + inline float distancePointToEdge(const Vec2f& p, const Vec2f& a, const Vec2f& b) + { + Vec2f ab = b - a; + Vec2f ap = p - a; + float t = Vec2f::dot(ap, ab) / Vec2f::dot(ab, ab); + t = std::max(0.0f, std::min(1.0f, t)); + Vec2f projection(a.x + ab.x * t, a.y + ab.y * t); + Vec2f diff = p - projection; + return diff.length(); + } + + inline float computeConvexDistance(const std::vector& poly1, const std::vector& poly2) + { + float minDist = std::numeric_limits::max(); + for (const auto& p : poly1) + { + float dist = std::numeric_limits::max(); + size_t n = poly2.size(); + for (size_t i = 0; i < n; ++i) + { + float d = distancePointToEdge(p, poly2[i], poly2[(i + 1) % n]); + dist = std::min(dist, d); + if (d < minDist) + break; + } + minDist = std::min(minDist, dist); + } + for (const auto& p : poly2) + { + float dist = std::numeric_limits::max(); + size_t n = poly1.size(); + for (size_t i = 0; i < n; ++i) + { + float d = distancePointToEdge(p, poly1[i], poly1[(i + 1) % n]); + dist = std::min(dist, d); + if (d < minDist) + break; + } + minDist = std::min(minDist, dist); + } + return minDist; + } } // namespace indigo #endif diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 1895e6c1c0..08704c1416 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -96,7 +96,7 @@ namespace indigo void createSpecialZones(); void addPlusZones(const Vec2f& pos); void addArrowZones(const Vec2f& tale, const Vec2f& head); - std::unordered_map> findSpecialZones(int mol_idx); + std::unordered_map> findSpecialZones(size_t mol_idx); void mergeCloseComponents(); bool isMergeable(size_t mol_idx1, size_t mol_idx2); std::unique_ptr extractComponent(int index); @@ -112,7 +112,7 @@ namespace indigo std::vector _reaction_components; std::vector _component_summ_blocks; std::list _component_summ_blocks_list; - std::vector> _components; + std::vector, std::vector>> _components; std::vector _mol_distances; std::vector _zones; int _moleculeCount; diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 3f95a86e12..a7f4814266 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -57,13 +57,13 @@ void ReactionMultistepDetector::createSummBlocks() for (int i = 0; i < _moleculeCount; ++i) { Rect2f bbox; - _components[i]->getBoundingBox(bbox, MIN_MOL_SIZE); + _components[i].first->getBoundingBox(bbox, MIN_MOL_SIZE); mol_tops.emplace_back(bbox.top(), i); mol_bottoms.emplace_back(bbox.bottom(), i); mol_lefts.emplace_back(bbox.left(), i); mol_rights.emplace_back(bbox.right(), i); - _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(_components[i])); + _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(_components[i].first)); } for (int i = 0; i < _bmol.meta().getMetaCount(ReactionPlusObject::CID); ++i) @@ -246,8 +246,7 @@ void ReactionMultistepDetector::collectSortedDistances() { for (int j = i + 1; j < _moleculeCount; ++j) { - float dist = _components[i]->distance1(*_components[j]); - + float dist = computeConvexDistance(_components[i].second, _components[j].second); auto& mdi = _mol_distances[i]; auto it = std::lower_bound(mdi.sorted_distances.begin(), mdi.sorted_distances.end(), std::make_pair(j, dist), [](auto& lhs, auto& rhs) { return lhs.second < rhs.second; }); @@ -284,7 +283,6 @@ void ReactionMultistepDetector::createSpecialZones() { auto& multi = (const ReactionMultitailArrowObject&)_bmol.meta().getMetaObject(ReactionMultitailArrowObject::CID, i); auto& tails = multi.getTails(); - // TODO: add zones for multitail arrows } } @@ -347,8 +345,9 @@ void ReactionMultistepDetector::addArrowZones(const Vec2f& tale, const Vec2f& he _zones.push_back(szd); } -std::unordered_map> ReactionMultistepDetector::findSpecialZones(int mol_idx) +std::unordered_map> ReactionMultistepDetector::findSpecialZones(size_t mol_idx) { + auto& mol = *_components[mol_idx].first; std::unordered_map> result; for (int i = 0; i < static_cast(_zones.size()); ++i) { @@ -365,7 +364,7 @@ void ReactionMultistepDetector::mergeCloseComponents() { for (std::size_t i = 0; i < _components.size(); ++i) { - if (!_components[i]) + if (!_components[i].first) continue; std::queue bfs_queue; std::vector cluster; @@ -377,7 +376,7 @@ void ReactionMultistepDetector::mergeCloseComponents() bfs_queue.pop(); for (std::size_t j = 0; j < _components.size(); ++j) { - if (!_components[j] || j == idx) + if (!_components[j].first || j == idx) continue; if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) continue; @@ -391,11 +390,11 @@ void ReactionMultistepDetector::mergeCloseComponents() for (std::size_t k = 1; k < cluster.size(); ++k) { QS_DEF(Array, mapping); - _components[i]->mergeWithMolecule(*_components[cluster[k]], &mapping, 0); - _components[cluster[k]].reset(); + _components[i].first->mergeWithMolecule(*_components[cluster[k]].first, &mapping, 0); + _components[cluster[k]].first.reset(); } } - _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p; }), _components.end()); + _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p.first; }), _components.end()); _moleculeCount = (int)_components.size(); } @@ -406,7 +405,8 @@ bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) auto dist_it = mdi1.distances_map.find(mol_idx2); if (dist_it != mdi1.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) { - // TODO: add merge conditions + findSpecialZones(mol_idx1); + findSpecialZones(mol_idx2); return true; } return false; @@ -453,7 +453,11 @@ ReactionMultistepDetector::ReactionType ReactionMultistepDetector::detectReactio getSGroupAtoms(_bmol, s_neighbors); _moleculeCount = _bmol.countComponents(s_neighbors); for (int i = 0; i < _moleculeCount; ++i) - _components.push_back(std::move(extractComponent(i))); + { + auto component = extractComponent(i); + auto hull = component->getConvexHull(Vec2f(LayoutOptions::DEFAULT_BOND_LENGTH, LayoutOptions::DEFAULT_BOND_LENGTH)); + _components.emplace_back(std::move(component), hull); + } collectSortedDistances(); mergeCloseComponents(); From 367729043ec35c24bb4e466795d91cfe14fc3d7a Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 31 Dec 2024 11:48:44 +0100 Subject: [PATCH 07/27] step 1 --- core/indigo-core/common/math/algebra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index f2f3f51d77..67ed81d7cd 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -888,7 +888,7 @@ namespace indigo Vec2f d1 = p2 - p1; Vec2f d2 = p4 - p3; float denom = Vec2f::cross(d1, d2); - if(denom != 0.0f) + if( denom != 0.0f ) { float t = Vec2f::cross((p3 - p1), d2) / denom; res = Vec2f(p1.x + d1.x * t, p1.y + d1.y * t); From 72912cda779787cfedd4e37c50375e81830b4bf3 Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 31 Dec 2024 11:51:24 +0100 Subject: [PATCH 08/27] step 1 --- core/indigo-core/common/math/algebra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 67ed81d7cd..f2f3f51d77 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -888,7 +888,7 @@ namespace indigo Vec2f d1 = p2 - p1; Vec2f d2 = p4 - p3; float denom = Vec2f::cross(d1, d2); - if( denom != 0.0f ) + if(denom != 0.0f) { float t = Vec2f::cross((p3 - p1), d2) / denom; res = Vec2f(p1.x + d1.x * t, p1.y + d1.y * t); From 4ee56c0c4abe895fb37d43b7e13593c1ab7c6114 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 6 Jan 2025 11:55:19 +0100 Subject: [PATCH 09/27] step 2 --- core/indigo-core/common/math/algebra.h | 139 +++++++++---- core/indigo-core/molecule/base_molecule.h | 4 - .../molecule/src/base_molecule.cpp | 48 ----- .../reaction/reaction_multistep_detector.h | 12 +- .../reaction/src/reaction_json_loader.cpp | 2 +- .../src/reaction_multistep_detector.cpp | 189 ++++++++++++++++-- 6 files changed, 283 insertions(+), 111 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index f2f3f51d77..11e031eab2 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -30,8 +30,8 @@ #define SQR(x) ((x) * (x)) -#define DEG2RAD(x) ((x)*M_PI / 180) -#define RAD2DEG(x) ((x)*180 / M_PI) +#define DEG2RAD(x) ((x) * M_PI / 180) +#define RAD2DEG(x) ((x) * 180 / M_PI) #define HYPOT(a, b) (sqrt((a) * (a) + (b) * (b))) namespace indigo @@ -877,58 +877,83 @@ namespace indigo return std::abs(area) * 0.5f; } - inline bool isCCW(const Vec2f& edgeStart, const Vec2f& edgeEnd, const Vec2f& point) + inline bool isInside(const Vec2f& edgeStart, const Vec2f& edgeEnd, const Vec2f& point) { - return Vec2f::cross(edgeEnd - edgeStart, point - edgeStart) >= 0.0f; + return (edgeEnd.x - edgeStart.x) * (point.y - edgeStart.y) - (edgeEnd.y - edgeStart.y) * (point.x - edgeStart.x) <= 0; } - inline Vec2f computeIntersection(const Vec2f& p1, const Vec2f& p2, const Vec2f& p3, const Vec2f& p4) + inline bool convexPolygonsIntersect(const std::vector& poly1, const std::vector& poly2) { - Vec2f res; - Vec2f d1 = p2 - p1; - Vec2f d2 = p4 - p3; - float denom = Vec2f::cross(d1, d2); - if(denom != 0.0f) - { - float t = Vec2f::cross((p3 - p1), d2) / denom; - res = Vec2f(p1.x + d1.x * t, p1.y + d1.y * t); - } - return res; + auto project = [](const std::vector& poly, const Vec2f& axis) { + auto [min, max] = std::minmax_element(poly.begin(), poly.end(), [&](const Vec2f& a, const Vec2f& b) { return a * axis < b * axis; }); + return std::pair{*min * axis, *max * axis}; + }; + + auto overlap = [](const auto& range1, const auto& range2) { return !(range1.first > range2.second || range2.first > range1.second); }; + + auto getNormals = [](const std::vector& poly) { + std::vector normals; + for (size_t i = 0; i < poly.size(); ++i) + { + Vec2f edge = poly[(i + 1) % poly.size()] - poly[i]; + normals.emplace_back(-edge.y, edge.x); + } + return normals; + }; + + auto normals1 = getNormals(poly1), normals2 = getNormals(poly2); + for (const auto& normal : normals1) + if (!overlap(project(poly1, normal), project(poly2, normal))) + return false; + for (const auto& normal : normals2) + if (!overlap(project(poly1, normal), project(poly2, normal))) + return false; + return true; + } + + inline Vec2f computeIntersection(const Vec2f& s, const Vec2f& e, const Vec2f& edgeStart, const Vec2f& edgeEnd) + { + float dx1 = e.x - s.x, dy1 = e.y - s.y, dx2 = edgeEnd.x - edgeStart.x, dy2 = edgeEnd.y - edgeStart.y; + float det = dx1 * dy2 - dy1 * dx2; + if (std::abs(det) < 1e-6) + return s; + float t = ((edgeStart.x - s.x) * dy2 - (edgeStart.y - s.y) * dx2) / det; + return {s.x + t * dx1, s.y + t * dy1}; } inline std::vector convexClip(const std::vector& subject, const std::vector& clip) { - std::vector output = subject; - size_t clipCount = clip.size(); - for (size_t i = 0; i < clipCount; ++i) - { - std::vector input = std::move(output); - output.clear(); - Vec2f A = clip[i]; - Vec2f B = clip[(i + 1) % clipCount]; - size_t inputCount = input.size(); - if (inputCount == 0) + std::vector result = subject; + for (size_t i = 0; i < clip.size(); ++i) + { + const Vec2f& edgeStart = clip[i]; + const Vec2f& edgeEnd = clip[(i + 1) % clip.size()]; + std::vector input = std::move(result); + result.clear(); + if (input.empty()) break; - Vec2f S = input[inputCount - 1]; - for (size_t j = 0; j < inputCount; ++j) + Vec2f prev = input.back(); + for (const Vec2f& curr : input) { - Vec2f E = input[j]; - if (isCCW(A, B, E)) + if (isInside(edgeStart, edgeEnd, curr)) { - if (!isCCW(A, B, S)) - { - output.emplace_back(computeIntersection(S, E, A, B)); - } - output.emplace_back(E); + if (!isInside(edgeStart, edgeEnd, prev)) + result.push_back(computeIntersection(prev, curr, edgeStart, edgeEnd)); + result.push_back(curr); } - else if (isCCW(A, B, S)) + else if (isInside(edgeStart, edgeEnd, prev)) { - output.emplace_back(computeIntersection(S, E, A, B)); + result.push_back(computeIntersection(prev, curr, edgeStart, edgeEnd)); } - S = E; + prev = curr; } } - return output; + + std::cout << "result: " << std::endl; + for (const auto& p : result) + std::cout << p.x << " " << p.y << std::endl; + + return result; } inline float computeConvexContainment(const std::vector& poly1, const std::vector& poly2) @@ -987,5 +1012,43 @@ namespace indigo } return minDist; } + + inline bool doesVerticalLineIntersectPolygon(float x, const std::vector& poly) + { + for (size_t i = 0, n = poly.size(); i < n; ++i) + { + const Vec2f& a = poly[i]; + const Vec2f& b = poly[(i + 1) % n]; + if ((x > std::min(a.x, b.x) && x < std::max(a.x, b.x))) + return true; + } + return false; + } + + inline bool doesHorizontalLineIntersectPolygon(float y, const std::vector& poly) + { + for (size_t i = 0, n = poly.size(); i < n; ++i) + { + const Vec2f& a = poly[i]; + const Vec2f& b = poly[(i + 1) % n]; + if ((y > std::min(a.y, b.y) && y < std::max(a.y, b.y))) + return true; + } + return false; + } + + inline bool doesRayIntersectPolygon(const Vec2f& p1, const Vec2f& p2, const std::vector& poly) + { + Vec2f dir = {p2.x - p1.x, p2.y - p1.y}; + for (size_t i = 0, n = poly.size(); i < n; ++i) + { + Vec2f a = {poly[i].x - p1.x, poly[i].y - p1.y}; + Vec2f b = {poly[(i + 1) % n].x - p1.x, poly[(i + 1) % n].y - p1.y}; + if (Vec2f::cross(dir, a) * Vec2f::cross(dir, b) < 0 && Vec2f::cross(a, b) * Vec2f::cross(a, dir) < 0) + return true; + } + return false; + } + } // namespace indigo #endif diff --git a/core/indigo-core/molecule/base_molecule.h b/core/indigo-core/molecule/base_molecule.h index 48d5119aee..ec5d42c7fc 100644 --- a/core/indigo-core/molecule/base_molecule.h +++ b/core/indigo-core/molecule/base_molecule.h @@ -592,10 +592,6 @@ namespace indigo // calc convex hull std::vector getConvexHull(const Vec2f& min_box) const; - // calc distance between molecules - float distance(BaseMolecule& other); - float distance1(const BaseMolecule& other); - // aliases bool isAlias(int atom_idx) const; const char* getAlias(int atom_idx) const; diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index f1b256a526..c383b4a5be 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -4809,54 +4809,6 @@ std::vector BaseMolecule::getConvexHull(const Vec2f& min_box) const return hull; } -float BaseMolecule::distance(BaseMolecule& other) -{ - float min_dist = -1; - for (int atom_idx = 0; atom_idx < vertexCount(); ++atom_idx) - { - const auto& vec3d = _xyz[atom_idx]; - for (int j = 0; j < other.vertexCount(); ++j) - { - float dist = std::hypot(vec3d.x - other._xyz[j].x, vec3d.y - other._xyz[j].y, vec3d.z - other._xyz[j].z); - if (atom_idx == 0 && j == 0) - min_dist = dist; - else - min_dist = std::min(min_dist, dist); - } - } - return min_dist; -} - -float BaseMolecule::distance1(const BaseMolecule& other) -{ - auto build_kd_tree = [](const Array& points) -> std::vector { - std::vector sorted_points(points.ptr(), points.ptr() + points.size()); - std::sort(sorted_points.begin(), sorted_points.end(), [](const Vec3f& a, const Vec3f& b) { return a.x < b.x; }); - return sorted_points; - }; - - auto nearest_neighbor = [](const std::vector& tree, const Vec3f& target) -> float { - float best_dist = std::numeric_limits::infinity(); - for (const auto& point : tree) - { - float dist = std::hypot(point.x - target.x, point.y - target.y, point.z - target.z); - best_dist = std::min(best_dist, dist); - } - return best_dist; - }; - - if (_xyz.size() == 0 || other._xyz.size() == 0) - return std::numeric_limits::infinity(); - - auto kd_tree = build_kd_tree(other._xyz); - float min_dist = std::numeric_limits::infinity(); - - for (const auto& atom : _xyz) - min_dist = std::min(min_dist, nearest_neighbor(kd_tree, atom)); - - return min_dist; -} - void BaseMolecule::getBoundingBox(Vec2f& a, Vec2f& b) const { for (int atom_idx = 0; atom_idx < vertexCount(); ++atom_idx) diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 08704c1416..ad545e118d 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -62,13 +62,14 @@ namespace indigo { EPlus, EArrow, - EPathPay + EPathWay }; struct SPECIAL_ZONE_DESC { ZoneType zone_type; std::vector> zone_sections; + std::vector origin_coordinates; }; ReactionMultistepDetector(BaseMolecule& mol); @@ -85,7 +86,8 @@ namespace indigo typedef std::vector FLOAT_INT_PAIRS; const Vec2f PLUS_BBOX_SHIFT = {0.9f, 0.9f}; const Vec2f ARROW_BBOX_SHIFT = {0.0f, 0.9f}; - const float PLUS_DETECTION_DISTANCE = LayoutOptions::DEFAULT_BOND_LENGTH * 5; + const float PLUS_DETECTION_DISTANCE = LayoutOptions::DEFAULT_BOND_LENGTH * 2.5; + const float ARROW_DETECTION_DISTANCE = LayoutOptions::DEFAULT_BOND_LENGTH * 3; DECL_ERROR; @@ -95,10 +97,12 @@ namespace indigo void collectSortedDistances(); void createSpecialZones(); void addPlusZones(const Vec2f& pos); - void addArrowZones(const Vec2f& tale, const Vec2f& head); - std::unordered_map> findSpecialZones(size_t mol_idx); + void addArrowZones(const Vec2f& tail, const Vec2f& head); + void addPathwayZones(const Vec2f& head, const Vec2f& sp_beg, const Vec2f& sp_end, const std::vector& tails); + std::map> findSpecialZones(size_t mol_idx); void mergeCloseComponents(); bool isMergeable(size_t mol_idx1, size_t mol_idx2); + bool checkForOppositeSections(ZoneType zt, const std::unordered_set& sections1, const std::unordered_set& sections2); std::unique_ptr extractComponent(int index); void sortSummblocks(); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 35a0ec7867..4a630ec30c 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -72,7 +72,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) if (arrow_count == 0 && multi_count == 0) throw Error("No arrow in the reaction"); - if (arrow_count > 0 || multi_count > 0) + if (arrow_count > 1 || multi_count > 0) { ReactionMultistepDetector md(*_pmol); switch (md.detectReaction()) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index a7f4814266..10f7670fdc 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -283,7 +283,11 @@ void ReactionMultistepDetector::createSpecialZones() { auto& multi = (const ReactionMultitailArrowObject&)_bmol.meta().getMetaObject(ReactionMultitailArrowObject::CID, i); auto& tails = multi.getTails(); - // TODO: add zones for multitail arrows + auto& head = multi.getHead(); + auto& spine_beg = multi.getSpineBegin(); + auto& spine_end = multi.getSpineEnd(); + std::vector tails_vec(tails.begin(), tails.end()); + addPathwayZones(head, spine_beg, spine_end, tails_vec); } } @@ -292,8 +296,10 @@ void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) Rect2f bbox(pos - PLUS_BBOX_SHIFT, pos + PLUS_BBOX_SHIFT); SPECIAL_ZONE_DESC szd; szd.zone_type = ZoneType::EPlus; + szd.origin_coordinates.push_back(pos); std::vector left, right, bottom, top; + // left zone left.push_back(pos); left.push_back(bbox.leftBottom()); left.push_back(Vec2f(left.back().x - PLUS_DETECTION_DISTANCE, left.back().y)); @@ -301,6 +307,7 @@ void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) left.push_back(bbox.leftTop()); left.push_back(pos); + // right zone right.push_back(pos); right.push_back(bbox.rightTop()); right.push_back(Vec2f(right.back().x + PLUS_DETECTION_DISTANCE, right.back().y)); @@ -308,6 +315,7 @@ void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) right.push_back(bbox.rightBottom()); right.push_back(pos); + // bottom zone bottom.push_back(pos); bottom.push_back(bbox.rightBottom()); bottom.push_back(Vec2f(bottom.back().x, bottom.back().y - PLUS_DETECTION_DISTANCE)); @@ -315,6 +323,7 @@ void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) bottom.push_back(bbox.leftBottom()); bottom.push_back(pos); + // top zone top.push_back(pos); top.push_back(bbox.leftTop()); top.push_back(Vec2f(top.back().x, top.back().y + PLUS_DETECTION_DISTANCE)); @@ -328,34 +337,111 @@ void ReactionMultistepDetector::addPlusZones(const Vec2f& pos) _zones.push_back(szd); } -void ReactionMultistepDetector::addArrowZones(const Vec2f& tale, const Vec2f& head) +void ReactionMultistepDetector::addArrowZones(const Vec2f& tail, const Vec2f& head) { - float dx = head.x - tale.x, dy = head.y - tale.y; - float length = std::hypot(dx, dy), half = length * 0.5f; + float dx = head.x - tail.x, dy = head.y - tail.y; + Vec2f dir = {dx, dy}; + float length = std::hypot(dx, dy), half_length = length * 0.5f; float inv = 1.0f / length; - Vec2f nTop = {-dy * inv * half, dx * inv * half}; - Vec2f nBottom = {dy * inv * half, -dx * inv * half}; + Vec2f nT = {-dy * inv, dx * inv}; + Vec2f nB = {dy * inv, -dx * inv}; + + Vec2f nTop = nT * half_length; + Vec2f nBottom = nB * half_length; + + std::vector top{{head.x, head.y}, {tail.x, tail.y}, {tail.x + nTop.x, tail.y + nTop.y}, {head.x + nTop.x, head.y + nTop.y}}; + std::vector bottom{{tail.x, tail.y}, {head.x, head.y}, {head.x + nBottom.x, head.y + nBottom.y}, {tail.x + nBottom.x, tail.y + nBottom.y}}; + + std::vector left, right; + Vec2f pos = tail + nB / 2; + left.push_back(pos); + pos -= dir * ARROW_DETECTION_DISTANCE; + left.push_back(pos); + pos += nT; + left.push_back(pos); + pos += dir * ARROW_DETECTION_DISTANCE; + left.push_back(pos); + pos += nB; + left.push_back(pos); + + pos = head + nT / 2; + right.push_back(pos); + pos += dir * ARROW_DETECTION_DISTANCE; + right.push_back(pos); + pos += nB; + right.push_back(pos); + pos -= dir * ARROW_DETECTION_DISTANCE; + right.push_back(pos); + pos += nT; + right.push_back(pos); - std::vector top{{head.x, head.y}, {tale.x, tale.y}, {tale.x + nTop.x, tale.y + nTop.y}, {head.x + nTop.x, head.y + nTop.y}}; - std::vector bottom{{tale.x, tale.y}, {head.x, head.y}, {head.x + nBottom.x, head.y + nBottom.y}, {tale.x + nBottom.x, tale.y + nBottom.y}}; SPECIAL_ZONE_DESC szd; szd.zone_type = ZoneType::EArrow; szd.zone_sections.push_back(top); szd.zone_sections.push_back(bottom); + szd.zone_sections.push_back(left); + szd.zone_sections.push_back(right); + szd.origin_coordinates.push_back(tail); + szd.origin_coordinates.push_back(head); _zones.push_back(szd); } -std::unordered_map> ReactionMultistepDetector::findSpecialZones(size_t mol_idx) +void ReactionMultistepDetector::addPathwayZones(const Vec2f& head, const Vec2f& sp_beg, const Vec2f& sp_end, const std::vector& tails) { - auto& mol = *_components[mol_idx].first; - std::unordered_map> result; + std::vector right; + Vec2f pos(head); + pos.y += LayoutOptions::DEFAULT_BOND_LENGTH / 2.0f; + right.push_back(pos); + pos.x += ARROW_DETECTION_DISTANCE; + right.push_back(pos); + pos.y -= LayoutOptions::DEFAULT_BOND_LENGTH; + right.push_back(pos); + pos.x -= ARROW_DETECTION_DISTANCE; + right.push_back(pos); + pos.y += LayoutOptions::DEFAULT_BOND_LENGTH; + right.push_back(pos); + SPECIAL_ZONE_DESC szd; + szd.zone_type = ZoneType::EPathWay; + szd.zone_sections.push_back(right); + szd.origin_coordinates.push_back(head); + szd.origin_coordinates.push_back(sp_beg); + szd.origin_coordinates.push_back(sp_end); + for (const auto& tail : tails) + { + std::vector left; + pos = tail; + pos.y -= LayoutOptions::DEFAULT_BOND_LENGTH / 2.0f; + left.push_back(pos); + pos.x -= ARROW_DETECTION_DISTANCE; + left.push_back(pos); + pos.y += LayoutOptions::DEFAULT_BOND_LENGTH; + left.push_back(pos); + pos.x += ARROW_DETECTION_DISTANCE; + left.push_back(pos); + pos.y -= LayoutOptions::DEFAULT_BOND_LENGTH; + left.push_back(pos); + szd.zone_sections.push_back(left); + szd.origin_coordinates.push_back(tail); + } + _zones.push_back(szd); +} + +std::map> ReactionMultistepDetector::findSpecialZones(size_t mol_idx) +{ + auto& hull = _components[mol_idx].second; + std::map> result; for (int i = 0; i < static_cast(_zones.size()); ++i) { auto& zone = _zones[i]; + std::pair> cur_zone(i, {}); for (int j = 0; j < static_cast(zone.zone_sections.size()); ++j) { auto& section = zone.zone_sections[j]; + if (convexPolygonsIntersect(hull, section)) + cur_zone.second.insert(j); } + if (cur_zone.second.size()) + result.insert(cur_zone); } return result; } @@ -390,8 +476,11 @@ void ReactionMultistepDetector::mergeCloseComponents() for (std::size_t k = 1; k < cluster.size(); ++k) { QS_DEF(Array, mapping); - _components[i].first->mergeWithMolecule(*_components[cluster[k]].first, &mapping, 0); - _components[cluster[k]].first.reset(); + if (_components[cluster[k]].first) + { + _components[i].first->mergeWithMolecule(*_components[cluster[k]].first, &mapping, 0); + _components[cluster[k]].first.reset(); + } } } _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p.first; }), _components.end()); @@ -405,13 +494,80 @@ bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) auto dist_it = mdi1.distances_map.find(mol_idx2); if (dist_it != mdi1.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) { - findSpecialZones(mol_idx1); - findSpecialZones(mol_idx2); - return true; + // collect surrounding zones for both molecules + auto zones1 = findSpecialZones(mol_idx1); + auto zones2 = findSpecialZones(mol_idx2); + if (zones2.empty()) + return true; + + // find common zones + std::map> intersection; + std::set_intersection(zones1.begin(), zones1.end(), zones2.begin(), zones2.end(), std::inserter(intersection, intersection.begin()), + [](const auto& a, const auto& b) { return a.first < b.first; }); + + // if there are common zones check for opposite sections. if molecules are connected by opposite sections, they are not mergeable + for (auto& [key, values] : intersection) + { + auto zones2_it = zones2.find(key); + if (zones2_it != zones2.end() && _zones[key].zone_type != ZoneType::EPathWay && + checkForOppositeSections(_zones[key].zone_type, values, zones2_it->second)) + return false; + } + + if (intersection.empty()) + { + std::map> zones_union; + std::set_union(zones1.begin(), zones1.end(), zones2.begin(), zones2.end(), std::inserter(zones_union, zones_union.begin()), + [](const auto& a, const auto& b) { return a.first < b.first; }); + // check if special zone affects both molecules + const auto& hull1 = _components[mol_idx1].second; + const auto& hull2 = _components[mol_idx2].second; + for (auto& [key, values] : zones_union) + { + const auto& coords = _zones[key].origin_coordinates; + switch (_zones[key].zone_type) + { + case ZoneType::EPlus: + if ((doesVerticalLineIntersectPolygon(coords[0].x, hull1) && doesVerticalLineIntersectPolygon(coords[0].x, hull2)) || + (doesHorizontalLineIntersectPolygon(coords[0].x, hull1) && doesHorizontalLineIntersectPolygon(coords[0].x, hull2))) + return true; + break; + case ZoneType::EArrow: + if ((doesRayIntersectPolygon(coords[0], coords[1], hull1) && doesRayIntersectPolygon(coords[0], coords[1], hull2)) || + (doesRayIntersectPolygon(coords[1], coords[0], hull1) && doesRayIntersectPolygon(coords[1], coords[0], hull2))) + return true; + break; + case ZoneType::EPathWay: { + auto c_it = coords.begin(); + const Vec2f& head = *c_it++; + const Vec2f& spine_beg = *c_it++; + const Vec2f& spine_end = *c_it++; + Vec2f tail(spine_beg.x, head.y); + if (doesRayIntersectPolygon(tail, head, hull1) && doesRayIntersectPolygon(tail, head, hull2)) + return true; + for (; c_it != coords.end(); ++c_it) + { + Vec2f tail_start(spine_end.x, c_it->y); + if (doesRayIntersectPolygon(tail_start, *c_it, hull1) && doesRayIntersectPolygon(tail_start, *c_it, hull2)) + return true; + } + } + break; + } + } + } } return false; } +bool ReactionMultistepDetector::checkForOppositeSections(ZoneType /* zt */, const std::unordered_set& sections1, const std::unordered_set& sections2) +{ + for (int section1 : sections1) + if (sections2.count(section1 ^ 1)) + return true; + return false; +} + void ReactionMultistepDetector::sortSummblocks() { // Create a list of original indices @@ -449,6 +605,7 @@ void ReactionMultistepDetector::sortSummblocks() ReactionMultistepDetector::ReactionType ReactionMultistepDetector::detectReaction() { + createSpecialZones(); std::list> s_neighbors; getSGroupAtoms(_bmol, s_neighbors); _moleculeCount = _bmol.countComponents(s_neighbors); From c7fd02f45c38cfc394de034a38f8ce71cceba163 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 8 Jan 2025 11:34:54 +0100 Subject: [PATCH 10/27] step 3 --- .../reaction/reaction_multistep_detector.h | 3 +- .../reaction/src/reaction_json_loader.cpp | 2 +- .../src/reaction_multistep_detector.cpp | 169 +++++++++++------- 3 files changed, 109 insertions(+), 65 deletions(-) diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index ad545e118d..88ec615072 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -100,8 +100,9 @@ namespace indigo void addArrowZones(const Vec2f& tail, const Vec2f& head); void addPathwayZones(const Vec2f& head, const Vec2f& sp_beg, const Vec2f& sp_end, const std::vector& tails); std::map> findSpecialZones(size_t mol_idx); + std::optional> findMaxSpecialZone(size_t mol_idx); void mergeCloseComponents(); - bool isMergeable(size_t mol_idx1, size_t mol_idx2); + std::optional> isMergeable(size_t mol_idx1, size_t mol_idx2, std::optional> current_zone); bool checkForOppositeSections(ZoneType zt, const std::unordered_set& sections1, const std::unordered_set& sections2); std::unique_ptr extractComponent(int index); void sortSummblocks(); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 4a630ec30c..35a0ec7867 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -72,7 +72,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) if (arrow_count == 0 && multi_count == 0) throw Error("No arrow in the reaction"); - if (arrow_count > 1 || multi_count > 0) + if (arrow_count > 0 || multi_count > 0) { ReactionMultistepDetector md(*_pmol); switch (md.detectReaction()) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 10f7670fdc..86267be5e9 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -388,7 +388,9 @@ void ReactionMultistepDetector::addArrowZones(const Vec2f& tail, const Vec2f& he void ReactionMultistepDetector::addPathwayZones(const Vec2f& head, const Vec2f& sp_beg, const Vec2f& sp_end, const std::vector& tails) { - std::vector right; + std::vector right, top, bottom; + + // form products zone Vec2f pos(head); pos.y += LayoutOptions::DEFAULT_BOND_LENGTH / 2.0f; right.push_back(pos); @@ -400,8 +402,30 @@ void ReactionMultistepDetector::addPathwayZones(const Vec2f& head, const Vec2f& right.push_back(pos); pos.y += LayoutOptions::DEFAULT_BOND_LENGTH; right.push_back(pos); + + // form top agents zone + pos = head; + top.push_back(pos); + pos.x = sp_beg.x; + top.push_back(pos); + pos.y = sp_beg.y; + top.push_back(pos); + pos.x = head.x; + top.push_back(pos); + pos = head; + top.push_back(pos); + bottom.push_back(pos); + pos.y = sp_end.y; + bottom.push_back(pos); + pos.x = sp_end.x; + bottom.push_back(pos); + pos.y = head.y; + bottom.push_back(pos); + bottom.push_back(head); SPECIAL_ZONE_DESC szd; szd.zone_type = ZoneType::EPathWay; + szd.zone_sections.push_back(top); + szd.zone_sections.push_back(bottom); szd.zone_sections.push_back(right); szd.origin_coordinates.push_back(head); szd.origin_coordinates.push_back(sp_beg); @@ -446,6 +470,29 @@ std::map> ReactionMultistepDetector::findSpecialZon return result; } +std::optional> ReactionMultistepDetector::findMaxSpecialZone(size_t mol_idx) +{ + std::optional> result{}; + float max_containment = 0.0f; + auto& hull = _components[mol_idx].second; + for (int i = 0; i < static_cast(_zones.size()); ++i) + { + auto& zone = _zones[i]; + std::pair> cur_zone(i, {}); + for (int j = 0; j < static_cast(zone.zone_sections.size()); ++j) + { + auto& section = zone.zone_sections[j]; + float cont = computeConvexContainment(hull, section); + if (cont > max_containment) + { + max_containment = cont; + result = {i, j}; + } + } + } + return result; +} + void ReactionMultistepDetector::mergeCloseComponents() { for (std::size_t i = 0; i < _components.size(); ++i) @@ -454,6 +501,7 @@ void ReactionMultistepDetector::mergeCloseComponents() continue; std::queue bfs_queue; std::vector cluster; + std::optional> current_zone{}; bfs_queue.push(i); cluster.push_back(i); while (!bfs_queue.empty()) @@ -466,8 +514,10 @@ void ReactionMultistepDetector::mergeCloseComponents() continue; if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) continue; - if (isMergeable(idx, j)) + auto zone = isMergeable(idx, j, current_zone); + if (zone.has_value()) { + current_zone = zone; cluster.push_back(j); bfs_queue.push(j); } @@ -487,84 +537,77 @@ void ReactionMultistepDetector::mergeCloseComponents() _moleculeCount = (int)_components.size(); } -bool ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2) +std::optional> ReactionMultistepDetector::isMergeable(size_t mol_idx1, size_t mol_idx2, std::optional> current_zone) { - auto& mdi1 = _mol_distances[mol_idx1]; - auto& mdi2 = _mol_distances[mol_idx2]; - auto dist_it = mdi1.distances_map.find(mol_idx2); - if (dist_it != mdi1.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) + auto& mdi = _mol_distances[mol_idx1]; + auto dist_it = mdi.distances_map.find(mol_idx2); + if (dist_it != mdi.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) { // collect surrounding zones for both molecules - auto zones1 = findSpecialZones(mol_idx1); - auto zones2 = findSpecialZones(mol_idx2); - if (zones2.empty()) - return true; - - // find common zones - std::map> intersection; - std::set_intersection(zones1.begin(), zones1.end(), zones2.begin(), zones2.end(), std::inserter(intersection, intersection.begin()), - [](const auto& a, const auto& b) { return a.first < b.first; }); - - // if there are common zones check for opposite sections. if molecules are connected by opposite sections, they are not mergeable - for (auto& [key, values] : intersection) + auto zone1 = findMaxSpecialZone(mol_idx1); + auto zone2 = findMaxSpecialZone(mol_idx2); + // no zone - no reason to merge + if (zone1.has_value()) { - auto zones2_it = zones2.find(key); - if (zones2_it != zones2.end() && _zones[key].zone_type != ZoneType::EPathWay && - checkForOppositeSections(_zones[key].zone_type, values, zones2_it->second)) - return false; + // if both molecules has the same zone and section - merge + // we never merge molecules with different sections of the same zone + if (zone1.value().first == zone2.value().first) + return zone1.value().second == zone2.value().second ? zone1 : std::nullopt; + if (!current_zone.has_value()) + current_zone = zone1; } + else if (!current_zone.has_value()) + return std::nullopt; + + auto zidx = current_zone.value().first; + // if molecules have different zones - check if they are mergeable + auto& hull1 = _components[mol_idx1].second; + auto& hull2 = _components[mol_idx2].second; - if (intersection.empty()) + const auto& coords = _zones[zidx].origin_coordinates; + // check if both molecules are on the same zone continuation + switch (_zones[zidx].zone_type) { - std::map> zones_union; - std::set_union(zones1.begin(), zones1.end(), zones2.begin(), zones2.end(), std::inserter(zones_union, zones_union.begin()), - [](const auto& a, const auto& b) { return a.first < b.first; }); - // check if special zone affects both molecules - const auto& hull1 = _components[mol_idx1].second; - const auto& hull2 = _components[mol_idx2].second; - for (auto& [key, values] : zones_union) + case ZoneType::EPlus: + if ((doesVerticalLineIntersectPolygon(coords[0].x, hull1) && doesVerticalLineIntersectPolygon(coords[0].x, hull2)) || + (doesHorizontalLineIntersectPolygon(coords[0].x, hull1) && doesHorizontalLineIntersectPolygon(coords[0].x, hull2))) + return zone1; + break; + case ZoneType::EArrow: + if ((doesRayIntersectPolygon(coords[0], coords[1], hull1) && doesRayIntersectPolygon(coords[0], coords[1], hull2)) || + (doesRayIntersectPolygon(coords[1], coords[0], hull1) && doesRayIntersectPolygon(coords[1], coords[0], hull2))) + return zone1; + break; + case ZoneType::EPathWay: { + auto c_it = coords.begin(); + const Vec2f& head = *c_it++; + const Vec2f& spine_beg = *c_it++; + const Vec2f& spine_end = *c_it++; + Vec2f tail(spine_beg.x, head.y); + if (doesRayIntersectPolygon(tail, head, hull1) && doesRayIntersectPolygon(tail, head, hull2)) + return zone1; + for (; c_it != coords.end(); ++c_it) { - const auto& coords = _zones[key].origin_coordinates; - switch (_zones[key].zone_type) - { - case ZoneType::EPlus: - if ((doesVerticalLineIntersectPolygon(coords[0].x, hull1) && doesVerticalLineIntersectPolygon(coords[0].x, hull2)) || - (doesHorizontalLineIntersectPolygon(coords[0].x, hull1) && doesHorizontalLineIntersectPolygon(coords[0].x, hull2))) - return true; - break; - case ZoneType::EArrow: - if ((doesRayIntersectPolygon(coords[0], coords[1], hull1) && doesRayIntersectPolygon(coords[0], coords[1], hull2)) || - (doesRayIntersectPolygon(coords[1], coords[0], hull1) && doesRayIntersectPolygon(coords[1], coords[0], hull2))) - return true; - break; - case ZoneType::EPathWay: { - auto c_it = coords.begin(); - const Vec2f& head = *c_it++; - const Vec2f& spine_beg = *c_it++; - const Vec2f& spine_end = *c_it++; - Vec2f tail(spine_beg.x, head.y); - if (doesRayIntersectPolygon(tail, head, hull1) && doesRayIntersectPolygon(tail, head, hull2)) - return true; - for (; c_it != coords.end(); ++c_it) - { - Vec2f tail_start(spine_end.x, c_it->y); - if (doesRayIntersectPolygon(tail_start, *c_it, hull1) && doesRayIntersectPolygon(tail_start, *c_it, hull2)) - return true; - } - } - break; - } + Vec2f tail_start(spine_end.x, c_it->y); + if (doesRayIntersectPolygon(tail_start, *c_it, hull1) && doesRayIntersectPolygon(tail_start, *c_it, hull2)) + return zone1; } } + break; + } } - return false; + return std::nullopt; } -bool ReactionMultistepDetector::checkForOppositeSections(ZoneType /* zt */, const std::unordered_set& sections1, const std::unordered_set& sections2) +bool ReactionMultistepDetector::checkForOppositeSections(ZoneType zt, const std::unordered_set& sections1, const std::unordered_set& sections2) { for (int section1 : sections1) + { + if (zt == ZoneType::EPathWay && section1 > 1) // pathway has only 2 opposite agents sections + break; if (sections2.count(section1 ^ 1)) return true; + } return false; } From 0cc03e818c79cc9dd3b1e089557e8b86eec57a91 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 8 Jan 2025 11:37:27 +0100 Subject: [PATCH 11/27] step 3 --- core/indigo-core/common/math/algebra.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 11e031eab2..2da3212a52 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -30,8 +30,8 @@ #define SQR(x) ((x) * (x)) -#define DEG2RAD(x) ((x) * M_PI / 180) -#define RAD2DEG(x) ((x) * 180 / M_PI) +#define DEG2RAD(x) ((x)*M_PI / 180) +#define RAD2DEG(x) ((x)*180 / M_PI) #define HYPOT(a, b) (sqrt((a) * (a) + (b) * (b))) namespace indigo From 8ffa3be2a6d9cacdfdd5c9b29cca2938616e12e4 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 8 Jan 2025 11:47:24 +0100 Subject: [PATCH 12/27] step 3 --- .../reaction/src/reaction_multistep_detector.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 86267be5e9..db86cc6077 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -281,11 +281,11 @@ void ReactionMultistepDetector::createSpecialZones() for (int i = 0; i < _bmol.meta().getMetaCount(ReactionMultitailArrowObject::CID); ++i) { - auto& multi = (const ReactionMultitailArrowObject&)_bmol.meta().getMetaObject(ReactionMultitailArrowObject::CID, i); - auto& tails = multi.getTails(); - auto& head = multi.getHead(); - auto& spine_beg = multi.getSpineBegin(); - auto& spine_end = multi.getSpineEnd(); + const auto& multi = (const ReactionMultitailArrowObject&)_bmol.meta().getMetaObject(ReactionMultitailArrowObject::CID, i); + const auto& tails = multi.getTails(); + const auto& head = multi.getHead(); + const auto& spine_beg = multi.getSpineBegin(); + const auto& spine_end = multi.getSpineEnd(); std::vector tails_vec(tails.begin(), tails.end()); addPathwayZones(head, spine_beg, spine_end, tails_vec); } From 792403a85a2784c08e2e2ca6d2f0d3e0fad3aee3 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 8 Jan 2025 23:47:40 +0100 Subject: [PATCH 13/27] step 3 --- core/indigo-core/common/math/algebra.h | 5 ----- .../indigo-core/reaction/src/reaction_multistep_detector.cpp | 2 +- utils/indigo-depict/main.c | 3 ++- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 2da3212a52..2fb5e4b8aa 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -948,11 +948,6 @@ namespace indigo prev = curr; } } - - std::cout << "result: " << std::endl; - for (const auto& p : result) - std::cout << p.x << " " << p.y << std::endl; - return result; } diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index db86cc6077..20ef028884 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -551,7 +551,7 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t { // if both molecules has the same zone and section - merge // we never merge molecules with different sections of the same zone - if (zone1.value().first == zone2.value().first) + if (zone2.has_value() && zone1.value().first == zone2.value().first) return zone1.value().second == zone2.value().second ? zone1 : std::nullopt; if (!current_zone.has_value()) current_zone = zone1; diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 74f0c58b84..46bee95196 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -869,6 +869,7 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); indigoSetOptionBool("json-saving-pretty", "on"); + indigoSetOptionFloat("reaction-component-margin-size", 0.0f); if (parseParams(&p, argc, argv) < 0) return -1; @@ -1058,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - indigoLayout(obj); + // indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From 87b661e6417832f2dd2c82b18dfb2cdd8719c7f5 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 00:02:42 +0100 Subject: [PATCH 14/27] step 3 --- core/indigo-core/reaction/src/reaction_json_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 35a0ec7867..4a630ec30c 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -72,7 +72,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) if (arrow_count == 0 && multi_count == 0) throw Error("No arrow in the reaction"); - if (arrow_count > 0 || multi_count > 0) + if (arrow_count > 1 || multi_count > 0) { ReactionMultistepDetector md(*_pmol); switch (md.detectReaction()) From 2d0f08eef4169ec7e25417f5c10cec48d50d37a0 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 11:36:45 +0100 Subject: [PATCH 15/27] step 3 --- core/indigo-core/common/math/algebra.h | 16 +++++++--- .../src/reaction_multistep_detector.cpp | 31 ++++++++++++------- utils/indigo-depict/main.c | 2 +- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 2fb5e4b8aa..79649d600e 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -1034,12 +1034,20 @@ namespace indigo inline bool doesRayIntersectPolygon(const Vec2f& p1, const Vec2f& p2, const std::vector& poly) { - Vec2f dir = {p2.x - p1.x, p2.y - p1.y}; + Vec2f dir = p2 - p1; for (size_t i = 0, n = poly.size(); i < n; ++i) { - Vec2f a = {poly[i].x - p1.x, poly[i].y - p1.y}; - Vec2f b = {poly[(i + 1) % n].x - p1.x, poly[(i + 1) % n].y - p1.y}; - if (Vec2f::cross(dir, a) * Vec2f::cross(dir, b) < 0 && Vec2f::cross(a, b) * Vec2f::cross(a, dir) < 0) + Vec2f A = poly[i]; + Vec2f B = poly[(i + 1) % n]; + Vec2f a = A - p1; + Vec2f b = B - p1; + Vec2f s = b - a; + float den = Vec2f::cross(dir, s); + if (std::fabs(den) <= +0.0f) + continue; + float t = Vec2f::cross(a, s) / den; + float u = Vec2f::cross(a, dir) / den; + if (t >= 0.f && u >= 0.f && u <= 1.f) return true; } return false; diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 20ef028884..bd04a85403 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -499,27 +499,26 @@ void ReactionMultistepDetector::mergeCloseComponents() { if (!_components[i].first) continue; - std::queue bfs_queue; + std::queue>>> bfs_queue; std::vector cluster; - std::optional> current_zone{}; - bfs_queue.push(i); + bfs_queue.emplace(i, std::nullopt); cluster.push_back(i); while (!bfs_queue.empty()) { - auto idx = bfs_queue.front(); + auto qel = bfs_queue.front(); bfs_queue.pop(); for (std::size_t j = 0; j < _components.size(); ++j) { - if (!_components[j].first || j == idx) + if (!_components[j].first || j == qel.first) continue; if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) continue; - auto zone = isMergeable(idx, j, current_zone); + auto zone = isMergeable(qel.first, j, qel.second); + std::cout << qel.first << " " << j << " " << zone.has_value() << std::endl; if (zone.has_value()) { - current_zone = zone; cluster.push_back(j); - bfs_queue.push(j); + bfs_queue.emplace(j, zone); } } } @@ -571,12 +570,12 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t case ZoneType::EPlus: if ((doesVerticalLineIntersectPolygon(coords[0].x, hull1) && doesVerticalLineIntersectPolygon(coords[0].x, hull2)) || (doesHorizontalLineIntersectPolygon(coords[0].x, hull1) && doesHorizontalLineIntersectPolygon(coords[0].x, hull2))) - return zone1; + return zone1 ? zone1 : current_zone; break; case ZoneType::EArrow: if ((doesRayIntersectPolygon(coords[0], coords[1], hull1) && doesRayIntersectPolygon(coords[0], coords[1], hull2)) || (doesRayIntersectPolygon(coords[1], coords[0], hull1) && doesRayIntersectPolygon(coords[1], coords[0], hull2))) - return zone1; + return zone1 ? zone1 : current_zone; break; case ZoneType::EPathWay: { auto c_it = coords.begin(); @@ -584,13 +583,21 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t const Vec2f& spine_beg = *c_it++; const Vec2f& spine_end = *c_it++; Vec2f tail(spine_beg.x, head.y); + if (mol_idx1 == 3 && mol_idx2 == 4) + { + std::cout << "p1: " << tail.x << " " << tail.y << std::endl; + std::cout << "p2: " << head.x << " " << head.y << std::endl; + std::cout << "polygon: " << std::endl; + for (auto& p : hull1) + std::cout << p.x << " " << p.y << std::endl; + } if (doesRayIntersectPolygon(tail, head, hull1) && doesRayIntersectPolygon(tail, head, hull2)) - return zone1; + return zone1 ? zone1 : current_zone; for (; c_it != coords.end(); ++c_it) { Vec2f tail_start(spine_end.x, c_it->y); if (doesRayIntersectPolygon(tail_start, *c_it, hull1) && doesRayIntersectPolygon(tail_start, *c_it, hull2)) - return zone1; + return zone1 ? zone1 : current_zone; } } break; diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 46bee95196..6febc5b518 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1059,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - // indigoLayout(obj); + //indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From c02ddbc77539e09c3dfd990d25b31255f1401b91 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 11:39:20 +0100 Subject: [PATCH 16/27] step 3 --- utils/indigo-depict/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 6febc5b518..b420a7360c 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1059,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - //indigoLayout(obj); + indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From 008d2ccb721a1f6675253ddb4ece28252545f44d Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 11:41:00 +0100 Subject: [PATCH 17/27] step 3 --- .../reaction/src/reaction_multistep_detector.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index bd04a85403..4c3a9370b4 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -583,14 +583,6 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t const Vec2f& spine_beg = *c_it++; const Vec2f& spine_end = *c_it++; Vec2f tail(spine_beg.x, head.y); - if (mol_idx1 == 3 && mol_idx2 == 4) - { - std::cout << "p1: " << tail.x << " " << tail.y << std::endl; - std::cout << "p2: " << head.x << " " << head.y << std::endl; - std::cout << "polygon: " << std::endl; - for (auto& p : hull1) - std::cout << p.x << " " << p.y << std::endl; - } if (doesRayIntersectPolygon(tail, head, hull1) && doesRayIntersectPolygon(tail, head, hull2)) return zone1 ? zone1 : current_zone; for (; c_it != coords.end(); ++c_it) From 60af8c645b2b1dde895b16cdeee9632af47a68a5 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 11:59:18 +0100 Subject: [PATCH 18/27] step 3 --- .../formats/reactions/pathway_merge1.ket | 1538 +++++++++++++++++ .../src/reaction_multistep_detector.cpp | 1 - 2 files changed, 1538 insertions(+), 1 deletion(-) create mode 100644 api/tests/integration/tests/formats/reactions/pathway_merge1.ket diff --git a/api/tests/integration/tests/formats/reactions/pathway_merge1.ket b/api/tests/integration/tests/formats/reactions/pathway_merge1.ket new file mode 100644 index 0000000000..46f8944b43 --- /dev/null +++ b/api/tests/integration/tests/formats/reactions/pathway_merge1.ket @@ -0,0 +1,1538 @@ +{ + "root": { + "nodes": [ + { + "$ref": "mol0" + }, + { + "$ref": "mol1" + }, + { + "$ref": "mol2" + }, + { + "$ref": "mol3" + }, + { + "$ref": "mol4" + }, + { + "$ref": "mol5" + }, + { + "type": "multi-tailed-arrow", + "data": { + "head": { + "position": { + "x": 14.0, + "y": -8.774066925048829, + "z": 0.0 + } + }, + "spine": { + "pos": [ + { + "x": 7.5, + "y": -3.2660446166992189, + "z": 0.0 + }, + { + "x": 7.5, + "y": -14.282089233398438, + "z": 0.0 + } + ] + }, + "tails": { + "pos": [ + { + "x": 7.0, + "y": -3.2660446166992189, + "z": 0.0 + }, + { + "x": 7.0, + "y": -9.032089233398438, + "z": 0.0 + }, + { + "x": 7.0, + "y": -14.282089233398438, + "z": 0.0 + } + ] + }, + "zOrder": 0 + } + } + ] + }, + "mol0": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 2.291954278945923, + -4.705737113952637, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.708045482635498, + -1.8263521194458008, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.8572123050689699, + -5.0320892333984379, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.291954278945923, + -1.8263518810272217, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.142787933349609, + -1.500000238418579, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.6491668224334717, + -3.5923962593078615, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.633974552154541, + -3.7660446166992189, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.366025447845459, + -2.7660446166992189, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 5.350832939147949, + -2.939692497253418, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.70804500579834, + -4.705737590789795, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.142787456512451, + -5.0320892333984379, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 3.5, + -4.266044616699219, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 3.5, + -2.2660446166992189, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.8572120666503908, + -1.500000238418579, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.633974552154541, + -2.7660446166992189, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.6491668224334717, + -2.939692974090576, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 5.350832939147949, + -3.5923964977264406, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.366024971008301, + -3.7660446166992189, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 6, + 14 + ] + }, + { + "type": 1, + "atoms": [ + 14, + 12 + ] + }, + { + "type": 1, + "atoms": [ + 12, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 17 + ] + }, + { + "type": 1, + "atoms": [ + 17, + 11 + ] + }, + { + "type": 1, + "atoms": [ + 11, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 11, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 14, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 12 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 8 + ] + }, + { + "type": 1, + "atoms": [ + 9, + 17 + ] + }, + { + "type": 1, + "atoms": [ + 10, + 11 + ] + }, + { + "type": 1, + "atoms": [ + 12, + 13 + ] + }, + { + "type": 1, + "atoms": [ + 14, + 15 + ] + }, + { + "type": 1, + "atoms": [ + 16, + 17 + ] + } + ] + }, + "mol1": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 2.633974552154541, + -10.532089233398438, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 3.5, + -10.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.366025447845459, + -10.532089233398438, + 0.0 + ] + }, + { + "label": "P", + "location": [ + 3.5, + -9.032089233398438, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 2.633974552154541, + -8.532089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.767949104309082, + -9.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.633974075317383, + -7.5320892333984379, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 4.366025447845459, + -8.532089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 5.232050895690918, + -9.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.366024971008301, + -7.5320892333984379, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 8 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 9 + ] + } + ] + }, + "mol2": { + "type": "molecule", + "atoms": [ + { + "label": "Si", + "location": [ + 3.5, + -14.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 3.500000476837158, + -15.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 3.5, + -13.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.366025924682617, + -15.532089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.633975028991699, + -15.532089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.5, + -14.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 2.0, + -13.166064262390137, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.0, + -13.166064262390137, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.9999998807907105, + -14.898115158081055, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 1.0, + -14.898115158081055, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 0.5, + -14.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 4.5, + -14.032089233398438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 5.0, + -14.898115158081055, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 6.0, + -14.898114204406739, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 5.0, + -13.16606330871582, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 6.0, + -13.16606330871582, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 6.5, + -14.032089233398438, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 6, + 5 + ] + }, + { + "type": 2, + "atoms": [ + 6, + 7 + ] + }, + { + "type": 2, + "atoms": [ + 5, + 8 + ] + }, + { + "type": 1, + "atoms": [ + 8, + 9 + ] + }, + { + "type": 2, + "atoms": [ + 9, + 10 + ] + }, + { + "type": 1, + "atoms": [ + 10, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 11 + ] + }, + { + "type": 1, + "atoms": [ + 12, + 11 + ] + }, + { + "type": 2, + "atoms": [ + 12, + 13 + ] + }, + { + "type": 2, + "atoms": [ + 11, + 14 + ] + }, + { + "type": 1, + "atoms": [ + 14, + 15 + ] + }, + { + "type": 2, + "atoms": [ + 15, + 16 + ] + }, + { + "type": 1, + "atoms": [ + 16, + 13 + ] + } + ], + "sgroups": [ + { + "type": "SUP", + "atoms": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "name": "TBDPS", + "expanded": true, + "attachmentPoints": [ + { + "attachmentAtom": 0, + "attachmentId": " 1" + } + ] + } + ] + }, + "mol3": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 14.500000953674317, + -9.524066925048829, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 15.366025924682618, + -9.024066925048829, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 15.366025924682618, + -8.024066925048829, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 16.232051849365236, + -9.524066925048829, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 17.09807586669922, + -9.024066925048829, + 0.0 + ] + }, + { + "label": "S", + "location": [ + 17.964101791381837, + -8.524066925048829, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 2, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 2, + "atoms": [ + 4, + 5 + ] + } + ] + }, + "mol4": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 20.248552322387697, + -9.84934139251709, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 19.941761016845704, + -8.897564888000489, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 18.964101791381837, + -8.687366485595704, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 20.612627029418947, + -8.155986785888672, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 21.590286254882814, + -8.36618423461914, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 22.334991455078126, + -7.698792457580566, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 23.199846267700197, + -8.20081615447998, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 24.151622772216798, + -7.894023895263672, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 24.89320182800293, + -8.564889907836914, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 24.683002471923829, + -9.542549133300782, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 23.731225967407228, + -9.84934139251709, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 22.989648818969728, + -9.178475379943848, + 0.0 + ] + }, + { + "label": "O", + "location": [ + 21.994884490966798, + -9.280677795410157, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 4, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 4, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 4, + "atoms": [ + 6, + 7 + ] + }, + { + "type": 4, + "atoms": [ + 7, + 8 + ] + }, + { + "type": 4, + "atoms": [ + 8, + 9 + ] + }, + { + "type": 4, + "atoms": [ + 9, + 10 + ] + }, + { + "type": 4, + "atoms": [ + 10, + 11 + ] + }, + { + "type": 4, + "atoms": [ + 11, + 12 + ] + }, + { + "type": 4, + "atoms": [ + 12, + 4 + ] + }, + { + "type": 4, + "atoms": [ + 11, + 6 + ] + } + ] + }, + "mol5": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 35.228172302246097, + -6.782937049865723, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 34.38882827758789, + -7.326540946960449, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 33.498382568359378, + -6.8714518547058109, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 34.43993377685547, + -8.325234413146973, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 33.60059356689453, + -8.868839263916016, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 32.71014404296875, + -8.413749694824219, + 0.0 + ] + }, + { + "label": "O", + "location": [ + 32.65904235839844, + -7.415056228637695, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 31.870803833007814, + -8.957353591918946, + 0.0 + ] + }, + { + "label": "O", + "location": [ + 30.980358123779298, + -8.502264976501465, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 30.141016006469728, + -9.045869827270508, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 30.192119598388673, + -10.044562339782715, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 29.352779388427736, + -10.588167190551758, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 28.46233367919922, + -10.133077621459961, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 27.62299156188965, + -10.676682472229004, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 26.7325439453125, + -10.221592903137207, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 26.681442260742189, + -9.222900390625, + 0.0 + ] + }, + { + "label": "O", + "location": [ + 25.893203735351564, + -10.76519775390625, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 28.41122817993164, + -9.134384155273438, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 29.25057029724121, + -8.590780258178711, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 35.330379486083987, + -8.780323028564454, + 0.0 + ] + }, + { + "label": "N", + "location": [ + 36.221946716308597, + -8.327431678771973, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 36.92818069458008, + -9.035409927368164, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 37.92687225341797, + -8.984305381774903, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 38.47047805786133, + -9.823647499084473, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 38.01538848876953, + -10.714093208312989, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 37.016693115234378, + -10.76519775390625, + 0.0 + ] + }, + { + "label": "C", + "location": [ + 36.47309112548828, + -9.92585563659668, + 0.0 + ] + }, + { + "label": "O", + "location": [ + 35.485595703125, + -9.768203735351563, + 0.0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 8 + ] + }, + { + "type": 1, + "atoms": [ + 8, + 9 + ] + }, + { + "type": 4, + "atoms": [ + 9, + 10 + ] + }, + { + "type": 4, + "atoms": [ + 10, + 11 + ] + }, + { + "type": 4, + "atoms": [ + 11, + 12 + ] + }, + { + "type": 1, + "atoms": [ + 12, + 13 + ] + }, + { + "type": 1, + "atoms": [ + 13, + 14 + ] + }, + { + "type": 1, + "atoms": [ + 14, + 15 + ] + }, + { + "type": 2, + "atoms": [ + 14, + 16 + ] + }, + { + "type": 4, + "atoms": [ + 12, + 17 + ] + }, + { + "type": 4, + "atoms": [ + 17, + 18 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 19 + ] + }, + { + "type": 4, + "atoms": [ + 19, + 20 + ] + }, + { + "type": 4, + "atoms": [ + 20, + 21 + ] + }, + { + "type": 4, + "atoms": [ + 21, + 22 + ] + }, + { + "type": 4, + "atoms": [ + 22, + 23 + ] + }, + { + "type": 4, + "atoms": [ + 23, + 24 + ] + }, + { + "type": 4, + "atoms": [ + 24, + 25 + ] + }, + { + "type": 4, + "atoms": [ + 25, + 26 + ] + }, + { + "type": 4, + "atoms": [ + 26, + 27 + ] + }, + { + "type": 4, + "atoms": [ + 18, + 9 + ] + }, + { + "type": 4, + "atoms": [ + 27, + 19 + ] + }, + { + "type": 4, + "atoms": [ + 26, + 21 + ] + } + ] + } +} \ No newline at end of file diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 4c3a9370b4..09e54d0710 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -514,7 +514,6 @@ void ReactionMultistepDetector::mergeCloseComponents() if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) continue; auto zone = isMergeable(qel.first, j, qel.second); - std::cout << qel.first << " " << j << " " << zone.has_value() << std::endl; if (zone.has_value()) { cluster.push_back(j); From 496cf10a856c51ff72b67ae2762601bf1205cf92 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 12:11:18 +0100 Subject: [PATCH 19/27] step 3 --- .../integration/ref/formats/ket_to_rdf.py.out | 1 + .../integration/tests/formats/ket_to_rdf.py | 1 + .../tests/formats/ref/pathway10.rdf | 234 +++++++++++------- .../tests/formats/ref/pathway_merge1.rdf | 230 +++++++++++++++++ 4 files changed, 378 insertions(+), 88 deletions(-) create mode 100644 api/tests/integration/tests/formats/ref/pathway_merge1.rdf diff --git a/api/tests/integration/ref/formats/ket_to_rdf.py.out b/api/tests/integration/ref/formats/ket_to_rdf.py.out index 9ad5628411..7cfe450ee8 100644 --- a/api/tests/integration/ref/formats/ket_to_rdf.py.out +++ b/api/tests/integration/ref/formats/ket_to_rdf.py.out @@ -13,3 +13,4 @@ pathway6.rdf:SUCCEED pathway7.rdf:SUCCEED pathway8.rdf:SUCCEED pathway9.rdf:SUCCEED +pathway_merge1.rdf:SUCCEED diff --git a/api/tests/integration/tests/formats/ket_to_rdf.py b/api/tests/integration/tests/formats/ket_to_rdf.py index 7c3f8aec7b..0048f85829 100644 --- a/api/tests/integration/tests/formats/ket_to_rdf.py +++ b/api/tests/integration/tests/formats/ket_to_rdf.py @@ -39,6 +39,7 @@ def find_diff(a, b): "pathway10", "pathway11", "pathway12", + "pathway_merge1" ] files.sort() diff --git a/api/tests/integration/tests/formats/ref/pathway10.rdf b/api/tests/integration/tests/formats/ref/pathway10.rdf index 2f76d9307d..440f9b8aa8 100644 --- a/api/tests/integration/tests/formats/ref/pathway10.rdf +++ b/api/tests/integration/tests/formats/ref/pathway10.rdf @@ -7,118 +7,70 @@ $RXN -INDIGO- 0100000000 - 7 3 + 2 1 $MOL -INDIGO-01000000002D - 5 5 0 0 0 0 0 0 0 0999 V2000 - 1.7303 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.7266 0.9951 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7183 0.0129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7158 0.9951 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.0087 1.7022 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 1 0 0 0 0 - 2 4 1 0 0 0 0 - 4 3 1 0 0 0 0 - 3 1 1 0 0 0 0 - 4 5 1 0 0 0 0 -M END -$MOL - - -INDIGO-01000000002D - - 4 4 0 0 0 0 0 0 0 0999 V2000 - 0.7290 4.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.7303 4.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.2297 5.0671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.2297 6.0671 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 1 0 0 0 0 - 2 3 1 0 0 0 0 - 3 1 1 0 0 0 0 - 3 4 1 0 0 0 0 -M END -$MOL - - -INDIGO-01000000002D - - 5 5 0 0 0 0 0 0 0 0999 V2000 - 0.9207 10.1072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.4211 8.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.7303 9.5133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.4203 8.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.1110 9.5133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1 5 1 0 0 0 0 - 5 4 2 0 0 0 0 - 4 2 1 0 0 0 0 - 2 3 2 0 0 0 0 - 3 1 1 0 0 0 0 -M END -$MOL - - -INDIGO-01000000002D - - 6 6 0 0 0 0 0 0 0 0999 V2000 - 0.0000 14.1071 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.7303 14.1076 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.8668 14.6072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1.7303 13.1067 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.0000 13.1022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.8690 12.6072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 3 1 2 0 0 0 0 - 1 5 1 0 0 0 0 - 5 6 2 0 0 0 0 - 6 4 1 0 0 0 0 - 4 2 2 0 0 0 0 - 2 3 1 0 0 0 0 -M END -$MOL - - -INDIGO-01000000002D - - 4 4 0 0 0 0 0 0 0 0999 V2000 - 7.8497 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 8.8509 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 8.3504 2.5878 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 8.6092 3.5537 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 1 0 0 0 0 - 2 3 1 0 0 0 0 - 3 1 1 0 0 0 0 - 3 4 1 0 0 0 0 -M END -$MOL - - -INDIGO-01000000002D - - 6 6 0 0 0 0 0 0 0 0999 V2000 + 11 11 0 0 0 0 0 0 0 0999 V2000 9.8367 11.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 9.8367 10.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 10.7027 10.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 11.5687 10.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 11.5687 11.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 10.7027 12.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8745 10.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8708 11.4673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8626 10.4851 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8601 11.4673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8367 11.7261 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0 6 1 1 0 0 0 0 1 2 1 0 0 0 0 2 3 1 0 0 0 0 3 4 1 0 0 0 0 4 5 1 0 0 0 0 5 6 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 10 1 0 0 0 0 + 10 9 1 0 0 0 0 + 9 7 1 0 0 0 0 + 8 11 1 0 0 0 0 M END $MOL -INDIGO-01000000002D - 5 5 0 0 0 0 0 0 0 0999 V2000 + 15 15 0 0 0 0 0 0 0 0999 V2000 10.8653 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 10.8616 2.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 9.8534 1.7357 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 9.8509 2.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 11.5687 3.4250 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8497 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8509 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3504 2.5878 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6092 3.5537 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0401 3.2629 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5405 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8497 2.6691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5397 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2303 2.6691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0401 4.2629 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 2 4 1 0 0 0 0 4 3 1 0 0 0 0 3 1 1 0 0 0 0 2 5 1 0 0 0 0 + 6 7 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 6 1 0 0 0 0 + 8 9 1 0 0 0 0 + 10 14 1 0 0 0 0 + 14 13 2 0 0 0 0 + 13 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 15 1 0 0 0 0 M END $MOL @@ -150,37 +102,143 @@ $MOL 9 3 1 6 0 0 0 10 4 1 6 0 0 0 M END +$RFMT +$RXN + + -INDIGO- 0100000000 + + 2 1 $MOL -INDIGO-01000000002D - 6 6 0 0 0 0 0 0 0 0999 V2000 + 4 4 0 0 0 0 0 0 0 0999 V2000 + 0.7290 4.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7303 4.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2297 5.0671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2297 6.0671 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 1 1 0 0 0 0 + 3 4 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 1.7303 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7266 0.9951 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7183 0.0129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7158 0.9951 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0087 1.7022 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 4 1 0 0 0 0 + 4 3 1 0 0 0 0 + 3 1 1 0 0 0 0 + 4 5 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 15 15 0 0 0 0 0 0 0 0999 V2000 + 10.8653 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8616 2.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8534 1.7357 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8509 2.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5687 3.4250 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8497 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8509 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3504 2.5878 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6092 3.5537 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 6.0401 3.2629 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.5405 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.8497 2.6691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.5397 1.7228 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 5.2303 2.6691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.0401 4.2629 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 4 1 0 0 0 0 + 4 3 1 0 0 0 0 + 3 1 1 0 0 0 0 + 2 5 1 0 0 0 0 + 6 7 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 6 1 0 0 0 0 + 8 9 1 0 0 0 0 + 10 14 1 0 0 0 0 + 14 13 2 0 0 0 0 + 13 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 15 1 0 0 0 0 +M END +$RFMT +$RXN + + -INDIGO- 0100000000 + + 2 1 +$MOL + + -INDIGO-01000000002D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 0.0000 14.1071 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7303 14.1076 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8668 14.6072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7303 13.1067 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0000 13.1022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8690 12.6072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3 1 2 0 0 0 0 + 1 5 1 0 0 0 0 + 5 6 2 0 0 0 0 + 6 4 1 0 0 0 0 + 4 2 2 0 0 0 0 + 2 3 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 0.9207 10.1072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4211 8.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7303 9.5133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4203 8.5671 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.1110 9.5133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 5 1 0 0 0 0 5 4 2 0 0 0 0 4 2 1 0 0 0 0 2 3 2 0 0 0 0 3 1 1 0 0 0 0 - 1 6 1 0 0 0 0 M END $MOL -INDIGO-01000000002D - 5 5 0 0 0 0 0 0 0 0999 V2000 + 11 11 0 0 0 0 0 0 0 0999 V2000 + 9.8367 11.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8367 10.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7027 10.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5687 10.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.5687 11.9722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7027 12.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 7.8745 10.4722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 7.8708 11.4673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.8626 10.4851 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 6.8601 11.4673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 8.8367 11.7261 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0 + 6 1 1 0 0 0 0 1 2 1 0 0 0 0 - 2 4 1 0 0 0 0 - 4 3 1 0 0 0 0 - 3 1 1 0 0 0 0 - 2 5 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 6 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 10 1 0 0 0 0 + 10 9 1 0 0 0 0 + 9 7 1 0 0 0 0 + 8 11 1 0 0 0 0 M END diff --git a/api/tests/integration/tests/formats/ref/pathway_merge1.rdf b/api/tests/integration/tests/formats/ref/pathway_merge1.rdf new file mode 100644 index 0000000000..72103f790f --- /dev/null +++ b/api/tests/integration/tests/formats/ref/pathway_merge1.rdf @@ -0,0 +1,230 @@ +$RDFILE 1 +$DATM 01/00/00 00:00 +$RDFILE 1 +$DATM 01/00/00 00:00 +$RFMT +$RXN + + -INDIGO- 0100000000 + + 3 1 +$MOL + + -INDIGO-01000000002D + + 18 18 0 0 0 0 0 0 0 0999 V2000 + 2.2920 -4.7057 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7080 -1.8264 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8572 -5.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2920 -1.8264 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1428 -1.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6492 -3.5924 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6340 -3.7660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -2.7660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3508 -2.9397 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7080 -4.7057 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1428 -5.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -4.2660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -2.2660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8572 -1.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6340 -2.7660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6492 -2.9397 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3508 -3.5924 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -3.7660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7 15 1 0 0 0 0 + 15 13 1 0 0 0 0 + 13 8 1 0 0 0 0 + 8 18 1 0 0 0 0 + 18 12 1 0 0 0 0 + 12 7 1 0 0 0 0 + 1 7 1 0 0 0 0 + 8 2 1 0 0 0 0 + 12 3 1 0 0 0 0 + 15 4 1 0 0 0 0 + 5 13 1 0 0 0 0 + 6 7 1 0 0 0 0 + 8 9 1 0 0 0 0 + 10 18 1 0 0 0 0 + 11 12 1 0 0 0 0 + 13 14 1 0 0 0 0 + 15 16 1 0 0 0 0 + 17 18 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 10 9 0 0 0 0 0 0 0 0999 V2000 + 2.6340 -10.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -10.0321 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -10.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -9.0321 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6340 -8.5321 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7679 -9.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6340 -7.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -8.5321 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2321 -9.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -7.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 2 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 6 1 0 0 0 0 + 5 7 1 0 0 0 0 + 4 8 1 0 0 0 0 + 8 9 1 0 0 0 0 + 8 10 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 17 18 0 0 0 0 0 0 0 0999 V2000 + 3.5000 -14.0321 0.0000 Si 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -15.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5000 -13.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3660 -15.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6340 -15.5321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5000 -14.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0000 -13.1661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0000 -13.1661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0000 -14.8981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0000 -14.8981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5000 -14.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5000 -14.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0000 -14.8981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0000 -14.8981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0000 -13.1661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0000 -13.1661 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5000 -14.0321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 1 3 1 0 0 0 0 + 2 4 1 0 0 0 0 + 2 5 1 0 0 0 0 + 1 6 1 0 0 0 0 + 7 6 1 0 0 0 0 + 7 8 2 0 0 0 0 + 6 9 2 0 0 0 0 + 9 10 1 0 0 0 0 + 10 11 2 0 0 0 0 + 11 8 1 0 0 0 0 + 1 12 1 0 0 0 0 + 13 12 1 0 0 0 0 + 13 14 2 0 0 0 0 + 12 15 2 0 0 0 0 + 15 16 1 0 0 0 0 + 16 17 2 0 0 0 0 + 17 14 1 0 0 0 0 +M STY 1 1 SUP +M SLB 1 1 1 +M SAL 1 8 1 2 3 4 5 6 7 8 +M SAL 1 8 9 10 11 12 13 14 15 16 +M SAL 1 1 17 +M SMT 1 TBDPS +M SDS EXP 1 1 +M SAP 1 1 1 0 1 +M SDI 1 4 0.0000 0.0000 0.0000 0.0000 +M SDI 1 4 0.0000 0.0000 0.0000 0.0000 +M END +$MOL + + -INDIGO-01000000002D + + 47 49 0 0 0 0 0 0 0 0999 V2000 + 14.5000 -9.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3660 -9.0241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3660 -8.0241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.2321 -9.5241 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0981 -9.0241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9641 -8.5241 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0 + 20.2486 -9.8493 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.9418 -8.8976 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.9641 -8.6874 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.6126 -8.1560 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 21.5903 -8.3662 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.3350 -7.6988 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 23.1998 -8.2008 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.1516 -7.8940 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.8932 -8.5649 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.6830 -9.5425 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.7312 -9.8493 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.9896 -9.1785 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.9949 -9.2807 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 35.2282 -6.7829 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 34.3888 -7.3265 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 33.4984 -6.8715 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 34.4399 -8.3252 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 33.6006 -8.8688 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 32.7101 -8.4137 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 32.6590 -7.4151 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 31.8708 -8.9574 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.9804 -8.5023 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 30.1410 -9.0459 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.1921 -10.0446 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.3528 -10.5882 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.4623 -10.1331 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6230 -10.6767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.7325 -10.2216 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.6814 -9.2229 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 25.8932 -10.7652 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 28.4112 -9.1344 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.2506 -8.5908 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 35.3304 -8.7803 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 36.2219 -8.3274 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 36.9282 -9.0354 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 37.9269 -8.9843 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 38.4705 -9.8236 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 38.0154 -10.7141 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 37.0167 -10.7652 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 36.4731 -9.9259 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 35.4856 -9.7682 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 2 4 1 0 0 0 0 + 4 5 2 0 0 0 0 + 5 6 2 0 0 0 0 + 7 8 1 0 0 0 0 + 8 9 1 0 0 0 0 + 8 10 1 0 0 0 0 + 10 11 1 0 0 0 0 + 11 12 4 0 0 0 0 + 12 13 4 0 0 0 0 + 13 14 4 0 0 0 0 + 14 15 4 0 0 0 0 + 15 16 4 0 0 0 0 + 16 17 4 0 0 0 0 + 17 18 4 0 0 0 0 + 18 19 4 0 0 0 0 + 19 11 4 0 0 0 0 + 18 13 4 0 0 0 0 + 20 21 1 0 0 0 0 + 21 22 1 0 0 0 0 + 21 23 1 0 0 0 0 + 23 24 1 0 0 0 0 + 24 25 1 0 0 0 0 + 25 26 1 0 0 0 0 + 25 27 1 0 0 0 0 + 27 28 1 0 0 0 0 + 28 29 1 0 0 0 0 + 29 30 4 0 0 0 0 + 30 31 4 0 0 0 0 + 31 32 4 0 0 0 0 + 32 33 1 0 0 0 0 + 33 34 1 0 0 0 0 + 34 35 1 0 0 0 0 + 34 36 2 0 0 0 0 + 32 37 4 0 0 0 0 + 37 38 4 0 0 0 0 + 23 39 1 0 0 0 0 + 39 40 4 0 0 0 0 + 40 41 4 0 0 0 0 + 41 42 4 0 0 0 0 + 42 43 4 0 0 0 0 + 43 44 4 0 0 0 0 + 44 45 4 0 0 0 0 + 45 46 4 0 0 0 0 + 46 47 4 0 0 0 0 + 38 29 4 0 0 0 0 + 47 39 4 0 0 0 0 + 46 41 4 0 0 0 0 +M END From c0a2308749c5aa36a622b253eb39100b69553aa9 Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 12:25:52 +0100 Subject: [PATCH 20/27] step 3 --- .../integration/ref/formats/ket_to_rdf.py.out | 1 + .../integration/tests/formats/ket_to_rdf.py | 3 +- .../formats/reactions/pathway_merge2.ket | 861 ++++++++++++++++++ 3 files changed, 864 insertions(+), 1 deletion(-) create mode 100644 api/tests/integration/tests/formats/reactions/pathway_merge2.ket diff --git a/api/tests/integration/ref/formats/ket_to_rdf.py.out b/api/tests/integration/ref/formats/ket_to_rdf.py.out index 7cfe450ee8..61c3346bc0 100644 --- a/api/tests/integration/ref/formats/ket_to_rdf.py.out +++ b/api/tests/integration/ref/formats/ket_to_rdf.py.out @@ -14,3 +14,4 @@ pathway7.rdf:SUCCEED pathway8.rdf:SUCCEED pathway9.rdf:SUCCEED pathway_merge1.rdf:SUCCEED +pathway_merge2.rdf:SUCCEED diff --git a/api/tests/integration/tests/formats/ket_to_rdf.py b/api/tests/integration/tests/formats/ket_to_rdf.py index 0048f85829..6a34509d8f 100644 --- a/api/tests/integration/tests/formats/ket_to_rdf.py +++ b/api/tests/integration/tests/formats/ket_to_rdf.py @@ -39,7 +39,8 @@ def find_diff(a, b): "pathway10", "pathway11", "pathway12", - "pathway_merge1" + "pathway_merge1", + "pathway_merge2" ] files.sort() diff --git a/api/tests/integration/tests/formats/reactions/pathway_merge2.ket b/api/tests/integration/tests/formats/reactions/pathway_merge2.ket new file mode 100644 index 0000000000..f02658cd39 --- /dev/null +++ b/api/tests/integration/tests/formats/reactions/pathway_merge2.ket @@ -0,0 +1,861 @@ +{ + "root": { + "nodes": [ + { + "$ref": "mol0" + }, + { + "$ref": "mol1" + }, + { + "$ref": "mol2" + }, + { + "$ref": "mol3" + }, + { + "$ref": "mol4" + }, + { + "$ref": "mol5" + }, + { + "$ref": "mol6" + }, + { + "$ref": "mol7" + }, + { + "$ref": "mol8" + }, + { + "$ref": "mol9" + }, + { + "$ref": "mol10" + }, + { + "type": "arrow", + "data": { + "mode": "open-angle", + "pos": [ + { + "x": 15.700000000000001, + "y": -0.9428649902343751, + "z": 0 + }, + { + "x": 18.125515409145038, + "y": -0.9428649902343751, + "z": 0 + } + ] + } + }, + { + "type": "plus", + "location": [ + 13.175000000000002, + -0.8928649902343748, + 0 + ], + "prop": {} + }, + { + "type": "plus", + "location": [ + 20.55, + -0.992864990234375, + 0 + ], + "prop": {} + }, + { + "type": "multi-tailed-arrow", + "data": { + "head": { + "position": { + "x": 19.8, + "y": -7.77722, + "z": 0 + } + }, + "spine": { + "pos": [ + { + "x": 15.6, + "y": -5.30222, + "z": 0 + }, + { + "x": 15.6, + "y": -10.52722, + "z": 0 + } + ] + }, + "tails": { + "pos": [ + { + "x": 15.2, + "y": -5.30222, + "z": 0 + }, + { + "x": 15.2, + "y": -10.52722, + "z": 0 + } + ] + }, + "zOrder": 0 + } + } + ], + "connections": [], + "templates": [] + }, + "mol0": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 10.88220745473898, + -1.3904137336990934, + 0 + ] + }, + { + "label": "C", + "location": [ + 10.878504114664912, + -0.3953162467696558, + 0 + ] + }, + { + "label": "C", + "location": [ + 9.870294802067827, + -1.37750208857599, + 0 + ] + }, + { + "label": "C", + "location": [ + 9.867792545261024, + -0.3953162467696558, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol1": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 12.282207454738979, + -1.3904137336990934, + 0 + ] + }, + { + "label": "C", + "location": [ + 12.27850411466491, + -0.3953162467696558, + 0 + ] + }, + { + "label": "C", + "location": [ + 11.270294802067825, + -1.37750208857599, + 0 + ] + }, + { + "label": "C", + "location": [ + 11.267792545261022, + -0.3953162467696558, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol2": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 13.97437421436393, + -1.3753354057557805, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.97562578563607, + -1.3753354057557805, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.475050188048687, + -0.5103945747129699, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol3": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 18.94937421436393, + -1.3503354057557804, + 0 + ] + }, + { + "label": "C", + "location": [ + 19.950625785636074, + -1.3503354057557804, + 0 + ] + }, + { + "label": "C", + "location": [ + 19.45005018804869, + -0.4853945747129699, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol4": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 21.50447637995553, + -0.5614682611298911, + 0 + ] + }, + { + "label": "C", + "location": [ + 22.288409765774517, + 0.05610338278985827, + 0 + ] + }, + { + "label": "C", + "location": [ + 23.261440664360368, + -0.1664467620025003, + 0 + ] + }, + { + "label": "C", + "location": [ + 23.695523620044476, + -1.0622561657031553, + 0 + ] + }, + { + "label": "C", + "location": [ + 21.509985046905832, + -1.5686528948076393, + 0 + ] + }, + { + "label": "C", + "location": [ + 23.262141767426773, + -1.9692832184662508, + 0 + ] + }, + { + "label": "C", + "location": [ + 22.288409765774517, + -2.1918333632586093, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 1, + 0 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 6, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 1 + ] + } + ] + }, + "mol5": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 25.125, + -0.2734245387858093, + 0 + ] + }, + { + "label": "C", + "location": [ + 25.933989960649672, + -0.8612172444346063, + 0 + ] + }, + { + "label": "C", + "location": [ + 25.62499379520993, + -1.8123054416829407, + 0 + ] + }, + { + "label": "C", + "location": [ + 24.62500620479007, + -1.8123054416829407, + 0 + ] + }, + { + "label": "C", + "location": [ + 24.316010039350328, + -0.8612172444346063, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 0 + ] + } + ] + }, + "mol6": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 13.574374214363932, + -5.584692095208905, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.57562578563607, + -5.584692095208905, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.075050188048685, + -4.719751264166094, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol7": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 13.20720745473898, + -5.699770423152219, + 0 + ] + }, + { + "label": "C", + "location": [ + 13.203504114664911, + -4.7046729362227815, + 0 + ] + }, + { + "label": "C", + "location": [ + 12.195294802067824, + -5.686858778029116, + 0 + ] + }, + { + "label": "C", + "location": [ + 12.192792545261023, + -4.7046729362227815, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol8": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 12.858987298340658, + -10.00221434616594, + 0 + ] + }, + { + "label": "C", + "location": [ + 12.858987298340658, + -11.002229013209064, + 0 + ] + }, + { + "label": "C", + "location": [ + 13.725000000000001, + -11.502236346730625, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.591012701659345, + -11.002229013209064, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.591012701659345, + -10.00221434616594, + 0 + ] + }, + { + "label": "C", + "location": [ + 13.725000000000001, + -9.50220701264438, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 5, + 0 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 5 + ] + } + ] + }, + "mol9": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 21.27505003874321, + -6.907175460437001, + 0 + ] + }, + { + "label": "C", + "location": [ + 21.77543747083789, + -8.447267898937998, + 0 + ] + }, + { + "label": "C", + "location": [ + 22.0846769038724, + -7.501035264846965, + 0 + ] + }, + { + "label": "C", + "location": [ + 20.774662606648533, + -8.447267898937998, + 0 + ] + }, + { + "label": "C", + "location": [ + 20.465323096127605, + -7.501035264846965, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 4 + ] + }, + { + "type": 2, + "atoms": [ + 4, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 1 + ] + }, + { + "type": 2, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 0 + ] + } + ] + }, + "mol10": { + "type": "molecule", + "atoms": [ + { + "label": "Br", + "location": [ + 23.150000000000002, + -7.7522216796875005, + 0 + ] + } + ] + } +} \ No newline at end of file From 0654e276599cb0d9fd473f66681ad842279bce6f Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 12:26:37 +0100 Subject: [PATCH 21/27] step 3 --- .../tests/formats/ref/pathway_merge2.rdf | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 api/tests/integration/tests/formats/ref/pathway_merge2.rdf diff --git a/api/tests/integration/tests/formats/ref/pathway_merge2.rdf b/api/tests/integration/tests/formats/ref/pathway_merge2.rdf new file mode 100644 index 0000000000..733e864a3e --- /dev/null +++ b/api/tests/integration/tests/formats/ref/pathway_merge2.rdf @@ -0,0 +1,147 @@ +$RDFILE 1 +$DATM 01/00/00 00:00 +$RDFILE 1 +$DATM 01/00/00 00:00 +$RFMT +$RXN + + -INDIGO- 0100000000 + + 2 2 +$MOL + + -INDIGO-01000000002D + + 8 8 0 0 0 0 0 0 0 0999 V2000 + 10.8822 -1.3904 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8785 -0.3953 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8703 -1.3775 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8678 -0.3953 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2822 -1.3904 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2785 -0.3953 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2703 -1.3775 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2678 -0.3953 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 4 1 0 0 0 0 + 4 3 1 0 0 0 0 + 3 1 1 0 0 0 0 + 5 6 1 0 0 0 0 + 6 8 1 0 0 0 0 + 8 7 1 0 0 0 0 + 7 5 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 3 3 0 0 0 0 0 0 0 0999 V2000 + 13.9744 -1.3753 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.9756 -1.3753 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4750 -0.5104 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 1 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 3 3 0 0 0 0 0 0 0 0999 V2000 + 18.9494 -1.3503 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.9506 -1.3503 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.4501 -0.4854 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 1 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 12 12 0 0 0 0 0 0 0 0999 V2000 + 25.1250 -0.2734 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.9340 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3160 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.5045 -0.5615 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.2884 0.0561 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.2614 -0.1664 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.6955 -1.0623 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.5100 -1.5687 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.2621 -1.9693 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.2884 -2.1918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 5 1 0 0 0 0 + 5 4 1 0 0 0 0 + 4 3 1 0 0 0 0 + 3 2 1 0 0 0 0 + 2 1 1 0 0 0 0 + 7 6 1 0 0 0 0 + 6 10 1 0 0 0 0 + 10 12 1 0 0 0 0 + 12 11 1 0 0 0 0 + 11 9 1 0 0 0 0 + 9 8 1 0 0 0 0 + 8 7 1 0 0 0 0 +M END +$RFMT +$RXN + + -INDIGO- 0100000000 + + 2 1 +$MOL + + -INDIGO-01000000002D + + 7 7 0 0 0 0 0 0 0 0999 V2000 + 13.5744 -5.5847 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5756 -5.5847 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0751 -4.7198 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2072 -5.6998 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.2035 -4.7047 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1953 -5.6869 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1928 -4.7047 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 1 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 7 1 0 0 0 0 + 7 6 1 0 0 0 0 + 6 4 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 12.8590 -10.0022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8590 -11.0022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7250 -11.5022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5910 -11.0022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5910 -10.0022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.7250 -9.5022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6 1 1 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 6 1 0 0 0 0 +M END +$MOL + + -INDIGO-01000000002D + + 6 5 0 0 0 0 0 0 0 0999 V2000 + 21.2750 -6.9072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7754 -8.4473 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.0847 -7.5010 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.7747 -8.4473 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.4653 -7.5010 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.1500 -7.7522 0.0000 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 1 5 1 0 0 0 0 + 5 4 2 0 0 0 0 + 4 2 1 0 0 0 0 + 2 3 2 0 0 0 0 + 3 1 1 0 0 0 0 +M END From 55983b77f18b452ba4d1450dedc72340b70c2f5c Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 12:27:24 +0100 Subject: [PATCH 22/27] step 3 --- api/tests/integration/tests/formats/ket_to_rdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tests/integration/tests/formats/ket_to_rdf.py b/api/tests/integration/tests/formats/ket_to_rdf.py index 6a34509d8f..10e95e0248 100644 --- a/api/tests/integration/tests/formats/ket_to_rdf.py +++ b/api/tests/integration/tests/formats/ket_to_rdf.py @@ -40,7 +40,7 @@ def find_diff(a, b): "pathway11", "pathway12", "pathway_merge1", - "pathway_merge2" + "pathway_merge2", ] files.sort() From 2fe842c4bdcbf0ad17f1d923815683a445eb260c Mon Sep 17 00:00:00 2001 From: even1024 Date: Thu, 9 Jan 2025 12:38:20 +0100 Subject: [PATCH 23/27] step 3 --- utils/indigo-depict/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index b420a7360c..74f0c58b84 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -869,7 +869,6 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); indigoSetOptionBool("json-saving-pretty", "on"); - indigoSetOptionFloat("reaction-component-margin-size", 0.0f); if (parseParams(&p, argc, argv) < 0) return -1; From cf38192aa3f769155dbe30390a08ab8a9f4b9943 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 13 Jan 2025 11:50:28 +0100 Subject: [PATCH 24/27] step 3 --- .../tests/formats/ref/pathway_merge2.rdf | 24 +-- .../ref/acs_after_layout_default_margin.ket | 2 +- .../ref/acs_after_layout_zero_margin.ket | 2 +- core/indigo-core/molecule/meta_commons.h | 3 +- .../reaction/reaction_multistep_detector.h | 3 +- .../reaction/src/reaction_json_loader.cpp | 6 +- .../src/reaction_multistep_detector.cpp | 174 ++++++++++++++---- utils/indigo-depict/main.c | 3 +- 8 files changed, 164 insertions(+), 53 deletions(-) diff --git a/api/tests/integration/tests/formats/ref/pathway_merge2.rdf b/api/tests/integration/tests/formats/ref/pathway_merge2.rdf index 733e864a3e..a4d5cc9e00 100644 --- a/api/tests/integration/tests/formats/ref/pathway_merge2.rdf +++ b/api/tests/integration/tests/formats/ref/pathway_merge2.rdf @@ -59,11 +59,6 @@ $MOL -INDIGO-01000000002D 12 12 0 0 0 0 0 0 0 0999 V2000 - 25.1250 -0.2734 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 25.9340 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 25.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 24.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 24.3160 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 21.5045 -0.5615 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 22.2884 0.0561 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 23.2614 -0.1664 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 @@ -71,18 +66,23 @@ $MOL 21.5100 -1.5687 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 23.2621 -1.9693 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 22.2884 -2.1918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.1250 -0.2734 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.9340 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.6250 -1.8123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3160 -0.8612 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 0 0 0 1 5 1 0 0 0 0 - 5 4 1 0 0 0 0 + 5 7 1 0 0 0 0 + 7 6 1 0 0 0 0 + 6 4 1 0 0 0 0 4 3 1 0 0 0 0 3 2 1 0 0 0 0 - 2 1 1 0 0 0 0 - 7 6 1 0 0 0 0 - 6 10 1 0 0 0 0 - 10 12 1 0 0 0 0 + 8 12 1 0 0 0 0 12 11 1 0 0 0 0 - 11 9 1 0 0 0 0 + 11 10 1 0 0 0 0 + 10 9 1 0 0 0 0 9 8 1 0 0 0 0 - 8 7 1 0 0 0 0 M END $RFMT $RXN diff --git a/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket b/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket index 9c22d22719..819fd93ff1 100644 --- a/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket +++ b/api/tests/integration/tests/layout/ref/acs_after_layout_default_margin.ket @@ -27,7 +27,7 @@ { "type": "plus", "location": [ - 19.282232, + 19.157232, 0.0, 0.0 ] diff --git a/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket b/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket index 71b28d2c33..8059a7d042 100644 --- a/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket +++ b/api/tests/integration/tests/layout/ref/acs_after_layout_zero_margin.ket @@ -27,7 +27,7 @@ { "type": "plus", "location": [ - 15.782232, + 15.657232, 0.0, 0.0 ] diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/meta_commons.h index 8e72c9eb5c..feea02eaee 100644 --- a/core/indigo-core/molecule/meta_commons.h +++ b/core/indigo-core/molecule/meta_commons.h @@ -495,7 +495,8 @@ namespace indigo ARROW_ELLIPTICAL_ARC_OPEN_ANGLE, ARROW_ELLIPTICAL_ARC_OPEN_HALF_ANGLE, ARROW_RETROSYNTHETIC, - ARROW_MULTITAIL + ARROW_MULTITAIL, + TEXT }; enum diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 88ec615072..4bd699d4da 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -100,7 +100,8 @@ namespace indigo void addArrowZones(const Vec2f& tail, const Vec2f& head); void addPathwayZones(const Vec2f& head, const Vec2f& sp_beg, const Vec2f& sp_end, const std::vector& tails); std::map> findSpecialZones(size_t mol_idx); - std::optional> findMaxSpecialZone(size_t mol_idx); + std::optional> findMaxSpecialZone(size_t mol_idx, std::map>& other_zones); + void mergeCloseComponents(); std::optional> isMergeable(size_t mol_idx1, size_t mol_idx2, std::optional> current_zone); bool checkForOppositeSections(ZoneType zt, const std::unordered_set& sections1, const std::unordered_set& sections2); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 4a630ec30c..ca72b5c41d 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -72,7 +72,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) if (arrow_count == 0 && multi_count == 0) throw Error("No arrow in the reaction"); - if (arrow_count > 1 || multi_count > 0) + if (arrow_count > 0 || multi_count > 0) { ReactionMultistepDetector md(*_pmol); switch (md.detectReaction()) @@ -89,8 +89,8 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) break; } } - else - parseOneArrowReaction(rxn); + //else + // parseOneArrowReaction(rxn); } void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 09e54d0710..a41e365a67 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -377,10 +377,10 @@ void ReactionMultistepDetector::addArrowZones(const Vec2f& tail, const Vec2f& he SPECIAL_ZONE_DESC szd; szd.zone_type = ZoneType::EArrow; - szd.zone_sections.push_back(top); - szd.zone_sections.push_back(bottom); szd.zone_sections.push_back(left); szd.zone_sections.push_back(right); + szd.zone_sections.push_back(top); + szd.zone_sections.push_back(bottom); szd.origin_coordinates.push_back(tail); szd.origin_coordinates.push_back(head); _zones.push_back(szd); @@ -470,7 +470,7 @@ std::map> ReactionMultistepDetector::findSpecialZon return result; } -std::optional> ReactionMultistepDetector::findMaxSpecialZone(size_t mol_idx) +std::optional> ReactionMultistepDetector::findMaxSpecialZone(size_t mol_idx, std::map>& zones) { std::optional> result{}; float max_containment = 0.0f; @@ -488,6 +488,14 @@ std::optional> ReactionMultistepDetector::findMaxSpecialZone max_containment = cont; result = {i, j}; } + if (cont > 0.0f) + { + auto& zone_it = zones.find(i); + if (zone_it != zones.end()) + zone_it->second.insert(j); + else + zones.insert({i, {j}}); + } } } return result; @@ -542,15 +550,49 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t if (dist_it != mdi.distances_map.end() && dist_it->second < LayoutOptions::DEFAULT_BOND_LENGTH * 2) { // collect surrounding zones for both molecules - auto zone1 = findMaxSpecialZone(mol_idx1); - auto zone2 = findMaxSpecialZone(mol_idx2); + std::map> other_zones1; + std::map> other_zones2; + std::map> comm_zones; + + auto zone1 = findMaxSpecialZone(mol_idx1, other_zones1); + auto zone2 = findMaxSpecialZone(mol_idx2, other_zones2); + std::set_intersection(other_zones1.begin(), other_zones1.end(), other_zones2.begin(), other_zones2.end(), std::inserter(comm_zones, comm_zones.begin()), + [](auto& a, auto& b) { return a.first < b.first; }); + // no zone - no reason to merge if (zone1.has_value()) { // if both molecules has the same zone and section - merge // we never merge molecules with different sections of the same zone - if (zone2.has_value() && zone1.value().first == zone2.value().first) - return zone1.value().second == zone2.value().second ? zone1 : std::nullopt; + if (zone2.has_value()) + { + // disable catalysts merging + if ((_zones[zone1.value().first].zone_type == ZoneType::EArrow && zone1.value().second > 1) || + (_zones[zone2.value().first].zone_type == ZoneType::EArrow && zone2.value().second > 1)) + return std::nullopt; + + // if both molecules are on the same zone - check if they are mergeable + for (auto& cz : comm_zones) + { + auto it_oz2 = other_zones2.find(cz.first); + if (it_oz2 != other_zones2.end()) + { + for (auto& section : cz.second) + { + if (!(_zones[cz.first].zone_type == ZoneType::EPathWay && section > 1) && it_oz2->second.count(section ^ 1)) + return std::nullopt; + + if (it_oz2->second.count(section)) + return zone1; + } + } + } + + // different zone types are not mergeable + if (_zones[zone1.value().first].zone_type != _zones[zone2.value().first].zone_type && comm_zones.empty()) + return std::nullopt; + } + if (!current_zone.has_value()) current_zone = zone1; } @@ -1194,44 +1236,110 @@ void ReactionMultistepDetector::constructMultipleArrowReaction(BaseReaction& rxn void ReactionMultistepDetector::constructSimpleArrowReaction(BaseReaction& rxn) { - for (auto& csb : _component_summ_blocks) + enum RecordIndexes + { + BBOX_IDX = 0, + FRAGMENT_TYPE_IDX, + MOLECULE_IDX + }; + + auto& arrow = (const ReactionArrowObject&)rxn.meta().getMetaObject(ReactionArrowObject::CID, 0); + bool reverseReactionOrder = arrow.getArrowType() == ReactionArrowObject::ERetrosynthetic; + + if (reverseReactionOrder) + rxn.setIsRetrosyntetic(); + + for (int i = 0; i < rxn.meta().getMetaCount(SimpleTextObject::CID); ++i) + { + auto& text = (const SimpleTextObject&)rxn.meta().getMetaObject(SimpleTextObject::CID, i); + Rect2f bbox(Vec2f(text._pos.x, text._pos.y), Vec2f(text._pos.x, text._pos.y)); // change to real text box later + _reaction_components.emplace_back(ReactionComponent::TEXT, bbox, i, nullptr); + } + + int text_meta_idx = 0; + for (const auto& comp : _reaction_components) { - switch (csb.role) + switch (comp.component_type) { - case BaseReaction::PRODUCT: { - for (auto idx : csb.indexes) + case ReactionComponent::MOLECULE: { + auto& cmol = *comp.molecule; + for (int idx = cmol.vertexBegin(); idx < cmol.vertexEnd(); idx = cmol.vertexNext(idx)) { - auto& rc = _reaction_components[idx]; - rxn.addProductCopy(*rc.molecule, 0, 0); - } - } - break; - case BaseReaction::REACTANT: { - for (auto idx : csb.indexes) - { - auto& rc = _reaction_components[idx]; - rxn.addReactantCopy(*rc.molecule, 0, 0); - } - } - break; - case BaseReaction::INTERMEDIATE: { - for (auto idx : csb.indexes) - { - auto& rc = _reaction_components[idx]; - rxn.addIntermediateCopy(*rc.molecule, 0, 0); + Vec3f& pt3d = cmol.getAtomXyz(idx); + Vec2f pt(pt3d.x, pt3d.y); + int side = !reverseReactionOrder ? getPointSide(pt, arrow.getTail(), arrow.getHead()) : getPointSide(pt, arrow.getHead(), arrow.getTail()); + switch (side) + { + case KReagentUpArea: + case KReagentDownArea: + rxn.addCatalystCopy(cmol, 0, 0); + break; + case KProductArea: + rxn.addProductCopy(cmol, 0, 0); + break; + default: + rxn.addReactantCopy(cmol, 0, 0); + break; + } + break; } } break; - case BaseReaction::UNDEFINED: { - for (auto idx : csb.indexes) + case ReactionComponent::TEXT: { + const auto& bbox = comp.bbox; + Vec2f pt(bbox.center()); + int side = !reverseReactionOrder ? getPointSide(pt, arrow.getTail(), arrow.getHead()) : getPointSide(pt, arrow.getHead(), arrow.getTail()); + if (side == KReagentUpArea || side == KReagentDownArea) { - auto& rc = _reaction_components[idx]; - rxn.addUndefinedCopy(*rc.molecule, 0, 0); + rxn.addSpecialCondition(text_meta_idx, bbox); + break; } + text_meta_idx++; } break; default: break; } } + + // for (auto& csb : _component_summ_blocks) + //{ + // switch (csb.role) + // { + // case BaseReaction::PRODUCT: { + // for (auto idx : csb.indexes) + // { + // auto& rc = _reaction_components[idx]; + // rxn.addProductCopy(*rc.molecule, 0, 0); + // } + // } + // break; + // case BaseReaction::REACTANT: { + // for (auto idx : csb.indexes) + // { + // auto& rc = _reaction_components[idx]; + // rxn.addReactantCopy(*rc.molecule, 0, 0); + // } + // } + // break; + // case BaseReaction::INTERMEDIATE: { + // for (auto idx : csb.indexes) + // { + // auto& rc = _reaction_components[idx]; + // rxn.addIntermediateCopy(*rc.molecule, 0, 0); + // } + // } + // break; + // case BaseReaction::UNDEFINED: { + // for (auto idx : csb.indexes) + // { + // auto& rc = _reaction_components[idx]; + // rxn.addUndefinedCopy(*rc.molecule, 0, 0); + // } + // } + // break; + // default: + // break; + // } + // } } \ No newline at end of file diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 74f0c58b84..6febc5b518 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -869,6 +869,7 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); indigoSetOptionBool("json-saving-pretty", "on"); + indigoSetOptionFloat("reaction-component-margin-size", 0.0f); if (parseParams(&p, argc, argv) < 0) return -1; @@ -1058,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - indigoLayout(obj); + //indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From 2f507905ed8c14829227d172f1fc8561a2ae7060 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 13 Jan 2025 22:45:27 +0100 Subject: [PATCH 25/27] step 3 --- .../integration/ref/formats/ket_to_rxn.py.out | 2 + .../integration/tests/formats/ket_to_rxn.py | 44 +++++ .../tests/formats/reactions/merge_test1.ket | 182 ++++++++++++++++++ .../tests/formats/ref/merge_test1.rxn | 30 +++ .../reaction/reaction_multistep_detector.h | 12 +- .../src/reaction_multistep_detector.cpp | 29 +-- 6 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 api/tests/integration/ref/formats/ket_to_rxn.py.out create mode 100644 api/tests/integration/tests/formats/ket_to_rxn.py create mode 100644 api/tests/integration/tests/formats/reactions/merge_test1.ket create mode 100644 api/tests/integration/tests/formats/ref/merge_test1.rxn diff --git a/api/tests/integration/ref/formats/ket_to_rxn.py.out b/api/tests/integration/ref/formats/ket_to_rxn.py.out new file mode 100644 index 0000000000..7bf6c7f398 --- /dev/null +++ b/api/tests/integration/ref/formats/ket_to_rxn.py.out @@ -0,0 +1,2 @@ +*** KET to RXN *** +merge_test1.rxn:SUCCEED diff --git a/api/tests/integration/tests/formats/ket_to_rxn.py b/api/tests/integration/tests/formats/ket_to_rxn.py new file mode 100644 index 0000000000..9813863d18 --- /dev/null +++ b/api/tests/integration/tests/formats/ket_to_rxn.py @@ -0,0 +1,44 @@ +import difflib +import os +import sys + + +def find_diff(a, b): + return "\n".join(difflib.unified_diff(a.splitlines(), b.splitlines())) + + +sys.path.append( + os.path.normpath( + os.path.join(os.path.abspath(__file__), "..", "..", "..", "common") + ) +) +from env_indigo import Indigo, joinPathPy # noqa + +indigo = Indigo() +indigo.setOption("json-saving-pretty", True) +indigo.setOption("ignore-stereochemistry-errors", True) + +print("*** KET to RXN ***") + +root = joinPathPy("reactions/", __file__) +ref_path = joinPathPy("ref/", __file__) + +files = [ + "merge_test1", +] + +files.sort() +for filename in files: + rea = indigo.loadReactionFromFile(os.path.join(root, filename + ".ket")) + + with open(os.path.join(ref_path, filename) + ".rxn", "w") as file: + file.write(rea.rxnfile()) + with open(os.path.join(ref_path, filename) + ".rxn", "r") as file: + rxn_ref = file.read() + rxn = rea.rxnfile() + diff = find_diff(rxn_ref, rxn) + if not diff: + print(filename + ".rxn:SUCCEED") + else: + print(filename + ".rxn:FAILED") + print(diff) diff --git a/api/tests/integration/tests/formats/reactions/merge_test1.ket b/api/tests/integration/tests/formats/reactions/merge_test1.ket new file mode 100644 index 0000000000..d37bfdf3c5 --- /dev/null +++ b/api/tests/integration/tests/formats/reactions/merge_test1.ket @@ -0,0 +1,182 @@ +{ + "root": { + "nodes": [ + { + "$ref": "mol0" + }, + { + "$ref": "mol1" + }, + { + "type": "arrow", + "data": { + "mode": "open-angle", + "pos": [ + { + "x": 13.975000000000001, + "y": -9.850000000000001, + "z": 0 + }, + { + "x": 16.62511792190461, + "y": -9.850000000000001, + "z": 0 + } + ] + } + } + ], + "connections": [], + "templates": [] + }, + "mol0": { + "type": "molecule", + "atoms": [ + { + "label": "N", + "location": [ + 9.9, + -10, + 0 + ], + "charge": 1 + }, + { + "label": "C", + "location": [ + 9.9, + -9, + 0 + ] + }, + { + "label": "C", + "location": [ + 10.76602540378444, + -8.5, + 0 + ] + }, + { + "label": "C", + "location": [ + 8.9, + -10, + 0 + ] + }, + { + "label": "C", + "location": [ + 8.033974596215561, + -9.5, + 0 + ] + }, + { + "label": "C", + "location": [ + 9.9, + -11, + 0 + ] + }, + { + "label": "C", + "location": [ + 9.033974596215561, + -11.5, + 0 + ] + }, + { + "label": "C", + "location": [ + 10.9, + -10, + 0 + ] + }, + { + "label": "C", + "location": [ + 11.607106781186548, + -10.707106781186548, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 3 + ] + }, + { + "type": 1, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 8 + ] + } + ] + }, + "mol1": { + "type": "molecule", + "atoms": [ + { + "label": "Cl", + "location": [ + 12.525, + -9.9, + 0 + ], + "charge": -1 + } + ] + } +} \ No newline at end of file diff --git a/api/tests/integration/tests/formats/ref/merge_test1.rxn b/api/tests/integration/tests/formats/ref/merge_test1.rxn new file mode 100644 index 0000000000..5531ca526a --- /dev/null +++ b/api/tests/integration/tests/formats/ref/merge_test1.rxn @@ -0,0 +1,30 @@ +$RXN + + -INDIGO- 0113252231 + + 1 0 +$MOL + + -INDIGO-01132522312D + + 10 8 0 0 0 0 0 0 0 0999 V2000 + 9.9000 -10.0000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9000 -9.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7660 -8.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9000 -10.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0340 -9.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9000 -11.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0340 -11.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9000 -10.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6071 -10.7071 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5250 -9.9000 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 1 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 1 6 1 0 0 0 0 + 6 7 1 0 0 0 0 + 1 8 1 0 0 0 0 + 8 9 1 0 0 0 0 +M CHG 2 1 1 10 -1 +M END diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index 4bd699d4da..f78d093c44 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -72,6 +72,16 @@ namespace indigo std::vector origin_coordinates; }; + struct COMPONENT_DESC + { + COMPONENT_DESC(std::unique_ptr mol, std::vector poly, int idx) : mol(std::move(mol)), hull(poly), mapped_idx(idx) + { + } + std::unique_ptr mol; + std::vector hull; + int mapped_idx; + }; + ReactionMultistepDetector(BaseMolecule& mol); ~ReactionMultistepDetector(); ReactionType detectReaction(); @@ -118,7 +128,7 @@ namespace indigo std::vector _reaction_components; std::vector _component_summ_blocks; std::list _component_summ_blocks_list; - std::vector, std::vector>> _components; + std::vector _components; std::vector _mol_distances; std::vector _zones; int _moleculeCount; diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index a41e365a67..b616f30a5b 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -57,13 +57,13 @@ void ReactionMultistepDetector::createSummBlocks() for (int i = 0; i < _moleculeCount; ++i) { Rect2f bbox; - _components[i].first->getBoundingBox(bbox, MIN_MOL_SIZE); + _components[i].mol->getBoundingBox(bbox, MIN_MOL_SIZE); mol_tops.emplace_back(bbox.top(), i); mol_bottoms.emplace_back(bbox.bottom(), i); mol_lefts.emplace_back(bbox.left(), i); mol_rights.emplace_back(bbox.right(), i); - _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(_components[i].first)); + _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(_components[i].mol)); } for (int i = 0; i < _bmol.meta().getMetaCount(ReactionPlusObject::CID); ++i) @@ -246,7 +246,7 @@ void ReactionMultistepDetector::collectSortedDistances() { for (int j = i + 1; j < _moleculeCount; ++j) { - float dist = computeConvexDistance(_components[i].second, _components[j].second); + float dist = computeConvexDistance(_components[i].hull, _components[j].hull); auto& mdi = _mol_distances[i]; auto it = std::lower_bound(mdi.sorted_distances.begin(), mdi.sorted_distances.end(), std::make_pair(j, dist), [](auto& lhs, auto& rhs) { return lhs.second < rhs.second; }); @@ -452,7 +452,7 @@ void ReactionMultistepDetector::addPathwayZones(const Vec2f& head, const Vec2f& std::map> ReactionMultistepDetector::findSpecialZones(size_t mol_idx) { - auto& hull = _components[mol_idx].second; + auto& hull = _components[mol_idx].hull; std::map> result; for (int i = 0; i < static_cast(_zones.size()); ++i) { @@ -474,7 +474,7 @@ std::optional> ReactionMultistepDetector::findMaxSpecialZone { std::optional> result{}; float max_containment = 0.0f; - auto& hull = _components[mol_idx].second; + auto& hull = _components[mol_idx].hull; for (int i = 0; i < static_cast(_zones.size()); ++i) { auto& zone = _zones[i]; @@ -505,7 +505,7 @@ void ReactionMultistepDetector::mergeCloseComponents() { for (std::size_t i = 0; i < _components.size(); ++i) { - if (!_components[i].first) + if (!_components[i].mol) continue; std::queue>>> bfs_queue; std::vector cluster; @@ -517,7 +517,7 @@ void ReactionMultistepDetector::mergeCloseComponents() bfs_queue.pop(); for (std::size_t j = 0; j < _components.size(); ++j) { - if (!_components[j].first || j == qel.first) + if (!_components[j].mol || j == qel.first) continue; if (std::find(cluster.begin(), cluster.end(), j) != cluster.end()) continue; @@ -532,14 +532,15 @@ void ReactionMultistepDetector::mergeCloseComponents() for (std::size_t k = 1; k < cluster.size(); ++k) { QS_DEF(Array, mapping); - if (_components[cluster[k]].first) + if (_components[cluster[k]].mol) { - _components[i].first->mergeWithMolecule(*_components[cluster[k]].first, &mapping, 0); - _components[cluster[k]].first.reset(); + _components[i].mol->mergeWithMolecule(*_components[cluster[k]].mol, &mapping, 0); + _components[cluster[k]].mapped_idx = (int)i; + _components[cluster[k]].mol.reset(); } } } - _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p.first; }), _components.end()); + _components.erase(std::remove_if(_components.begin(), _components.end(), [](auto& p) { return !p.mol; }), _components.end()); _moleculeCount = (int)_components.size(); } @@ -601,8 +602,8 @@ std::optional> ReactionMultistepDetector::isMergeable(size_t auto zidx = current_zone.value().first; // if molecules have different zones - check if they are mergeable - auto& hull1 = _components[mol_idx1].second; - auto& hull2 = _components[mol_idx2].second; + auto& hull1 = _components[mol_idx1].hull; + auto& hull2 = _components[mol_idx2].hull; const auto& coords = _zones[zidx].origin_coordinates; // check if both molecules are on the same zone continuation @@ -696,7 +697,7 @@ ReactionMultistepDetector::ReactionType ReactionMultistepDetector::detectReactio { auto component = extractComponent(i); auto hull = component->getConvexHull(Vec2f(LayoutOptions::DEFAULT_BOND_LENGTH, LayoutOptions::DEFAULT_BOND_LENGTH)); - _components.emplace_back(std::move(component), hull); + _components.emplace_back(std::move(component), hull, i); } collectSortedDistances(); From e34c99f059cb3d1d69a0602bf387b87dfdb9db05 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 13 Jan 2025 22:49:58 +0100 Subject: [PATCH 26/27] step 3 --- core/indigo-core/reaction/src/reaction_json_loader.cpp | 2 -- utils/indigo-depict/main.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index ca72b5c41d..84f849de85 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -89,8 +89,6 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) break; } } - //else - // parseOneArrowReaction(rxn); } void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 6febc5b518..b420a7360c 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1059,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - //indigoLayout(obj); + indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From 5437b375dbd7293a96870421500f9f0d5357d47d Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 13 Jan 2025 23:32:40 +0100 Subject: [PATCH 27/27] step 3 --- core/indigo-core/reaction/src/reaction_multistep_detector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index b616f30a5b..0c1fe93f85 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -490,7 +490,7 @@ std::optional> ReactionMultistepDetector::findMaxSpecialZone } if (cont > 0.0f) { - auto& zone_it = zones.find(i); + auto zone_it = zones.find(i); if (zone_it != zones.end()) zone_it->second.insert(j); else