From 5fb70df1d8e3ba98fd061f4b7641a9ef40cc46d7 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 27 Aug 2024 07:38:40 +0200 Subject: [PATCH 01/25] multitale rendering --- api/c/indigo/src/indigo_savers.cpp | 27 +- core/indigo-core/common/base_cpp/array.h | 6 + core/indigo-core/layout/pathway_layout.h | 111 ++++++ .../indigo-core/layout/src/pathway_layout.cpp | 208 ++++++++++ core/indigo-core/molecule/metadata_storage.h | 1 + .../molecule/src/metadata_storage.cpp | 11 +- .../molecule/src/molecule_json_loader.cpp | 49 +++ core/indigo-core/reaction/pathway_reaction.h | 44 ++- .../reaction/pathway_reaction_builder.h | 113 ++++++ .../reaction/reaction_json_loader.h | 21 - .../reaction/src/pathway_reaction.cpp | 267 +++++++------ .../reaction/src/pathway_reaction_builder.cpp | 197 ++++++++++ .../src/pathway_reaction_json_saver.cpp | 2 +- .../reaction/src/reaction_auto_loader.cpp | 7 +- .../reaction/src/reaction_json_loader.cpp | 372 +----------------- third_party/inchi/INCHI_BASE/src/ichicans.c | 2 +- utils/indigo-depict/main.c | 7 +- 17 files changed, 908 insertions(+), 537 deletions(-) create mode 100644 core/indigo-core/layout/pathway_layout.h create mode 100644 core/indigo-core/layout/src/pathway_layout.cpp create mode 100644 core/indigo-core/reaction/pathway_reaction_builder.h create mode 100644 core/indigo-core/reaction/src/pathway_reaction_builder.cpp diff --git a/api/c/indigo/src/indigo_savers.cpp b/api/c/indigo/src/indigo_savers.cpp index 257a85aaee..481f02c1a8 100644 --- a/api/c/indigo/src/indigo_savers.cpp +++ b/api/c/indigo/src/indigo_savers.cpp @@ -35,9 +35,12 @@ #include "reaction/reaction_cdxml_saver.h" #include "reaction/reaction_cml_saver.h" #include "reaction/reaction_json_saver.h" +#include "reaction/pathway_reaction_json_saver.h" #include "reaction/rsmiles_saver.h" #include "reaction/rxnfile_loader.h" #include "reaction/rxnfile_saver.h" +#include "reaction/pathway_reaction.h" + #include #include "indigo_io.h" @@ -706,12 +709,24 @@ CEXPORT int indigoSaveJson(int item, int output) } else if (IndigoBaseReaction::is(obj)) { - ReactionJsonSaver saver(out); - self.initReactionJsonSaver(saver); - BaseReaction& rxn = obj.getBaseReaction(); - saver.saveReaction(rxn); - out.flush(); - return 1; + if (obj.type == IndigoObject::PATHWAY_REACTION) + { + PathwayReactionJsonSaver jn(out); + self.initReactionJsonSaver(jn); + BaseReaction& br = obj.getBaseReaction(); + jn.saveReaction(dynamic_cast(br)); + out.flush(); + return 1; + } + else + { + ReactionJsonSaver saver(out); + self.initReactionJsonSaver(saver); + BaseReaction& rxn = obj.getBaseReaction(); + saver.saveReaction(rxn); + out.flush(); + return 1; + } } else if (IndigoKetDocument::is(obj)) { diff --git a/core/indigo-core/common/base_cpp/array.h b/core/indigo-core/common/base_cpp/array.h index c091bf393e..eb7b6882a6 100644 --- a/core/indigo-core/common/base_cpp/array.h +++ b/core/indigo-core/common/base_cpp/array.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "base_c/defs.h" #include "base_cpp/exception.h" @@ -167,6 +168,11 @@ namespace indigo return _length * sizeof(T); } + void copy(const std::vector other) + { + copy(other.data(), static_cast(other.size())); + } + void copy(const Array& other) { copy(other._array, other._length); diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h new file mode 100644 index 0000000000..4831c43923 --- /dev/null +++ b/core/indigo-core/layout/pathway_layout.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#ifndef __pathway_layout_h__ +#define __pathway_layout_h__ + +#include "reaction/pathway_reaction.h" + +namespace indigo +{ + // PathwayLayoutItem is a struct that represents a reaction in the pathway + struct PathwayLayoutItem + { + std::pair> associatedReactionItems; + int number = -1; + double prelim = 0; + double mod = 0; + int ancestor = -1; + int thread = -1; + double change = 0; + double shift = 0; + double width = 0, height = 0; + double x = 0, y = 0; + std::vector precursors; + int successor = -1; + int nextSibling = -1; + int prevSibling = -1; + + int getFirstPrecursor() const + { + return precursors.empty() ? -1 : precursors.front(); + } + + int getLastPrecursor() const + { + return precursors.empty() ? -1 : precursors.back(); + } + + void clear() + { + number = -2; + prelim = mod = shift = change = 0; + ancestor = thread = -1; + } + }; + + // PathwayLayout is a class which makes a tree layout of the reactions in O(N) time + class PathwayLayout + { + public: + static constexpr float MARGIN = 1.f; + static constexpr float ARROW_HEAD_WIDTH = 2.5f; + static constexpr float ARROW_TAIL_WIDTH = 0.5f; + static constexpr float ARROW_WIDTH = ARROW_HEAD_WIDTH + ARROW_TAIL_WIDTH; + + PathwayLayout(PathwayReaction& reaction) : _depths(10, 0.0), _reaction(reaction) + { + } + // make layout + void make(); + + private: + + double spacing(const PathwayLayoutItem& l, const PathwayLayoutItem& r, bool siblings) + { + return 0.5 * (l.width + r.width); + } + + void updateDepths(int depth, const PathwayLayoutItem& item); + + void determineDepths(); + + std::vector getLayoutItems() const; + + DECL_ERROR; + + private: + // firstWalk function calculates the preliminary x-coordinate of each node in the tree + void firstWalk(std::vector& nodes, int nIndex, int num, int depth); + // apportion function is used to calculate the preliminary x-coordinate of the children of a node + int apportion(std::vector& nodes, int vIndex, int aIndex); + int nextLeft(const std::vector& nodes, int nIndex) const; + int nextRight(const std::vector& nodes, int nIndex) const; + void moveSubtree(std::vector& nodes, int wmIndex, int wpIndex, double shift); + void executeShifts(std::vector& nodes, int nIndex); + int ancestor(const std::vector& nodes, int vimIndex, int vIndex, int aIndex) const; + void secondWalk(std::vector& nodes, int nIndex, double m, int depth); + + std::vector _depths; + int _maxDepth = 0; + PathwayReaction& _reaction; + }; + +} // namespace indigo + +#endif diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp new file mode 100644 index 0000000000..d93545dc09 --- /dev/null +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#include "layout/pathway_layout.h" + +using namespace indigo; + +IMPL_ERROR(PathwayLayout, "pathway_layout"); + +void PathwayLayout::updateDepths(int depth, const PathwayLayoutItem& item) +{ + double d = item.height; + if (_depths.size() <= depth) + _depths.resize(3 * depth / 2); + _depths[depth] = std::max(_depths[depth], d); + _maxDepth = std::max(_maxDepth, depth); +} + +void PathwayLayout::determineDepths() +{ + for (int i = 1; i < _maxDepth; ++i) + _depths[i] += _depths[i - 1]; +} + +std::vector PathwayLayout::getLayoutItems() const +{ + // convert _reactionNodes to std::vector + return std::vector(); +} + +// make layout +void PathwayLayout::make() +{ + std::vector nodes; + auto roots = _reaction.getRootReactions(); + for (auto rootIndex : roots) + { + std::fill(_depths.begin(), _depths.end(), 0); + _maxDepth = 0; + firstWalk(nodes, rootIndex, 0, 1); + determineDepths(); + secondWalk(nodes, rootIndex, -nodes[rootIndex].prelim, 0); + } +} + +void PathwayLayout::firstWalk(std::vector& nodes, int nIndex, int num, int depth) +{ + PathwayLayoutItem& n = nodes[nIndex]; + n.number = num; + updateDepths(depth, n); + + if (n.precursors.empty()) + { + int lIndex = n.prevSibling; + if (lIndex == -1) + { + n.prelim = 0; + } + else + { + n.prelim = nodes[lIndex].prelim + spacing(nodes[lIndex], n, true); + } + } + else + { + int leftMost = n.getFirstPrecursor(); + int rightMost = n.getLastPrecursor(); + int defaultAncestor = leftMost; + + for (int i = 0, c = leftMost; c != -1; ++i, c = nodes[c].nextSibling) + { + firstWalk(nodes, c, i, depth + 1); + defaultAncestor = apportion(nodes, c, defaultAncestor); + } + + executeShifts(nodes, nIndex); + + double midpoint = 0.5 * (nodes[leftMost].prelim + nodes[rightMost].prelim); + int leftIndex = n.prevSibling; + if (leftIndex != -1) + { + n.prelim = nodes[leftIndex].prelim + spacing(nodes[leftIndex], n, true); + n.mod = n.prelim - midpoint; + } + else + { + n.prelim = midpoint; + } + } +} + +// apportion function is used to calculate the preliminary x-coordinate of the children of a node +int PathwayLayout::apportion(std::vector& nodes, int vIndex, int aIndex) +{ + int wIndex = nodes[vIndex].prevSibling; + if (wIndex != -1) + { + int vip = vIndex, vim = wIndex; + int vop = vIndex, vom = nodes[vip].getFirstPrecursor(); + double sip = nodes[vip].mod, sim = nodes[vim].mod; + double sop = nodes[vop].mod, som = nodes[vom].mod; + + while (vim != -1 && vip != -1) + { + vim = nextRight(nodes, vim); + vip = nextLeft(nodes, vip); + vom = nextLeft(nodes, vom); + vop = nextRight(nodes, vop); + nodes[vop].ancestor = vIndex; + + double shift = (nodes[vim].prelim + sim) - (nodes[vip].prelim + sip) + spacing(nodes[vim], nodes[vip], false); + if (shift > 0) + { + moveSubtree(nodes, ancestor(nodes, vim, vIndex, aIndex), vIndex, shift); + sip += shift; + sop += shift; + } + + sim += nodes[vim].mod; + sip += nodes[vip].mod; + som += nodes[vom].mod; + sop += nodes[vop].mod; + + vim = nextRight(nodes, vim); + vip = nextLeft(nodes, vip); + } + + if (vim != -1 && nextRight(nodes, vop) == -1) + { + nodes[vop].thread = vim; + nodes[vop].mod += sim - sop; + } + if (vip != -1 && nextLeft(nodes, vom) == -1) + { + nodes[vom].thread = vip; + nodes[vom].mod += sip - som; + aIndex = vIndex; + } + } + return aIndex; +} + +int PathwayLayout::nextLeft(const std::vector& nodes, int nIndex) const +{ + int child = nodes[nIndex].getFirstPrecursor(); + return child != -1 ? child : nodes[nIndex].thread; +} + +int PathwayLayout::nextRight(const std::vector& nodes, int nIndex) const +{ + int child = nodes[nIndex].getLastPrecursor(); + return child != -1 ? child : nodes[nIndex].thread; +} + +void PathwayLayout::moveSubtree(std::vector& nodes, int wmIndex, int wpIndex, double shift) +{ + double subtrees = nodes[wpIndex].number - nodes[wmIndex].number; + nodes[wpIndex].change -= shift / subtrees; + nodes[wpIndex].shift += shift; + nodes[wmIndex].change += shift / subtrees; + nodes[wpIndex].prelim += shift; + nodes[wpIndex].mod += shift; +} + +void PathwayLayout::executeShifts(std::vector& nodes, int nIndex) +{ + double shift = 0, change = 0; + for (int c = nodes[nIndex].getLastPrecursor(); c != -1; c = nodes[c].prevSibling) + { + nodes[c].prelim += shift; + nodes[c].mod += shift; + change += nodes[c].change; + shift += nodes[c].shift + change; + } +} + +int PathwayLayout::ancestor(const std::vector& nodes, int vimIndex, int vIndex, int aIndex) const +{ + return nodes[vimIndex].ancestor == nodes[vIndex].successor ? nodes[vimIndex].ancestor : aIndex; +} + +void PathwayLayout::secondWalk(std::vector& nodes, int nIndex, double m, int depth) +{ + nodes[nIndex].x = nodes[nIndex].prelim + m; + nodes[nIndex].y = _depths[depth]; + + for (int c = nodes[nIndex].getFirstPrecursor(); c != -1; c = nodes[c].nextSibling) + { + secondWalk(nodes, c, m + nodes[nIndex].mod, depth + 1); + } + + nodes[nIndex].clear(); +} diff --git a/core/indigo-core/molecule/metadata_storage.h b/core/indigo-core/molecule/metadata_storage.h index b789e98887..6229af1e8f 100644 --- a/core/indigo-core/molecule/metadata_storage.h +++ b/core/indigo-core/molecule/metadata_storage.h @@ -75,6 +75,7 @@ namespace indigo PtrArray _meta_data; // TODO: should be replaced with list of unique_ptr Array _plus_indexes; Array _arrow_indexes; + Array _multi_tail_indexes; Array _simple_object_indexes; Array _text_object_indexes; Array _image_indexes; diff --git a/core/indigo-core/molecule/src/metadata_storage.cpp b/core/indigo-core/molecule/src/metadata_storage.cpp index 463b708e1f..0bdc3e7c75 100644 --- a/core/indigo-core/molecule/src/metadata_storage.cpp +++ b/core/indigo-core/molecule/src/metadata_storage.cpp @@ -29,6 +29,9 @@ int MetaDataStorage::addMetaObject(MetaObject* pobj) case KETImage::CID: _image_indexes.push() = index; break; + case KETReactionMultitailArrow::CID: + _multi_tail_indexes.push() = index; + break; default: break; } @@ -67,6 +70,8 @@ int MetaDataStorage::getMetaObjectIndex(uint32_t meta_type, int index) const case KETImage::CID: return _image_indexes[index]; break; + case KETReactionMultitailArrow::CID: + return _multi_tail_indexes[index]; default: throw Error("Unknown meta type"); break; @@ -102,6 +107,9 @@ int MetaDataStorage::getMetaCount(uint32_t meta_type) const case KETImage::CID: return _image_indexes.size(); break; + case KETReactionMultitailArrow::CID: + return _multi_tail_indexes.size(); + break; default: break; } @@ -112,9 +120,10 @@ void MetaDataStorage::resetReactionData() { _plus_indexes.clear(); _arrow_indexes.clear(); + _multi_tail_indexes.clear(); for (int i = _meta_data.size() - 1; i >= 0; i--) { - if (_meta_data[i]->_class_id == KETReactionArrow::CID || _meta_data[i]->_class_id == KETReactionPlus::CID) + if (_meta_data[i]->_class_id == KETReactionArrow::CID || _meta_data[i]->_class_id == KETReactionPlus::CID || _meta_data[i]->_class_id == KETReactionMultitailArrow::CID) _meta_data.remove(i); } } diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index a84f8ccfe5..628a4fbe30 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1929,6 +1929,55 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat meta_interface.addMetaObject(new KETImage(Rect2f(lt, rb), image_format, mobj["data"].GetString())); } + else if (node_type == "multi-tailed-arrow") + { + if (mobj.HasMember("data")) + { + auto& data_obj = mobj["data"]; + if (data_obj.HasMember("head")) + { + auto& head_obj = data_obj["head"]; + if (head_obj.HasMember("position")) + { + auto& head_pos = head_obj["position"]; + Vec2f head_position(head_pos["x"].GetFloat(), head_pos["y"].GetFloat()); + if (data_obj.HasMember("spine")) + { + auto& spine_obj = data_obj["spine"]; + if (spine_obj.HasMember("pos")) + { + auto& spine_pos = spine_obj["pos"]; + if (spine_pos.Size() == 2) + { + Vec2f spine_begin(spine_pos[0]["x"].GetFloat(), spine_pos[0]["y"].GetFloat()); + Vec2f spine_end(spine_pos[1]["x"].GetFloat(), spine_pos[1]["y"].GetFloat()); + if (data_obj.HasMember("tails")) + { + auto& tails = data_obj["tails"]; + if (tails.HasMember("pos")) + { + auto& tails_pos_array = tails["pos"]; + if (tails_pos_array.IsArray()) + { + Array tails_array; + for (auto it = tails_pos_array.Begin(); it != tails_pos_array.End(); ++it) + { + auto& tail_pos = *it; + Vec2f tail_position(tail_pos["x"].GetFloat(), tail_pos["y"].GetFloat()); + tails_array.push(tail_position); + } + meta_interface.addMetaObject( + new KETReactionMultitailArrow(head_position, tails_array, spine_begin, spine_end)); + } + } + } + } + } + } + } + } + } + } } } } diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 0ac4b60512..461b444a37 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -23,8 +23,9 @@ #pragma warning(disable : 4251) #endif -#include "reaction/base_reaction.h" #include +#include "base_cpp/array.h" +#include "reaction/base_reaction.h" namespace indigo { @@ -33,20 +34,42 @@ namespace indigo class DLLEXPORT PathwayReaction : public BaseReaction { - static constexpr float MARGIN = 1.f; - static constexpr float ARROW_HEAD_WIDTH = 2.5f; - static constexpr float ARROW_TAIL_WIDTH = 0.5f; - static constexpr float ARROW_WIDTH = ARROW_HEAD_WIDTH + ARROW_TAIL_WIDTH; - public: + struct SuccessorReaction + { + SuccessorReaction(int reactionIdx, Array& ridxs) : reactionIdx(reactionIdx){ + reactantIndices.copy(ridxs); + } + SuccessorReaction(const SuccessorReaction& other) : reactionIdx(other.reactionIdx){ + reactantIndices.copy(other.reactantIndices); + } + SuccessorReaction& operator = (const SuccessorReaction& other) + { + reactionIdx = other.reactionIdx; + reactantIndices.copy(other.reactantIndices); + return *this; + } + int reactionIdx; + Array reactantIndices; + }; + + struct ReactionNode + { + // we don't keep products and reactants here, because they are stored in the Reaction object at reactionIdx + int reactionIdx; + // vector of successor reactions indexes and their corresponding reactant indexes + ObjArray successorReactions; + // vector of precursor reactions indexes + Array precursorReactionsIndexes; + }; + PathwayReaction(); - PathwayReaction(std::deque&); + PathwayReaction(std::deque& reactions, const Array& nodes); ~PathwayReaction() override; + std::vector getRootReactions() const; - int reactionId(int moleculeId) const; int reactionsCount() const; void clone(PathwayReaction&); - std::pair>, std::vector>> makeTreePoints(); BaseReaction* neu() override; bool aromatize(const AromaticityOptions& options) override; @@ -57,7 +80,8 @@ namespace indigo int _addBaseMolecule(int side) override; private: - Array _reactions; + Array _reactionNodes; + ObjArray< RedBlackMap > _reactions; }; } // namespace indigo diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h new file mode 100644 index 0000000000..20778ec301 --- /dev/null +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -0,0 +1,113 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#ifndef __pathway_reaction_builder__ +#define __pathway_reaction_builder__ + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base_cpp/exception.h" +#include "molecule/ket_commons.h" +#include "reaction/pathway_reaction.h" + +namespace indigo +{ + class BaseMolecule; + class BaseReaction; + + // PathwayLayoutItem is a struct that represents a reaction in the pathway + struct PathwayLayoutItem + { + std::pair> associatedReactionItems; + int number = -1; + double prelim = 0; + double mod = 0; + int ancestor = -1; + int thread = -1; + double change = 0; + double shift = 0; + double width = 0, height = 0; + double x = 0, y = 0; + std::vector precursors; + int successor = -1; + int nextSibling = -1; + int prevSibling = -1; + + int getFirstPrecursor() const + { + return precursors.empty() ? -1 : precursors.front(); + } + + int getLastPrecursor() const + { + return precursors.empty() ? -1 : precursors.back(); + } + + void clear() + { + number = -2; + prelim = mod = shift = change = 0; + ancestor = thread = -1; + } + }; + + // PathwayReactionBuilder is a class that builds a pathway reaction tree from a list of reactions in O(N) time + class PathwayReactionBuilder + { + public: + PathwayReactionBuilder(); + ~PathwayReactionBuilder(); + std::unique_ptr buildPathwayReaction(std::deque& reactions); + DECL_ERROR; + + private: + struct ReactionInchiDescriptor + { + std::unordered_set reactants; + std::vector products; + }; + + void buildInchiDescriptors(std::deque& reactions); + void populatePossibleReactions(); + auto findPossibleSuccessorReactions(int reactionIdx); + auto getReactionComponents(const PathwayReaction::ReactionNode& rn, Reaction& reaction); + std::vector _reactionDescriptors; + Array _reactionNodes; + std::unordered_map> _reactantToReactions; + std::unordered_set _ambigousSuccessorReactions; // reactions that have more than one possible successor + }; + +} // namespace indigo + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#endif diff --git a/core/indigo-core/reaction/reaction_json_loader.h b/core/indigo-core/reaction/reaction_json_loader.h index a54ac4d108..686779494a 100644 --- a/core/indigo-core/reaction/reaction_json_loader.h +++ b/core/indigo-core/reaction/reaction_json_loader.h @@ -31,16 +31,6 @@ namespace indigo { - inline void merge_bbox(Rect2f& bb1, const Rect2f& bb2) - { - Vec2f lb, rt; - lb.x = std::min(bb1.left(), bb2.left()); - rt.x = std::max(bb1.right(), bb2.right()); - lb.y = std::min(bb1.bottom(), bb2.bottom()); - rt.y = std::max(bb1.top(), bb2.top()); - bb1 = Rect2f(lb, rt); - } - class Scanner; class BaseReaction; class Reaction; @@ -53,9 +43,6 @@ namespace indigo public: DECL_ERROR; - typedef std::pair FLOAT_INT_PAIR; - typedef std::vector FLOAT_INT_PAIRS; - ReactionJsonLoader(rapidjson::Document& ket); ~ReactionJsonLoader(); @@ -67,17 +54,9 @@ namespace indigo bool treat_x_as_pseudoatom; bool ignore_no_chiral_flag; - const Vec2f PLUS_BBOX_SHIFT = {0.9f, 0.9f}; - const Vec2f ARROW_BBOX_SHIFT = {0.0f, 0.9f}; - private: ReactionJsonLoader(const ReactionJsonLoader&); // no implicit copy void parseOneArrowReaction(BaseReaction& rxn); - void parseMultipleArrowReaction(BaseReaction& rxn); - void constructMultipleArrowReaction(BaseReaction& rxn); - bool 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); - rapidjson::Value _molecule; MoleculeJsonLoader _loader; diff --git a/core/indigo-core/reaction/src/pathway_reaction.cpp b/core/indigo-core/reaction/src/pathway_reaction.cpp index 041a0ad10e..4adf2ee177 100644 --- a/core/indigo-core/reaction/src/pathway_reaction.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction.cpp @@ -19,6 +19,7 @@ #include #include "molecule/inchi_wrapper.h" +#include "molecule/ket_commons.h" #include "reaction/pathway_reaction.h" #include "reaction/reaction.h" @@ -34,25 +35,32 @@ PathwayReaction::~PathwayReaction() { } -PathwayReaction::PathwayReaction(std::deque& reactions) +PathwayReaction::PathwayReaction(std::deque& reactions, const Array& nodes) { + _reactionNodes.copy(nodes); for (size_t i = 0; i < reactions.size(); i++) { + auto& reactionComponents = _reactions.push(); for (int j = reactions[i].begin(); j < reactions[i].end(); j = reactions[i].next(j)) { auto molecule = std::make_unique(); molecule->clone(reactions[i].getBaseMolecule(j)); int id = _allMolecules.add(molecule.release()); _addedBaseMolecule(id, reactions[i].getSideType(j), *_allMolecules[id]); - _reactions.expand(id + 1); - _reactions[id] = static_cast(i); + reactionComponents.insert(j, id); } } } -int PathwayReaction::reactionId(int moleculeId) const +std::vector PathwayReaction::getRootReactions() const { - return _reactions.at(moleculeId); + std::vector root_reactions; + for (const auto& rn : _reactionNodes) + { + if (rn.successorReactions.size() == 0) + root_reactions.push_back(rn.reactionIdx); + } + return root_reactions; } int PathwayReaction::reactionsCount() const @@ -63,128 +71,137 @@ int PathwayReaction::reactionsCount() const void PathwayReaction::clone(PathwayReaction& reaction) { BaseReaction::clone(reaction); - _reactions.copy(reaction._reactions); + _reactionNodes.copy(reaction._reactionNodes); + // copy reactions ObjArray + for (int i = 0; i < reaction._reactions.size(); i++) + { + auto& other = reaction._reactions[i]; + auto& reactionComponents = _reactions.push(); + reactionComponents.copy(other); + } } -std::pair>, std::vector>> PathwayReaction::makeTreePoints() -{ - auto reaction = this; - std::vector inchiKeys(reaction->reactionsCount()); - InchiWrapper inchiWrapper; - Array inchi, inchiKey; - for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) - { - auto& molecule = dynamic_cast(reaction->getBaseMolecule(i)); - inchiWrapper.saveMoleculeIntoInchi(molecule, inchi); - InchiWrapper::InChIKey(inchi.ptr(), inchiKey); - inchiKeys.at(i).assign(inchiKey.ptr(), inchiKey.size()); - } - - int finalProductId; - std::vector> reactantIdsByReactions(reaction->reactionsCount()); - std::unordered_map productIds; - for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) - { - if (BaseReaction::REACTANT == reaction->getSideType(i)) - reactantIdsByReactions.at(reaction->reactionId(i)).push_back(i); - else if (BaseReaction::PRODUCT == reaction->getSideType(i)) - { - productIds.emplace(inchiKeys.at(i), i); - finalProductId = i; - } - } - - std::unordered_map sumBoxes; - std::stack dfsStack; - dfsStack.push(finalProductId); - while (!dfsStack.empty()) - { - auto stackSize = dfsStack.size(); - auto id = dfsStack.top(); - - auto productIter = productIds.find(inchiKeys.at(id)); - if (productIter == productIds.cend()) - { - sumBoxes[id]; - dfsStack.pop(); - continue; - } - - auto productId = productIter->second; - for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) - if (!sumBoxes.count(reactantId)) - dfsStack.push(reactantId); - if (dfsStack.size() > stackSize) - continue; - - Vec2f rightTop(0, -2 * MARGIN); - for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) - { - Rect2f box; - reaction->getBaseMolecule(reactantId).getBoundingBox(box); - rightTop.x = std::max(rightTop.x, box.width()); - rightTop.y += std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; - } - sumBoxes[id] = {{}, rightTop}; - dfsStack.pop(); - } - - std::unordered_map points; - std::vector> arrows; - std::queue bfsQueue; - bfsQueue.push(finalProductId); - Rect2f box; - reaction->getBaseMolecule(finalProductId).getBoundingBox(box); - float offsetX = box.width() / 2 + ARROW_WIDTH + MARGIN; - while (!bfsQueue.empty()) - { - float nextOffsetX = 0; - auto size = bfsQueue.size(); - for (size_t i = 0; i < size; i++) - { - auto id = bfsQueue.front(); - bfsQueue.pop(); - - auto productIter = productIds.find(inchiKeys.at(id)); - if (productIter == productIds.cend()) - continue; - - auto zero = points[id]; - auto& reactantIds = reactantIdsByReactions[reaction->reactionId(productIter->second)]; - float offsetY = sumBoxes[id].height() / 2; - Rect2f boxFront, boxBack; - reaction->getBaseMolecule(reactantIds.front()).getBoundingBox(boxFront); - reaction->getBaseMolecule(reactantIds.back()).getBoundingBox(boxBack); - offsetY -= -std::max(boxFront.height(), sumBoxes[reactantIds.front()].height()) / 4; - offsetY -= std::max(boxBack.height(), sumBoxes[reactantIds.back()].height()) / 4; - nextOffsetX = std::max(nextOffsetX, sumBoxes[id].width()); - - arrows.emplace_back().reserve(1 + reactantIds.size()); - arrows.back().emplace_back(zero.x - offsetX + ARROW_WIDTH, zero.y); - for (int reactantId : reactantIds) - { - Rect2f box; - reaction->getBaseMolecule(reactantId).getBoundingBox(box); - float x = offsetX + sumBoxes[id].width() / 2 + MARGIN; - float y = -offsetY + std::max(box.height(), sumBoxes[reactantId].height()) / 2; - points[reactantId] = zero - Vec2f(x, y); - bfsQueue.push(reactantId); - offsetY -= std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; - arrows.back().emplace_back(zero.x - offsetX, zero.y - y); - } - - if (arrows.back().size() > 2) - { - // Add spines. The first and the last reactant arrows "y" are the highest and the lowest. - arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back().back().y); - arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back()[1].y); - } - } - offsetX = nextOffsetX / 2 + ARROW_WIDTH + MARGIN; - } - - return {std::piecewise_construct, std::forward_as_tuple(points.cbegin(), points.cend()), std::forward_as_tuple(arrows)}; -} +//std::pair>, std::vector>> PathwayReaction::makeTreePoints() +//{ +// auto reaction = this; +// std::vector inchiKeys(reaction->reactionsCount()); +// InchiWrapper inchiWrapper; +// Array inchi, inchiKey; +// for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) +// { +// auto& molecule = dynamic_cast(reaction->getBaseMolecule(i)); +// inchiWrapper.saveMoleculeIntoInchi(molecule, inchi); +// InchiWrapper::InChIKey(inchi.ptr(), inchiKey); +// inchiKeys.at(i).assign(inchiKey.ptr(), inchiKey.size()); +// } +// +// int finalProductId; +// std::vector> reactantIdsByReactions(reaction->reactionsCount()); // reaction index -> reactant molecule ids +// std::unordered_map productIds; // inchiKey -> product molecule id +// for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) +// { +// if (BaseReaction::REACTANT == reaction->getSideType(i)) +// reactantIdsByReactions.at(reaction->reactionId(i)).push_back(i); +// else if (BaseReaction::PRODUCT == reaction->getSideType(i)) +// { +// productIds.emplace(inchiKeys.at(i), i); +// finalProductId = i; +// } +// } +// +// std::unordered_map sumBoxes; +// std::stack dfsStack; +// dfsStack.push(finalProductId); // push last product +// while (!dfsStack.empty()) +// { +// auto stackSize = dfsStack.size(); +// auto id = dfsStack.top(); +// +// auto productIter = productIds.find(inchiKeys.at(id)); // take id from stack and find it in productIds by inchi key +// if (productIter == productIds.cend()) +// { +// // dead end, add reactant to sumBoxes with empty bounding box +// sumBoxes[id]; // add reactant to sumBoxes with empty bounding box +// dfsStack.pop(); // pop reactant +// continue; +// } +// +// auto productId = productIter->second; +// for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) // enumerate reactants of the reaction with productId +// if (!sumBoxes.count(reactantId)) // if reactant is not in sumBoxes, then push it to stack for further processing +// dfsStack.push(reactantId); +// if (dfsStack.size() > stackSize) // if there are reactants to process, then go while loop +// continue; +// +// // +// Vec2f rightTop(0, -2 * MARGIN); +// for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) +// { +// Rect2f box; +// reaction->getBaseMolecule(reactantId).getBoundingBox(box); +// rightTop.x = std::max(rightTop.x, box.width()); +// rightTop.y += std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; +// } +// sumBoxes[id] = {{}, rightTop}; +// dfsStack.pop(); +// } +// +// std::unordered_map points; +// std::vector> arrows; +// std::queue bfsQueue; +// bfsQueue.push(finalProductId); +// Rect2f box; +// reaction->getBaseMolecule(finalProductId).getBoundingBox(box); +// float offsetX = box.width() / 2 + ARROW_WIDTH + MARGIN; +// while (!bfsQueue.empty()) +// { +// float nextOffsetX = 0; +// auto size = bfsQueue.size(); +// for (size_t i = 0; i < size; i++) +// { +// auto id = bfsQueue.front(); +// bfsQueue.pop(); +// +// auto productIter = productIds.find(inchiKeys.at(id)); +// if (productIter == productIds.cend()) +// continue; +// +// auto zero = points[id]; +// auto& reactantIds = reactantIdsByReactions[reaction->reactionId(productIter->second)]; +// float offsetY = sumBoxes[id].height() / 2; +// Rect2f boxFront, boxBack; +// reaction->getBaseMolecule(reactantIds.front()).getBoundingBox(boxFront); +// reaction->getBaseMolecule(reactantIds.back()).getBoundingBox(boxBack); +// offsetY -= -std::max(boxFront.height(), sumBoxes[reactantIds.front()].height()) / 4; +// offsetY -= std::max(boxBack.height(), sumBoxes[reactantIds.back()].height()) / 4; +// nextOffsetX = std::max(nextOffsetX, sumBoxes[id].width()); +// +// arrows.emplace_back().reserve(1 + reactantIds.size()); +// arrows.back().emplace_back(zero.x - offsetX + ARROW_WIDTH, zero.y); +// for (int reactantId : reactantIds) +// { +// Rect2f box; +// reaction->getBaseMolecule(reactantId).getBoundingBox(box); +// float x = offsetX + sumBoxes[id].width() / 2 + MARGIN; +// float y = -offsetY + std::max(box.height(), sumBoxes[reactantId].height()) / 2; +// points[reactantId] = zero - Vec2f(x, y); +// bfsQueue.push(reactantId); +// offsetY -= std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; +// arrows.back().emplace_back(zero.x - offsetX, zero.y - y); +// } +// +// if (arrows.back().size() > 2) +// { +// // Add spines. The first and the last reactant arrows "y" are the highest and the lowest. +// arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back().back().y); +// arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back()[1].y); +// } +// } +// offsetX = nextOffsetX / 2 + ARROW_WIDTH + MARGIN; +// } +// +// return {std::piecewise_construct, std::forward_as_tuple(points.cbegin(), points.cend()), std::forward_as_tuple(arrows)}; +//} BaseReaction* PathwayReaction::neu() { diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp new file mode 100644 index 0000000000..a16dfe0e0c --- /dev/null +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#include +#include + +#include "molecule/inchi_wrapper.h" +#include "reaction/pathway_reaction_builder.h" +#include "reaction/reaction.h" + +using namespace indigo; + +IMPL_ERROR(PathwayReactionBuilder, "pathway reaction builder"); + +PathwayReactionBuilder::~PathwayReactionBuilder() +{ +} + +PathwayReactionBuilder::PathwayReactionBuilder() +{ +} + +auto PathwayReactionBuilder::findPossibleSuccessorReactions(int reactionIdx) +{ + // find possible precursors + std::map> matchedReactions; + // iterate over products of the reaction + for (auto& product : _reactionDescriptors[reactionIdx].products) + { + // find all reactions that have this product as a reactant (successors) + auto rtr_it = _reactantToReactions.find(product); + if (rtr_it != _reactantToReactions.end()) + { + // if this is a first iteration and matchedReactions is empty, + // then we just copy the set of reactions where the product is a reactant + std::map> reactionReactantIndices; + std::transform(rtr_it->second.begin(), rtr_it->second.end(), std::inserter(reactionReactantIndices, reactionReactantIndices.end()), + [](const auto& pair) { return std::make_pair(pair.first, std::vector{pair.second}); }); + + if (matchedReactions.empty()) + matchedReactions = reactionReactantIndices; + else + { + // if matchedReactions is not empty, then we find the intersection of the sets + // because we need to find only the reactions that have all given products as reactants + // typically we have only one product, but just it case it is possible to have more than one + std::map> intersection; + std::set_intersection(matchedReactions.begin(), matchedReactions.end(), reactionReactantIndices.begin(), reactionReactantIndices.end(), + std::inserter(intersection, intersection.begin()), [](const auto& a, const auto& b) { return a.first < b.first; }); + + for (auto& [key, values] : intersection) + values.insert(values.end(), intersection.at(key).begin(), intersection.at(key).end()); + + matchedReactions = std::move(intersection); + // we need at least one reaction where all products are reactants + if (matchedReactions.empty()) + break; + } + } + } + // remove the reaction itself from the set of possible precursors + matchedReactions.erase(reactionIdx); + return matchedReactions; +} + +void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactions) +{ + _reactionDescriptors.clear(); + InchiWrapper inchiWrapper; + Array inchi, inchiKey; + for (auto& reaction : reactions) + { + ReactionInchiDescriptor rd; + // iterate over molecules in the reaction, calculate inchiKeys for reactants and products + for (int i = reaction.begin(); i < reaction.end(); i = reaction.next(i)) + { + inchiWrapper.saveMoleculeIntoInchi(reaction.getBaseMolecule(i).asMolecule(), inchi); + InchiWrapper::InChIKey(inchi.ptr(), inchiKey); + switch (reaction.getSideType(i)) + { + case BaseReaction::REACTANT: { + std::string inchi_str(inchiKey.ptr(), inchiKey.size()); + rd.reactants.insert(inchi_str); + auto rtr_it = _reactantToReactions.find(inchi_str); + if (rtr_it == _reactantToReactions.end()) + { + _reactantToReactions.emplace(std::piecewise_construct, std::forward_as_tuple(inchi_str), + std::forward_as_tuple(std::initializer_list>{ + {static_cast(_reactionDescriptors.size()), static_cast(i)}})); + } + else + rtr_it->second.insert(std::make_pair(static_cast(_reactionDescriptors.size()), static_cast(i))); + } + break; + case BaseReaction::PRODUCT: + rd.products.emplace_back(inchiKey.ptr(), inchiKey.size()); + break; + default: + break; + } + } + _reactionDescriptors.push_back(rd); + } +} + +void PathwayReactionBuilder::populatePossibleReactions() +{ + // iterate over reactionDescriptors and fill possibleSuccessors + _reactionNodes.resize((int)_reactionDescriptors.size()); + _reactionNodes.zerofill(); + for (auto i = 0; i < _reactionDescriptors.size(); i++) + { + _reactionNodes[i].reactionIdx = i; + auto matchedReactions = findPossibleSuccessorReactions(i); + for (auto& [j, val] : matchedReactions) // [j, val] - j is the index of the reaction, val is the vector of reactant indexes + { + Array val_arr; + val_arr.copy(val); + _reactionNodes[i].successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); + _reactionNodes[j].precursorReactionsIndexes.push(i); + if (_reactionNodes[i].successorReactions.size() > 1 && _ambigousSuccessorReactions.count(i) == 0) + _ambigousSuccessorReactions.insert(i); + } + } +} + +auto PathwayReactionBuilder::getReactionComponents(const PathwayReaction::ReactionNode& rn, Reaction& reaction) +{ + std::vector products, reactants; + std::vector> incoming_reactants; + + std::unordered_set used_reactants; + // look up for incoming reactants from precursor reactions + for (auto precursor_idx : rn.precursorReactionsIndexes) + { + auto& precursor_rd = _reactionNodes[precursor_idx]; + if (precursor_rd.successorReactions.size() == 1) + { + auto& reactant = precursor_rd.successorReactions[0].reactantIndices; + incoming_reactants.push_back(std::vector(reactant.begin(), reactant.end())); + used_reactants.insert(reactant.begin(), reactant.end()); + } + } + + for (int i = reaction.begin(); i < reaction.end(); i = reaction.next(i)) + { + switch (reaction.getSideType(i)) + { + case BaseReaction::REACTANT: + if (used_reactants.count(i) == 0) + reactants.emplace_back(i); + break; + case BaseReaction::PRODUCT: + products.emplace_back(i); + break; + } + } + // return std::make_pair(products, reactants); + return 1; +} + +std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(std::deque& reactions) +{ + buildInchiDescriptors(reactions); + populatePossibleReactions(); + + if (_ambigousSuccessorReactions.size() > 0) + { + int product = 1; + for (auto ridx : _ambigousSuccessorReactions) + product *= static_cast(_reactionNodes[ridx].successorReactions.size()); + throw Error("Unable to build the pathway. The provided reaction set has multiple potential connection sites for products, resulting in %d possible " + "combination pathways.", + product); + } + + auto pathway_reaction = std::make_unique(reactions, _reactionNodes); + auto rr = pathway_reaction->getRootReactions(); + std::cout << "Root reactions: " << rr.size() << std::endl; + // layout the reactions + return pathway_reaction; +} \ No newline at end of file diff --git a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp index 4747267fb4..4a6a1f1bcb 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp @@ -40,7 +40,7 @@ void PathwayReactionJsonSaver::saveReaction(PathwayReaction& rxn) std::vector> points; std::vector> arrows; - std::tie(points, arrows) = reaction->makeTreePoints(); + // std::tie(points, arrows) = reaction->makeTreePoints(); // Ensure the same order across different platforms. std::sort(points.begin(), points.end()); diff --git a/core/indigo-core/reaction/src/reaction_auto_loader.cpp b/core/indigo-core/reaction/src/reaction_auto_loader.cpp index b6b5ed3751..3017d7ef32 100644 --- a/core/indigo-core/reaction/src/reaction_auto_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_auto_loader.cpp @@ -31,8 +31,7 @@ #include "reaction/reaction_json_loader.h" #include "reaction/rsmiles_loader.h" #include "reaction/rxnfile_loader.h" - -#include +#include "reaction/pathway_reaction_builder.h" using namespace indigo; @@ -354,7 +353,9 @@ std::unique_ptr ReactionAutoLoader::_loadReaction(bool query) reactions.emplace_back(); loader.loadReaction(reactions.back()); } - return std::make_unique(reactions); + + PathwayReactionBuilder builder; + return builder.buildPathwayReaction(reactions); } } diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 42f3c66a2e..b3daeb8dfd 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -27,6 +27,7 @@ #include "reaction/query_reaction.h" #include "reaction/reaction.h" #include "reaction/reaction_json_loader.h" +#include "reaction/reaction_multistep_detector.h" using namespace indigo; using namespace rapidjson; @@ -78,375 +79,12 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) throw Error("No arrow in the reaction"); if (arrow_count > 1) - parseMultipleArrowReaction(rxn); - else - parseOneArrowReaction(rxn); -} - -bool ReactionJsonLoader::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) -{ - auto plus_pos_y = std::make_pair(plus_pos.y, 0); - auto plus_pos_x = std::make_pair(plus_pos.x, 0); - - 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; }; - // look for mols where top > y - auto tops_above_it = std::upper_bound(mol_tops.begin(), mol_tops.end(), plus_pos_y, pair_comp_asc); - // look for mols where bottom < y - auto bottoms_below_it = std::upper_bound(mol_bottoms.begin(), mol_bottoms.end(), plus_pos_y, pair_comp_des); - // look for mols where right > x - auto rights_after_it = std::upper_bound(mol_rights.begin(), mol_rights.end(), plus_pos_x, pair_comp_asc); - // look for mols where left < x - auto lefts_before_it = std::upper_bound(mol_lefts.begin(), mol_lefts.end(), plus_pos_x, pair_comp_des); - - FLOAT_INT_PAIRS tops_above, bottoms_below, lefts_before, rights_after; - - std::copy(tops_above_it, mol_tops.end(), std::back_inserter(tops_above)); - std::copy(bottoms_below_it, mol_bottoms.end(), std::back_inserter(bottoms_below)); - std::copy(rights_after_it, mol_rights.end(), std::back_inserter(rights_after)); - std::copy(lefts_before_it, mol_lefts.end(), std::back_inserter(lefts_before)); - - std::sort(tops_above.begin(), tops_above.end(), pair_comp_mol_asc); - std::sort(bottoms_below.begin(), bottoms_below.end(), pair_comp_mol_asc); - std::sort(rights_after.begin(), rights_after.end(), pair_comp_mol_asc); - std::sort(lefts_before.begin(), lefts_before.end(), pair_comp_mol_asc); - - // build intersections - FLOAT_INT_PAIRS intersection_top_bottom, intersection_left_right; - std::set_intersection(tops_above.begin(), tops_above.end(), bottoms_below.begin(), bottoms_below.end(), std::back_inserter(intersection_top_bottom), - pair_comp_mol_asc); - - std::set_intersection(lefts_before.begin(), lefts_before.end(), rights_after.begin(), rights_after.end(), std::back_inserter(intersection_left_right), - pair_comp_mol_asc); - - // collect left-right - FLOAT_INT_PAIRS rights_row, lefts_row, tops_col, bottoms_col; - for (const auto& kvp : intersection_top_bottom) - { - auto& tb_box = _reaction_components[kvp.second].bbox; - if (tb_box.pointInRect(plus_pos)) - continue; - rights_row.emplace_back(tb_box.right(), kvp.second); - lefts_row.emplace_back(tb_box.left(), kvp.second); - } - - // collect top-bottom - for (const auto& kvp : intersection_left_right) - { - auto& lr_box = _reaction_components[kvp.second].bbox; - if (lr_box.pointInRect(plus_pos)) - continue; - tops_col.emplace_back(lr_box.top(), kvp.second); - bottoms_col.emplace_back(lr_box.bottom(), kvp.second); - } - - 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); - std::sort(bottoms_col.begin(), bottoms_col.end(), pair_comp_des); - - auto rights_row_it = std::upper_bound(rights_row.begin(), rights_row.end(), plus_pos_x, pair_comp_des); - auto lefts_row_it = std::upper_bound(lefts_row.begin(), lefts_row.end(), plus_pos_x, pair_comp_asc); - auto tops_col_it = std::upper_bound(tops_col.begin(), tops_col.end(), plus_pos_y, pair_comp_asc); - auto bottoms_col_it = std::upper_bound(bottoms_col.begin(), bottoms_col.end(), plus_pos_y, pair_comp_des); - - float min_distance_h = 0, min_distance_v = 0; - - bool result = false; - - if (rights_row_it != rights_row.end() && lefts_row_it != lefts_row.end()) - { - 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.first = lefts_row_it->second; - connection.second = rights_row_it->second; - result = _reaction_components[connection.first].component_type == ReactionComponent::MOLECULE && - _reaction_components[connection.second].component_type == ReactionComponent::MOLECULE; - } - - if (tops_col_it != tops_col.end() && bottoms_col_it != bottoms_col.end()) - { - min_distance_v = std::min(tops_col_it->first - plus_pos_y.first, bottoms_col_it->first - plus_pos_y.first); - if (!result || min_distance_v < min_distance_h) - { - connection.first = tops_col_it->second; - connection.second = bottoms_col_it->second; - result = _reaction_components[connection.first].component_type == ReactionComponent::MOLECULE && - _reaction_components[connection.second].component_type == ReactionComponent::MOLECULE; - } - } - return result; -} - -void ReactionJsonLoader::constructMultipleArrowReaction(BaseReaction& rxn) -{ - // _reaction_components -> allMolecules - // _component_summ_blocks -> - for (auto& rc : _reaction_components) - { - if (rc.component_type == ReactionComponent::MOLECULE) - { - auto& csb = _component_summ_blocks[rc.summ_block_idx]; - switch (csb.role) - { - case BaseReaction::REACTANT: - rxn.addReactantCopy(*rc.molecule, 0, 0); - break; - case BaseReaction::PRODUCT: - rxn.addProductCopy(*rc.molecule, 0, 0); - break; - case BaseReaction::INTERMEDIATE: - rxn.addIntermediateCopy(*rc.molecule, 0, 0); - break; - case BaseReaction::UNDEFINED: - rxn.addUndefinedCopy(*rc.molecule, 0, 0); - break; - case BaseReaction::CATALYST: - rxn.addCatalystCopy(*rc.molecule, 0, 0); - break; - } - } - } -} - -void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) -{ - 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(*_pmol, s_neighbors); - int count = _pmol->countComponents(s_neighbors); - _reaction_components.reserve(count); - FLOAT_INT_PAIRS mol_tops, mol_bottoms, mol_lefts, mol_rights; - - // collect components - for (int i = 0; i < count; ++i) - { - Filter filter(_pmol->getDecomposition().ptr(), Filter::EQ, i); - std::unique_ptr component; - if (rxn.isQueryReaction()) - component = std::make_unique(); - else - component = std::make_unique(); - - BaseMolecule& mol = *component; - mol.makeSubmolecule(*_pmol, filter, 0, 0); - Rect2f bbox; - 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(component)); - } - - for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) - { - auto& plus = (const KETReactionPlus&)rxn.meta().getMetaObject(KETReactionPlus::CID, i); - const auto& plus_pos = plus.getPos(); - Rect2f bbox(plus_pos - PLUS_BBOX_SHIFT, plus_pos + PLUS_BBOX_SHIFT); - _reaction_components.emplace_back(ReactionComponent::PLUS, bbox, i, std::unique_ptr(nullptr)); - _reaction_components.back().coordinates.push_back(plus_pos); - int index = static_cast(_reaction_components.size() - 1); - mol_tops.emplace_back(bbox.top(), index); - mol_bottoms.emplace_back(bbox.bottom(), index); - mol_lefts.emplace_back(bbox.left(), index); - mol_rights.emplace_back(bbox.right(), index); - } - - for (int i = 0; i < rxn.meta().getMetaCount(KETReactionArrow::CID); ++i) { - auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, i); - int arrow_type = arrow.getArrowType(); - bool reverseReactionOrder = arrow_type == KETReactionArrow::ERetrosynthetic; - const Vec2f& arr_begin = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); - const Vec2f& arr_end = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); - Rect2f bbox(arr_begin - ARROW_BBOX_SHIFT, arr_end + ARROW_BBOX_SHIFT); - _reaction_components.emplace_back(arrow_type, bbox, i, std::unique_ptr(nullptr)); - _reaction_components.back().coordinates.push_back(arr_begin); - _reaction_components.back().coordinates.push_back(arr_end); - int index = static_cast(_reaction_components.size() - 1); - mol_tops.emplace_back(bbox.top(), index); - mol_bottoms.emplace_back(bbox.bottom(), index); - mol_lefts.emplace_back(bbox.left(), index); - mol_rights.emplace_back(bbox.right(), index); + ReactionMultistepDetector md(*_pmol); + md.buildReaction(rxn); } - - // sort components - std::sort(mol_tops.begin(), mol_tops.end(), pair_comp_asc); - std::sort(mol_bottoms.begin(), mol_bottoms.end(), pair_comp_des); - std::sort(mol_lefts.begin(), mol_lefts.end(), pair_comp_des); - std::sort(mol_rights.begin(), mol_rights.end(), pair_comp_asc); - - for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) - { - auto& plus = static_cast(rxn.meta().getMetaObject(KETReactionPlus::CID, i)); - auto& plus_pos = plus.getPos(); - std::pair plus_connection; // (component1_index, component2_index) - - if (findPlusNeighbours(plus_pos, mol_tops, mol_bottoms, mol_lefts, mol_rights, plus_connection)) - { - _reaction_components[count + i].summ_block_idx = ReactionComponent::CONNECTED; // mark plus as connected - - auto rc_connection = std::make_pair(std::ref(_reaction_components[plus_connection.first]), - std::ref(_reaction_components[plus_connection.second])); // component1, component2 - - enum - { - LI_NEW_CONNECTION = 0, - LI_FIRST_ONLY, - LI_SECOND_ONLY, - LI_BOTH - }; - - int logic_index = (rc_connection.first.summ_block_idx == ReactionComponent::NOT_CONNECTED ? 0 : 1) + - (rc_connection.second.summ_block_idx == ReactionComponent::NOT_CONNECTED ? 0 : 2); - - switch (logic_index) - { - case LI_NEW_CONNECTION: { - // create brand new connection - Rect2f bbox = rc_connection.first.bbox; - merge_bbox(bbox, rc_connection.second.bbox); - _component_summ_blocks_list.emplace_back(bbox); // add merged boxes of both components - auto& last_sb = _component_summ_blocks_list.back(); - last_sb.indexes.push_back(plus_connection.first); - last_sb.indexes.push_back(plus_connection.second); - - rc_connection.first.summ_block_idx = ReactionComponent::CONNECTED; // mark as connected - rc_connection.second.summ_block_idx = ReactionComponent::CONNECTED; - auto last_it = std::prev(_component_summ_blocks_list.end()); - rc_connection.first.summ_block_it = last_it; // bind to summ blocks list - rc_connection.second.summ_block_it = last_it; - } - break; - - case LI_BOTH: { - // merge two blocks - auto& block_first = *rc_connection.first.summ_block_it; - auto& block_second = *rc_connection.second.summ_block_it; - auto second_block_it = rc_connection.second.summ_block_it; - merge_bbox(block_first.bbox, block_second.bbox); - for (int v : block_second.indexes) - { - block_first.indexes.push_back(v); // copy all indexes of block_second to block_first - _reaction_components[v].summ_block_it = rc_connection.first.summ_block_it; // patch copied components. now they belong to block_first. - } - _component_summ_blocks_list.erase(second_block_it); // remove block_second - } - break; - - case LI_FIRST_ONLY: { - // connect second to the existing first block - auto& block = *rc_connection.first.summ_block_it; - block.indexes.push_back(plus_connection.second); // add second component - merge_bbox(block.bbox, rc_connection.second.bbox); // merge second box with block box - rc_connection.second.summ_block_it = rc_connection.first.summ_block_it; // bind second to the first block - rc_connection.second.summ_block_idx = ReactionComponent::CONNECTED; // mark second as connected - } - break; - - case LI_SECOND_ONLY: { - // connect first to the existing second block - auto& block = *rc_connection.second.summ_block_it; - block.indexes.push_back(plus_connection.first); // add second component - merge_bbox(block.bbox, rc_connection.first.bbox); // merge second box with block box - rc_connection.first.summ_block_it = rc_connection.second.summ_block_it; // bind second to the first block - rc_connection.first.summ_block_idx = ReactionComponent::CONNECTED; // mark second as connected - } - break; - } - } - } - - // copy list to vector and set summ block indexes - for (auto& csb : _component_summ_blocks_list) - { - for (int v : csb.indexes) - _reaction_components[v].summ_block_idx = static_cast(_component_summ_blocks.size()); - _component_summ_blocks.push_back(csb); - } - - // add all single molecules to _component_summ_blocks - for (size_t i = 0; i < _reaction_components.size(); ++i) - { - auto& rc = _reaction_components[i]; - if (rc.component_type != ReactionComponent::MOLECULE) - break; - if (rc.summ_block_idx == ReactionComponent::NOT_CONNECTED) - { - rc.summ_block_idx = static_cast(_component_summ_blocks.size()); - _component_summ_blocks.push_back(_reaction_components[i].bbox); - _component_summ_blocks.back().indexes.push_back(static_cast(i)); - } - } - - // handle arrows - for (int i = 0; i < rxn.meta().getMetaCount(KETReactionArrow::CID); ++i) - { - auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, i); - int arrow_type = arrow.getArrowType(); - bool reverseReactionOrder = arrow_type == KETReactionArrow::ERetrosynthetic; - const Vec2f& arr_begin = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); - const Vec2f& arr_end = !reverseReactionOrder ? arrow.getHead() : arrow.getTail(); - double min_dist_prod = -1, min_dist_reac = -1; - int idx_cs_min_prod = -1, idx_cs_min_reac = -1; - for (int index_cs = 0; index_cs < static_cast(_component_summ_blocks.size()); ++index_cs) - { - auto& csb = _component_summ_blocks[index_cs]; - if (csb.bbox.rayIntersectsRect(arr_end, arr_begin)) - { - double dist = csb.bbox.pointDistance(arr_end); - if (min_dist_prod < 0 || dist < min_dist_prod) - { - min_dist_prod = dist; - idx_cs_min_prod = index_cs; - } - } - else if (csb.bbox.rayIntersectsRect(arr_begin, arr_end)) - { - double dist = csb.bbox.pointDistance(arr_begin); - if (min_dist_reac < 0 || dist < min_dist_reac) - { - min_dist_reac = dist; - idx_cs_min_reac = index_cs; - } - } - } - - auto& rb = rxn.addReactionBlock(); - rb.arrow_index = i; - - if (min_dist_prod > 0 && min_dist_reac > 0) // if both ends present - { - auto& rc_arrow = _reaction_components[count + rxn.meta().getMetaCount(KETReactionPlus::CID) + i]; - rc_arrow.summ_block_idx = ReactionComponent::CONNECTED; // mark arrow as connected - auto& csb_min_prod = _component_summ_blocks[idx_cs_min_prod]; - if (csb_min_prod.role == BaseReaction::UNDEFINED) - csb_min_prod.role = BaseReaction::PRODUCT; - else if (csb_min_prod.role == BaseReaction::REACTANT) - csb_min_prod.role = BaseReaction::INTERMEDIATE; - - auto& csb_min_reac = _component_summ_blocks[idx_cs_min_reac]; - if (csb_min_reac.role == BaseReaction::UNDEFINED) - csb_min_reac.role = BaseReaction::REACTANT; - else if (csb_min_reac.role == BaseReaction::PRODUCT) - csb_min_reac.role = BaseReaction::INTERMEDIATE; - - // idx_cs_min_reac -> idx_cs_min_prod - csb_min_reac.arrows_to.push_back(idx_cs_min_prod); - for (auto ri : csb_min_reac.indexes) - rb.reactants.push(_reaction_components[ri].index); - for (auto pi : csb_min_prod.indexes) - rb.products.push(_reaction_components[pi].index); - } - } - - // _component_summ_blocks, _reaction_components - result - constructMultipleArrowReaction(rxn); + else + parseOneArrowReaction(rxn); } void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) diff --git a/third_party/inchi/INCHI_BASE/src/ichicans.c b/third_party/inchi/INCHI_BASE/src/ichicans.c index 7e72359306..bd03cce2ef 100755 --- a/third_party/inchi/INCHI_BASE/src/ichicans.c +++ b/third_party/inchi/INCHI_BASE/src/ichicans.c @@ -322,7 +322,7 @@ int UnmarkNonStereo( CANON_GLOBALS *pCG, AT_RANK nNeighborNumber[MAX_NUM_STEREO_ATOM_NEIGH]; AT_RANK nPrevAtomRank, nPrevNeighRank; #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG - int num_in_same_ring_system, nRingSystem, num_with_eq_neigh_in_same_ring_system = 0; + int num_in_same_ring_system = 0, nRingSystem, num_with_eq_neigh_in_same_ring_system = 0; #endif diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index f5007c65a9..455a80b135 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -245,6 +245,7 @@ enum OEXT_CML, OEXT_KET, OEXT_KER, + OEXT_RDR, OEXT_CDX, OEXT_CDX64, OEXT_CDR, @@ -347,7 +348,7 @@ int parseParams(Params* p, int argc, char* argv[]) strcasecmp(p->infile_ext, "seq") == 0 || strcasecmp(p->infile_ext, "fst") == 0) p->mode = MODE_SINGLE_MOLECULE; else if (strcasecmp(p->infile_ext, "rxn") == 0 || strcasecmp(p->infile_ext, "ker") == 0 || strcasecmp(p->infile_ext, "cdr") == 0 || - strcasecmp(p->infile_ext, "xmr") == 0 || strcasecmp(p->infile_ext, "r64") == 0) + strcasecmp(p->infile_ext, "xmr") == 0 || strcasecmp(p->infile_ext, "r64") == 0 || strcasecmp(p->infile_ext, "rdr") == 0) { p->mode = MODE_SINGLE_REACTION; } @@ -887,6 +888,8 @@ int main(int argc, char* argv[]) p.out_ext = OEXT_KET; else if (strcmp(p.outfile_ext, "ker") == 0) p.out_ext = OEXT_KER; + else if (strcmp(p.outfile_ext, "rdr") == 0) + p.out_ext = OEXT_RDR; else if (strcmp(p.outfile_ext, "smi") == 0) p.out_ext = OEXT_SMI; else if (strcmp(p.outfile_ext, "cdxml") == 0) @@ -1055,7 +1058,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 c486842d85926f8668000636ad35fc1581b8554a Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 27 Aug 2024 07:47:29 +0200 Subject: [PATCH 02/25] multitale rendering --- .../reaction/reaction_multistep_detector.h | 70 +++ .../src/reaction_multistep_detector.cpp | 418 ++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 core/indigo-core/reaction/reaction_multistep_detector.h create mode 100644 core/indigo-core/reaction/src/reaction_multistep_detector.cpp diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h new file mode 100644 index 0000000000..c99d33d968 --- /dev/null +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#ifndef __reaction_multistep_detector__ +#define __reaction_multistep_detector__ + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +#include +#include +#include + +#include "base_cpp/exception.h" +#include "molecule/ket_commons.h" + +namespace indigo +{ + + class BaseMolecule; + class BaseReaction; + + class ReactionMultistepDetector + { + public: + ReactionMultistepDetector(BaseMolecule& mol); + ~ReactionMultistepDetector(); + void buildReaction(BaseReaction& rxn); + typedef std::pair FLOAT_INT_PAIR; + typedef std::vector FLOAT_INT_PAIRS; + const Vec2f PLUS_BBOX_SHIFT = {0.9f, 0.9f}; + const Vec2f ARROW_BBOX_SHIFT = {0.0f, 0.9f}; + + DECL_ERROR; + + private: + void constructMultipleArrowReaction(BaseReaction& rxn); + bool 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); + + BaseMolecule& _bmol; + std::vector _reaction_components; + std::vector _component_summ_blocks; + std::list _component_summ_blocks_list; + }; + +} // namespace indigo + +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#endif diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp new file mode 100644 index 0000000000..a97aefab86 --- /dev/null +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -0,0 +1,418 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#include "reaction/reaction_multistep_detector.h" +#include "reaction/reaction.h" + +using namespace indigo; + +inline void merge_bbox(Rect2f& bb1, const Rect2f& bb2) +{ + Vec2f lb, rt; + lb.x = std::min(bb1.left(), bb2.left()); + rt.x = std::max(bb1.right(), bb2.right()); + lb.y = std::min(bb1.bottom(), bb2.bottom()); + rt.y = std::max(bb1.top(), bb2.top()); + bb1 = Rect2f(lb, rt); +} + +IMPL_ERROR(ReactionMultistepDetector, "reaction multistep detector"); + +ReactionMultistepDetector::~ReactionMultistepDetector() +{ +} + +#include "molecule/molecule_json_saver.h" + +ReactionMultistepDetector::ReactionMultistepDetector(BaseMolecule& bmol) : _bmol(bmol) +{ + rapidjson::StringBuffer buffer; + JsonWriter writer(true); + writer.Reset(buffer); + std::string str_json; + StringOutput output( str_json ); + MoleculeJsonSaver moleculeSaver(output); + moleculeSaver.saveMolecule(bmol, writer); + std::cout << str_json << std::endl; +} + +void ReactionMultistepDetector::buildReaction(BaseReaction& rxn) +{ + 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); + int count = _bmol.countComponents(s_neighbors); + _reaction_components.reserve(count); + FLOAT_INT_PAIRS mol_tops, mol_bottoms, mol_lefts, mol_rights; + + // collect components + for (int i = 0; i < count; ++i) + { + Filter filter(_bmol.getDecomposition().ptr(), Filter::EQ, i); + std::unique_ptr component; + if (rxn.isQueryReaction()) + 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); + + 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)); + } + + for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) + { + auto& plus = (const KETReactionPlus&)rxn.meta().getMetaObject(KETReactionPlus::CID, i); + const auto& plus_pos = plus.getPos(); + Rect2f bbox(plus_pos - PLUS_BBOX_SHIFT, plus_pos + PLUS_BBOX_SHIFT); + _reaction_components.emplace_back(ReactionComponent::PLUS, bbox, i, std::unique_ptr(nullptr)); + _reaction_components.back().coordinates.push_back(plus_pos); + int index = static_cast(_reaction_components.size() - 1); + mol_tops.emplace_back(bbox.top(), index); + mol_bottoms.emplace_back(bbox.bottom(), index); + mol_lefts.emplace_back(bbox.left(), index); + mol_rights.emplace_back(bbox.right(), index); + } + + for (int i = 0; i < rxn.meta().getMetaCount(KETReactionArrow::CID); ++i) + { + auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, i); + int arrow_type = arrow.getArrowType(); + bool reverseReactionOrder = arrow_type == KETReactionArrow::ERetrosynthetic; + const Vec2f& arr_begin = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); + const Vec2f& arr_end = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); + Rect2f bbox(arr_begin - ARROW_BBOX_SHIFT, arr_end + ARROW_BBOX_SHIFT); + _reaction_components.emplace_back(arrow_type, bbox, i, std::unique_ptr(nullptr)); + _reaction_components.back().coordinates.push_back(arr_begin); + _reaction_components.back().coordinates.push_back(arr_end); + int index = static_cast(_reaction_components.size() - 1); + mol_tops.emplace_back(bbox.top(), index); + mol_bottoms.emplace_back(bbox.bottom(), index); + mol_lefts.emplace_back(bbox.left(), index); + mol_rights.emplace_back(bbox.right(), index); + } + + // sort components + std::sort(mol_tops.begin(), mol_tops.end(), pair_comp_asc); + std::sort(mol_bottoms.begin(), mol_bottoms.end(), pair_comp_des); + std::sort(mol_lefts.begin(), mol_lefts.end(), pair_comp_des); + std::sort(mol_rights.begin(), mol_rights.end(), pair_comp_asc); + + for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) + { + auto& plus = static_cast(rxn.meta().getMetaObject(KETReactionPlus::CID, i)); + auto& plus_pos = plus.getPos(); + std::pair plus_connection; // (component1_index, component2_index) + + if (findPlusNeighbours(plus_pos, mol_tops, mol_bottoms, mol_lefts, mol_rights, plus_connection)) + { + _reaction_components[count + i].summ_block_idx = ReactionComponent::CONNECTED; // mark plus as connected + + auto rc_connection = std::make_pair(std::ref(_reaction_components[plus_connection.first]), + std::ref(_reaction_components[plus_connection.second])); // component1, component2 + + enum + { + LI_NEW_CONNECTION = 0, + LI_FIRST_ONLY, + LI_SECOND_ONLY, + LI_BOTH + }; + + int logic_index = (rc_connection.first.summ_block_idx == ReactionComponent::NOT_CONNECTED ? 0 : 1) + + (rc_connection.second.summ_block_idx == ReactionComponent::NOT_CONNECTED ? 0 : 2); + + switch (logic_index) + { + case LI_NEW_CONNECTION: { + // create brand new connection + Rect2f bbox = rc_connection.first.bbox; + merge_bbox(bbox, rc_connection.second.bbox); + _component_summ_blocks_list.emplace_back(bbox); // add merged boxes of both components + auto& last_sb = _component_summ_blocks_list.back(); + last_sb.indexes.push_back(plus_connection.first); + last_sb.indexes.push_back(plus_connection.second); + + rc_connection.first.summ_block_idx = ReactionComponent::CONNECTED; // mark as connected + rc_connection.second.summ_block_idx = ReactionComponent::CONNECTED; + auto last_it = std::prev(_component_summ_blocks_list.end()); + rc_connection.first.summ_block_it = last_it; // bind to summ blocks list + rc_connection.second.summ_block_it = last_it; + } + break; + + case LI_BOTH: { + // merge two blocks + auto& block_first = *rc_connection.first.summ_block_it; + auto& block_second = *rc_connection.second.summ_block_it; + auto second_block_it = rc_connection.second.summ_block_it; + merge_bbox(block_first.bbox, block_second.bbox); + for (int v : block_second.indexes) + { + block_first.indexes.push_back(v); // copy all indexes of block_second to block_first + _reaction_components[v].summ_block_it = rc_connection.first.summ_block_it; // patch copied components. now they belong to block_first. + } + _component_summ_blocks_list.erase(second_block_it); // remove block_second + } + break; + + case LI_FIRST_ONLY: { + // connect second to the existing first block + auto& block = *rc_connection.first.summ_block_it; + block.indexes.push_back(plus_connection.second); // add second component + merge_bbox(block.bbox, rc_connection.second.bbox); // merge second box with block box + rc_connection.second.summ_block_it = rc_connection.first.summ_block_it; // bind second to the first block + rc_connection.second.summ_block_idx = ReactionComponent::CONNECTED; // mark second as connected + } + break; + + case LI_SECOND_ONLY: { + // connect first to the existing second block + auto& block = *rc_connection.second.summ_block_it; + block.indexes.push_back(plus_connection.first); // add second component + merge_bbox(block.bbox, rc_connection.first.bbox); // merge second box with block box + rc_connection.first.summ_block_it = rc_connection.second.summ_block_it; // bind second to the first block + rc_connection.first.summ_block_idx = ReactionComponent::CONNECTED; // mark second as connected + } + break; + } + } + } + + // copy list to vector and set summ block indexes + for (auto& csb : _component_summ_blocks_list) + { + for (int v : csb.indexes) + _reaction_components[v].summ_block_idx = static_cast(_component_summ_blocks.size()); + _component_summ_blocks.push_back(csb); + } + + // add all single molecules to _component_summ_blocks + for (size_t i = 0; i < _reaction_components.size(); ++i) + { + auto& rc = _reaction_components[i]; + if (rc.component_type != ReactionComponent::MOLECULE) + break; + if (rc.summ_block_idx == ReactionComponent::NOT_CONNECTED) + { + rc.summ_block_idx = static_cast(_component_summ_blocks.size()); + _component_summ_blocks.push_back(_reaction_components[i].bbox); + _component_summ_blocks.back().indexes.push_back(static_cast(i)); + } + } + + // handle arrows + for (int i = 0; i < rxn.meta().getMetaCount(KETReactionArrow::CID); ++i) + { + auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, i); + int arrow_type = arrow.getArrowType(); + bool reverseReactionOrder = arrow_type == KETReactionArrow::ERetrosynthetic; + const Vec2f& arr_begin = !reverseReactionOrder ? arrow.getTail() : arrow.getHead(); + const Vec2f& arr_end = !reverseReactionOrder ? arrow.getHead() : arrow.getTail(); + double min_dist_prod = -1, min_dist_reac = -1; + int idx_cs_min_prod = -1, idx_cs_min_reac = -1; + for (int index_cs = 0; index_cs < static_cast(_component_summ_blocks.size()); ++index_cs) + { + auto& csb = _component_summ_blocks[index_cs]; + if (csb.bbox.rayIntersectsRect(arr_end, arr_begin)) + { + double dist = csb.bbox.pointDistance(arr_end); + if (min_dist_prod < 0 || dist < min_dist_prod) + { + min_dist_prod = dist; + idx_cs_min_prod = index_cs; + } + } + else if (csb.bbox.rayIntersectsRect(arr_begin, arr_end)) + { + double dist = csb.bbox.pointDistance(arr_begin); + if (min_dist_reac < 0 || dist < min_dist_reac) + { + min_dist_reac = dist; + idx_cs_min_reac = index_cs; + } + } + } + + auto& rb = rxn.addReactionBlock(); + rb.arrow_index = i; + + if (min_dist_prod > 0 && min_dist_reac > 0) // if both ends present + { + auto& rc_arrow = _reaction_components[count + rxn.meta().getMetaCount(KETReactionPlus::CID) + i]; + rc_arrow.summ_block_idx = ReactionComponent::CONNECTED; // mark arrow as connected + auto& csb_min_prod = _component_summ_blocks[idx_cs_min_prod]; + if (csb_min_prod.role == BaseReaction::UNDEFINED) + csb_min_prod.role = BaseReaction::PRODUCT; + else if (csb_min_prod.role == BaseReaction::REACTANT) + csb_min_prod.role = BaseReaction::INTERMEDIATE; + + auto& csb_min_reac = _component_summ_blocks[idx_cs_min_reac]; + if (csb_min_reac.role == BaseReaction::UNDEFINED) + csb_min_reac.role = BaseReaction::REACTANT; + else if (csb_min_reac.role == BaseReaction::PRODUCT) + csb_min_reac.role = BaseReaction::INTERMEDIATE; + + // idx_cs_min_reac -> idx_cs_min_prod + csb_min_reac.arrows_to.push_back(idx_cs_min_prod); + for (auto ri : csb_min_reac.indexes) + rb.reactants.push(_reaction_components[ri].index); + for (auto pi : csb_min_prod.indexes) + rb.products.push(_reaction_components[pi].index); + } + } + + // _component_summ_blocks, _reaction_components - result + constructMultipleArrowReaction(rxn); +} + +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) +{ + auto plus_pos_y = std::make_pair(plus_pos.y, 0); + auto plus_pos_x = std::make_pair(plus_pos.x, 0); + + 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; }; + // look for mols where top > y + auto tops_above_it = std::upper_bound(mol_tops.begin(), mol_tops.end(), plus_pos_y, pair_comp_asc); + // look for mols where bottom < y + auto bottoms_below_it = std::upper_bound(mol_bottoms.begin(), mol_bottoms.end(), plus_pos_y, pair_comp_des); + // look for mols where right > x + auto rights_after_it = std::upper_bound(mol_rights.begin(), mol_rights.end(), plus_pos_x, pair_comp_asc); + // look for mols where left < x + auto lefts_before_it = std::upper_bound(mol_lefts.begin(), mol_lefts.end(), plus_pos_x, pair_comp_des); + + FLOAT_INT_PAIRS tops_above, bottoms_below, lefts_before, rights_after; + + std::copy(tops_above_it, mol_tops.end(), std::back_inserter(tops_above)); + std::copy(bottoms_below_it, mol_bottoms.end(), std::back_inserter(bottoms_below)); + std::copy(rights_after_it, mol_rights.end(), std::back_inserter(rights_after)); + std::copy(lefts_before_it, mol_lefts.end(), std::back_inserter(lefts_before)); + + std::sort(tops_above.begin(), tops_above.end(), pair_comp_mol_asc); + std::sort(bottoms_below.begin(), bottoms_below.end(), pair_comp_mol_asc); + std::sort(rights_after.begin(), rights_after.end(), pair_comp_mol_asc); + std::sort(lefts_before.begin(), lefts_before.end(), pair_comp_mol_asc); + + // build intersections + FLOAT_INT_PAIRS intersection_top_bottom, intersection_left_right; + std::set_intersection(tops_above.begin(), tops_above.end(), bottoms_below.begin(), bottoms_below.end(), std::back_inserter(intersection_top_bottom), + pair_comp_mol_asc); + + std::set_intersection(lefts_before.begin(), lefts_before.end(), rights_after.begin(), rights_after.end(), std::back_inserter(intersection_left_right), + pair_comp_mol_asc); + + // collect left-right + FLOAT_INT_PAIRS rights_row, lefts_row, tops_col, bottoms_col; + for (const auto& kvp : intersection_top_bottom) + { + auto& tb_box = _reaction_components[kvp.second].bbox; + if (tb_box.pointInRect(plus_pos)) + continue; + rights_row.emplace_back(tb_box.right(), kvp.second); + lefts_row.emplace_back(tb_box.left(), kvp.second); + } + + // collect top-bottom + for (const auto& kvp : intersection_left_right) + { + auto& lr_box = _reaction_components[kvp.second].bbox; + if (lr_box.pointInRect(plus_pos)) + continue; + tops_col.emplace_back(lr_box.top(), kvp.second); + bottoms_col.emplace_back(lr_box.bottom(), kvp.second); + } + + 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); + std::sort(bottoms_col.begin(), bottoms_col.end(), pair_comp_des); + + auto rights_row_it = std::upper_bound(rights_row.begin(), rights_row.end(), plus_pos_x, pair_comp_des); + auto lefts_row_it = std::upper_bound(lefts_row.begin(), lefts_row.end(), plus_pos_x, pair_comp_asc); + auto tops_col_it = std::upper_bound(tops_col.begin(), tops_col.end(), plus_pos_y, pair_comp_asc); + auto bottoms_col_it = std::upper_bound(bottoms_col.begin(), bottoms_col.end(), plus_pos_y, pair_comp_des); + + float min_distance_h = 0, min_distance_v = 0; + + bool result = false; + + if (rights_row_it != rights_row.end() && lefts_row_it != lefts_row.end()) + { + 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.first = lefts_row_it->second; + connection.second = rights_row_it->second; + result = _reaction_components[connection.first].component_type == ReactionComponent::MOLECULE && + _reaction_components[connection.second].component_type == ReactionComponent::MOLECULE; + } + + if (tops_col_it != tops_col.end() && bottoms_col_it != bottoms_col.end()) + { + min_distance_v = std::min(tops_col_it->first - plus_pos_y.first, bottoms_col_it->first - plus_pos_y.first); + if (!result || min_distance_v < min_distance_h) + { + connection.first = tops_col_it->second; + connection.second = bottoms_col_it->second; + result = _reaction_components[connection.first].component_type == ReactionComponent::MOLECULE && + _reaction_components[connection.second].component_type == ReactionComponent::MOLECULE; + } + } + return result; +} + +void ReactionMultistepDetector::constructMultipleArrowReaction(BaseReaction& rxn) +{ + // _reaction_components -> allMolecules + // _component_summ_blocks -> + for (auto& rc : _reaction_components) + { + if (rc.component_type == ReactionComponent::MOLECULE) + { + auto& csb = _component_summ_blocks[rc.summ_block_idx]; + switch (csb.role) + { + case BaseReaction::REACTANT: + rxn.addReactantCopy(*rc.molecule, 0, 0); + break; + case BaseReaction::PRODUCT: + rxn.addProductCopy(*rc.molecule, 0, 0); + break; + case BaseReaction::INTERMEDIATE: + rxn.addIntermediateCopy(*rc.molecule, 0, 0); + break; + case BaseReaction::UNDEFINED: + rxn.addUndefinedCopy(*rc.molecule, 0, 0); + break; + case BaseReaction::CATALYST: + rxn.addCatalystCopy(*rc.molecule, 0, 0); + break; + } + } + } +} From 04f46e1137f1d526999837971e38a41dabd9f76b Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 27 Aug 2024 07:54:20 +0200 Subject: [PATCH 03/25] multitale rendering --- core/indigo-core/layout/pathway_layout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index 4831c43923..76ce5a26d2 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -59,7 +59,7 @@ namespace indigo } }; - // PathwayLayout is a class which makes a tree layout of the reactions in O(N) time + // PathwayLayout is a class which makes a tree layout of the pathway reaction in O(N) time class PathwayLayout { public: From 39cca9f200cdab79b6cd1199fdd2d92da20b7d49 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 27 Aug 2024 08:31:25 +0200 Subject: [PATCH 04/25] multitale rendering --- .../reaction/pathway_reaction_builder.h | 2 +- .../reaction/src/pathway_reaction_builder.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index 20778ec301..86df4507d5 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -98,7 +98,7 @@ namespace indigo void populatePossibleReactions(); auto findPossibleSuccessorReactions(int reactionIdx); auto getReactionComponents(const PathwayReaction::ReactionNode& rn, Reaction& reaction); - std::vector _reactionDescriptors; + std::vector _reactionInchiDescriptors; Array _reactionNodes; std::unordered_map> _reactantToReactions; std::unordered_set _ambigousSuccessorReactions; // reactions that have more than one possible successor diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index a16dfe0e0c..3bf9caa9ba 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -40,7 +40,7 @@ auto PathwayReactionBuilder::findPossibleSuccessorReactions(int reactionIdx) // find possible precursors std::map> matchedReactions; // iterate over products of the reaction - for (auto& product : _reactionDescriptors[reactionIdx].products) + for (auto& product : _reactionInchiDescriptors[reactionIdx].products) { // find all reactions that have this product as a reactant (successors) auto rtr_it = _reactantToReactions.find(product); @@ -80,7 +80,7 @@ auto PathwayReactionBuilder::findPossibleSuccessorReactions(int reactionIdx) void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactions) { - _reactionDescriptors.clear(); + _reactionInchiDescriptors.clear(); InchiWrapper inchiWrapper; Array inchi, inchiKey; for (auto& reaction : reactions) @@ -101,10 +101,10 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio { _reactantToReactions.emplace(std::piecewise_construct, std::forward_as_tuple(inchi_str), std::forward_as_tuple(std::initializer_list>{ - {static_cast(_reactionDescriptors.size()), static_cast(i)}})); + {static_cast(_reactionInchiDescriptors.size()), static_cast(i)}})); } else - rtr_it->second.insert(std::make_pair(static_cast(_reactionDescriptors.size()), static_cast(i))); + rtr_it->second.insert(std::make_pair(static_cast(_reactionInchiDescriptors.size()), static_cast(i))); } break; case BaseReaction::PRODUCT: @@ -114,16 +114,16 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio break; } } - _reactionDescriptors.push_back(rd); + _reactionInchiDescriptors.push_back(rd); } } void PathwayReactionBuilder::populatePossibleReactions() { // iterate over reactionDescriptors and fill possibleSuccessors - _reactionNodes.resize((int)_reactionDescriptors.size()); + _reactionNodes.resize((int)_reactionInchiDescriptors.size()); _reactionNodes.zerofill(); - for (auto i = 0; i < _reactionDescriptors.size(); i++) + for (auto i = 0; i < _reactionInchiDescriptors.size(); i++) { _reactionNodes[i].reactionIdx = i; auto matchedReactions = findPossibleSuccessorReactions(i); From d0a2269b00ceab37ceba66d8babc89799e72cf79 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 27 Aug 2024 08:35:24 +0200 Subject: [PATCH 05/25] multitale rendering --- .../reaction/pathway_reaction_builder.h | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index 86df4507d5..e7596dbcc5 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -42,42 +42,6 @@ namespace indigo class BaseMolecule; class BaseReaction; - // PathwayLayoutItem is a struct that represents a reaction in the pathway - struct PathwayLayoutItem - { - std::pair> associatedReactionItems; - int number = -1; - double prelim = 0; - double mod = 0; - int ancestor = -1; - int thread = -1; - double change = 0; - double shift = 0; - double width = 0, height = 0; - double x = 0, y = 0; - std::vector precursors; - int successor = -1; - int nextSibling = -1; - int prevSibling = -1; - - int getFirstPrecursor() const - { - return precursors.empty() ? -1 : precursors.front(); - } - - int getLastPrecursor() const - { - return precursors.empty() ? -1 : precursors.back(); - } - - void clear() - { - number = -2; - prelim = mod = shift = change = 0; - ancestor = thread = -1; - } - }; - // PathwayReactionBuilder is a class that builds a pathway reaction tree from a list of reactions in O(N) time class PathwayReactionBuilder { From ebd05895ba9556e60ca55666e971fd50e8b8bfdd Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Wed, 28 Aug 2024 11:56:55 +0200 Subject: [PATCH 06/25] multitale rendering --- core/indigo-core/layout/pathway_layout.h | 23 ++-- .../indigo-core/layout/src/pathway_layout.cpp | 58 +++++++- core/indigo-core/reaction/pathway_reaction.h | 5 +- .../reaction/pathway_reaction_builder.h | 4 +- .../reaction/src/pathway_reaction.cpp | 129 +----------------- .../reaction/src/pathway_reaction_builder.cpp | 64 +++------ 6 files changed, 100 insertions(+), 183 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index 76ce5a26d2..ee01a7d0fa 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -26,7 +26,15 @@ namespace indigo // PathwayLayoutItem is a struct that represents a reaction in the pathway struct PathwayLayoutItem { - std::pair> associatedReactionItems; + int reactionIdx = -1; + std::pair> associatedReactionItems; // which components are involved into layout + int successor = -1; + std::vector precursors; + double width = 0, height = 0; + double x = 0, y = 0; + int nextSibling = -1; + int prevSibling = -1; + int number = -1; double prelim = 0; double mod = 0; @@ -34,12 +42,6 @@ namespace indigo int thread = -1; double change = 0; double shift = 0; - double width = 0, height = 0; - double x = 0, y = 0; - std::vector precursors; - int successor = -1; - int nextSibling = -1; - int prevSibling = -1; int getFirstPrecursor() const { @@ -75,7 +77,6 @@ namespace indigo void make(); private: - double spacing(const PathwayLayoutItem& l, const PathwayLayoutItem& r, bool siblings) { return 0.5 * (l.width + r.width); @@ -85,7 +86,7 @@ namespace indigo void determineDepths(); - std::vector getLayoutItems() const; + std::vector PathwayLayout::getLayoutItems(const std::vector& nodes, int rootIndex); DECL_ERROR; @@ -101,6 +102,10 @@ namespace indigo int ancestor(const std::vector& nodes, int vimIndex, int vIndex, int aIndex) const; void secondWalk(std::vector& nodes, int nIndex, double m, int depth); + std::vector> PathwayLayout::levelTraversalAndMapping(const std::vector& nodes, int rootIndex, + std::vector& layout_nodes, + std::unordered_map& node_mapping); + std::vector _depths; int _maxDepth = 0; PathwayReaction& _reaction; diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index d93545dc09..c59ad95b30 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -37,19 +37,67 @@ void PathwayLayout::determineDepths() _depths[i] += _depths[i - 1]; } -std::vector PathwayLayout::getLayoutItems() const +#include +#include +#include + +struct Node +{ + std::vector parent; + std::vector children; +}; + +std::vector> PathwayLayout::levelTraversalAndMapping(const std::vector& nodes, int rootIndex, + std::vector& layout_nodes, std::unordered_map& node_mapping) { - // convert _reactionNodes to std::vector - return std::vector(); + std::vector> levels; + std::queue> nodeQueue; + + nodeQueue.push({rootIndex, 0}); + + while (!nodeQueue.empty()) + { + auto [currentIndex, currentLevel] = nodeQueue.front(); + nodeQueue.pop(); + if (currentLevel >= levels.size()) + levels.emplace_back(); + + levels[currentLevel].push_back(currentIndex); + // create layout node + auto& ln = layout_nodes.emplace_back(); + // create mapping between node index and layout node index + node_mapping.emplace(currentIndex, layout_nodes.size() - 1); + // copy everything we can from the reaction node to the layout node + + // bind reaction index to layout node + ln.reactionIdx = nodes[currentIndex].reactionIdx; + + // here we add only products + + ln.associatedReactionItems = nodes[currentIndex].; + + + for (int precursorIdx : nodes[currentIndex].precursorReactionsIndexes) + nodeQueue.push({precursorIdx, currentLevel + 1}); + } + return levels; +} + +std::vector PathwayLayout::getLayoutItems(const std::vector& nodes, int rootIndex) +{ + std::vector layoutNodes; + return layoutNodes; } // make layout void PathwayLayout::make() { - std::vector nodes; auto roots = _reaction.getRootReactions(); - for (auto rootIndex : roots) + int rootIndex = 0; + for (auto rc : roots) { + auto nodes = getLayoutItems(rc); + std::fill(_depths.begin(), _depths.end(), 0); _maxDepth = 0; firstWalk(nodes, rootIndex, 0, 1); diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 461b444a37..4e65b8c757 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -57,6 +57,8 @@ namespace indigo { // we don't keep products and reactants here, because they are stored in the Reaction object at reactionIdx int reactionIdx; + RedBlackSet reactantIndexes; + RedBlackSet productIndexes; // vector of successor reactions indexes and their corresponding reactant indexes ObjArray successorReactions; // vector of precursor reactions indexes @@ -66,7 +68,8 @@ namespace indigo PathwayReaction(); PathwayReaction(std::deque& reactions, const Array& nodes); ~PathwayReaction() override; - std::vector getRootReactions() const; + std::vector> getRootReactions() const; + const ObjArray>& getReactionNodes() { return _reactions; } int reactionsCount() const; void clone(PathwayReaction&); diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index e7596dbcc5..e253717847 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -56,12 +56,14 @@ namespace indigo { std::unordered_set reactants; std::vector products; + // useful to collect it here to avoid look them up in the reaction object + std::vector productIndexes; + std::vector reactantIndexes; }; void buildInchiDescriptors(std::deque& reactions); void populatePossibleReactions(); auto findPossibleSuccessorReactions(int reactionIdx); - auto getReactionComponents(const PathwayReaction::ReactionNode& rn, Reaction& reaction); std::vector _reactionInchiDescriptors; Array _reactionNodes; std::unordered_map> _reactantToReactions; diff --git a/core/indigo-core/reaction/src/pathway_reaction.cpp b/core/indigo-core/reaction/src/pathway_reaction.cpp index 4adf2ee177..28ee1deb5a 100644 --- a/core/indigo-core/reaction/src/pathway_reaction.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction.cpp @@ -52,13 +52,14 @@ PathwayReaction::PathwayReaction(std::deque& reactions, const Array PathwayReaction::getRootReactions() const + +std::vector> PathwayReaction::getRootReactions() const { - std::vector root_reactions; + std::vector> root_reactions; for (const auto& rn : _reactionNodes) { if (rn.successorReactions.size() == 0) - root_reactions.push_back(rn.reactionIdx); + root_reactions.push_back(std::cref(rn)); } return root_reactions; } @@ -81,128 +82,6 @@ void PathwayReaction::clone(PathwayReaction& reaction) } } -//std::pair>, std::vector>> PathwayReaction::makeTreePoints() -//{ -// auto reaction = this; -// std::vector inchiKeys(reaction->reactionsCount()); -// InchiWrapper inchiWrapper; -// Array inchi, inchiKey; -// for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) -// { -// auto& molecule = dynamic_cast(reaction->getBaseMolecule(i)); -// inchiWrapper.saveMoleculeIntoInchi(molecule, inchi); -// InchiWrapper::InChIKey(inchi.ptr(), inchiKey); -// inchiKeys.at(i).assign(inchiKey.ptr(), inchiKey.size()); -// } -// -// int finalProductId; -// std::vector> reactantIdsByReactions(reaction->reactionsCount()); // reaction index -> reactant molecule ids -// std::unordered_map productIds; // inchiKey -> product molecule id -// for (int i = reaction->begin(); i < reaction->end(); i = reaction->next(i)) -// { -// if (BaseReaction::REACTANT == reaction->getSideType(i)) -// reactantIdsByReactions.at(reaction->reactionId(i)).push_back(i); -// else if (BaseReaction::PRODUCT == reaction->getSideType(i)) -// { -// productIds.emplace(inchiKeys.at(i), i); -// finalProductId = i; -// } -// } -// -// std::unordered_map sumBoxes; -// std::stack dfsStack; -// dfsStack.push(finalProductId); // push last product -// while (!dfsStack.empty()) -// { -// auto stackSize = dfsStack.size(); -// auto id = dfsStack.top(); -// -// auto productIter = productIds.find(inchiKeys.at(id)); // take id from stack and find it in productIds by inchi key -// if (productIter == productIds.cend()) -// { -// // dead end, add reactant to sumBoxes with empty bounding box -// sumBoxes[id]; // add reactant to sumBoxes with empty bounding box -// dfsStack.pop(); // pop reactant -// continue; -// } -// -// auto productId = productIter->second; -// for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) // enumerate reactants of the reaction with productId -// if (!sumBoxes.count(reactantId)) // if reactant is not in sumBoxes, then push it to stack for further processing -// dfsStack.push(reactantId); -// if (dfsStack.size() > stackSize) // if there are reactants to process, then go while loop -// continue; -// -// // -// Vec2f rightTop(0, -2 * MARGIN); -// for (int reactantId : reactantIdsByReactions[reaction->reactionId(productId)]) -// { -// Rect2f box; -// reaction->getBaseMolecule(reactantId).getBoundingBox(box); -// rightTop.x = std::max(rightTop.x, box.width()); -// rightTop.y += std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; -// } -// sumBoxes[id] = {{}, rightTop}; -// dfsStack.pop(); -// } -// -// std::unordered_map points; -// std::vector> arrows; -// std::queue bfsQueue; -// bfsQueue.push(finalProductId); -// Rect2f box; -// reaction->getBaseMolecule(finalProductId).getBoundingBox(box); -// float offsetX = box.width() / 2 + ARROW_WIDTH + MARGIN; -// while (!bfsQueue.empty()) -// { -// float nextOffsetX = 0; -// auto size = bfsQueue.size(); -// for (size_t i = 0; i < size; i++) -// { -// auto id = bfsQueue.front(); -// bfsQueue.pop(); -// -// auto productIter = productIds.find(inchiKeys.at(id)); -// if (productIter == productIds.cend()) -// continue; -// -// auto zero = points[id]; -// auto& reactantIds = reactantIdsByReactions[reaction->reactionId(productIter->second)]; -// float offsetY = sumBoxes[id].height() / 2; -// Rect2f boxFront, boxBack; -// reaction->getBaseMolecule(reactantIds.front()).getBoundingBox(boxFront); -// reaction->getBaseMolecule(reactantIds.back()).getBoundingBox(boxBack); -// offsetY -= -std::max(boxFront.height(), sumBoxes[reactantIds.front()].height()) / 4; -// offsetY -= std::max(boxBack.height(), sumBoxes[reactantIds.back()].height()) / 4; -// nextOffsetX = std::max(nextOffsetX, sumBoxes[id].width()); -// -// arrows.emplace_back().reserve(1 + reactantIds.size()); -// arrows.back().emplace_back(zero.x - offsetX + ARROW_WIDTH, zero.y); -// for (int reactantId : reactantIds) -// { -// Rect2f box; -// reaction->getBaseMolecule(reactantId).getBoundingBox(box); -// float x = offsetX + sumBoxes[id].width() / 2 + MARGIN; -// float y = -offsetY + std::max(box.height(), sumBoxes[reactantId].height()) / 2; -// points[reactantId] = zero - Vec2f(x, y); -// bfsQueue.push(reactantId); -// offsetY -= std::max(box.height(), sumBoxes[reactantId].height()) + 2 * MARGIN; -// arrows.back().emplace_back(zero.x - offsetX, zero.y - y); -// } -// -// if (arrows.back().size() > 2) -// { -// // Add spines. The first and the last reactant arrows "y" are the highest and the lowest. -// arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back().back().y); -// arrows.back().emplace_back(zero.x - offsetX + ARROW_TAIL_WIDTH, arrows.back()[1].y); -// } -// } -// offsetX = nextOffsetX / 2 + ARROW_WIDTH + MARGIN; -// } -// -// return {std::piecewise_construct, std::forward_as_tuple(points.cbegin(), points.cend()), std::forward_as_tuple(arrows)}; -//} - BaseReaction* PathwayReaction::neu() { return new PathwayReaction; diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 3bf9caa9ba..3e1c2fd229 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -94,6 +94,7 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio switch (reaction.getSideType(i)) { case BaseReaction::REACTANT: { + rd.reactantIndexes.push_back(static_cast(i)); std::string inchi_str(inchiKey.ptr(), inchiKey.size()); rd.reactants.insert(inchi_str); auto rtr_it = _reactantToReactions.find(inchi_str); @@ -109,6 +110,7 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio break; case BaseReaction::PRODUCT: rd.products.emplace_back(inchiKey.ptr(), inchiKey.size()); + rd.productIndexes.push_back(static_cast(i)); break; default: break; @@ -126,52 +128,29 @@ void PathwayReactionBuilder::populatePossibleReactions() for (auto i = 0; i < _reactionInchiDescriptors.size(); i++) { _reactionNodes[i].reactionIdx = i; + + for (auto reactantIndex : _reactionInchiDescriptors[i].reactantIndexes) + _reactionNodes[i].reactantIndexes.insert(reactantIndex); + for (auto productIndex : _reactionInchiDescriptors[i].productIndexes) + _reactionNodes[i].productIndexes.insert(productIndex); + + // collect products auto matchedReactions = findPossibleSuccessorReactions(i); for (auto& [j, val] : matchedReactions) // [j, val] - j is the index of the reaction, val is the vector of reactant indexes { Array val_arr; val_arr.copy(val); - _reactionNodes[i].successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); - _reactionNodes[j].precursorReactionsIndexes.push(i); - if (_reactionNodes[i].successorReactions.size() > 1 && _ambigousSuccessorReactions.count(i) == 0) - _ambigousSuccessorReactions.insert(i); - } - } -} - -auto PathwayReactionBuilder::getReactionComponents(const PathwayReaction::ReactionNode& rn, Reaction& reaction) -{ - std::vector products, reactants; - std::vector> incoming_reactants; - - std::unordered_set used_reactants; - // look up for incoming reactants from precursor reactions - for (auto precursor_idx : rn.precursorReactionsIndexes) - { - auto& precursor_rd = _reactionNodes[precursor_idx]; - if (precursor_rd.successorReactions.size() == 1) - { - auto& reactant = precursor_rd.successorReactions[0].reactantIndices; - incoming_reactants.push_back(std::vector(reactant.begin(), reactant.end())); - used_reactants.insert(reactant.begin(), reactant.end()); - } - } - - for (int i = reaction.begin(); i < reaction.end(); i = reaction.next(i)) - { - switch (reaction.getSideType(i)) - { - case BaseReaction::REACTANT: - if (used_reactants.count(i) == 0) - reactants.emplace_back(i); - break; - case BaseReaction::PRODUCT: - products.emplace_back(i); - break; + if (_reactionNodes[i].successorReactions.size() == 0) + { + _reactionNodes[i].successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); + _reactionNodes[j].precursorReactionsIndexes.push(i); + } + else + { + // only one successor reaction is allowed. skip the reaction if there are more than one. + } } } - // return std::make_pair(products, reactants); - return 1; } std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(std::deque& reactions) @@ -190,8 +169,9 @@ std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(st } auto pathway_reaction = std::make_unique(reactions, _reactionNodes); - auto rr = pathway_reaction->getRootReactions(); - std::cout << "Root reactions: " << rr.size() << std::endl; - // layout the reactions + pathway_reaction->getRootReactions(); + // auto rr = pathway_reaction->getRootReactions(); + // std::cout << "Root reactions: " << rr.size() << std::endl; + // layout the reactions return pathway_reaction; } \ No newline at end of file From 098fe539b2896291765e7b9d629b31b780ed1b2c Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Fri, 30 Aug 2024 14:57:27 +0200 Subject: [PATCH 07/25] fix positions --- core/indigo-core/layout/pathway_layout.h | 10 +- .../indigo-core/layout/src/pathway_layout.cpp | 40 +++---- core/indigo-core/reaction/pathway_reaction.h | 98 +++++++++++---- .../reaction/pathway_reaction_builder.h | 15 ++- .../reaction/src/pathway_reaction.cpp | 48 +++----- .../reaction/src/pathway_reaction_builder.cpp | 112 ++++++++++-------- 6 files changed, 196 insertions(+), 127 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index ee01a7d0fa..3e2fed1927 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -26,9 +26,12 @@ namespace indigo // PathwayLayoutItem is a struct that represents a reaction in the pathway struct PathwayLayoutItem { - int reactionIdx = -1; - std::pair> associatedReactionItems; // which components are involved into layout + // which components are involved into layout. + // The first element is the index of the reaction, the second element is the index of the reaction component + std::pair> associatedReactionItems; + // successor component index (parent) int successor = -1; + // precursors component indexes (children) std::vector precursors; double width = 0, height = 0; double x = 0, y = 0; @@ -86,7 +89,8 @@ namespace indigo void determineDepths(); - std::vector PathwayLayout::getLayoutItems(const std::vector& nodes, int rootIndex); + std::vector PathwayLayout::getLayoutItems(const ObjArray& nodes, int rootIndex); + DECL_ERROR; diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index c59ad95b30..0034c55c65 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -16,6 +16,8 @@ * limitations under the License. ***************************************************************************/ +#include + #include "layout/pathway_layout.h" using namespace indigo; @@ -37,18 +39,8 @@ void PathwayLayout::determineDepths() _depths[i] += _depths[i - 1]; } -#include -#include -#include - -struct Node -{ - std::vector parent; - std::vector children; -}; - std::vector> PathwayLayout::levelTraversalAndMapping(const std::vector& nodes, int rootIndex, - std::vector& layout_nodes, std::unordered_map& node_mapping) + std::vector& layout_nodes, std::unordered_map& node_mapping) { std::vector> levels; std::queue> nodeQueue; @@ -63,19 +55,25 @@ std::vector> PathwayLayout::levelTraversalAndMapping(const std: levels.emplace_back(); levels[currentLevel].push_back(currentIndex); - // create layout node + + auto& cur_node = nodes[currentIndex]; + // create layout node for products of current reaction auto& ln = layout_nodes.emplace_back(); - // create mapping between node index and layout node index - node_mapping.emplace(currentIndex, layout_nodes.size() - 1); - // copy everything we can from the reaction node to the layout node - // bind reaction index to layout node - ln.reactionIdx = nodes[currentIndex].reactionIdx; + // create mapping between node index and layout node index + node_mapping.emplace(currentIndex, static_cast(layout_nodes.size()) - 1); - // here we add only products + // add only products to the layout node + auto& products = _reaction.getReactions()[currentIndex].productIndexes; + ln.associatedReactionItems.first = cur_node.reactionIdx; + // _reaction. + for (auto pidx : products) + { + ln.associatedReactionItems.second.push_back(pidx); + } - ln.associatedReactionItems = nodes[currentIndex].; + // ln.associatedReactionItems = nodes[currentIndex].; for (int precursorIdx : nodes[currentIndex].precursorReactionsIndexes) nodeQueue.push({precursorIdx, currentLevel + 1}); @@ -83,7 +81,7 @@ std::vector> PathwayLayout::levelTraversalAndMapping(const std: return levels; } -std::vector PathwayLayout::getLayoutItems(const std::vector& nodes, int rootIndex) +std::vector PathwayLayout::getLayoutItems(const ObjArray& nodes, int rootIndex) { std::vector layoutNodes; return layoutNodes; @@ -96,7 +94,7 @@ void PathwayLayout::make() int rootIndex = 0; for (auto rc : roots) { - auto nodes = getLayoutItems(rc); + auto nodes = getLayoutItems(_reaction.getReactionNodes(), rc.get().reactionIdx); std::fill(_depths.begin(), _depths.end(), 0); _maxDepth = 0; diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 4e65b8c757..92a7d6c0fe 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -23,9 +23,9 @@ #pragma warning(disable : 4251) #endif -#include #include "base_cpp/array.h" #include "reaction/base_reaction.h" +#include namespace indigo { @@ -36,29 +36,48 @@ namespace indigo { public: struct SuccessorReaction - { - SuccessorReaction(int reactionIdx, Array& ridxs) : reactionIdx(reactionIdx){ - reactantIndices.copy(ridxs); + { + SuccessorReaction(int reactionIdx, Array& ridxs) : reactionIdx(reactionIdx) + { + reactantIndexes.copy(ridxs); } - SuccessorReaction(const SuccessorReaction& other) : reactionIdx(other.reactionIdx){ - reactantIndices.copy(other.reactantIndices); - } - SuccessorReaction& operator = (const SuccessorReaction& other) + SuccessorReaction(const SuccessorReaction& other) : reactionIdx(other.reactionIdx) + { + reactantIndexes.copy(other.reactantIndexes); + } + SuccessorReaction& operator=(const SuccessorReaction& other) { reactionIdx = other.reactionIdx; - reactantIndices.copy(other.reactantIndices); + reactantIndexes.copy(other.reactantIndexes); return *this; } - int reactionIdx; - Array reactantIndices; - }; + int reactionIdx; + Array reactantIndexes; + }; + + struct SimpleReaction + { + SimpleReaction() = default; + SimpleReaction(const SimpleReaction& other) + { + reactantIndexes.copy(other.reactantIndexes); + productIndexes.copy(other.productIndexes); + } + Array reactantIndexes; + Array productIndexes; + }; struct ReactionNode { - // we don't keep products and reactants here, because they are stored in the Reaction object at reactionIdx + ReactionNode() : reactionIdx(-1){}; + ReactionNode(const ReactionNode& other) + { + reactionIdx = other.reactionIdx; + for (int i = 0; i < other.successorReactions.size(); ++i) + successorReactions.push(other.successorReactions[i]); + precursorReactionsIndexes.copy(other.precursorReactionsIndexes); + } int reactionIdx; - RedBlackSet reactantIndexes; - RedBlackSet productIndexes; // vector of successor reactions indexes and their corresponding reactant indexes ObjArray successorReactions; // vector of precursor reactions indexes @@ -66,25 +85,60 @@ namespace indigo }; PathwayReaction(); - PathwayReaction(std::deque& reactions, const Array& nodes); ~PathwayReaction() override; + std::vector> getRootReactions() const; - const ObjArray>& getReactionNodes() { return _reactions; } - int reactionsCount() const; - void clone(PathwayReaction&); + auto& getReactionNodes() + { + return _reactionNodes; + } + + const auto& getMolecules() + { + return _molecules; + } + + const auto& getReactions() + { + return _reactions; + } + ReactionNode& addReactionNode() + { + ReactionNode rn; + rn.reactionIdx = static_cast(_reactionNodes.size()); + _reactionNodes.push(rn); + return _reactionNodes[_reactionNodes.size() - 1]; + } + + int addMolecule(BaseMolecule& mol) + { + std::unique_ptr mol_copy(mol.neu()); + mol_copy->clone(mol); + _molecules.add(mol_copy.release()); + return static_cast(_molecules.size() - 1); + } + + std::pair addReaction() + { + SimpleReaction sr; + _reactions.push(sr); + return {static_cast(_reactions.size() - 1), _reactions[_reactions.size() - 1]}; + } + + void clone(PathwayReaction&); BaseReaction* neu() override; bool aromatize(const AromaticityOptions& options) override; - DECL_ERROR; protected: int _addBaseMolecule(int side) override; private: - Array _reactionNodes; - ObjArray< RedBlackMap > _reactions; + ObjArray _reactionNodes; + PtrArray _molecules; + ObjArray _reactions; }; } // namespace indigo diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index e253717847..2f059f365b 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -42,7 +42,7 @@ namespace indigo class BaseMolecule; class BaseReaction; - // PathwayReactionBuilder is a class that builds a pathway reaction tree from a list of reactions in O(N) time + // PathwayReactionBuilder is a class that builds a pathway reaction tree from a list of reactions class PathwayReactionBuilder { public: @@ -52,6 +52,7 @@ namespace indigo DECL_ERROR; private: + struct ReactionInchiDescriptor { std::unordered_set reactants; @@ -59,15 +60,19 @@ namespace indigo // useful to collect it here to avoid look them up in the reaction object std::vector productIndexes; std::vector reactantIndexes; + std::map> successor; // productIndexes <-> successor }; void buildInchiDescriptors(std::deque& reactions); - void populatePossibleReactions(); - auto findPossibleSuccessorReactions(int reactionIdx); + void buildNodes(std::deque& reactions); + auto findSuccessorReactions(int reactionIdx); + void buildReactions(std::deque& reactions); + + std::vector _reactionInchiDescriptors; - Array _reactionNodes; std::unordered_map> _reactantToReactions; - std::unordered_set _ambigousSuccessorReactions; // reactions that have more than one possible successor + std::unique_ptr _pathwayReaction; + std::unordered_map< std::pair, int, pair_hash> _moleculeMapping; }; } // namespace indigo diff --git a/core/indigo-core/reaction/src/pathway_reaction.cpp b/core/indigo-core/reaction/src/pathway_reaction.cpp index 28ee1deb5a..db91ce16b2 100644 --- a/core/indigo-core/reaction/src/pathway_reaction.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction.cpp @@ -35,50 +35,40 @@ PathwayReaction::~PathwayReaction() { } -PathwayReaction::PathwayReaction(std::deque& reactions, const Array& nodes) -{ - _reactionNodes.copy(nodes); - for (size_t i = 0; i < reactions.size(); i++) - { - auto& reactionComponents = _reactions.push(); - for (int j = reactions[i].begin(); j < reactions[i].end(); j = reactions[i].next(j)) - { - auto molecule = std::make_unique(); - molecule->clone(reactions[i].getBaseMolecule(j)); - int id = _allMolecules.add(molecule.release()); - _addedBaseMolecule(id, reactions[i].getSideType(j), *_allMolecules[id]); - reactionComponents.insert(j, id); - } - } -} - - std::vector> PathwayReaction::getRootReactions() const { std::vector> root_reactions; - for (const auto& rn : _reactionNodes) + for(int i = 0; i < _reactionNodes.size(); ++i ) { + const auto& rn = _reactionNodes[i]; if (rn.successorReactions.size() == 0) root_reactions.push_back(std::cref(rn)); } return root_reactions; } -int PathwayReaction::reactionsCount() const -{ - return _reactions.size(); -} - void PathwayReaction::clone(PathwayReaction& reaction) { BaseReaction::clone(reaction); - _reactionNodes.copy(reaction._reactionNodes); - // copy reactions ObjArray - for (int i = 0; i < reaction._reactions.size(); i++) + for (int i = 0; i < _reactionNodes.size(); ++i) + { + auto& other = _reactionNodes[i]; + auto& rn = reaction._reactionNodes.push(); + rn.reactionIdx = other.reactionIdx; + rn.precursorReactionsIndexes.copy(other.precursorReactionsIndexes); + for (int j = 0; j < other.successorReactions.size(); ++j) + { + auto& sr = other.successorReactions[j]; + rn.successorReactions.push(sr); + } + } + + for (int i = 0; i < reaction._reactions.size(); ++i) { auto& other = reaction._reactions[i]; - auto& reactionComponents = _reactions.push(); - reactionComponents.copy(other); + auto& rc = _reactions.push(); + rc.productIndexes.copy(other.productIndexes); + rc.reactantIndexes.copy(other.reactantIndexes); } } diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 3e1c2fd229..6d2b567292 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -21,6 +21,7 @@ #include "molecule/inchi_wrapper.h" #include "reaction/pathway_reaction_builder.h" +#include "layout/pathway_layout.h" #include "reaction/reaction.h" using namespace indigo; @@ -31,13 +32,13 @@ PathwayReactionBuilder::~PathwayReactionBuilder() { } -PathwayReactionBuilder::PathwayReactionBuilder() +PathwayReactionBuilder::PathwayReactionBuilder() : _pathwayReaction(std::make_unique()) { } -auto PathwayReactionBuilder::findPossibleSuccessorReactions(int reactionIdx) +auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) { - // find possible precursors + // key - reaction index, value - vector of reactant indexes std::map> matchedReactions; // iterate over products of the reaction for (auto& product : _reactionInchiDescriptors[reactionIdx].products) @@ -78,23 +79,48 @@ auto PathwayReactionBuilder::findPossibleSuccessorReactions(int reactionIdx) return matchedReactions; } +void PathwayReactionBuilder::buildReactions(std::deque& reactions) +{ + for (int i = 0; i < _reactionInchiDescriptors.size(); ++i) + { + auto& rid = _reactionInchiDescriptors[i]; + auto [sri, sr] = _pathwayReaction->addReaction(); + for (auto rci : rid.reactantIndexes) + { + auto mol_idx = _moleculeMapping.at(std::make_pair(i, rci)); + sr.reactantIndexes.push(mol_idx); + } + + for (auto pid : rid.productIndexes) + { + auto mol_idx = _moleculeMapping.at(std::make_pair(i, pid)); + sr.productIndexes.push(mol_idx); + } + } +} + void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactions) { _reactionInchiDescriptors.clear(); InchiWrapper inchiWrapper; Array inchi, inchiKey; - for (auto& reaction : reactions) + for (int i = 0; i < reactions.size(); ++i) { - ReactionInchiDescriptor rd; + _pathwayReaction->addReactionNode(); + auto& reaction = reactions[i]; + ReactionInchiDescriptor& rd = _reactionInchiDescriptors.emplace_back(); // iterate over molecules in the reaction, calculate inchiKeys for reactants and products - for (int i = reaction.begin(); i < reaction.end(); i = reaction.next(i)) + for (int j = reaction.begin(); j < reaction.end(); j = reaction.next(j)) { - inchiWrapper.saveMoleculeIntoInchi(reaction.getBaseMolecule(i).asMolecule(), inchi); + inchiWrapper.saveMoleculeIntoInchi(reaction.getBaseMolecule(j).asMolecule(), inchi); InchiWrapper::InChIKey(inchi.ptr(), inchiKey); - switch (reaction.getSideType(i)) + switch (reaction.getSideType(j)) { case BaseReaction::REACTANT: { - rd.reactantIndexes.push_back(static_cast(i)); + rd.reactantIndexes.push_back(static_cast(j)); + // copy reactant molecule to the pathway reaction, add mapping + _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, j), + std::forward_as_tuple(_pathwayReaction->addMolecule(reaction.getBaseMolecule(j).asMolecule()))); std::string inchi_str(inchiKey.ptr(), inchiKey.size()); rd.reactants.insert(inchi_str); auto rtr_it = _reactantToReactions.find(inchi_str); @@ -102,48 +128,51 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio { _reactantToReactions.emplace(std::piecewise_construct, std::forward_as_tuple(inchi_str), std::forward_as_tuple(std::initializer_list>{ - {static_cast(_reactionInchiDescriptors.size()), static_cast(i)}})); + {i, static_cast(j)}})); } else - rtr_it->second.insert(std::make_pair(static_cast(_reactionInchiDescriptors.size()), static_cast(i))); + rtr_it->second.insert(std::make_pair(static_cast(i), static_cast(j))); } break; case BaseReaction::PRODUCT: rd.products.emplace_back(inchiKey.ptr(), inchiKey.size()); - rd.productIndexes.push_back(static_cast(i)); + rd.productIndexes.push_back(static_cast(j)); break; default: break; } } - _reactionInchiDescriptors.push_back(rd); } } -void PathwayReactionBuilder::populatePossibleReactions() +void PathwayReactionBuilder::buildNodes(std::deque& reactions) { - // iterate over reactionDescriptors and fill possibleSuccessors - _reactionNodes.resize((int)_reactionInchiDescriptors.size()); - _reactionNodes.zerofill(); + // find all reactants of a reaction that match the products of the current reaction for (auto i = 0; i < _reactionInchiDescriptors.size(); i++) { - _reactionNodes[i].reactionIdx = i; - - for (auto reactantIndex : _reactionInchiDescriptors[i].reactantIndexes) - _reactionNodes[i].reactantIndexes.insert(reactantIndex); - for (auto productIndex : _reactionInchiDescriptors[i].productIndexes) - _reactionNodes[i].productIndexes.insert(productIndex); + auto matching_successor = findSuccessorReactions(i); + _reactionInchiDescriptors[i].successor = matching_successor; + auto& productIndexes = _reactionInchiDescriptors[i].productIndexes; + for (auto j = 0; j < productIndexes.size(); ++j) + { + // copy reactant molecule to the pathway reaction, add mapping + auto pidx = productIndexes[j]; + int mol_idx = matching_successor.empty() + ? _pathwayReaction->addMolecule(reactions[i].getBaseMolecule(productIndexes[j]).asMolecule()) + : _moleculeMapping.at(std::make_pair(matching_successor.begin()->first, matching_successor.begin()->second[j])); + _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, pidx), std::forward_as_tuple(mol_idx)); + } - // collect products - auto matchedReactions = findPossibleSuccessorReactions(i); - for (auto& [j, val] : matchedReactions) // [j, val] - j is the index of the reaction, val is the vector of reactant indexes + for (auto& [j, val] : matching_successor) // [j, val] - j is the index of the reaction, val is the vector of reactant indexes { Array val_arr; val_arr.copy(val); - if (_reactionNodes[i].successorReactions.size() == 0) + auto& rnodes = _pathwayReaction->getReactionNodes(); + auto& rn = rnodes[i]; + if (rn.successorReactions.size() == 0) { - _reactionNodes[i].successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); - _reactionNodes[j].precursorReactionsIndexes.push(i); + rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); + rnodes[j].precursorReactionsIndexes.push(i); } else { @@ -156,22 +185,11 @@ void PathwayReactionBuilder::populatePossibleReactions() std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(std::deque& reactions) { buildInchiDescriptors(reactions); - populatePossibleReactions(); - - if (_ambigousSuccessorReactions.size() > 0) - { - int product = 1; - for (auto ridx : _ambigousSuccessorReactions) - product *= static_cast(_reactionNodes[ridx].successorReactions.size()); - throw Error("Unable to build the pathway. The provided reaction set has multiple potential connection sites for products, resulting in %d possible " - "combination pathways.", - product); - } - - auto pathway_reaction = std::make_unique(reactions, _reactionNodes); - pathway_reaction->getRootReactions(); - // auto rr = pathway_reaction->getRootReactions(); - // std::cout << "Root reactions: " << rr.size() << std::endl; - // layout the reactions - return pathway_reaction; + buildNodes(reactions); + buildReactions(reactions); + auto& rr = _pathwayReaction->getRootReactions(); + PathwayLayout pl(*_pathwayReaction); + pl.make(); + std::cout << "root nodes: " << rr.size() << std::endl; + return std::move(_pathwayReaction); } \ No newline at end of file From aea9531e18bd1032e4ec58382fc4916b99a5df09 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Sat, 31 Aug 2024 23:50:32 +0200 Subject: [PATCH 08/25] new err case --- core/indigo-core/layout/pathway_layout.h | 164 +++++----- .../indigo-core/layout/src/pathway_layout.cpp | 288 ++++++++---------- core/indigo-core/reaction/pathway_reaction.h | 32 +- .../reaction/pathway_reaction_builder.h | 4 +- .../reaction/src/pathway_reaction.cpp | 29 +- .../reaction/src/pathway_reaction_builder.cpp | 55 ++-- 6 files changed, 295 insertions(+), 277 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index 3e2fed1927..b5869ecd0f 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -23,98 +23,126 @@ namespace indigo { - // PathwayLayoutItem is a struct that represents a reaction in the pathway - struct PathwayLayoutItem +#include +#include +#include + +#include +#include +#include + + class PathwayLayoutItem { - // which components are involved into layout. - // The first element is the index of the reaction, the second element is the index of the reaction component - std::pair> associatedReactionItems; - // successor component index (parent) - int successor = -1; - // precursors component indexes (children) - std::vector precursors; - double width = 0, height = 0; - double x = 0, y = 0; - int nextSibling = -1; - int prevSibling = -1; - - int number = -1; - double prelim = 0; - double mod = 0; - int ancestor = -1; - int thread = -1; - double change = 0; - double shift = 0; - - int getFirstPrecursor() const + public: + PathwayLayoutItem(PathwayReaction& reaction, int nodeIdx, int reactantIdx = -1) + : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), + thread(nullptr), children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr) + { + auto& rn = reaction.getReactionNode(nodeIdx); + auto& sr = reaction.getReaction(rn.reactionIdx); + // create as a final reactant child + if (reactantIdx != -1) + { + auto& mol = reaction.getMolecule(reactantIdx); + Rect2f bbox; + mol.getBoundingBox(bbox); + molecules.push_back(std::make_pair(reactantIdx, bbox)); + width += bbox.width(); + height = std::max(bbox.height(), height); + } + else + { + for (auto pidx : sr.productIndexes) + { + auto& mol = reaction.getMolecule(pidx); + Rect2f bbox; + mol.getBoundingBox(bbox); + molecules.push_back(std::make_pair(pidx, bbox)); + width += bbox.width(); + height = std::max(bbox.height(), height); + } + + // enumerate only final reactants here + // how to check if it is a final reactant? + // rn.precursorReactionsIndexes + for ( int i = 0; i < sr.reactantIndexes.size(); ++i) + { + // check if it is a final reactant + auto ridx = sr.reactantIndexes[i]; + PathwayLayoutItem* item = new PathwayLayoutItem(reaction, nodeIdx, ridx); + children.push_back(item); + item->parent = this; + } + } + // fill parent and children + } + + PathwayLayoutItem* getFirstChild() { - return precursors.empty() ? -1 : precursors.front(); + return children.empty() ? nullptr : children.front(); } - int getLastPrecursor() const + PathwayLayoutItem* getLastChild() { - return precursors.empty() ? -1 : precursors.back(); + return children.empty() ? nullptr : children.back(); } void clear() { number = -2; - prelim = mod = shift = change = 0; - ancestor = thread = -1; + prelim = 0.0; + mod = shift = change = 0.0; + ancestor = thread = nullptr; } + + // required for the layout algorithm + float width, height; + std::vector children; + PathwayLayoutItem* parent; + PathwayLayoutItem* nextSibling; + PathwayLayoutItem* prevSibling; + + // computed fields + int number; + float prelim, mod, shift, change; + float x, y; + PathwayLayoutItem* ancestor; + PathwayLayoutItem* thread; + + // some data + std::vector< std::pair> molecules; }; - // PathwayLayout is a class which makes a tree layout of the pathway reaction in O(N) time class PathwayLayout { - public: - static constexpr float MARGIN = 1.f; - static constexpr float ARROW_HEAD_WIDTH = 2.5f; - static constexpr float ARROW_TAIL_WIDTH = 0.5f; - static constexpr float ARROW_WIDTH = ARROW_HEAD_WIDTH + ARROW_TAIL_WIDTH; + DECL_ERROR; - PathwayLayout(PathwayReaction& reaction) : _depths(10, 0.0), _reaction(reaction) + public: + PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0) { } - // make layout + void make(); + void buildLayoutTree(); private: - double spacing(const PathwayLayoutItem& l, const PathwayLayoutItem& r, bool siblings) - { - return 0.5 * (l.width + r.width); - } - - void updateDepths(int depth, const PathwayLayoutItem& item); - + float spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool /*siblings*/); + PathwayLayoutItem* nextLeft(PathwayLayoutItem* n); + PathwayLayoutItem* nextRight(PathwayLayoutItem* n); + PathwayLayoutItem* ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a); + void updateDepths(int depth, PathwayLayoutItem* item); void determineDepths(); + void firstWalk(PathwayLayoutItem* v, int num, int depth); + void secondWalk(PathwayLayoutItem* v, PathwayLayoutItem* p, float m, int depth); - std::vector PathwayLayout::getLayoutItems(const ObjArray& nodes, int rootIndex); - - - DECL_ERROR; - - private: - // firstWalk function calculates the preliminary x-coordinate of each node in the tree - void firstWalk(std::vector& nodes, int nIndex, int num, int depth); - // apportion function is used to calculate the preliminary x-coordinate of the children of a node - int apportion(std::vector& nodes, int vIndex, int aIndex); - int nextLeft(const std::vector& nodes, int nIndex) const; - int nextRight(const std::vector& nodes, int nIndex) const; - void moveSubtree(std::vector& nodes, int wmIndex, int wpIndex, double shift); - void executeShifts(std::vector& nodes, int nIndex); - int ancestor(const std::vector& nodes, int vimIndex, int vIndex, int aIndex) const; - void secondWalk(std::vector& nodes, int nIndex, double m, int depth); - - std::vector> PathwayLayout::levelTraversalAndMapping(const std::vector& nodes, int rootIndex, - std::vector& layout_nodes, - std::unordered_map& node_mapping); - - std::vector _depths; - int _maxDepth = 0; + PathwayLayoutItem* apportion(PathwayLayoutItem* v, PathwayLayoutItem* a); + void moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, float shift); + void executeShifts(PathwayLayoutItem* v); PathwayReaction& _reaction; + std::vector _depths; + int _maxDepth; + std::vector _layoutItems; }; - -} // namespace indigo +} #endif diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index 0034c55c65..72affece4a 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -24,231 +24,189 @@ using namespace indigo; IMPL_ERROR(PathwayLayout, "pathway_layout"); -void PathwayLayout::updateDepths(int depth, const PathwayLayoutItem& item) +float PathwayLayout::spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool /*siblings*/) { - double d = item.height; - if (_depths.size() <= depth) - _depths.resize(3 * depth / 2); - _depths[depth] = std::max(_depths[depth], d); - _maxDepth = std::max(_maxDepth, depth); + return (l->width + r->width)/2; } -void PathwayLayout::determineDepths() +PathwayLayoutItem* PathwayLayout::nextLeft(PathwayLayoutItem* n) { - for (int i = 1; i < _maxDepth; ++i) - _depths[i] += _depths[i - 1]; + return n->getFirstChild() ? n->getFirstChild() : n->thread; } -std::vector> PathwayLayout::levelTraversalAndMapping(const std::vector& nodes, int rootIndex, - std::vector& layout_nodes, std::unordered_map& node_mapping) +PathwayLayoutItem* PathwayLayout::nextRight(PathwayLayoutItem* n) { - std::vector> levels; - std::queue> nodeQueue; + return n->getLastChild() ? n->getLastChild() : n->thread; +} - nodeQueue.push({rootIndex, 0}); +PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) +{ + return (vim->ancestor->parent == v->parent) ? vim->ancestor : a; +} - while (!nodeQueue.empty()) +void PathwayLayout::make() +{ + buildLayoutTree(); + auto rrs = _reaction.getRootReactions(); + if (rrs.size()) { - auto [currentIndex, currentLevel] = nodeQueue.front(); - nodeQueue.pop(); - if (currentLevel >= levels.size()) - levels.emplace_back(); - - levels[currentLevel].push_back(currentIndex); - - auto& cur_node = nodes[currentIndex]; - // create layout node for products of current reaction - auto& ln = layout_nodes.emplace_back(); - - // create mapping between node index and layout node index - node_mapping.emplace(currentIndex, static_cast(layout_nodes.size()) - 1); - - // add only products to the layout node - auto& products = _reaction.getReactions()[currentIndex].productIndexes; - ln.associatedReactionItems.first = cur_node.reactionIdx; - // _reaction. - for (auto pidx : products) - { - ln.associatedReactionItems.second.push_back(pidx); - } - - - // ln.associatedReactionItems = nodes[currentIndex].; - - for (int precursorIdx : nodes[currentIndex].precursorReactionsIndexes) - nodeQueue.push({precursorIdx, currentLevel + 1}); + auto& li = _layoutItems[rrs[0]]; + PathwayLayoutItem* root = &li; + std::fill(_depths.begin(), _depths.end(), 0.0f); + _maxDepth = 0; + firstWalk(root, 0, 1); + determineDepths(); + secondWalk(root, nullptr, -root->prelim, 0); } - return levels; } -std::vector PathwayLayout::getLayoutItems(const ObjArray& nodes, int rootIndex) +void PathwayLayout::buildLayoutTree() { - std::vector layoutNodes; - return layoutNodes; + for (int i = 0; i < _reaction.getReactionNodeCount(); ++i) + _layoutItems.emplace_back(_reaction, i); } -// make layout -void PathwayLayout::make() +void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) { - auto roots = _reaction.getRootReactions(); - int rootIndex = 0; - for (auto rc : roots) + float d = item->height; + if (_depths.size() <= static_cast(depth)) { - auto nodes = getLayoutItems(_reaction.getReactionNodes(), rc.get().reactionIdx); - - std::fill(_depths.begin(), _depths.end(), 0); - _maxDepth = 0; - firstWalk(nodes, rootIndex, 0, 1); - determineDepths(); - secondWalk(nodes, rootIndex, -nodes[rootIndex].prelim, 0); + _depths.resize(3 * depth / 2); } + _depths[depth] = std::max(_depths[depth], d); + _maxDepth = std::max(_maxDepth, depth); } -void PathwayLayout::firstWalk(std::vector& nodes, int nIndex, int num, int depth) +void PathwayLayout::determineDepths() { - PathwayLayoutItem& n = nodes[nIndex]; - n.number = num; - updateDepths(depth, n); + for (int i = 1; i < _maxDepth; ++i) + { + _depths[i] += _depths[i - 1]; + } +} - if (n.precursors.empty()) +void PathwayLayout::firstWalk(PathwayLayoutItem* v, int num, int depth) +{ + v->number = num; + updateDepths(depth, v); + if (v->children.empty()) { - int lIndex = n.prevSibling; - if (lIndex == -1) - { - n.prelim = 0; - } + if (PathwayLayoutItem* l = v->prevSibling) + v->prelim = l->prelim + spacing(l, v, true); else - { - n.prelim = nodes[lIndex].prelim + spacing(nodes[lIndex], n, true); - } + v->prelim = 0.0; } else { - int leftMost = n.getFirstPrecursor(); - int rightMost = n.getLastPrecursor(); - int defaultAncestor = leftMost; - - for (int i = 0, c = leftMost; c != -1; ++i, c = nodes[c].nextSibling) + PathwayLayoutItem* leftMost = v->getFirstChild(); + PathwayLayoutItem* rightMost = v->getLastChild(); + PathwayLayoutItem* defaultAncestor = leftMost; + for (PathwayLayoutItem* c = leftMost; c != nullptr; ++num) { - firstWalk(nodes, c, i, depth + 1); - defaultAncestor = apportion(nodes, c, defaultAncestor); + firstWalk(c, num, depth + 1); + defaultAncestor = apportion(c, defaultAncestor); + c = c->nextSibling; } - - executeShifts(nodes, nIndex); - - double midpoint = 0.5 * (nodes[leftMost].prelim + nodes[rightMost].prelim); - int leftIndex = n.prevSibling; - if (leftIndex != -1) + executeShifts(v); + float midPoint = (leftMost->prelim + rightMost->prelim)/2; + if (PathwayLayoutItem* l = v->prevSibling) { - n.prelim = nodes[leftIndex].prelim + spacing(nodes[leftIndex], n, true); - n.mod = n.prelim - midpoint; + v->prelim = l->prelim + spacing(l, v, true); + v->mod += v->prelim - midPoint; } else { - n.prelim = midpoint; + v->prelim = midPoint; } } } -// apportion function is used to calculate the preliminary x-coordinate of the children of a node -int PathwayLayout::apportion(std::vector& nodes, int vIndex, int aIndex) +void PathwayLayout::secondWalk(PathwayLayoutItem* v, PathwayLayoutItem* p, float m, int depth) { - int wIndex = nodes[vIndex].prevSibling; - if (wIndex != -1) + v->x = v->prelim + m; + v->y = _depths[depth]; + m += v->mod; + for (PathwayLayoutItem* w : v->children) { - int vip = vIndex, vim = wIndex; - int vop = vIndex, vom = nodes[vip].getFirstPrecursor(); - double sip = nodes[vip].mod, sim = nodes[vim].mod; - double sop = nodes[vop].mod, som = nodes[vom].mod; + secondWalk(w, v, m, depth + 1); + } + v->clear(); +} - while (vim != -1 && vip != -1) +PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* v, PathwayLayoutItem* a) +{ + if (PathwayLayoutItem* w = v->prevSibling) + { + PathwayLayoutItem *vip = v, *vop = v; + PathwayLayoutItem *vim = w, *vom = v->getFirstChild(); + float sip = vip->mod, sop = vop->mod; + float sim = vim->mod, som = vom != nullptr ? vom->mod : 0; + PathwayLayoutItem* nr = nextRight(vim); + PathwayLayoutItem* nl = nextLeft(vip); + while (nr != nullptr && nl != nullptr) { - vim = nextRight(nodes, vim); - vip = nextLeft(nodes, vip); - vom = nextLeft(nodes, vom); - vop = nextRight(nodes, vop); - nodes[vop].ancestor = vIndex; - - double shift = (nodes[vim].prelim + sim) - (nodes[vip].prelim + sip) + spacing(nodes[vim], nodes[vip], false); + vim = nr; + vip = nl; + vom = nextLeft(vom); + vop = nextRight(vop); + if (vop) + vop->ancestor = v; + float shift = (vim->prelim + sim) - (vip->prelim + sip) + spacing(vim, vip, false); if (shift > 0) { - moveSubtree(nodes, ancestor(nodes, vim, vIndex, aIndex), vIndex, shift); + PathwayLayoutItem* from = ancestor(vim, v, a); + moveSubtree(from, v, shift); sip += shift; sop += shift; } - - sim += nodes[vim].mod; - sip += nodes[vip].mod; - som += nodes[vom].mod; - sop += nodes[vop].mod; - - vim = nextRight(nodes, vim); - vip = nextLeft(nodes, vip); + sim += vim->mod; + sip += vip->mod; + if (vom) + som += vom->mod; + if (vop) + sop += vop->mod; + + nr = nextRight(vim); + nl = nextLeft(vip); } - - if (vim != -1 && nextRight(nodes, vop) == -1) + if (nr && vop && !nextRight(vop)) { - nodes[vop].thread = vim; - nodes[vop].mod += sim - sop; + vop->thread = nr; + vop->mod += sim - sop; } - if (vip != -1 && nextLeft(nodes, vom) == -1) + if (nl && (!vom || !nextLeft(vom))) { - nodes[vom].thread = vip; - nodes[vom].mod += sip - som; - aIndex = vIndex; + if (vom) + { + vom->thread = nl; + vom->mod += sip - som; + } + a = v; } } - return aIndex; -} - -int PathwayLayout::nextLeft(const std::vector& nodes, int nIndex) const -{ - int child = nodes[nIndex].getFirstPrecursor(); - return child != -1 ? child : nodes[nIndex].thread; + return a; } -int PathwayLayout::nextRight(const std::vector& nodes, int nIndex) const +void PathwayLayout::moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, float shift) { - int child = nodes[nIndex].getLastPrecursor(); - return child != -1 ? child : nodes[nIndex].thread; + float subtrees = static_cast(wp->number - wm->number); + wp->change -= shift / subtrees; + wp->shift += shift; + wm->change += shift / subtrees; + wp->prelim += shift; + wp->mod += shift; } -void PathwayLayout::moveSubtree(std::vector& nodes, int wmIndex, int wpIndex, double shift) +void PathwayLayout::executeShifts(PathwayLayoutItem* v) { - double subtrees = nodes[wpIndex].number - nodes[wmIndex].number; - nodes[wpIndex].change -= shift / subtrees; - nodes[wpIndex].shift += shift; - nodes[wmIndex].change += shift / subtrees; - nodes[wpIndex].prelim += shift; - nodes[wpIndex].mod += shift; -} - -void PathwayLayout::executeShifts(std::vector& nodes, int nIndex) -{ - double shift = 0, change = 0; - for (int c = nodes[nIndex].getLastPrecursor(); c != -1; c = nodes[c].prevSibling) + float shift = 0, change = 0; + for (auto it = v->children.rbegin(); it != v->children.rend(); ++it) { - nodes[c].prelim += shift; - nodes[c].mod += shift; - change += nodes[c].change; - shift += nodes[c].shift + change; + PathwayLayoutItem* c = *it; + c->prelim += shift; + c->mod += shift; + change += c->change; + shift += c->shift + change; } } -int PathwayLayout::ancestor(const std::vector& nodes, int vimIndex, int vIndex, int aIndex) const -{ - return nodes[vimIndex].ancestor == nodes[vIndex].successor ? nodes[vimIndex].ancestor : aIndex; -} - -void PathwayLayout::secondWalk(std::vector& nodes, int nIndex, double m, int depth) -{ - nodes[nIndex].x = nodes[nIndex].prelim + m; - nodes[nIndex].y = _depths[depth]; - - for (int c = nodes[nIndex].getFirstPrecursor(); c != -1; c = nodes[c].nextSibling) - { - secondWalk(nodes, c, m + nodes[nIndex].mod, depth + 1); - } - - nodes[nIndex].clear(); -} diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 92a7d6c0fe..7815970119 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -82,26 +82,44 @@ namespace indigo ObjArray successorReactions; // vector of precursor reactions indexes Array precursorReactionsIndexes; + // utility information + RedBlackSet derivedReactants; + ObjArray< Array > derivedReactantGroups; }; PathwayReaction(); ~PathwayReaction() override; - std::vector> getRootReactions() const; + std::vector getRootReactions() const; - auto& getReactionNodes() + auto& getReactionNode(int node_idx) { - return _reactionNodes; + return _reactionNodes[node_idx]; } - const auto& getMolecules() + int getReactionNodeCount() const + { + return static_cast(_reactionNodes.size()); + } + + auto& getMolecule( int mol_idx ) + { + return *_molecules[mol_idx]; + } + + int getMoleculeCount() const + { + return static_cast(_molecules.size()); + } + + const auto& getReaction(int reaction_idx) { - return _molecules; + return _reactions[reaction_idx]; } - const auto& getReactions() + int getReactionCount() const { - return _reactions; + return static_cast(_reactions.size()); } ReactionNode& addReactionNode() diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index 2f059f365b..44dcc91c6b 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -55,12 +55,12 @@ namespace indigo struct ReactionInchiDescriptor { - std::unordered_set reactants; + // std::unordered_set reactants; std::vector products; // useful to collect it here to avoid look them up in the reaction object std::vector productIndexes; std::vector reactantIndexes; - std::map> successor; // productIndexes <-> successor + // std::map> successor; // productIndexes <-> successor }; void buildInchiDescriptors(std::deque& reactions); diff --git a/core/indigo-core/reaction/src/pathway_reaction.cpp b/core/indigo-core/reaction/src/pathway_reaction.cpp index db91ce16b2..c38a10b0b2 100644 --- a/core/indigo-core/reaction/src/pathway_reaction.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction.cpp @@ -35,15 +35,12 @@ PathwayReaction::~PathwayReaction() { } -std::vector> PathwayReaction::getRootReactions() const +std::vector PathwayReaction::getRootReactions() const { - std::vector> root_reactions; - for(int i = 0; i < _reactionNodes.size(); ++i ) - { - const auto& rn = _reactionNodes[i]; - if (rn.successorReactions.size() == 0) - root_reactions.push_back(std::cref(rn)); - } + std::vector root_reactions; + for (int i = 0; i < _reactionNodes.size(); ++i) + if (_reactionNodes[i].successorReactions.size() == 0) + root_reactions.push_back(i); return root_reactions; } @@ -57,19 +54,19 @@ void PathwayReaction::clone(PathwayReaction& reaction) rn.reactionIdx = other.reactionIdx; rn.precursorReactionsIndexes.copy(other.precursorReactionsIndexes); for (int j = 0; j < other.successorReactions.size(); ++j) - { - auto& sr = other.successorReactions[j]; - rn.successorReactions.push(sr); - } + { + auto& sr = other.successorReactions[j]; + rn.successorReactions.push(sr); + } } for (int i = 0; i < reaction._reactions.size(); ++i) - { + { auto& other = reaction._reactions[i]; - auto& rc = _reactions.push(); + auto& rc = _reactions.push(); rc.productIndexes.copy(other.productIndexes); rc.reactantIndexes.copy(other.reactantIndexes); - } + } } BaseReaction* PathwayReaction::neu() @@ -92,4 +89,4 @@ bool PathwayReaction::aromatize(const AromaticityOptions& options) arom_found |= MoleculeAromatizer::aromatizeBonds(*(Molecule*)_allMolecules[i], options); } return arom_found; -} +} \ No newline at end of file diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 6d2b567292..2e5fad628b 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -19,9 +19,9 @@ #include #include +#include "layout/pathway_layout.h" #include "molecule/inchi_wrapper.h" #include "reaction/pathway_reaction_builder.h" -#include "layout/pathway_layout.h" #include "reaction/reaction.h" using namespace indigo; @@ -49,19 +49,19 @@ auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) { // if this is a first iteration and matchedReactions is empty, // then we just copy the set of reactions where the product is a reactant - std::map> reactionReactantIndices; - std::transform(rtr_it->second.begin(), rtr_it->second.end(), std::inserter(reactionReactantIndices, reactionReactantIndices.end()), + std::map> reactionReactantIndexes; + std::transform(rtr_it->second.begin(), rtr_it->second.end(), std::inserter(reactionReactantIndexes, reactionReactantIndexes.end()), [](const auto& pair) { return std::make_pair(pair.first, std::vector{pair.second}); }); if (matchedReactions.empty()) - matchedReactions = reactionReactantIndices; + matchedReactions = reactionReactantIndexes; else { // if matchedReactions is not empty, then we find the intersection of the sets // because we need to find only the reactions that have all given products as reactants // typically we have only one product, but just it case it is possible to have more than one std::map> intersection; - std::set_intersection(matchedReactions.begin(), matchedReactions.end(), reactionReactantIndices.begin(), reactionReactantIndices.end(), + std::set_intersection(matchedReactions.begin(), matchedReactions.end(), reactionReactantIndexes.begin(), reactionReactantIndexes.end(), std::inserter(intersection, intersection.begin()), [](const auto& a, const auto& b) { return a.first < b.first; }); for (auto& [key, values] : intersection) @@ -106,6 +106,7 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio Array inchi, inchiKey; for (int i = 0; i < reactions.size(); ++i) { + // add empty reaction nodes meanwhile calculating inchiKeys for reactants and products _pathwayReaction->addReactionNode(); auto& reaction = reactions[i]; ReactionInchiDescriptor& rd = _reactionInchiDescriptors.emplace_back(); @@ -118,20 +119,16 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio { case BaseReaction::REACTANT: { rd.reactantIndexes.push_back(static_cast(j)); - // copy reactant molecule to the pathway reaction, add mapping _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, j), std::forward_as_tuple(_pathwayReaction->addMolecule(reaction.getBaseMolecule(j).asMolecule()))); std::string inchi_str(inchiKey.ptr(), inchiKey.size()); - rd.reactants.insert(inchi_str); auto rtr_it = _reactantToReactions.find(inchi_str); + auto ridx = static_cast(rd.reactantIndexes.size() - 1); if (rtr_it == _reactantToReactions.end()) - { _reactantToReactions.emplace(std::piecewise_construct, std::forward_as_tuple(inchi_str), - std::forward_as_tuple(std::initializer_list>{ - {i, static_cast(j)}})); - } + std::forward_as_tuple(std::initializer_list>{{i, ridx}})); else - rtr_it->second.insert(std::make_pair(static_cast(i), static_cast(j))); + rtr_it->second.insert(std::make_pair(static_cast(i), ridx)); } break; case BaseReaction::PRODUCT: @@ -150,15 +147,15 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) // find all reactants of a reaction that match the products of the current reaction for (auto i = 0; i < _reactionInchiDescriptors.size(); i++) { + // looking for the reaction continuation auto matching_successor = findSuccessorReactions(i); - _reactionInchiDescriptors[i].successor = matching_successor; + // iterate over products of the reaction auto& productIndexes = _reactionInchiDescriptors[i].productIndexes; for (auto j = 0; j < productIndexes.size(); ++j) { - // copy reactant molecule to the pathway reaction, add mapping auto pidx = productIndexes[j]; int mol_idx = matching_successor.empty() - ? _pathwayReaction->addMolecule(reactions[i].getBaseMolecule(productIndexes[j]).asMolecule()) + ? _pathwayReaction->addMolecule(reactions[i].getBaseMolecule(pidx).asMolecule()) : _moleculeMapping.at(std::make_pair(matching_successor.begin()->first, matching_successor.begin()->second[j])); _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, pidx), std::forward_as_tuple(mol_idx)); } @@ -167,12 +164,32 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) { Array val_arr; val_arr.copy(val); - auto& rnodes = _pathwayReaction->getReactionNodes(); - auto& rn = rnodes[i]; + auto& rn = _pathwayReaction->getReactionNode(i); if (rn.successorReactions.size() == 0) { - rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); - rnodes[j].precursorReactionsIndexes.push(i); + auto& rnj = _pathwayReaction->getReactionNode(j); + bool found = false; + for (auto ridx : val) + { + found = rnj.derivedReactants.find(ridx); + if (found) + break; + } + if (!found) + { + rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); + rnj.precursorReactionsIndexes.push(i); + auto& drg = rnj.derivedReactantGroups.push(); + for (auto ridx : val) + { + rnj.derivedReactants.find_or_insert(ridx); + drg.push(ridx); + } + } + else + { + // it's possible to connect a product to the same reactant more than one + } } else { From 836bca7223b2f5ee6d40cb1486921b68ef966105 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Sun, 1 Sep 2024 12:56:55 +0200 Subject: [PATCH 09/25] layout debug --- core/indigo-core/layout/pathway_layout.h | 89 +++++---- .../indigo-core/layout/src/pathway_layout.cpp | 186 ++++++++++-------- core/indigo-core/reaction/pathway_reaction.h | 3 +- .../reaction/src/pathway_reaction_builder.cpp | 21 +- 4 files changed, 168 insertions(+), 131 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index b5869ecd0f..ab4a7777f3 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -23,10 +23,6 @@ namespace indigo { -#include -#include -#include - #include #include #include @@ -35,20 +31,20 @@ namespace indigo { public: PathwayLayoutItem(PathwayReaction& reaction, int nodeIdx, int reactantIdx = -1) - : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), - thread(nullptr), children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr) + : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), thread(nullptr), children(), + parent(nullptr), nextSibling(nullptr), prevSibling(nullptr) { auto& rn = reaction.getReactionNode(nodeIdx); auto& sr = reaction.getReaction(rn.reactionIdx); // create as a final reactant child if (reactantIdx != -1) - { - auto& mol = reaction.getMolecule(reactantIdx); - Rect2f bbox; - mol.getBoundingBox(bbox); - molecules.push_back(std::make_pair(reactantIdx, bbox)); - width += bbox.width(); - height = std::max(bbox.height(), height); + { + auto& mol = reaction.getMolecule(reactantIdx); + Rect2f bbox; + mol.getBoundingBox(bbox); + molecules.push_back(std::make_pair(reactantIdx, bbox)); + width += bbox.width(); + height = std::max(bbox.height(), height); } else { @@ -62,19 +58,24 @@ namespace indigo height = std::max(bbox.height(), height); } - // enumerate only final reactants here - // how to check if it is a final reactant? - // rn.precursorReactionsIndexes - for ( int i = 0; i < sr.reactantIndexes.size(); ++i) - { + // add precursors free reactants as children + for (int i = 0; i < sr.reactantIndexes.size(); ++i) + { // check if it is a final reactant - auto ridx = sr.reactantIndexes[i]; - PathwayLayoutItem* item = new PathwayLayoutItem(reaction, nodeIdx, ridx); - children.push_back(item); - item->parent = this; - } + if (!rn.successorReactants.find(i)) + { + auto ridx = sr.reactantIndexes[i]; + PathwayLayoutItem* item = new PathwayLayoutItem(reaction, nodeIdx, ridx); + children.push_back(item); + item->parent = this; + if (children.size() > 1) + { + children[children.size() - 2]->nextSibling = item; + item->prevSibling = children[children.size() - 2]; + } + } + } } - // fill parent and children } PathwayLayoutItem* getFirstChild() @@ -90,8 +91,7 @@ namespace indigo void clear() { number = -2; - prelim = 0.0; - mod = shift = change = 0.0; + prelim = mod = shift = change = 0.0; ancestor = thread = nullptr; } @@ -110,7 +110,7 @@ namespace indigo PathwayLayoutItem* thread; // some data - std::vector< std::pair> molecules; + std::vector> molecules; }; class PathwayLayout @@ -123,26 +123,41 @@ namespace indigo } void make(); - void buildLayoutTree(); private: - float spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool /*siblings*/); - PathwayLayoutItem* nextLeft(PathwayLayoutItem* n); - PathwayLayoutItem* nextRight(PathwayLayoutItem* n); - PathwayLayoutItem* ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a); + float spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool siblings) + { + return (l->height + r->height) / 2.0f; + } + void updateDepths(int depth, PathwayLayoutItem* item); + void determineDepths(); - void firstWalk(PathwayLayoutItem* v, int num, int depth); - void secondWalk(PathwayLayoutItem* v, PathwayLayoutItem* p, float m, int depth); + + void buildLayoutTree(); + + void firstWalk(PathwayLayoutItem* n, int num, int depth); PathwayLayoutItem* apportion(PathwayLayoutItem* v, PathwayLayoutItem* a); + + PathwayLayoutItem* nextTop(PathwayLayoutItem* n); + + PathwayLayoutItem* nextBottom(PathwayLayoutItem* n); + void moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, float shift); - void executeShifts(PathwayLayoutItem* v); - PathwayReaction& _reaction; + + void executeShifts(PathwayLayoutItem* n); + + PathwayLayoutItem* ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a); + + void secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth); + std::vector _depths; - int _maxDepth; + int _maxDepth = 0; + PathwayReaction& _reaction; std::vector _layoutItems; }; + } #endif diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index 72affece4a..ae8d1dc766 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -24,26 +24,6 @@ using namespace indigo; IMPL_ERROR(PathwayLayout, "pathway_layout"); -float PathwayLayout::spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool /*siblings*/) -{ - return (l->width + r->width)/2; -} - -PathwayLayoutItem* PathwayLayout::nextLeft(PathwayLayoutItem* n) -{ - return n->getFirstChild() ? n->getFirstChild() : n->thread; -} - -PathwayLayoutItem* PathwayLayout::nextRight(PathwayLayoutItem* n) -{ - return n->getLastChild() ? n->getLastChild() : n->thread; -} - -PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) -{ - return (vim->ancestor->parent == v->parent) ? vim->ancestor : a; -} - void PathwayLayout::make() { buildLayoutTree(); @@ -52,27 +32,60 @@ void PathwayLayout::make() { auto& li = _layoutItems[rrs[0]]; PathwayLayoutItem* root = &li; - std::fill(_depths.begin(), _depths.end(), 0.0f); + _depths.clear(); + _depths.resize(10, 0); _maxDepth = 0; + firstWalk(root, 0, 1); determineDepths(); secondWalk(root, nullptr, -root->prelim, 0); + + for (auto& li : _layoutItems) + { + std::cout << "width: " << li.width << " height: " << li.height << std::endl; + std::cout << "x: " << li.x << " y: " << li.y << std::endl; + } } } void PathwayLayout::buildLayoutTree() { + // create layout items for all reaction nodes + _layoutItems.reserve(_reaction.getReactionNodeCount()); + for (int i = 0; i < _reaction.getReactionNodeCount(); ++i) _layoutItems.emplace_back(_reaction, i); + + // fill layout tree + for (int i = 0; i < _reaction.getReactionNodeCount(); ++i) + { + auto& rn = _reaction.getReactionNode(i); + + auto& cur_li = _layoutItems[i]; + // add successor reactants to layout items + for (int j : rn.precursorReactionsIndexes) + { + auto& prec_li = _layoutItems[j]; + auto last_child = cur_li.getLastChild(); + if (last_child != nullptr) + { + last_child->nextSibling = &prec_li; + prec_li.prevSibling = last_child; + } + cur_li.children.push_back(&prec_li); + prec_li.parent = &cur_li; + } + std::cout << "reaction: " << i << " precursors:" << rn.precursorReactionsIndexes.size() << std::endl; + std::cout << "layout item: " << i << " children: " << cur_li.children.size() << std::endl; + // let's print siblings + } } void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) { float d = item->height; - if (_depths.size() <= static_cast(depth)) - { + if (_depths.size() <= depth) _depths.resize(3 * depth / 2); - } _depths[depth] = std::max(_depths[depth], d); _maxDepth = std::max(_maxDepth, depth); } @@ -80,107 +93,100 @@ void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) void PathwayLayout::determineDepths() { for (int i = 1; i < _maxDepth; ++i) - { _depths[i] += _depths[i - 1]; - } } -void PathwayLayout::firstWalk(PathwayLayoutItem* v, int num, int depth) +void PathwayLayout::firstWalk(PathwayLayoutItem* n, int num, int depth) { - v->number = num; - updateDepths(depth, v); - if (v->children.empty()) + n->number = num; + updateDepths(depth, n); + + if (n->children.empty()) { - if (PathwayLayoutItem* l = v->prevSibling) - v->prelim = l->prelim + spacing(l, v, true); - else - v->prelim = 0.0; + PathwayLayoutItem* l = n->prevSibling; + n->prelim = (l == nullptr) ? 0 : (l->prelim + spacing(l, n, true)); } else { - PathwayLayoutItem* leftMost = v->getFirstChild(); - PathwayLayoutItem* rightMost = v->getLastChild(); - PathwayLayoutItem* defaultAncestor = leftMost; - for (PathwayLayoutItem* c = leftMost; c != nullptr; ++num) + PathwayLayoutItem* topMost = n->getFirstChild(); + PathwayLayoutItem* bottomMost = n->getLastChild(); + PathwayLayoutItem* defaultAncestor = topMost; + for (auto c : n->children) { - firstWalk(c, num, depth + 1); + firstWalk(c, num++, depth + 1); defaultAncestor = apportion(c, defaultAncestor); - c = c->nextSibling; } - executeShifts(v); - float midPoint = (leftMost->prelim + rightMost->prelim)/2; - if (PathwayLayoutItem* l = v->prevSibling) + + executeShifts(n); + + float midpoint = (topMost->prelim + bottomMost->prelim) / 2.0f; + PathwayLayoutItem* top = n->prevSibling; + if (top != nullptr) { - v->prelim = l->prelim + spacing(l, v, true); - v->mod += v->prelim - midPoint; + n->prelim = top->prelim + spacing(top, n, true); + n->mod = n->prelim - midpoint; } else { - v->prelim = midPoint; + n->prelim = midpoint; } } } -void PathwayLayout::secondWalk(PathwayLayoutItem* v, PathwayLayoutItem* p, float m, int depth) +void PathwayLayout::secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth) { - v->x = v->prelim + m; - v->y = _depths[depth]; - m += v->mod; - for (PathwayLayoutItem* w : v->children) + n->y = n->prelim + m; + n->x = -_depths[depth]; + + for (PathwayLayoutItem* c = n->getFirstChild(); c != nullptr; c = c->nextSibling) { - secondWalk(w, v, m, depth + 1); + secondWalk(c, n, m + n->mod, depth + 1); } - v->clear(); + + n->clear(); } PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* v, PathwayLayoutItem* a) { - if (PathwayLayoutItem* w = v->prevSibling) + PathwayLayoutItem* w = v->prevSibling; + if (w != nullptr) { - PathwayLayoutItem *vip = v, *vop = v; - PathwayLayoutItem *vim = w, *vom = v->getFirstChild(); - float sip = vip->mod, sop = vop->mod; - float sim = vim->mod, som = vom != nullptr ? vom->mod : 0; - PathwayLayoutItem* nr = nextRight(vim); - PathwayLayoutItem* nl = nextLeft(vip); + PathwayLayoutItem *vip = v, *vim = w, *vop = v, *vom = v->parent->getFirstChild(); + float sip = vip->mod, sim = vim->mod, sop = vop->mod, som = vom->mod; + PathwayLayoutItem* nr = nextBottom(vim); + PathwayLayoutItem* nl = nextTop(vip); + while (nr != nullptr && nl != nullptr) { vim = nr; vip = nl; - vom = nextLeft(vom); - vop = nextRight(vop); - if (vop) - vop->ancestor = v; + vom = nextTop(vom); + vop = nextBottom(vop); + vop->ancestor = v; float shift = (vim->prelim + sim) - (vip->prelim + sip) + spacing(vim, vip, false); if (shift > 0) { - PathwayLayoutItem* from = ancestor(vim, v, a); - moveSubtree(from, v, shift); + moveSubtree(ancestor(vim, v, a), v, shift); sip += shift; sop += shift; } sim += vim->mod; sip += vip->mod; - if (vom) - som += vom->mod; - if (vop) - sop += vop->mod; + som += vom->mod; + sop += vop->mod; - nr = nextRight(vim); - nl = nextLeft(vip); + nr = nextBottom(vim); + nl = nextTop(vip); } - if (nr && vop && !nextRight(vop)) + if (nr != nullptr && nextBottom(vop) == nullptr) { vop->thread = nr; vop->mod += sim - sop; } - if (nl && (!vom || !nextLeft(vom))) + if (nl != nullptr && nextTop(vom) == nullptr) { - if (vom) - { - vom->thread = nl; - vom->mod += sip - som; - } + vom->thread = nl; + vom->mod += sip - som; a = v; } } @@ -197,12 +203,11 @@ void PathwayLayout::moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, fl wp->mod += shift; } -void PathwayLayout::executeShifts(PathwayLayoutItem* v) +void PathwayLayout::executeShifts(PathwayLayoutItem* n) { float shift = 0, change = 0; - for (auto it = v->children.rbegin(); it != v->children.rend(); ++it) + for (PathwayLayoutItem* c = n->getLastChild(); c != nullptr; c = c->prevSibling) { - PathwayLayoutItem* c = *it; c->prelim += shift; c->mod += shift; change += c->change; @@ -210,3 +215,20 @@ void PathwayLayout::executeShifts(PathwayLayoutItem* v) } } +PathwayLayoutItem* PathwayLayout::nextTop(PathwayLayoutItem* n) +{ + PathwayLayoutItem* c = n->getFirstChild(); + return (c != nullptr) ? c : n->thread; +} + +PathwayLayoutItem* PathwayLayout::nextBottom(PathwayLayoutItem* n) +{ + PathwayLayoutItem* c = n->getLastChild(); + return (c != nullptr) ? c : n->thread; +} + +PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) +{ + PathwayLayoutItem* p = v->parent; + return (vim->ancestor->parent == p) ? vim->ancestor : a; +} diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 7815970119..49221b2916 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -83,8 +83,7 @@ namespace indigo // vector of precursor reactions indexes Array precursorReactionsIndexes; // utility information - RedBlackSet derivedReactants; - ObjArray< Array > derivedReactantGroups; + RedBlackSet successorReactants; }; PathwayReaction(); diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 2e5fad628b..3761922a26 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -160,18 +160,20 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, pidx), std::forward_as_tuple(mol_idx)); } - for (auto& [j, val] : matching_successor) // [j, val] - j is the index of the reaction, val is the vector of reactant indexes + auto& rn = _pathwayReaction->getReactionNode(i); + + for (auto& [j, val] : matching_successor) // [j, val] - j is the index of the matched sucessor reaction, val is the vector of reactant indexes { Array val_arr; val_arr.copy(val); - auto& rn = _pathwayReaction->getReactionNode(i); if (rn.successorReactions.size() == 0) { auto& rnj = _pathwayReaction->getReactionNode(j); + // check if the reactant is already in use as a successor bool found = false; for (auto ridx : val) { - found = rnj.derivedReactants.find(ridx); + found = rnj.successorReactants.find(ridx); if (found) break; } @@ -179,21 +181,19 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) { rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); rnj.precursorReactionsIndexes.push(i); - auto& drg = rnj.derivedReactantGroups.push(); for (auto ridx : val) - { - rnj.derivedReactants.find_or_insert(ridx); - drg.push(ridx); - } + rnj.successorReactants.insert(ridx); } else { - // it's possible to connect a product to the same reactant more than one + // it's impossible that a reactant has multiple precursors. + // we can handle this case if needed. } } else { - // only one successor reaction is allowed. skip the reaction if there are more than one. + // only one successor reaction is allowed for a reaction. + // we can handle this case if needed. } } } @@ -207,6 +207,7 @@ std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(st auto& rr = _pathwayReaction->getRootReactions(); PathwayLayout pl(*_pathwayReaction); pl.make(); + std::cout << "root nodes: " << rr.size() << std::endl; return std::move(_pathwayReaction); } \ No newline at end of file From b3c13cbd671a812725c8a384e3fe20b081c2f744 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 2 Sep 2024 08:59:15 +0200 Subject: [PATCH 10/25] layout and model --- core/indigo-core/common/math/algebra.h | 6 + core/indigo-core/layout/pathway_layout.h | 208 +++++++++++------- .../indigo-core/layout/src/pathway_layout.cpp | 82 +++++-- core/indigo-core/molecule/base_molecule.h | 1 + .../molecule/src/base_molecule.cpp | 6 + core/indigo-core/reaction/pathway_reaction.h | 37 +++- .../src/pathway_reaction_json_saver.cpp | 72 +++--- 7 files changed, 274 insertions(+), 138 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index eb04ff16e5..d966f976b2 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -372,6 +372,12 @@ namespace indigo _rightTop.max(second._rightTop); } + inline void offset(const Vec2f& offset) + { + _leftBottom += offset; + _rightTop += offset; + } + inline float left() const { return _leftBottom.x; diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index ab4a7777f3..63b436c6f6 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -17,117 +17,160 @@ ***************************************************************************/ #ifndef __pathway_layout_h__ -#define __pathway_layout_h__ +#define __pathway_layout_h__molecules -#include "reaction/pathway_reaction.h" - -namespace indigo -{ #include #include +#include +#include #include - class PathwayLayoutItem +#include "reaction/pathway_reaction.h" + +namespace indigo +{ + class PathwayLayout { + DECL_ERROR; + public: - PathwayLayoutItem(PathwayReaction& reaction, int nodeIdx, int reactantIdx = -1) - : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), thread(nullptr), children(), - parent(nullptr), nextSibling(nullptr), prevSibling(nullptr) + PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0) { - auto& rn = reaction.getReactionNode(nodeIdx); - auto& sr = reaction.getReaction(rn.reactionIdx); - // create as a final reactant child - if (reactantIdx != -1) - { - auto& mol = reaction.getMolecule(reactantIdx); - Rect2f bbox; - mol.getBoundingBox(bbox); - molecules.push_back(std::make_pair(reactantIdx, bbox)); - width += bbox.width(); - height = std::max(bbox.height(), height); - } - else + } + + void make(); + + private: + struct PathwayLayoutItem + { + PathwayLayoutItem(PathwayReaction& pwr, int nodeIdx, int reactantIdx = -1) + : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), thread(nullptr), + children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr), reaction(pwr) { - for (auto pidx : sr.productIndexes) + auto& rn = reaction.getReactionNode(nodeIdx); + auto& sr = reaction.getReaction(rn.reactionIdx); + // create as a final reactant child + if (reactantIdx != -1) { - auto& mol = reaction.getMolecule(pidx); + auto& mol = reaction.getMolecule(reactantIdx); Rect2f bbox; mol.getBoundingBox(bbox); - molecules.push_back(std::make_pair(pidx, bbox)); - width += bbox.width(); - height = std::max(bbox.height(), height); + molecules.push_back(std::make_pair(reactantIdx, bbox)); + width = bbox.width(); + height = bbox.height(); } - - // add precursors free reactants as children - for (int i = 0; i < sr.reactantIndexes.size(); ++i) + else { - // check if it is a final reactant - if (!rn.successorReactants.find(i)) + for (auto pidx : sr.productIndexes) + { + auto& mol = reaction.getMolecule(pidx); + Rect2f bbox; + mol.getBoundingBox(bbox); + molecules.push_back(std::make_pair(pidx, bbox)); + width += bbox.width(); // add some spacing for plus + height = std::max(bbox.height(), height); + } + + // add precursors free reactants as children + for (int i = 0; i < sr.reactantIndexes.size(); ++i) { - auto ridx = sr.reactantIndexes[i]; - PathwayLayoutItem* item = new PathwayLayoutItem(reaction, nodeIdx, ridx); - children.push_back(item); - item->parent = this; - if (children.size() > 1) + // check if it is a final reactant + if (!rn.successorReactants.find(i)) { - children[children.size() - 2]->nextSibling = item; - item->prevSibling = children[children.size() - 2]; + auto ridx = sr.reactantIndexes[i]; + reactants_no_precursors.emplace_back(reaction, nodeIdx, ridx); + PathwayLayoutItem* item = &reactants_no_precursors.back(); + children.push_back(item); + item->parent = this; + if (children.size() > 1) + { + children[children.size() - 2]->nextSibling = item; + item->prevSibling = children[children.size() - 2]; + } } } } } - } - PathwayLayoutItem* getFirstChild() - { - return children.empty() ? nullptr : children.front(); - } + PathwayLayoutItem* getFirstChild() + { + return children.empty() ? nullptr : children.front(); + } - PathwayLayoutItem* getLastChild() - { - return children.empty() ? nullptr : children.back(); - } + PathwayLayoutItem* getLastChild() + { + return children.empty() ? nullptr : children.back(); + } - void clear() - { - number = -2; - prelim = mod = shift = change = 0.0; - ancestor = thread = nullptr; - } + void clear() + { + number = -2; + prelim = mod = shift = change = 0.0; + ancestor = thread = nullptr; + } - // required for the layout algorithm - float width, height; - std::vector children; - PathwayLayoutItem* parent; - PathwayLayoutItem* nextSibling; - PathwayLayoutItem* prevSibling; - - // computed fields - int number; - float prelim, mod, shift, change; - float x, y; - PathwayLayoutItem* ancestor; - PathwayLayoutItem* thread; - - // some data - std::vector> molecules; - }; + void applyLayout(const Vec2f& offset) + { + if (molecules.size()) + { + float totalWidth = std::accumulate(molecules.begin(), molecules.end(), 0.0f, + [](float acc, const std::pair& r) { return acc + r.second.width(); }); - class PathwayLayout - { - DECL_ERROR; + float spacing = molecules.size() > 1 ? (width - totalWidth) / (molecules.size() - 1) : (width - totalWidth) / 2; + float currentX = x - width / 2; + float currentY = y - height / 2; + for (auto& mol_desc : molecules) + { + auto& mol = reaction.getMolecule(mol_desc.first); + Vec2f item_offset(currentX - mol_desc.second.left(), currentY - mol_desc.second.bottom()); + mol.offsetCoordinates(Vec3f(item_offset.x + offset.x, item_offset.y + offset.y, 0)); + currentX += mol_desc.second.width() + spacing; + } + } + } - public: - PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0) + // required for the layout algorithm + float width, height; + std::vector children; + std::list reactants_no_precursors; + PathwayLayoutItem* parent; + PathwayLayoutItem* nextSibling; + PathwayLayoutItem* prevSibling; + + // computed fields + int number; + float prelim, mod, shift, change; + float x, y; + PathwayLayoutItem* ancestor; + PathwayLayoutItem* thread; + + // other data + std::vector> molecules; + PathwayReaction& reaction; + }; + + struct PathwayLayoutRootItem { - } + PathwayLayoutRootItem(int root) : root_index(root) + { + } + int root_index; + Vec2f offset; + std::vector li_items; + }; - void make(); + std::vector traverse(PathwayLayoutItem* root); - private: - float spacing(PathwayLayoutItem* l, PathwayLayoutItem* r, bool siblings) + void dumpLayoutItem(const PathwayLayout::PathwayLayoutItem& li) { - return (l->height + r->height) / 2.0f; + std::cout << "Layout Item: " << li.x << " " << li.y << " " << li.width << " " << li.height << std::endl; + } + + float spacing(PathwayLayoutItem* top, PathwayLayoutItem* bottom, bool siblings) + { + return (top->height + bottom->height) + 0.5f; + // return siblings ? (top->height + bottom->height) : std::max(top->width, bottom->width); + // return (top->height + bottom->height) / 2.0f; } void updateDepths(int depth, PathwayLayoutItem* item); @@ -152,10 +195,13 @@ namespace indigo void secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth); + void applyLayout(); + std::vector _depths; int _maxDepth = 0; PathwayReaction& _reaction; std::vector _layoutItems; + std::vector _layoutRootItems; }; } diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index ae8d1dc766..1c2e2633f5 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -27,11 +27,15 @@ IMPL_ERROR(PathwayLayout, "pathway_layout"); void PathwayLayout::make() { buildLayoutTree(); - auto rrs = _reaction.getRootReactions(); - if (rrs.size()) + auto roots = _reaction.getRootReactions(); + _layoutRootItems.reserve(roots.size()); + float total_height = 0; + // for (auto rri : roots) { - auto& li = _layoutItems[rrs[0]]; - PathwayLayoutItem* root = &li; + auto rri = roots.back(); + std::cout << "Root node: " << rri << std::endl; + auto& li_root = _layoutRootItems.emplace_back(rri); + PathwayLayoutItem* root = &_layoutItems[rri]; _depths.clear(); _depths.resize(10, 0); _maxDepth = 0; @@ -39,13 +43,29 @@ void PathwayLayout::make() firstWalk(root, 0, 1); determineDepths(); secondWalk(root, nullptr, -root->prelim, 0); - - for (auto& li : _layoutItems) + li_root.li_items = traverse(root); + // calculating bounding box for the one pathway + auto& li_items = li_root.li_items; + Rect2f pw_bbox; + for (auto i = 0; i < li_items.size(); ++i) { - std::cout << "width: " << li.width << " height: " << li.height << std::endl; - std::cout << "x: " << li.x << " y: " << li.y << std::endl; + auto& li = *li_items[i]; + Rect2f item_bbox(Vec2f(li.x - li.width / 2, li.y - li.height / 2), Vec2f(li.x + li.width / 2, li.y + li.height / 2)); + std::cout << "bbox: " << item_bbox.left() << " " << item_bbox.bottom() << " " << item_bbox.right() << " " << item_bbox.top() << std::endl; + if (i) + pw_bbox.extend(item_bbox); + else + pw_bbox = item_bbox; } + li_root.offset.x = -pw_bbox.left(); + li_root.offset.y = -pw_bbox.top() - total_height; + total_height += pw_bbox.height(); } + + for (auto& li_root : _layoutRootItems) + li_root.offset.y += total_height; + + applyLayout(); } void PathwayLayout::buildLayoutTree() @@ -70,14 +90,11 @@ void PathwayLayout::buildLayoutTree() if (last_child != nullptr) { last_child->nextSibling = &prec_li; - prec_li.prevSibling = last_child; + prec_li.prevSibling = last_child; } cur_li.children.push_back(&prec_li); prec_li.parent = &cur_li; } - std::cout << "reaction: " << i << " precursors:" << rn.precursorReactionsIndexes.size() << std::endl; - std::cout << "layout item: " << i << " children: " << cur_li.children.size() << std::endl; - // let's print siblings } } @@ -86,7 +103,7 @@ void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) float d = item->height; if (_depths.size() <= depth) _depths.resize(3 * depth / 2); - _depths[depth] = std::max(_depths[depth], d); + _depths[depth] = std::max(_depths[depth], d + 5.0f); _maxDepth = std::max(_maxDepth, depth); } @@ -146,7 +163,18 @@ void PathwayLayout::secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float n->clear(); } -PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* v, PathwayLayoutItem* a) +void PathwayLayout::applyLayout() +{ + // upload coordinates back to the reaction + for (auto& li_root : _layoutRootItems) + { + auto& li_items = li_root.li_items; + for (auto li : li_items) + li->applyLayout(li_root.offset); + } +} + +PathwayLayout::PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* v, PathwayLayoutItem* a) { PathwayLayoutItem* w = v->prevSibling; if (w != nullptr) @@ -215,20 +243,40 @@ void PathwayLayout::executeShifts(PathwayLayoutItem* n) } } -PathwayLayoutItem* PathwayLayout::nextTop(PathwayLayoutItem* n) +PathwayLayout::PathwayLayoutItem* PathwayLayout::nextTop(PathwayLayoutItem* n) { PathwayLayoutItem* c = n->getFirstChild(); return (c != nullptr) ? c : n->thread; } -PathwayLayoutItem* PathwayLayout::nextBottom(PathwayLayoutItem* n) +PathwayLayout::PathwayLayoutItem* PathwayLayout::nextBottom(PathwayLayoutItem* n) { PathwayLayoutItem* c = n->getLastChild(); return (c != nullptr) ? c : n->thread; } -PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) +PathwayLayout::PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) { PathwayLayoutItem* p = v->parent; return (vim->ancestor->parent == p) ? vim->ancestor : a; } + +std::vector PathwayLayout::traverse(PathwayLayoutItem* root) +{ + std::vector result; + std::stack stack; + + if (root != nullptr) + { + stack.push(root); + } + + while (!stack.empty()) + { + PathwayLayoutItem* node = stack.top(); + stack.pop(); + result.push_back(node); + std::for_each(node->children.rbegin(), node->children.rend(), [&stack](PathwayLayoutItem* child) { stack.push(child); }); + } + return result; +} diff --git a/core/indigo-core/molecule/base_molecule.h b/core/indigo-core/molecule/base_molecule.h index 0a049fb98a..4c5a7c95dc 100644 --- a/core/indigo-core/molecule/base_molecule.h +++ b/core/indigo-core/molecule/base_molecule.h @@ -534,6 +534,7 @@ namespace indigo void getBoundingBox(Rect2f& bbox) const; void getBoundingBox(Rect2f& bbox, const Vec2f& minbox) const; void getBoundingBox(Vec2f& a, Vec2f& b) const; + void offsetCoordinates(const Vec3f& offset); // aliases bool isAlias(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 e7443675e9..efaf7e93d3 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -4481,6 +4481,12 @@ void BaseMolecule::setBondCIP(int bond_idx, CIPDesc cip) have_cip = true; } +void BaseMolecule::offsetCoordinates(const Vec3f& offset) +{ + for (int i = 0; i < _xyz.size(); i++) + _xyz[i].add(offset); +} + 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/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 49221b2916..025478d617 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -57,22 +57,36 @@ namespace indigo struct SimpleReaction { - SimpleReaction() = default; - SimpleReaction(const SimpleReaction& other) + struct Plus + { + int metaIndex; + int componentIndex1; + int componentIndex2; + }; + + SimpleReaction() : arrowMetaIndex(-1) + { + } + + SimpleReaction(const SimpleReaction& other) : arrowMetaIndex(other.arrowMetaIndex) { reactantIndexes.copy(other.reactantIndexes); productIndexes.copy(other.productIndexes); + pluses.copy(other.pluses); } Array reactantIndexes; Array productIndexes; + Array pluses; + int arrowMetaIndex; }; struct ReactionNode { - ReactionNode() : reactionIdx(-1){}; + ReactionNode() : reactionIdx(-1), multiTailMetaIndex(-1){}; ReactionNode(const ReactionNode& other) { reactionIdx = other.reactionIdx; + multiTailMetaIndex = other.multiTailMetaIndex; for (int i = 0; i < other.successorReactions.size(); ++i) successorReactions.push(other.successorReactions[i]); precursorReactionsIndexes.copy(other.precursorReactionsIndexes); @@ -84,6 +98,7 @@ namespace indigo Array precursorReactionsIndexes; // utility information RedBlackSet successorReactants; + int multiTailMetaIndex; }; PathwayReaction(); @@ -97,19 +112,19 @@ namespace indigo } int getReactionNodeCount() const - { - return static_cast(_reactionNodes.size()); - } + { + return static_cast(_reactionNodes.size()); + } - auto& getMolecule( int mol_idx ) + auto& getMolecule(int mol_idx) { return *_molecules[mol_idx]; } int getMoleculeCount() const - { - return static_cast(_molecules.size()); - } + { + return static_cast(_molecules.size()); + } const auto& getReaction(int reaction_idx) { @@ -118,7 +133,7 @@ namespace indigo int getReactionCount() const { - return static_cast(_reactions.size()); + return static_cast(_reactions.size()); } ReactionNode& addReactionNode() diff --git a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp index 4a6a1f1bcb..9bf7744203 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp @@ -32,40 +32,15 @@ PathwayReactionJsonSaver::PathwayReactionJsonSaver(Output& output) : _output(out { } -void PathwayReactionJsonSaver::saveReaction(PathwayReaction& rxn) +void PathwayReactionJsonSaver::saveReaction(PathwayReaction& pwr) { auto merged = std::make_unique(); - auto reaction = std::make_unique(); - reaction->clone(rxn); - - std::vector> points; - std::vector> arrows; - // std::tie(points, arrows) = reaction->makeTreePoints(); - // Ensure the same order across different platforms. - std::sort(points.begin(), points.end()); - - for (auto& p : points) + for (int i = 0; i < pwr.getMoleculeCount(); ++i) { - auto& molecule = reaction->getBaseMolecule(p.first); - Rect2f box; - molecule.getBoundingBox(box); - auto offset = box.center(); - offset.negate(); - offset.add(p.second); - for (int j = molecule.vertexBegin(); j != molecule.vertexEnd(); j = molecule.vertexNext(j)) - { - Vec3f& xyz = molecule.getAtomXyz(j); - xyz.add(offset); - } - merged->mergeWithMolecule(molecule, 0, 0); + auto& molecule = pwr.getMolecule(i); + merged->mergeWithMolecule(molecule, 0, 0); } - for (auto& a : arrows) - if (a.size() > 2) - merged->meta().addMetaObject(new KETReactionMultitailArrow(a.begin(), a.end())); - else if (a.size() == 2) - merged->meta().addMetaObject(new KETReactionArrow(KETReactionArrow::EOpenAngle, a.back(), a.front())); - rapidjson::StringBuffer buffer; JsonWriter writer(pretty_json); writer.Reset(buffer); @@ -73,4 +48,43 @@ void PathwayReactionJsonSaver::saveReaction(PathwayReaction& rxn) moleculeSaver.add_stereo_desc = add_stereo_desc; moleculeSaver.saveMolecule(*merged, writer); _output.printf("%s", buffer.GetString()); + + // auto reaction = std::make_unique(); + //reaction->clone(rxn); + + //std::vector> points; + //std::vector> arrows; + //// std::tie(points, arrows) = reaction->makeTreePoints(); + //// Ensure the same order across different platforms. + //std::sort(points.begin(), points.end()); + + //for (auto& p : points) + //{ + // auto& molecule = reaction->getBaseMolecule(p.first); + // Rect2f box; + // molecule.getBoundingBox(box); + // auto offset = box.center(); + // offset.negate(); + // offset.add(p.second); + // for (int j = molecule.vertexBegin(); j != molecule.vertexEnd(); j = molecule.vertexNext(j)) + // { + // Vec3f& xyz = molecule.getAtomXyz(j); + // xyz.add(offset); + // } + // merged->mergeWithMolecule(molecule, 0, 0); + //} + + //for (auto& a : arrows) + // if (a.size() > 2) + // merged->meta().addMetaObject(new KETReactionMultitailArrow(a.begin(), a.end())); + // else if (a.size() == 2) + // merged->meta().addMetaObject(new KETReactionArrow(KETReactionArrow::EOpenAngle, a.back(), a.front())); + + //rapidjson::StringBuffer buffer; + //JsonWriter writer(pretty_json); + //writer.Reset(buffer); + //MoleculeJsonSaver moleculeSaver(_output); + //moleculeSaver.add_stereo_desc = add_stereo_desc; + //moleculeSaver.saveMolecule(*merged, writer); + //_output.printf("%s", buffer.GetString()); } From 8deaa6b0d4ad3db60ee07a5f8184d38881d36f81 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 2 Sep 2024 21:55:03 +0200 Subject: [PATCH 11/25] layout and model --- core/indigo-core/layout/pathway_layout.h | 24 ++++---- .../indigo-core/layout/src/pathway_layout.cpp | 55 ++++++++++++++----- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index 63b436c6f6..2bbf41cffe 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "reaction/pathway_reaction.h" @@ -34,7 +36,7 @@ namespace indigo DECL_ERROR; public: - PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0) + PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0), _log_file("pathway.svg") { } @@ -109,7 +111,7 @@ namespace indigo ancestor = thread = nullptr; } - void applyLayout(const Vec2f& offset) + void applyLayout() { if (molecules.size()) { @@ -117,13 +119,14 @@ namespace indigo [](float acc, const std::pair& r) { return acc + r.second.width(); }); float spacing = molecules.size() > 1 ? (width - totalWidth) / (molecules.size() - 1) : (width - totalWidth) / 2; - float currentX = x - width / 2; - float currentY = y - height / 2; + float currentX = x; + float currentY = y; for (auto& mol_desc : molecules) { auto& mol = reaction.getMolecule(mol_desc.first); - Vec2f item_offset(currentX - mol_desc.second.left(), currentY - mol_desc.second.bottom()); - mol.offsetCoordinates(Vec3f(item_offset.x + offset.x, item_offset.y + offset.y, 0)); + std::cout << "mol index: " << mol_desc.first << std::endl; + Vec2f item_offset(currentX - mol_desc.second.center().x, currentY - mol_desc.second.center().y); + mol.offsetCoordinates(Vec3f(item_offset.x, item_offset.y, 0)); currentX += mol_desc.second.width() + spacing; } } @@ -155,7 +158,7 @@ namespace indigo { } int root_index; - Vec2f offset; + Rect2f bbox; std::vector li_items; }; @@ -168,9 +171,7 @@ namespace indigo float spacing(PathwayLayoutItem* top, PathwayLayoutItem* bottom, bool siblings) { - return (top->height + bottom->height) + 0.5f; - // return siblings ? (top->height + bottom->height) : std::max(top->width, bottom->width); - // return (top->height + bottom->height) / 2.0f; + return 1.0f + (top->height + bottom->height) / 2.0f; } void updateDepths(int depth, PathwayLayoutItem* item); @@ -198,10 +199,13 @@ namespace indigo void applyLayout(); std::vector _depths; + std::vector _shifts; + int _maxDepth = 0; PathwayReaction& _reaction; std::vector _layoutItems; std::vector _layoutRootItems; + std::ofstream _log_file; }; } diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index 1c2e2633f5..bbf87c0b66 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -29,10 +29,9 @@ void PathwayLayout::make() buildLayoutTree(); auto roots = _reaction.getRootReactions(); _layoutRootItems.reserve(roots.size()); - float total_height = 0; - // for (auto rri : roots) + float yShift = 0; + for (auto rri : roots) { - auto rri = roots.back(); std::cout << "Root node: " << rri << std::endl; auto& li_root = _layoutRootItems.emplace_back(rri); PathwayLayoutItem* root = &_layoutItems[rri]; @@ -44,6 +43,7 @@ void PathwayLayout::make() determineDepths(); secondWalk(root, nullptr, -root->prelim, 0); li_root.li_items = traverse(root); + std::cout << "Number of items: " << li_root.li_items.size() << std::endl; // calculating bounding box for the one pathway auto& li_items = li_root.li_items; Rect2f pw_bbox; @@ -57,13 +57,34 @@ void PathwayLayout::make() else pw_bbox = item_bbox; } - li_root.offset.x = -pw_bbox.left(); - li_root.offset.y = -pw_bbox.top() - total_height; - total_height += pw_bbox.height(); - } - for (auto& li_root : _layoutRootItems) - li_root.offset.y += total_height; + li_root.bbox = pw_bbox; + if (rri == 5) + { + _log_file << "" + << std::endl; + for (auto i = 0; i < li_items.size(); ++i) + { + auto& li = *li_items[i]; + Rect2f item_bbox(Vec2f(li.x - li.width / 2, li.y - li.height / 2), Vec2f(li.x + li.width / 2, li.y + li.height / 2)); + _log_file << "" << std::endl; + } + + _log_file << "" << std::endl; + _log_file.close(); + } + + for (auto i = 0; i < li_items.size(); ++i) + { + auto& li = *li_items[i]; + li.x -= pw_bbox.left(); + li.y -= pw_bbox.bottom() + yShift; + } + yShift += pw_bbox.height(); + } applyLayout(); } @@ -100,17 +121,19 @@ void PathwayLayout::buildLayoutTree() void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) { - float d = item->height; + float d = item->width + 1.0f; if (_depths.size() <= depth) _depths.resize(3 * depth / 2); - _depths[depth] = std::max(_depths[depth], d + 5.0f); + _depths[depth] = std::max(_depths[depth], d); _maxDepth = std::max(_maxDepth, depth); + std::cout << "Depth: " << depth << " width: " << _depths[depth] << std::endl; } void PathwayLayout::determineDepths() { + _shifts = _depths; for (int i = 1; i < _maxDepth; ++i) - _depths[i] += _depths[i - 1]; + _shifts[i] += _shifts[i - 1]; } void PathwayLayout::firstWalk(PathwayLayoutItem* n, int num, int depth) @@ -153,7 +176,10 @@ void PathwayLayout::firstWalk(PathwayLayoutItem* n, int num, int depth) void PathwayLayout::secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth) { n->y = n->prelim + m; - n->x = -_depths[depth]; + + n->x = -(_shifts[depth] + _depths[depth + 1] / 2); + + std::cout << "depth:" << depth << " n->x " << n->x << " width:" << n->width << std::endl; for (PathwayLayoutItem* c = n->getFirstChild(); c != nullptr; c = c->nextSibling) { @@ -168,9 +194,10 @@ void PathwayLayout::applyLayout() // upload coordinates back to the reaction for (auto& li_root : _layoutRootItems) { + std::cout << " root:" << li_root.root_index << " count:" << li_root.li_items.size() << std::endl; auto& li_items = li_root.li_items; for (auto li : li_items) - li->applyLayout(li_root.offset); + li->applyLayout(); } } From 28f5c9b4713e1a187d25abb2c6c8b4c6bb1674e0 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 19:21:08 +0200 Subject: [PATCH 12/25] layout and model --- .../integration/tests/reaction/pathway.py | 8 +- .../tests/reaction/reactions/pathway10.rdf | 279 +++++ .../tests/reaction/reactions/pathway9.rdf | 1033 +++++++++++++++++ .../tests/reaction/ref/pathway1.ket | 2 +- .../tests/reaction/ref/pathway2.ket | 2 +- .../tests/reaction/ref/pathway3.ket | 2 +- .../tests/reaction/ref/pathway4.ket | 2 +- .../tests/reaction/ref/pathway5.ket | 2 +- .../tests/reaction/ref/pathway6.ket | 2 +- .../tests/reaction/ref/pathway7.ket | 2 +- .../tests/reaction/ref/pathway8.ket | 2 +- core/indigo-core/layout/pathway_layout.h | 47 +- .../indigo-core/layout/src/pathway_layout.cpp | 99 +- .../layout/src/reaction_layout.cpp | 1 + core/indigo-core/reaction/pathway_reaction.h | 9 +- .../reaction/pathway_reaction_builder.h | 11 +- .../reaction/src/pathway_reaction_builder.cpp | 46 +- .../src/pathway_reaction_json_saver.cpp | 41 +- utils/indigo-depict/main.c | 2 +- 19 files changed, 1457 insertions(+), 135 deletions(-) create mode 100644 api/tests/integration/tests/reaction/reactions/pathway10.rdf create mode 100644 api/tests/integration/tests/reaction/reactions/pathway9.rdf diff --git a/api/tests/integration/tests/reaction/pathway.py b/api/tests/integration/tests/reaction/pathway.py index bf64fc280c..d7a8abe9fa 100644 --- a/api/tests/integration/tests/reaction/pathway.py +++ b/api/tests/integration/tests/reaction/pathway.py @@ -27,16 +27,22 @@ def find_diff(a, b): "pathway6", "pathway7", "pathway8", + "pathway9", + "pathway10", ] for filename in files: rxn = indigo.loadReactionFromFile( os.path.join(input_path, filename + ".rdf") ) - rxn_ref = open(os.path.join(ref_path, filename) + ".ket", "r").read() rxn_txt = rxn.json() + # with open(os.path.join(ref_path, filename) + ".ket", "w") as file: + # file.write(rxn_txt) + + rxn_ref = open(os.path.join(ref_path, filename) + ".ket", "r").read() + diff = find_diff(rxn_ref, rxn_txt) if not diff: print(filename + ".rdf:SUCCEED") diff --git a/api/tests/integration/tests/reaction/reactions/pathway10.rdf b/api/tests/integration/tests/reaction/reactions/pathway10.rdf new file mode 100644 index 0000000000..3a6376e46f --- /dev/null +++ b/api/tests/integration/tests/reaction/reactions/pathway10.rdf @@ -0,0 +1,279 @@ +$RDFILE 1 +$RFMT +$RXN + + -INDIGO- 0903241149 + + 2 3 +$MOL + + -INDIGO-09032411492D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 5.1216 -4.8963 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1179 -3.9012 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1096 -4.8834 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1071 -3.9012 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.4000 -3.1941 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-09032411492D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 6.9387 -4.8812 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9400 -4.8812 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4394 -4.0163 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4394 -3.0163 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-09032411492D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 15.0894 -3.3537 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5898 -4.8938 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.8990 -3.9476 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5890 -4.8938 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2797 -3.9476 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.0894 -2.3537 0.0000 S 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-09032411492D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 17.6887 -4.6312 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.6900 -4.6312 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.1894 -3.7663 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.4482 -2.8004 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-09032411492D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 21.4966 -4.7213 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.4929 -3.7262 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.4846 -4.7084 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.4821 -3.7262 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.2000 -3.0191 0.0000 N 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 +M END + +$RFMT +$RXN + + -INDIGO- 0903241151 + + 2 2 +$MOL + + -INDIGO-09032411512D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 4.9844 -5.1799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4848 -6.7200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7940 -5.7738 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4840 -6.7200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1747 -5.7738 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-09032411512D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 7.7442 -5.3751 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4745 -5.3746 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6110 -4.8750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4745 -6.3755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7442 -6.3800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6132 -6.8750 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-09032411512D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 16.2665 -6.3225 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.2628 -5.3274 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.2546 -6.3096 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.2521 -5.3274 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.2288 -5.0686 0.0000 P 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 +M END +$MOL + + -INDIGO-09032411512D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 19.7433 -5.3250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.7433 -6.3250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.6093 -6.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.4753 -6.3250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.4753 -5.3250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.6093 -4.8250 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 + +$RFMT +$RXN + + -INDIGO- 0903241152 + + 5 1 +$MOL + + -INDIGO-09032411522D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 2.3905 -7.2966 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3917 -7.2966 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8912 -6.4316 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1500 -5.4657 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-09032411522D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 6.3501 -5.7811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3501 -6.7811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2161 -7.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0821 -6.7811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0821 -5.7811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2161 -5.2811 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-09032411522D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 11.2466 -6.8822 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2429 -5.8871 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2347 -6.8693 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.2322 -5.8871 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.9500 -5.1800 0.0000 N 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 +M END +$MOL + + -INDIGO-09032411522D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 14.7162 -5.7111 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.2166 -7.2512 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5258 -6.3049 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2158 -7.2512 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9064 -6.3049 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7162 -4.7111 0.0000 S 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-09032411522D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 18.5922 -6.8581 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.5885 -5.8630 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.5803 -6.8452 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.5778 -5.8630 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.5544 -5.6042 0.0000 P 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 +M END +$MOL + + -INDIGO-09032411522D + + 12 12 0 0 1 0 0 0 0 0999 V2000 + 30.0095 -4.9233 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 30.0095 -6.7984 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 28.1901 -7.7389 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 26.3706 -6.7985 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 28.1845 -4.9233 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 25.5727 -5.5176 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 29.0997 -5.3824 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 29.0997 -6.3338 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 28.1845 -6.7985 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 27.2749 -6.3340 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 27.2749 -5.3825 0.0000 C 0 0 1 0 0 0 0 0 0 0 0 0 + 26.3706 -4.9235 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6 12 1 0 0 0 0 + 11 5 1 0 0 0 0 + 5 7 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 9 1 0 0 0 0 + 9 10 1 0 0 0 0 + 10 11 1 0 0 0 0 + 11 12 1 1 0 0 0 + 7 1 1 6 0 0 0 + 8 2 1 6 0 0 0 + 9 3 1 6 0 0 0 + 10 4 1 6 0 0 0 +M END diff --git a/api/tests/integration/tests/reaction/reactions/pathway9.rdf b/api/tests/integration/tests/reaction/reactions/pathway9.rdf new file mode 100644 index 0000000000..6cf53496b3 --- /dev/null +++ b/api/tests/integration/tests/reaction/reactions/pathway9.rdf @@ -0,0 +1,1033 @@ +$RDFILE 1 +$RFMT +$RXN + + -INDIGO- 0815241543 + + 2 1 +$MOL + + -INDIGO-08152415432D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + -4.5193 -13.1239 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -4.0225 -14.6528 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7155 -13.7135 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.0160 -14.6528 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.3232 -13.7135 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-08152415432D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 0.7963 -13.6682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7963 -14.6682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6623 -15.1682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5283 -14.6682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5283 -13.6682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6623 -13.1681 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-08152415432D + + 59 73 0 0 0 0 0 0 0 0999 V2000 + 12.0621 -16.2835 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1344 -17.8231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6538 -17.0741 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0233 -17.7813 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.9510 -16.2417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.4316 -16.9906 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.3454 -17.4865 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.1464 -15.9580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.8047 -16.7797 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0290 -15.8433 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.2278 -17.3717 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.5695 -16.5501 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7595 -15.6650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1720 -16.2822 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6440 -15.5658 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8156 -17.0976 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4032 -16.4804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9313 -17.1968 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6604 -14.7806 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9011 -13.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5448 -14.6815 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3730 -13.1496 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1323 -14.0643 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4887 -13.2488 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6302 -11.4498 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3895 -12.3645 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2739 -12.2653 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8615 -11.6481 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1020 -10.7336 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2177 -10.8327 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.6851 -14.8933 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.1464 -14.8034 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.9418 -14.4042 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.0945 -15.6918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.6333 -15.7817 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.8379 -16.1809 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.0039 -13.5188 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.5426 -13.6089 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.7471 -14.0081 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.5945 -12.7205 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.0558 -12.6305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.8511 -12.2312 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9131 -11.3460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.4519 -11.4359 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.6565 -11.8351 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.5037 -10.5475 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9651 -10.4576 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.7604 -10.0584 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9321 -10.3957 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2808 -9.6496 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3911 -9.6333 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7116 -10.4282 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3630 -11.1744 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.2527 -11.1906 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.1623 -10.2076 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5834 -11.5847 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.8730 -10.7431 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.6936 -11.5692 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4333 -10.7182 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 + 9 7 2 0 0 0 0 + 7 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 8 2 0 0 0 0 + 8 9 1 0 0 0 0 + 6 9 1 0 0 0 0 + 15 13 2 0 0 0 0 + 13 17 1 0 0 0 0 + 17 18 2 0 0 0 0 + 18 16 1 0 0 0 0 + 16 14 2 0 0 0 0 + 14 15 1 0 0 0 0 + 14 3 1 0 0 0 0 + 21 19 2 0 0 0 0 + 19 23 1 0 0 0 0 + 23 24 2 0 0 0 0 + 24 22 1 0 0 0 0 + 22 20 2 0 0 0 0 + 20 21 1 0 0 0 0 + 19 13 1 0 0 0 0 + 21 15 1 0 0 0 0 + 27 25 2 0 0 0 0 + 25 29 1 0 0 0 0 + 29 30 2 0 0 0 0 + 30 28 1 0 0 0 0 + 28 26 2 0 0 0 0 + 26 27 1 0 0 0 0 + 22 27 1 0 0 0 0 + 24 26 1 0 0 0 0 + 33 31 2 0 0 0 0 + 31 35 1 0 0 0 0 + 35 36 2 0 0 0 0 + 36 34 1 0 0 0 0 + 34 32 2 0 0 0 0 + 32 33 1 0 0 0 0 + 12 34 1 0 0 0 0 + 39 37 2 0 0 0 0 + 37 41 1 0 0 0 0 + 41 42 2 0 0 0 0 + 42 40 1 0 0 0 0 + 40 38 2 0 0 0 0 + 38 39 1 0 0 0 0 + 45 43 2 0 0 0 0 + 43 47 1 0 0 0 0 + 47 48 2 0 0 0 0 + 48 46 1 0 0 0 0 + 46 44 2 0 0 0 0 + 44 45 1 0 0 0 0 + 39 32 1 0 0 0 0 + 38 33 1 0 0 0 0 + 45 41 1 0 0 0 0 + 44 42 1 0 0 0 0 + 51 49 2 0 0 0 0 + 49 53 1 0 0 0 0 + 53 54 2 0 0 0 0 + 54 52 1 0 0 0 0 + 52 50 2 0 0 0 0 + 50 51 1 0 0 0 0 + 25 49 1 0 0 0 0 + 55 59 1 0 0 0 0 + 59 58 2 0 0 0 0 + 58 56 1 0 0 0 0 + 56 57 2 0 0 0 0 + 57 55 1 0 0 0 0 + 52 59 1 0 0 0 0 + 57 47 1 0 0 0 0 +M END + +$RFMT +$RXN + + -INDIGO- 0815241429 + + 1 1 +$MOL + + -INDIGO-08152414292D + + 60 74 0 0 0 0 0 0 0 0999 V2000 + 6.4407 -7.8862 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5060 -9.3686 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0455 -8.6463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3618 -9.3309 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2965 -7.8486 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7571 -8.5709 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6470 -9.0546 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4727 -7.5812 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1345 -8.3682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3234 -7.4805 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4977 -8.9540 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8359 -8.1670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2575 -7.2204 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6224 -7.8025 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1080 -7.1174 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2863 -8.5904 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.9216 -8.0083 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4359 -8.6934 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1547 -6.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3411 -5.4791 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0050 -6.2670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8268 -4.7940 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6403 -5.6849 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.9763 -4.8970 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0599 -3.1557 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8733 -4.0466 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.7238 -3.9436 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.3590 -3.3615 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5455 -2.4706 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6951 -2.5736 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.0042 -6.6239 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.6596 -5.9968 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5129 -5.9222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2975 -6.7732 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.6422 -7.4003 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7889 -7.4749 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0936 -4.4417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.4383 -5.0688 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5849 -5.1434 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.8003 -4.2925 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4556 -3.6654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3090 -3.5907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8897 -2.1103 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.2344 -2.7373 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.3809 -2.8120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5964 -1.9609 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2517 -1.3339 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.1051 -1.2592 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3893 -1.7422 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5266 -0.7893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6829 -0.9375 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0768 -1.4459 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9394 -2.3989 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7831 -2.2508 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8933 -0.4140 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2095 -1.0988 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7490 -0.3764 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8142 -1.8588 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4980 -1.1740 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9584 -1.8964 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 + 9 7 2 0 0 0 0 + 7 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 8 2 0 0 0 0 + 8 9 1 0 0 0 0 + 6 9 1 0 0 0 0 + 15 13 2 0 0 0 0 + 13 17 1 0 0 0 0 + 17 18 2 0 0 0 0 + 18 16 1 0 0 0 0 + 16 14 2 0 0 0 0 + 14 15 1 0 0 0 0 + 14 3 1 0 0 0 0 + 21 19 2 0 0 0 0 + 19 23 1 0 0 0 0 + 23 24 2 0 0 0 0 + 24 22 1 0 0 0 0 + 22 20 2 0 0 0 0 + 20 21 1 0 0 0 0 + 19 13 1 0 0 0 0 + 21 15 1 0 0 0 0 + 27 25 2 0 0 0 0 + 25 29 1 0 0 0 0 + 29 30 2 0 0 0 0 + 30 28 1 0 0 0 0 + 28 26 2 0 0 0 0 + 26 27 1 0 0 0 0 + 22 27 1 0 0 0 0 + 24 26 1 0 0 0 0 + 33 31 2 0 0 0 0 + 31 35 1 0 0 0 0 + 35 36 2 0 0 0 0 + 36 34 1 0 0 0 0 + 34 32 2 0 0 0 0 + 32 33 1 0 0 0 0 + 12 34 1 0 0 0 0 + 39 37 2 0 0 0 0 + 37 41 1 0 0 0 0 + 41 42 2 0 0 0 0 + 42 40 1 0 0 0 0 + 40 38 2 0 0 0 0 + 38 39 1 0 0 0 0 + 45 43 2 0 0 0 0 + 43 47 1 0 0 0 0 + 47 48 2 0 0 0 0 + 48 46 1 0 0 0 0 + 46 44 2 0 0 0 0 + 44 45 1 0 0 0 0 + 39 32 1 0 0 0 0 + 38 33 1 0 0 0 0 + 45 41 1 0 0 0 0 + 44 42 1 0 0 0 0 + 51 49 2 0 0 0 0 + 49 53 1 0 0 0 0 + 53 54 2 0 0 0 0 + 54 52 1 0 0 0 0 + 52 50 2 0 0 0 0 + 50 51 1 0 0 0 0 + 57 55 2 0 0 0 0 + 55 59 1 0 0 0 0 + 59 60 2 0 0 0 0 + 60 58 1 0 0 0 0 + 58 56 2 0 0 0 0 + 56 57 1 0 0 0 0 + 25 49 1 0 0 0 0 + 52 59 1 0 0 0 0 + 56 43 1 0 0 0 0 +M END +$MOL + + -INDIGO-08152414292D + + 3 3 0 0 0 0 0 0 0 0999 V2000 + 28.4740 -4.4843 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.0258 -5.2607 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.9222 -5.2607 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 + +$RFMT +$RXN + + -INDIGO- 0815241430 + + 1 1 +$MOL + + -INDIGO-08152414302D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + -6.6085 -5.1777 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -4.8782 -5.1772 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.7418 -4.6776 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -4.8782 -6.1781 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -6.6085 -6.1826 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.7396 -6.6776 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-08152414302D + + 60 74 0 0 0 0 0 0 0 0999 V2000 + 6.4407 -7.8862 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5060 -9.3686 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.0455 -8.6463 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3618 -9.3309 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2965 -7.8486 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7571 -8.5709 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.6470 -9.0546 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4727 -7.5812 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1345 -8.3682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.3234 -7.4805 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4977 -8.9540 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8359 -8.1670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2575 -7.2204 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6224 -7.8025 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1080 -7.1174 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2863 -8.5904 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.9216 -8.0083 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4359 -8.6934 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1547 -6.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3411 -5.4791 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0050 -6.2670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8268 -4.7940 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6403 -5.6849 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.9763 -4.8970 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0599 -3.1557 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8733 -4.0466 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.7238 -3.9436 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.3590 -3.3615 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5455 -2.4706 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6951 -2.5736 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.0042 -6.6239 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.6596 -5.9968 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5129 -5.9222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2975 -6.7732 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.6422 -7.4003 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7889 -7.4749 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.0936 -4.4417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.4383 -5.0688 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.5849 -5.1434 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.8003 -4.2925 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4556 -3.6654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3090 -3.5907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.8897 -2.1103 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.2344 -2.7373 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.3809 -2.8120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.5964 -1.9609 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2517 -1.3339 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.1051 -1.2592 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3893 -1.7422 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5266 -0.7893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6829 -0.9375 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0768 -1.4459 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9394 -2.3989 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7831 -2.2508 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8933 -0.4140 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2095 -1.0988 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7490 -0.3764 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8142 -1.8588 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.4980 -1.1740 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9584 -1.8964 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 + 9 7 2 0 0 0 0 + 7 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 8 2 0 0 0 0 + 8 9 1 0 0 0 0 + 6 9 1 0 0 0 0 + 15 13 2 0 0 0 0 + 13 17 1 0 0 0 0 + 17 18 2 0 0 0 0 + 18 16 1 0 0 0 0 + 16 14 2 0 0 0 0 + 14 15 1 0 0 0 0 + 14 3 1 0 0 0 0 + 21 19 2 0 0 0 0 + 19 23 1 0 0 0 0 + 23 24 2 0 0 0 0 + 24 22 1 0 0 0 0 + 22 20 2 0 0 0 0 + 20 21 1 0 0 0 0 + 19 13 1 0 0 0 0 + 21 15 1 0 0 0 0 + 27 25 2 0 0 0 0 + 25 29 1 0 0 0 0 + 29 30 2 0 0 0 0 + 30 28 1 0 0 0 0 + 28 26 2 0 0 0 0 + 26 27 1 0 0 0 0 + 22 27 1 0 0 0 0 + 24 26 1 0 0 0 0 + 33 31 2 0 0 0 0 + 31 35 1 0 0 0 0 + 35 36 2 0 0 0 0 + 36 34 1 0 0 0 0 + 34 32 2 0 0 0 0 + 32 33 1 0 0 0 0 + 12 34 1 0 0 0 0 + 39 37 2 0 0 0 0 + 37 41 1 0 0 0 0 + 41 42 2 0 0 0 0 + 42 40 1 0 0 0 0 + 40 38 2 0 0 0 0 + 38 39 1 0 0 0 0 + 45 43 2 0 0 0 0 + 43 47 1 0 0 0 0 + 47 48 2 0 0 0 0 + 48 46 1 0 0 0 0 + 46 44 2 0 0 0 0 + 44 45 1 0 0 0 0 + 39 32 1 0 0 0 0 + 38 33 1 0 0 0 0 + 45 41 1 0 0 0 0 + 44 42 1 0 0 0 0 + 51 49 2 0 0 0 0 + 49 53 1 0 0 0 0 + 53 54 2 0 0 0 0 + 54 52 1 0 0 0 0 + 52 50 2 0 0 0 0 + 50 51 1 0 0 0 0 + 57 55 2 0 0 0 0 + 55 59 1 0 0 0 0 + 59 60 2 0 0 0 0 + 60 58 1 0 0 0 0 + 58 56 2 0 0 0 0 + 56 57 1 0 0 0 0 + 25 49 1 0 0 0 0 + 52 59 1 0 0 0 0 + 56 43 1 0 0 0 0 +M END + +$RFMT +$RXN + + -INDIGO- 0815241431 + + 1 1 +$MOL + + -INDIGO-08152414312D + + 59 73 0 0 0 0 0 0 0 0999 V2000 + 21.7184 -17.9101 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7912 -19.4610 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.3071 -18.7065 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6866 -19.4189 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6138 -17.8680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0979 -18.6224 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.0329 -19.1219 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.8325 -17.5823 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.4883 -18.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.7215 -17.4667 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.9218 -19.0063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.2660 -18.1787 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.3844 -17.2871 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.8072 -17.9088 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.2753 -17.1872 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.4482 -18.7302 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0255 -18.1085 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.5574 -18.8301 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.2845 -16.3963 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.5343 -15.4750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.1754 -16.2964 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.0023 -14.7534 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.7526 -15.6747 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.1116 -14.8533 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.2614 -13.0412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0117 -13.9625 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9025 -13.8626 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.4798 -13.2409 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.7294 -12.3197 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.8386 -12.4196 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.4116 -16.5098 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.8617 -16.4192 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.6629 -16.0171 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.8094 -17.3141 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.3594 -17.4047 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.5582 -17.8068 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.7108 -15.1253 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.2608 -15.2160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.4595 -15.6181 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.3130 -14.3211 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.7631 -14.2305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.5642 -13.8283 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6121 -12.9366 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.1621 -13.0272 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.3609 -13.4293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.2143 -12.1323 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6644 -12.0417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.4656 -11.6396 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.5801 -11.9794 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.9387 -11.2278 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.0425 -11.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.3726 -12.0121 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.0142 -12.7638 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.9104 -12.7801 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.8412 -11.7899 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.2654 -13.1770 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.5571 -12.3293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3691 -13.1614 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.1069 -12.3042 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 + 9 7 2 0 0 0 0 + 7 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 8 2 0 0 0 0 + 8 9 1 0 0 0 0 + 6 9 1 0 0 0 0 + 15 13 2 0 0 0 0 + 13 17 1 0 0 0 0 + 17 18 2 0 0 0 0 + 18 16 1 0 0 0 0 + 16 14 2 0 0 0 0 + 14 15 1 0 0 0 0 + 14 3 1 0 0 0 0 + 21 19 2 0 0 0 0 + 19 23 1 0 0 0 0 + 23 24 2 0 0 0 0 + 24 22 1 0 0 0 0 + 22 20 2 0 0 0 0 + 20 21 1 0 0 0 0 + 19 13 1 0 0 0 0 + 21 15 1 0 0 0 0 + 27 25 2 0 0 0 0 + 25 29 1 0 0 0 0 + 29 30 2 0 0 0 0 + 30 28 1 0 0 0 0 + 28 26 2 0 0 0 0 + 26 27 1 0 0 0 0 + 22 27 1 0 0 0 0 + 24 26 1 0 0 0 0 + 33 31 2 0 0 0 0 + 31 35 1 0 0 0 0 + 35 36 2 0 0 0 0 + 36 34 1 0 0 0 0 + 34 32 2 0 0 0 0 + 32 33 1 0 0 0 0 + 12 34 1 0 0 0 0 + 39 37 2 0 0 0 0 + 37 41 1 0 0 0 0 + 41 42 2 0 0 0 0 + 42 40 1 0 0 0 0 + 40 38 2 0 0 0 0 + 38 39 1 0 0 0 0 + 45 43 2 0 0 0 0 + 43 47 1 0 0 0 0 + 47 48 2 0 0 0 0 + 48 46 1 0 0 0 0 + 46 44 2 0 0 0 0 + 44 45 1 0 0 0 0 + 39 32 1 0 0 0 0 + 38 33 1 0 0 0 0 + 45 41 1 0 0 0 0 + 44 42 1 0 0 0 0 + 51 49 2 0 0 0 0 + 49 53 1 0 0 0 0 + 53 54 2 0 0 0 0 + 54 52 1 0 0 0 0 + 52 50 2 0 0 0 0 + 50 51 1 0 0 0 0 + 25 49 1 0 0 0 0 + 55 59 1 0 0 0 0 + 59 58 2 0 0 0 0 + 58 56 1 0 0 0 0 + 56 57 2 0 0 0 0 + 57 55 1 0 0 0 0 + 52 59 1 0 0 0 0 + 57 47 1 0 0 0 0 +M END +$MOL + + -INDIGO-08152414312D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 39.0563 -15.0431 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 39.0526 -14.0480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 38.0443 -15.0302 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 38.0419 -14.0480 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 +M END + +$RFMT +$RXN + + -INDIGO- 0815241431 + + 1 1 +$MOL + + -INDIGO-08152414312D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 9.5868 -14.6717 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0872 -16.2118 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.3965 -15.2656 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0865 -16.2118 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7771 -15.2656 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-08152414312D + + 59 73 0 0 0 0 0 0 0 0999 V2000 + 21.7184 -17.9101 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.7912 -19.4610 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.3071 -18.7065 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6866 -19.4189 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6138 -17.8680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0979 -18.6224 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.0329 -19.1219 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.8325 -17.5823 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.4883 -18.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.7215 -17.4667 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.9218 -19.0063 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.2660 -18.1787 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.3844 -17.2871 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.8072 -17.9088 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.2753 -17.1872 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.4482 -18.7302 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0255 -18.1085 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.5574 -18.8301 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.2845 -16.3963 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.5343 -15.4750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.1754 -16.2964 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.0023 -14.7534 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.7526 -15.6747 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.1116 -14.8533 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.2614 -13.0412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.0117 -13.9625 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.9025 -13.8626 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.4798 -13.2409 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 17.7294 -12.3197 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 16.8386 -12.4196 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.4116 -16.5098 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.8617 -16.4192 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.6629 -16.0171 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.8094 -17.3141 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.3594 -17.4047 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.5582 -17.8068 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.7108 -15.1253 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.2608 -15.2160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.4595 -15.6181 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.3130 -14.3211 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.7631 -14.2305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.5642 -13.8283 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6121 -12.9366 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.1621 -13.0272 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.3609 -13.4293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.2143 -12.1323 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6644 -12.0417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.4656 -11.6396 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.5801 -11.9794 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.9387 -11.2278 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.0425 -11.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.3726 -12.0121 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.0142 -12.7638 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.9104 -12.7801 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.8412 -11.7899 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.2654 -13.1770 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.5571 -12.3293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.3691 -13.1614 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.1069 -12.3042 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 + 9 7 2 0 0 0 0 + 7 11 1 0 0 0 0 + 11 12 2 0 0 0 0 + 12 10 1 0 0 0 0 + 10 8 2 0 0 0 0 + 8 9 1 0 0 0 0 + 6 9 1 0 0 0 0 + 15 13 2 0 0 0 0 + 13 17 1 0 0 0 0 + 17 18 2 0 0 0 0 + 18 16 1 0 0 0 0 + 16 14 2 0 0 0 0 + 14 15 1 0 0 0 0 + 14 3 1 0 0 0 0 + 21 19 2 0 0 0 0 + 19 23 1 0 0 0 0 + 23 24 2 0 0 0 0 + 24 22 1 0 0 0 0 + 22 20 2 0 0 0 0 + 20 21 1 0 0 0 0 + 19 13 1 0 0 0 0 + 21 15 1 0 0 0 0 + 27 25 2 0 0 0 0 + 25 29 1 0 0 0 0 + 29 30 2 0 0 0 0 + 30 28 1 0 0 0 0 + 28 26 2 0 0 0 0 + 26 27 1 0 0 0 0 + 22 27 1 0 0 0 0 + 24 26 1 0 0 0 0 + 33 31 2 0 0 0 0 + 31 35 1 0 0 0 0 + 35 36 2 0 0 0 0 + 36 34 1 0 0 0 0 + 34 32 2 0 0 0 0 + 32 33 1 0 0 0 0 + 12 34 1 0 0 0 0 + 39 37 2 0 0 0 0 + 37 41 1 0 0 0 0 + 41 42 2 0 0 0 0 + 42 40 1 0 0 0 0 + 40 38 2 0 0 0 0 + 38 39 1 0 0 0 0 + 45 43 2 0 0 0 0 + 43 47 1 0 0 0 0 + 47 48 2 0 0 0 0 + 48 46 1 0 0 0 0 + 46 44 2 0 0 0 0 + 44 45 1 0 0 0 0 + 39 32 1 0 0 0 0 + 38 33 1 0 0 0 0 + 45 41 1 0 0 0 0 + 44 42 1 0 0 0 0 + 51 49 2 0 0 0 0 + 49 53 1 0 0 0 0 + 53 54 2 0 0 0 0 + 54 52 1 0 0 0 0 + 52 50 2 0 0 0 0 + 50 51 1 0 0 0 0 + 25 49 1 0 0 0 0 + 55 59 1 0 0 0 0 + 59 58 2 0 0 0 0 + 58 56 1 0 0 0 0 + 56 57 2 0 0 0 0 + 57 55 1 0 0 0 0 + 52 59 1 0 0 0 0 + 57 47 1 0 0 0 0 +M END + +$RFMT +$RXN + + -INDIGO- 0815241432 + + 2 1 +$MOL + + -INDIGO-08152414322D + + 3 3 0 0 0 0 0 0 0 0999 V2000 + 2.5767 -10.9214 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5780 -10.9214 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0774 -10.0564 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-08152414322D + + 4 4 0 0 0 0 0 0 0 0999 V2000 + 7.1695 -11.1280 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1658 -10.1329 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1576 -11.1151 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1551 -10.1329 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 +M END +$MOL + + -INDIGO-08152414322D + + 8 8 0 0 0 0 0 0 0 0999 V2000 + 10.4084 -11.1788 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.4086 -10.1763 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1138 -9.4711 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1140 -11.8842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1164 -11.8842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8218 -11.1788 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.8217 -10.1763 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1164 -9.4710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 1 1 0 0 0 0 + 1 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 6 1 0 0 0 0 + 6 7 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 3 1 0 0 0 0 + 3 2 1 0 0 0 0 +M END + +$RFMT +$RXN + + -INDIGO- 0808240900 + + 2 1 +$MOL + + -INDIGO-08082409002D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + 0.0560 -6.4789 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7863 -6.4784 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9228 -5.9788 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7863 -7.4794 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0560 -7.4839 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9250 -7.9789 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-08082409002D + + 5 5 0 0 0 0 0 0 0 0999 V2000 + 6.2577 -6.2569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7581 -7.7970 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0674 -6.8507 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7574 -7.7970 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4480 -6.8507 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-08082409002D + + 7 7 0 0 0 0 0 0 0 0999 V2000 + 12.1705 -6.6231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.1705 -7.6231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0365 -8.1231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9026 -7.6231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.9026 -6.6231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.0365 -6.1231 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.7686 -6.1231 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 + 5 7 1 0 0 0 0 +M END + +$RFMT +$RXN + + -INDIGO- 0809241137 + + 3 1 +$MOL + + -INDIGO-08092411372D + + 7 7 0 0 0 0 0 0 0 0999 V2000 + 11.6489 -9.0554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.6489 -10.0554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5149 -10.5554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3810 -10.0554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.3810 -9.0554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.5149 -8.5554 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.2470 -8.5554 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 + 5 7 1 0 0 0 0 +M END +$MOL + + -INDIGO-08092411372D + + 7 7 0 0 0 0 0 0 0 0999 V2000 + 19.5343 -8.8815 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.0347 -10.4216 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.3439 -9.4753 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.0339 -10.4216 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 18.7246 -9.4753 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 19.5343 -7.8815 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.5343 -7.8815 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 2 0 0 0 0 + 6 7 1 0 0 0 0 +M END +$MOL + + -INDIGO-08092411372D + + 8 8 0 0 0 0 0 0 0 0999 V2000 + 5.9649 -9.1617 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7488 -8.5442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7218 -8.7667 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1559 -9.6625 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9704 -10.1689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7225 -10.5696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7488 -10.7921 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9990 -8.9029 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 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 + 1 8 1 0 0 0 0 +M END +$MOL + + -INDIGO-08092411372D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + 26.4095 -9.2478 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.1398 -9.2473 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.2763 -8.7477 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.1398 -10.2482 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.4095 -10.2527 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.2785 -10.7477 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.5435 -10.7527 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.5714 -11.4548 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.8469 -10.9553 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 + 5 7 1 0 0 0 0 + 6 8 2 0 0 0 0 + 4 9 1 0 0 0 0 +M END + diff --git a/api/tests/integration/tests/reaction/ref/pathway1.ket b/api/tests/integration/tests/reaction/ref/pathway1.ket index 2a432df444..e8c29d5172 100644 --- a/api/tests/integration/tests/reaction/ref/pathway1.ket +++ b/api/tests/integration/tests/reaction/ref/pathway1.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-2.651700019836426,"y":0.0,"z":0.0}},"spine":{"pos":[{"x":-5.151700019836426,"y":5.217075347900391,"z":0.0},{"x":-5.151700019836426,"y":-5.217075347900391,"z":0.0}]},"tails":{"pos":[{"x":-5.651700019836426,"y":5.217075347900391,"z":0.0},{"x":-5.651700019836426,"y":-0.8230750560760498,"z":0.0},{"x":-5.651700019836426,"y":-5.217075347900391,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-10.808600425720215,"y":5.217075347900391,"z":0.0}},"spine":{"pos":[{"x":-13.308600425720215,"y":7.10212516784668,"z":0.0},{"x":-13.308600425720215,"y":3.3320252895355226,"z":0.0}]},"tails":{"pos":[{"x":-13.808600425720215,"y":7.10212516784668,"z":0.0},{"x":-13.808600425720215,"y":3.3320252895355226,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-16.53890037536621,7.60207462310791,0.0]},{"label":"C","location":[-14.808600425720215,7.602574348449707,0.0]},{"label":"C","location":[-15.672100067138672,8.102174758911133,0.0]},{"label":"C","location":[-14.808600425720215,6.601574420928955,0.0]},{"label":"C","location":[-16.53890037536621,6.597074508666992,0.0]},{"label":"C","location":[-15.669899940490723,6.10207462310791,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-15.673749923706055,4.102075576782227,0.0]},{"label":"C","location":[-15.173349380493164,2.5619754791259767,0.0]},{"label":"C","location":[-14.864049911499024,3.5082755088806154,0.0]},{"label":"C","location":[-16.174049377441408,2.5619754791259767,0.0]},{"label":"C","location":[-16.483449935913087,3.5082755088806154,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-9.529200553894043,5.717075347900391,0.0]},{"label":"C","location":[-9.529200553894043,4.717075347900391,0.0]},{"label":"C","location":[-8.663200378417969,4.217075347900391,0.0]},{"label":"C","location":[-7.797101020812988,4.717075347900391,0.0]},{"label":"C","location":[-7.797101020812988,5.717075347900391,0.0]},{"label":"C","location":[-8.663200378417969,6.217075347900391,0.0]},{"label":"C","location":[-6.931100845336914,6.217075347900391,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-8.325300216674805,-0.5530252456665039,0.0]},{"label":"C","location":[-7.824899673461914,-2.093125343322754,0.0]},{"label":"C","location":[-7.51569938659668,-1.146824836730957,0.0]},{"label":"C","location":[-8.825700759887696,-2.093125343322754,0.0]},{"label":"C","location":[-9.135000228881836,-1.146824836730957,0.0]},{"label":"C","location":[-8.325300216674805,0.4469752311706543,0.0]},{"label":"C","location":[-7.325300216674805,0.4469752311706543,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[-8.842700004577637,-4.710625648498535,0.0]},{"label":"C","location":[-8.058799743652344,-4.093125343322754,0.0]},{"label":"C","location":[-7.0858001708984379,-4.315625190734863,0.0]},{"label":"C","location":[-6.651700019836426,-5.21142578125,0.0]},{"label":"C","location":[-8.837200164794922,-5.717824935913086,0.0]},{"label":"C","location":[-7.085100173950195,-6.118525505065918,0.0]},{"label":"C","location":[-8.058799743652344,-6.341025352478027,0.0]},{"label":"C","location":[-9.808599472045899,-4.451825141906738,0.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]},{"type":1,"atoms":[0,7]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[-0.7857017517089844,0.853449821472168,0.0]},{"label":"C","location":[0.9445972442626953,0.8539495468139648,0.0]},{"label":"C","location":[0.08109855651855469,1.3535499572753907,0.0]},{"label":"C","location":[0.9445972442626953,-0.14695072174072267,0.0]},{"label":"C","location":[-0.7857017517089844,-0.15145015716552735,0.0]},{"label":"C","location":[0.0832977294921875,-0.6464500427246094,0.0]},{"label":"C","location":[-1.6517009735107422,-0.6514501571655273,0.0]},{"label":"C","location":[-0.6238021850585938,-1.3535499572753907,0.0]},{"label":"C","location":[1.6516990661621094,-0.8540506362915039,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":10.887200355529786,"y":6.029025077819824,"z":0.0}},"spine":{"pos":[{"x":9.887200355529786,"y":10.788000106811524,"z":0.0},{"x":9.887200355529786,"y":1.2700501680374146,"z":0.0}]},"tails":{"pos":[{"x":9.387200355529786,"y":10.788000106811524,"z":0.0},{"x":9.387200355529786,"y":6.164050102233887,"z":0.0},{"x":9.387200355529786,"y":1.2700501680374146,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.789100646972656,"y":10.788000106811524,"z":0.0}},"spine":{"pos":[{"x":3.230299949645996,"y":12.923049926757813,"z":0.0},{"x":3.230299949645996,"y":8.652950286865235,"z":0.0}]},"tails":{"pos":[{"x":2.730299949645996,"y":12.923049926757813,"z":0.0},{"x":2.730299949645996,"y":8.652950286865235,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.0,9.152899742126465,0.0]},{"label":"C","location":[1.730299949645996,9.153399467468262,0.0]},{"label":"C","location":[0.8668000102043152,9.652999877929688,0.0]},{"label":"C","location":[1.730299949645996,8.152399063110352,0.0]},{"label":"C","location":[0.0,8.147899627685547,0.0]},{"label":"C","location":[0.8690000176429749,7.652899742126465,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.9205999374389648,13.693100929260254,0.0]},{"label":"C","location":[1.4210000038146973,12.153000831604004,0.0]},{"label":"C","location":[1.730299949645996,13.099300384521485,0.0]},{"label":"C","location":[0.4203000068664551,12.153000831604004,0.0]},{"label":"C","location":[0.1108999252319336,13.099300384521485,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[5.789100646972656,11.287999153137207,0.0]},{"label":"C","location":[5.789100646972656,10.287999153137207,0.0]},{"label":"C","location":[6.6551008224487309,9.787999153137207,0.0]},{"label":"C","location":[7.521200180053711,10.287999153137207,0.0]},{"label":"C","location":[7.521200180053711,11.287999153137207,0.0]},{"label":"C","location":[6.6551008224487309,11.787999153137207,0.0]},{"label":"C","location":[8.387200355529786,11.787999153137207,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[7.387200355529785,1.54010009765625,0.0]},{"label":"C","location":[7.887600898742676,0.0,0.0]},{"label":"C","location":[8.19680118560791,0.9463005065917969,0.0]},{"label":"C","location":[6.8867998123168949,0.0,0.0]},{"label":"C","location":[6.577500343322754,0.9463005065917969,0.0]},{"label":"C","location":[7.387200355529785,2.540100574493408,0.0]},{"label":"C","location":[8.387200355529786,2.540100574493408,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[6.196199893951416,6.670499801635742,0.0]},{"label":"C","location":[6.980099678039551,7.288000106811523,0.0]},{"label":"C","location":[7.953099727630615,7.065500259399414,0.0]},{"label":"C","location":[8.387199401855469,6.169699668884277,0.0]},{"label":"C","location":[6.201699733734131,5.663300514221191,0.0]},{"label":"C","location":[7.953799724578857,5.262599945068359,0.0]},{"label":"C","location":[6.980099678039551,5.04010009765625,0.0]},{"label":"C","location":[5.230299949645996,6.929300308227539,0.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]},{"type":1,"atoms":[0,7]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[12.753199577331543,6.882475852966309,0.0]},{"label":"C","location":[14.483498573303223,6.8829755783081059,0.0]},{"label":"C","location":[13.619999885559082,7.382575988769531,0.0]},{"label":"C","location":[14.483498573303223,5.882075309753418,0.0]},{"label":"C","location":[12.753199577331543,5.877575874328613,0.0]},{"label":"C","location":[13.622199058532715,5.382575988769531,0.0]},{"label":"C","location":[11.887200355529786,5.377575874328613,0.0]},{"label":"C","location":[12.915099143981934,4.67547607421875,0.0]},{"label":"C","location":[15.190600395202637,5.174975395202637,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway2.ket b/api/tests/integration/tests/reaction/ref/pathway2.ket index d66df3886b..1cf306faf8 100644 --- a/api/tests/integration/tests/reaction/ref/pathway2.ket +++ b/api/tests/integration/tests/reaction/ref/pathway2.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-2.651700019836426,"y":0.0,"z":0.0}},"spine":{"pos":[{"x":-5.151700019836426,"y":3.0200743675231935,"z":0.0},{"x":-5.151700019836426,"y":-3.020075559616089,"z":0.0}]},"tails":{"pos":[{"x":-5.651700019836426,"y":3.0200743675231935,"z":0.0},{"x":-5.651700019836426,"y":-3.020075559616089,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-10.249800682067871,"y":3.0200743675231935,"z":0.0}},"spine":{"pos":[{"x":-12.749800682067871,"y":4.905124664306641,"z":0.0},{"x":-12.749800682067871,"y":1.1350243091583253,"z":0.0}]},"tails":{"pos":[{"x":-13.249800682067871,"y":4.905124664306641,"z":0.0},{"x":-13.249800682067871,"y":1.1350243091583253,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-15.980100631713868,5.405074119567871,0.0]},{"label":"C","location":[-14.249800682067871,5.405573844909668,0.0]},{"label":"C","location":[-15.113300323486329,5.905174255371094,0.0]},{"label":"C","location":[-14.249800682067871,4.404573917388916,0.0]},{"label":"C","location":[-15.980100631713868,4.400074005126953,0.0]},{"label":"C","location":[-15.111100196838379,3.905074119567871,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-15.114950180053711,1.905074119567871,0.0]},{"label":"C","location":[-14.61454963684082,0.3649740219116211,0.0]},{"label":"C","location":[-14.30525016784668,1.3112740516662598,0.0]},{"label":"C","location":[-15.615249633789063,0.3649740219116211,0.0]},{"label":"C","location":[-15.924650192260743,1.3112740516662598,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-9.249799728393555,3.5200753211975099,0.0]},{"label":"C","location":[-9.249799728393555,2.5200753211975099,0.0]},{"label":"C","location":[-8.38379955291748,2.0200748443603517,0.0]},{"label":"C","location":[-7.517699241638184,2.5200753211975099,0.0]},{"label":"C","location":[-7.517699241638184,3.5200753211975099,0.0]},{"label":"C","location":[-8.38379955291748,4.02007532119751,0.0]},{"label":"C","location":[-6.651699066162109,4.02007532119751,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-8.045900344848633,-2.750025987625122,0.0]},{"label":"C","location":[-7.545499801635742,-4.290125846862793,0.0]},{"label":"C","location":[-7.236299514770508,-3.3438260555267336,0.0]},{"label":"C","location":[-8.54629898071289,-4.290125846862793,0.0]},{"label":"C","location":[-8.855600357055664,-3.3438260555267336,0.0]},{"label":"C","location":[-8.045900344848633,-1.750025987625122,0.0]},{"label":"C","location":[-7.045900344848633,-1.750025987625122,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[-0.7857017517089844,0.8534502983093262,0.0]},{"label":"C","location":[0.9445991516113281,0.853950023651123,0.0]},{"label":"C","location":[0.08109855651855469,1.3535499572753907,0.0]},{"label":"C","location":[0.9445991516113281,-0.14694976806640626,0.0]},{"label":"C","location":[-0.7857017517089844,-0.15145015716552735,0.0]},{"label":"C","location":[0.0832977294921875,-0.6464500427246094,0.0]},{"label":"C","location":[-1.6517009735107422,-0.6514501571655273,0.0]},{"label":"C","location":[-0.6238021850585938,-1.3535499572753907,0.0]},{"label":"C","location":[1.6516990661621094,-0.8540496826171875,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":10.328400611877442,"y":3.6550750732421877,"z":0.0}},"spine":{"pos":[{"x":9.328400611877442,"y":6.04010009765625,"z":0.0},{"x":9.328400611877442,"y":1.270049810409546,"z":0.0}]},"tails":{"pos":[{"x":8.828400611877442,"y":6.04010009765625,"z":0.0},{"x":8.828400611877442,"y":1.270049810409546,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.230299949645996,"y":6.04010009765625,"z":0.0}},"spine":{"pos":[{"x":3.230299949645996,"y":8.175149917602539,"z":0.0},{"x":3.230299949645996,"y":3.9050498008728029,"z":0.0}]},"tails":{"pos":[{"x":2.730299949645996,"y":8.175149917602539,"z":0.0},{"x":2.730299949645996,"y":3.9050498008728029,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.0,4.404999732971191,0.0]},{"label":"C","location":[1.730299949645996,4.405499458312988,0.0]},{"label":"C","location":[0.8668000102043152,4.905099868774414,0.0]},{"label":"C","location":[1.730299949645996,3.4044995307922365,0.0]},{"label":"C","location":[0.0,3.3999996185302736,0.0]},{"label":"C","location":[0.8690000176429749,2.9049997329711916,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.9205999374389648,8.945199966430664,0.0]},{"label":"C","location":[1.4210000038146973,7.405099868774414,0.0]},{"label":"C","location":[1.730299949645996,8.351400375366211,0.0]},{"label":"C","location":[0.4203000068664551,7.405099868774414,0.0]},{"label":"C","location":[0.1108999252319336,8.351400375366211,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[5.230299949645996,6.540100574493408,0.0]},{"label":"C","location":[5.230299949645996,5.540100574493408,0.0]},{"label":"C","location":[6.09630012512207,5.04010009765625,0.0]},{"label":"C","location":[6.962400436401367,5.540100574493408,0.0]},{"label":"C","location":[6.962400436401367,6.540100574493408,0.0]},{"label":"C","location":[6.09630012512207,7.040100574493408,0.0]},{"label":"C","location":[7.828400611877441,7.040100574493408,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[6.828400611877441,1.5400996208190919,0.0]},{"label":"C","location":[7.328801155090332,0.0,0.0]},{"label":"C","location":[7.638001441955566,0.9462995529174805,0.0]},{"label":"C","location":[6.328001976013184,0.0,0.0]},{"label":"C","location":[6.01870059967041,0.9462995529174805,0.0]},{"label":"C","location":[6.828400611877441,2.540099620819092,0.0]},{"label":"C","location":[7.828400611877441,2.540099620819092,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[12.1943998336792,4.508525371551514,0.0]},{"label":"C","location":[13.924700736999512,4.5090250968933109,0.0]},{"label":"C","location":[13.061200141906739,5.008625030517578,0.0]},{"label":"C","location":[13.924700736999512,3.5081253051757814,0.0]},{"label":"C","location":[12.1943998336792,3.50362491607666,0.0]},{"label":"C","location":[13.063399314880371,3.008625030517578,0.0]},{"label":"C","location":[11.328400611877442,3.00362491607666,0.0]},{"label":"C","location":[12.35629940032959,2.301525115966797,0.0]},{"label":"C","location":[14.631800651550293,2.801025390625,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway3.ket b/api/tests/integration/tests/reaction/ref/pathway3.ket index a207b28b66..4656d6271d 100644 --- a/api/tests/integration/tests/reaction/ref/pathway3.ket +++ b/api/tests/integration/tests/reaction/ref/pathway3.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-5.651700019836426,"y":2.384185791015625e-7,"z":0.0},{"x":-2.651700019836426,"y":0.0,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-10.249800682067871,"y":2.384185791015625e-7,"z":0.0}},"spine":{"pos":[{"x":-12.749800682067871,"y":1.8850502967834473,"z":0.0},{"x":-12.749800682067871,"y":-1.885049819946289,"z":0.0}]},"tails":{"pos":[{"x":-13.249800682067871,"y":1.8850502967834473,"z":0.0},{"x":-13.249800682067871,"y":-1.885049819946289,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-15.980100631713868,2.385000228881836,0.0]},{"label":"C","location":[-14.249800682067871,2.385499954223633,0.0]},{"label":"C","location":[-15.113300323486329,2.8851003646850588,0.0]},{"label":"C","location":[-14.249800682067871,1.3845000267028809,0.0]},{"label":"C","location":[-15.980100631713868,1.380000114440918,0.0]},{"label":"C","location":[-15.111100196838379,0.8850002288818359,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-15.114950180053711,-1.114999771118164,0.0]},{"label":"C","location":[-14.61454963684082,-2.655099868774414,0.0]},{"label":"C","location":[-14.30525016784668,-1.7087998390197755,0.0]},{"label":"C","location":[-15.615249633789063,-2.655099868774414,0.0]},{"label":"C","location":[-15.924650192260743,-1.7087998390197755,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-9.249799728393555,0.5000004768371582,0.0]},{"label":"C","location":[-9.249799728393555,-0.4999995231628418,0.0]},{"label":"C","location":[-8.38379955291748,-1.0,0.0]},{"label":"C","location":[-7.517699241638184,-0.4999995231628418,0.0]},{"label":"C","location":[-7.517699241638184,0.5000004768371582,0.0]},{"label":"C","location":[-8.38379955291748,1.0000004768371583,0.0]},{"label":"C","location":[-6.651699066162109,1.0000004768371583,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-0.7857017517089844,0.8534502983093262,0.0]},{"label":"C","location":[0.9445991516113281,0.853950023651123,0.0]},{"label":"C","location":[0.08109855651855469,1.3535499572753907,0.0]},{"label":"C","location":[0.9445991516113281,-0.14694976806640626,0.0]},{"label":"C","location":[-0.7857017517089844,-0.15145015716552735,0.0]},{"label":"C","location":[0.0832977294921875,-0.6464500427246094,0.0]},{"label":"C","location":[-1.6517009735107422,-0.6514501571655273,0.0]},{"label":"C","location":[-0.6238021850585938,-1.3535499572753907,0.0]},{"label":"C","location":[1.6516990661621094,-0.8540496826171875,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.828400611877442,"y":3.1351001262664797,"z":0.0},{"x":10.328400611877442,"y":3.1351003646850588,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.230299949645996,"y":3.1351001262664797,"z":0.0}},"spine":{"pos":[{"x":3.230299949645996,"y":5.270150184631348,"z":0.0},{"x":3.230299949645996,"y":1.0000500679016114,"z":0.0}]},"tails":{"pos":[{"x":2.730299949645996,"y":5.270150184631348,"z":0.0},{"x":2.730299949645996,"y":1.0000500679016114,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.0,1.5,0.0]},{"label":"C","location":[1.730299949645996,1.5004997253417969,0.0]},{"label":"C","location":[0.8668000102043152,2.0001001358032228,0.0]},{"label":"C","location":[1.730299949645996,0.4994997978210449,0.0]},{"label":"C","location":[0.0,0.49499988555908205,0.0]},{"label":"C","location":[0.8690000176429749,0.0,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.9205999374389648,6.040200233459473,0.0]},{"label":"C","location":[1.4210000038146973,4.500100135803223,0.0]},{"label":"C","location":[1.730299949645996,5.446400165557861,0.0]},{"label":"C","location":[0.4203000068664551,4.500100135803223,0.0]},{"label":"C","location":[0.1108999252319336,5.446400165557861,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[5.230299949645996,3.6350998878479006,0.0]},{"label":"C","location":[5.230299949645996,2.6350998878479006,0.0]},{"label":"C","location":[6.09630012512207,2.135099411010742,0.0]},{"label":"C","location":[6.962400436401367,2.6350998878479006,0.0]},{"label":"C","location":[6.962400436401367,3.6350998878479006,0.0]},{"label":"C","location":[6.09630012512207,4.1350998878479,0.0]},{"label":"C","location":[7.828400611877441,4.1350998878479,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[12.1943998336792,3.9885506629943849,0.0]},{"label":"C","location":[13.924700736999512,3.9890503883361818,0.0]},{"label":"C","location":[13.061200141906739,4.488650321960449,0.0]},{"label":"C","location":[13.924700736999512,2.9881505966186525,0.0]},{"label":"C","location":[12.1943998336792,2.9836502075195314,0.0]},{"label":"C","location":[13.063399314880371,2.488650321960449,0.0]},{"label":"C","location":[11.328400611877442,2.4836502075195314,0.0]},{"label":"C","location":[12.35629940032959,1.781550407409668,0.0]},{"label":"C","location":[14.631800651550293,2.281050682067871,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway4.ket b/api/tests/integration/tests/reaction/ref/pathway4.ket index d87e139f26..c2bae8cad9 100644 --- a/api/tests/integration/tests/reaction/ref/pathway4.ket +++ b/api/tests/integration/tests/reaction/ref/pathway4.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-5.651700019836426,"y":0.0,"z":0.0},{"x":-2.651700019836426,"y":0.0,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-13.249800682067871,"y":0.0,"z":0.0},{"x":-10.249800682067871,"y":0.0,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-15.059499740600586,0.770050048828125,0.0]},{"label":"C","location":[-14.559099197387696,-0.770050048828125,0.0]},{"label":"C","location":[-14.249799728393555,0.17624998092651368,0.0]},{"label":"C","location":[-15.559799194335938,-0.770050048828125,0.0]},{"label":"C","location":[-15.869199752807618,0.17624998092651368,0.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]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-9.249799728393555,0.5000004768371582,0.0]},{"label":"C","location":[-9.249799728393555,-0.4999995231628418,0.0]},{"label":"C","location":[-8.38379955291748,-1.0,0.0]},{"label":"C","location":[-7.517699241638184,-0.4999995231628418,0.0]},{"label":"C","location":[-7.517699241638184,0.5000004768371582,0.0]},{"label":"C","location":[-8.38379955291748,1.0000004768371583,0.0]},{"label":"C","location":[-6.651699066162109,1.0000004768371583,0.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]},{"type":1,"atoms":[4,6]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-0.7857017517089844,0.8534502983093262,0.0]},{"label":"C","location":[0.9445991516113281,0.853950023651123,0.0]},{"label":"C","location":[0.08109855651855469,1.3535499572753907,0.0]},{"label":"C","location":[0.9445991516113281,-0.14694976806640626,0.0]},{"label":"C","location":[-0.7857017517089844,-0.15145015716552735,0.0]},{"label":"C","location":[0.0832977294921875,-0.6464500427246094,0.0]},{"label":"C","location":[-1.6517009735107422,-0.6514501571655273,0.0]},{"label":"C","location":[-0.6238021850585938,-1.3535499572753907,0.0]},{"label":"C","location":[1.6516990661621094,-0.8540496826171875,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.717500686645508,"y":1.3535499572753907,"z":0.0},{"x":10.217500686645508,"y":1.3535499572753907,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.6194000244140627,"y":1.3535499572753907,"z":0.0},{"x":4.1194000244140629,"y":1.3535499572753907,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.8097000122070313,2.1236000061035158,0.0]},{"label":"C","location":[1.3101000785827637,0.5834999084472656,0.0]},{"label":"C","location":[1.6194000244140626,1.5297999382019044,0.0]},{"label":"C","location":[0.3094000816345215,0.5834999084472656,0.0]},{"label":"C","location":[0.0,1.5297999382019044,0.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]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[5.1194000244140629,1.8535504341125489,0.0]},{"label":"C","location":[5.1194000244140629,0.8535504341125488,0.0]},{"label":"C","location":[5.985400199890137,0.3535499572753906,0.0]},{"label":"C","location":[6.851500511169434,0.8535504341125488,0.0]},{"label":"C","location":[6.851500511169434,1.8535504341125489,0.0]},{"label":"C","location":[5.985400199890137,2.353550434112549,0.0]},{"label":"C","location":[7.717500686645508,2.353550434112549,0.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]},{"type":1,"atoms":[4,6]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[12.083499908447266,2.207000255584717,0.0]},{"label":"C","location":[13.813800811767579,2.2074999809265138,0.0]},{"label":"C","location":[12.950300216674805,2.7070999145507814,0.0]},{"label":"C","location":[13.813800811767579,1.2066001892089844,0.0]},{"label":"C","location":[12.083499908447266,1.2020998001098633,0.0]},{"label":"C","location":[12.952499389648438,0.7070999145507813,0.0]},{"label":"C","location":[11.217500686645508,0.7020998001098633,0.0]},{"label":"C","location":[12.245399475097657,0.0,0.0]},{"label":"C","location":[14.52090072631836,0.4995002746582031,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway5.ket b/api/tests/integration/tests/reaction/ref/pathway5.ket index 5ec782f571..058d99bcb7 100644 --- a/api/tests/integration/tests/reaction/ref/pathway5.ket +++ b/api/tests/integration/tests/reaction/ref/pathway5.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-5.651700019836426,"y":0.0,"z":0.0},{"x":-2.651700019836426,"y":0.0,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-9.249799728393555,0.5000004768371582,0.0]},{"label":"C","location":[-9.249799728393555,-0.4999995231628418,0.0]},{"label":"C","location":[-8.38379955291748,-1.0,0.0]},{"label":"C","location":[-7.517699241638184,-0.4999995231628418,0.0]},{"label":"C","location":[-7.517699241638184,0.5000004768371582,0.0]},{"label":"C","location":[-8.38379955291748,1.0000004768371583,0.0]},{"label":"C","location":[-6.651699066162109,1.0000004768371583,0.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]},{"type":1,"atoms":[4,6]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-0.7857017517089844,0.8534502983093262,0.0]},{"label":"C","location":[0.9445991516113281,0.853950023651123,0.0]},{"label":"C","location":[0.08109855651855469,1.3535499572753907,0.0]},{"label":"C","location":[0.9445991516113281,-0.14694976806640626,0.0]},{"label":"C","location":[-0.7857017517089844,-0.15145015716552735,0.0]},{"label":"C","location":[0.0832977294921875,-0.6464500427246094,0.0]},{"label":"C","location":[-1.6517009735107422,-0.6514501571655273,0.0]},{"label":"C","location":[-0.6238021850585938,-1.3535499572753907,0.0]},{"label":"C","location":[1.6516990661621094,-0.8540496826171875,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":3.5981006622314455,"y":1.3535499572753907,"z":0.0},{"x":5.098100662231445,"y":1.3535499572753907,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.0,1.8535504341125489,0.0]},{"label":"C","location":[0.0,0.8535504341125488,0.0]},{"label":"C","location":[0.8660001754760742,0.3535499572753906,0.0]},{"label":"C","location":[1.732100486755371,0.8535504341125488,0.0]},{"label":"C","location":[1.732100486755371,1.8535504341125489,0.0]},{"label":"C","location":[0.8660001754760742,2.353550434112549,0.0]},{"label":"C","location":[2.5981006622314455,2.353550434112549,0.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]},{"type":1,"atoms":[4,6]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[6.964099884033203,2.207000255584717,0.0]},{"label":"C","location":[8.694400787353516,2.2074999809265138,0.0]},{"label":"C","location":[7.830900192260742,2.7070999145507814,0.0]},{"label":"C","location":[8.694400787353516,1.2066001892089844,0.0]},{"label":"C","location":[6.964099884033203,1.2020998001098633,0.0]},{"label":"C","location":[7.833099365234375,0.7070999145507813,0.0]},{"label":"C","location":[6.098100662231445,0.7020998001098633,0.0]},{"label":"C","location":[7.125999450683594,0.0,0.0]},{"label":"C","location":[9.401500701904297,0.4995002746582031,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway6.ket b/api/tests/integration/tests/reaction/ref/pathway6.ket index 41965153bc..37c0309a4b 100644 --- a/api/tests/integration/tests/reaction/ref/pathway6.ket +++ b/api/tests/integration/tests/reaction/ref/pathway6.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-2.248349189758301,"y":0.0,"z":0.0}},"spine":{"pos":[{"x":-4.748349189758301,"y":5.185375213623047,"z":0.0},{"x":-4.748349189758301,"y":-5.185375690460205,"z":0.0}]},"tails":{"pos":[{"x":-5.248349189758301,"y":5.185375213623047,"z":0.0},{"x":-5.248349189758301,"y":-5.185375690460205,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-10.551749229431153,"y":5.185375213623047,"z":0.0}},"spine":{"pos":[{"x":-13.051749229431153,"y":10.402450561523438,"z":0.0},{"x":-13.051749229431153,"y":-0.03170013427734375,"z":0.0}]},"tails":{"pos":[{"x":-13.551749229431153,"y":10.402450561523438,"z":0.0},{"x":-13.551749229431153,"y":4.362299919128418,"z":0.0},{"x":-13.551749229431153,"y":-0.03170013427734375,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-13.551749229431153,"y":-5.185375690460205,"z":0.0},{"x":-10.551749229431153,"y":-5.185375690460205,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-18.708648681640626,"y":10.402450561523438,"z":0.0}},"spine":{"pos":[{"x":-21.208648681640626,"y":12.287500381469727,"z":0.0},{"x":-21.208648681640626,"y":8.517400741577149,"z":0.0}]},"tails":{"pos":[{"x":-21.708648681640626,"y":12.287500381469727,"z":0.0},{"x":-21.708648681640626,"y":8.517400741577149,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-20.939199447631837,"y":-5.185375690460205,"z":0.0},{"x":-17.939199447631837,"y":-5.185375690460205,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-24.438949584960939,12.787449836730957,0.0]},{"label":"C","location":[-22.708648681640626,12.787949562072754,0.0]},{"label":"C","location":[-23.5721492767334,13.28754997253418,0.0]},{"label":"C","location":[-22.708648681640626,11.786949157714844,0.0]},{"label":"C","location":[-24.438949584960939,11.782449722290039,0.0]},{"label":"C","location":[-23.569950103759767,11.287449836730957,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-23.57379913330078,9.287450790405274,0.0]},{"label":"C","location":[-23.07339859008789,7.747350692749023,0.0]},{"label":"C","location":[-22.76409912109375,8.69365119934082,0.0]},{"label":"C","location":[-24.074098587036134,7.747350692749023,0.0]},{"label":"C","location":[-24.383499145507814,8.69365119934082,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-17.429248809814454,10.902451515197754,0.0]},{"label":"C","location":[-17.429248809814454,9.902451515197754,0.0]},{"label":"C","location":[-16.563249588012697,9.402451515197754,0.0]},{"label":"C","location":[-15.697150230407715,9.902451515197754,0.0]},{"label":"C","location":[-15.697150230407715,10.902451515197754,0.0]},{"label":"C","location":[-16.563249588012697,11.402451515197754,0.0]},{"label":"C","location":[-14.83115005493164,11.402451515197754,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-16.225351333618165,4.632349967956543,0.0]},{"label":"C","location":[-15.724950790405274,3.092249870300293,0.0]},{"label":"C","location":[-15.415750503540039,4.03855037689209,0.0]},{"label":"C","location":[-16.725751876831056,3.092249870300293,0.0]},{"label":"C","location":[-17.035051345825197,4.03855037689209,0.0]},{"label":"C","location":[-16.225351333618165,5.632350444793701,0.0]},{"label":"C","location":[-15.225351333618164,5.632350444793701,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[-16.742748260498048,0.4747495651245117,0.0]},{"label":"C","location":[-15.95884895324707,1.092249870300293,0.0]},{"label":"C","location":[-14.985849380493164,0.8697500228881836,0.0]},{"label":"C","location":[-14.551749229431153,-0.026050567626953126,0.0]},{"label":"C","location":[-16.73724937438965,-0.5324497222900391,0.0]},{"label":"C","location":[-14.985149383544922,-0.9331502914428711,0.0]},{"label":"C","location":[-15.95884895324707,-1.1556501388549805,0.0]},{"label":"C","location":[-17.708648681640626,0.7335500717163086,0.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]},{"type":1,"atoms":[0,7]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[-22.940401077270509,-5.617875576019287,0.0]},{"label":"C","location":[-21.93920135498047,-5.617875576019287,0.0]},{"label":"C","location":[-22.439800262451173,-4.752875804901123,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[-15.360750198364258,-4.415926456451416,0.0]},{"label":"C","location":[-14.551750183105469,-5.003726482391357,0.0]},{"label":"C","location":[-14.860750198364258,-5.9548258781433109,0.0]},{"label":"C","location":[-15.860750198364258,-5.9548258781433109,0.0]},{"label":"C","location":[-16.169750213623048,-5.003726482391357,0.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]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[-8.685749053955079,6.038825988769531,0.0]},{"label":"C","location":[-6.955449104309082,6.039325714111328,0.0]},{"label":"C","location":[-7.818948745727539,6.5389251708984379,0.0]},{"label":"C","location":[-6.955449104309082,5.038425445556641,0.0]},{"label":"C","location":[-8.685749053955079,5.033926010131836,0.0]},{"label":"C","location":[-7.81674861907959,4.5389251708984379,0.0]},{"label":"C","location":[-9.551749229431153,4.533926010131836,0.0]},{"label":"C","location":[-8.523848533630371,3.8318252563476564,0.0]},{"label":"C","location":[-6.248349189758301,4.331325531005859,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]},"mol8":{"type":"molecule","atoms":[{"label":"C","location":[-9.106698989868164,-5.686625003814697,0.0]},{"label":"C","location":[-9.106500625610352,-4.6841254234313969,0.0]},{"label":"C","location":[-8.401399612426758,-3.978825092315674,0.0]},{"label":"C","location":[-8.401199340820313,-6.392025470733643,0.0]},{"label":"C","location":[-7.398799896240234,-6.392025470733643,0.0]},{"label":"C","location":[-6.693399429321289,-5.686625003814697,0.0]},{"label":"C","location":[-6.693500518798828,-4.6841254234313969,0.0]},{"label":"C","location":[-7.398799896240234,-3.978724956512451,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[-1.2483482360839844,-2.1053991317749025,0.0]},{"label":"C","location":[-1.2481498718261719,-1.1028995513916016,0.0]},{"label":"C","location":[-0.5429496765136719,-0.39769935607910159,0.0]},{"label":"C","location":[-0.5427494049072266,-2.8107995986938478,0.0]},{"label":"C","location":[0.4596519470214844,-2.8107995986938478,0.0]},{"label":"C","location":[1.1650505065917969,-2.1053991317749025,0.0]},{"label":"C","location":[1.1649513244628907,-1.1028995513916016,0.0]},{"label":"C","location":[0.4596519470214844,-0.3975992202758789,0.0]},{"label":"C","location":[-1.1649494171142579,1.102900505065918,0.0]},{"label":"C","location":[-1.1647491455078126,2.105400562286377,0.0]},{"label":"C","location":[-0.45964813232421877,2.8107004165649416,0.0]},{"label":"C","location":[-0.45944976806640627,0.39750003814697268,0.0]},{"label":"C","location":[0.5429515838623047,0.39750003814697268,0.0]},{"label":"C","location":[1.2483501434326172,1.102900505065918,0.0]},{"label":"C","location":[1.248250961303711,2.105400562286377,0.0]},{"label":"C","location":[0.5429515838623047,2.810800552368164,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]},{"type":1,"atoms":[9,8]},{"type":1,"atoms":[8,11]},{"type":1,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":1,"atoms":[15,10]},{"type":1,"atoms":[10,9]},{"type":1,"atoms":[11,2]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":17.69059944152832,"y":11.327312469482422,"z":0.0}},"spine":{"pos":[{"x":16.69059944152832,"y":16.625598907470704,"z":0.0},{"x":16.69059944152832,"y":6.029025077819824,"z":0.0}]},"tails":{"pos":[{"x":16.19059944152832,"y":16.625598907470704,"z":0.0},{"x":16.19059944152832,"y":6.029025077819824,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":10.887199401855469,"y":6.029025077819824,"z":0.0}},"spine":{"pos":[{"x":9.887199401855469,"y":10.788000106811524,"z":0.0},{"x":9.887199401855469,"y":1.270050048828125,"z":0.0}]},"tails":{"pos":[{"x":9.387199401855469,"y":10.788000106811524,"z":0.0},{"x":9.387199401855469,"y":6.164050102233887,"z":0.0},{"x":9.387199401855469,"y":1.270050048828125,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.78909969329834,"y":10.788000106811524,"z":0.0}},"spine":{"pos":[{"x":3.2302989959716799,"y":12.923049926757813,"z":0.0},{"x":3.2302989959716799,"y":8.652950286865235,"z":0.0}]},"tails":{"pos":[{"x":2.7302989959716799,"y":12.923049926757813,"z":0.0},{"x":2.7302989959716799,"y":8.652950286865235,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":9.387199401855469,"y":16.625598907470704,"z":0.0},{"x":11.777299880981446,"y":16.625598907470704,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.7302989959716799,"y":16.625598907470704,"z":0.0},{"x":5.769199371337891,"y":16.625598907470704,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.0,9.152899742126465,0.0]},{"label":"C","location":[1.730299949645996,9.153399467468262,0.0]},{"label":"C","location":[0.8668000102043152,9.652999877929688,0.0]},{"label":"C","location":[1.730299949645996,8.152399063110352,0.0]},{"label":"C","location":[0.0,8.147899627685547,0.0]},{"label":"C","location":[0.8690000176429749,7.652899742126465,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.9205989837646484,13.693100929260254,0.0]},{"label":"C","location":[1.4209990501403809,12.153000831604004,0.0]},{"label":"C","location":[1.7302989959716797,13.099300384521485,0.0]},{"label":"C","location":[0.42029905319213869,12.153000831604004,0.0]},{"label":"C","location":[0.11089897155761719,13.099300384521485,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[5.78909969329834,11.287999153137207,0.0]},{"label":"C","location":[5.78909969329834,10.287999153137207,0.0]},{"label":"C","location":[6.655099868774414,9.787999153137207,0.0]},{"label":"C","location":[7.5211992263793949,10.287999153137207,0.0]},{"label":"C","location":[7.5211992263793949,11.287999153137207,0.0]},{"label":"C","location":[6.655099868774414,11.787999153137207,0.0]},{"label":"C","location":[8.387199401855469,11.787999153137207,0.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]},{"type":1,"atoms":[4,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[7.387199401855469,1.54010009765625,0.0]},{"label":"C","location":[7.887599945068359,0.0,0.0]},{"label":"C","location":[8.196800231933594,0.9463005065917969,0.0]},{"label":"C","location":[6.886798858642578,0.0,0.0]},{"label":"C","location":[6.5774993896484379,0.9463005065917969,0.0]},{"label":"C","location":[7.387199401855469,2.540100574493408,0.0]},{"label":"C","location":[8.387199401855469,2.540100574493408,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[6.1961989402771,6.670499801635742,0.0]},{"label":"C","location":[6.980098724365234,7.288000106811523,0.0]},{"label":"C","location":[7.953098773956299,7.065500259399414,0.0]},{"label":"C","location":[8.387199401855469,6.169699668884277,0.0]},{"label":"C","location":[6.2016987800598148,5.663300514221191,0.0]},{"label":"C","location":[7.953798770904541,5.262599945068359,0.0]},{"label":"C","location":[6.980098724365234,5.04010009765625,0.0]},{"label":"C","location":[5.23029899597168,6.929300308227539,0.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]},{"type":1,"atoms":[0,7]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[0.7290992736816406,16.193099975585939,0.0]},{"label":"C","location":[1.730299472808838,16.193099975585939,0.0]},{"label":"C","location":[1.2296996116638184,17.0580997467041,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[7.57819938659668,17.395048141479493,0.0]},{"label":"C","location":[8.387199401855469,16.807247161865236,0.0]},{"label":"C","location":[8.07819938659668,15.856148719787598,0.0]},{"label":"C","location":[7.07819938659668,15.856148719787598,0.0]},{"label":"C","location":[6.769199371337891,16.807247161865236,0.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]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[12.753199577331543,6.882476806640625,0.0]},{"label":"C","location":[14.483499526977539,6.882976531982422,0.0]},{"label":"C","location":[13.619999885559082,7.382575988769531,0.0]},{"label":"C","location":[14.483499526977539,5.882076263427734,0.0]},{"label":"C","location":[12.753199577331543,5.87757682800293,0.0]},{"label":"C","location":[13.622200012207032,5.382575988769531,0.0]},{"label":"C","location":[11.887199401855469,5.37757682800293,0.0]},{"label":"C","location":[12.91510009765625,4.67547607421875,0.0]},{"label":"C","location":[15.19059944152832,5.174976348876953,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]},"mol8":{"type":"molecule","atoms":[{"label":"C","location":[12.777299880981446,16.12434959411621,0.0]},{"label":"C","location":[12.777498245239258,17.126850128173829,0.0]},{"label":"C","location":[13.482599258422852,17.832149505615236,0.0]},{"label":"C","location":[13.482799530029297,15.418949127197266,0.0]},{"label":"C","location":[14.485198974609375,15.418949127197266,0.0]},{"label":"C","location":[15.19059944152832,16.12434959411621,0.0]},{"label":"C","location":[15.190498352050782,17.126850128173829,0.0]},{"label":"C","location":[14.485198974609375,17.83224868774414,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[18.69059944152832,9.22191333770752,0.0]},{"label":"C","location":[18.690797805786134,10.22441291809082,0.0]},{"label":"C","location":[19.395998001098634,10.92961311340332,0.0]},{"label":"C","location":[19.396198272705079,8.516512870788575,0.0]},{"label":"C","location":[20.39859962463379,8.516512870788575,0.0]},{"label":"C","location":[21.1039981842041,9.22191333770752,0.0]},{"label":"C","location":[21.103899002075197,10.22441291809082,0.0]},{"label":"C","location":[20.39859962463379,10.929713249206543,0.0]},{"label":"C","location":[18.773998260498048,12.43021297454834,0.0]},{"label":"C","location":[18.774198532104493,13.43271255493164,0.0]},{"label":"C","location":[19.479299545288087,14.138012886047364,0.0]},{"label":"C","location":[19.4794979095459,11.724812507629395,0.0]},{"label":"C","location":[20.48189926147461,11.724812507629395,0.0]},{"label":"C","location":[21.187297821044923,12.43021297454834,0.0]},{"label":"C","location":[21.187198638916017,13.43271255493164,0.0]},{"label":"C","location":[20.48189926147461,14.138113021850586,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]},{"type":1,"atoms":[9,8]},{"type":1,"atoms":[8,11]},{"type":1,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":1,"atoms":[15,10]},{"type":1,"atoms":[10,9]},{"type":1,"atoms":[11,2]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway7.ket b/api/tests/integration/tests/reaction/ref/pathway7.ket index 98cf3604b0..d1f8e3558a 100644 --- a/api/tests/integration/tests/reaction/ref/pathway7.ket +++ b/api/tests/integration/tests/reaction/ref/pathway7.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-2.1703014373779299,"y":0.0,"z":0.0}},"spine":{"pos":[{"x":-4.67030143737793,"y":5.651976585388184,"z":0.0},{"x":-4.67030143737793,"y":-5.651975631713867,"z":0.0}]},"tails":{"pos":[{"x":-5.17030143737793,"y":5.651976585388184,"z":0.0},{"x":-5.17030143737793,"y":-5.651975631713867,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-25.090600967407228,"y":5.651976585388184,"z":0.0},{"x":-22.090600967407228,"y":5.651976585388184,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-22.090600967407228,"y":-5.651975631713867,"z":0.0}},"spine":{"pos":[{"x":-24.590600967407228,"y":-1.872199535369873,"z":0.0},{"x":-24.590600967407228,"y":-9.431751251220704,"z":0.0}]},"tails":{"pos":[{"x":-25.090600967407228,"y":-1.872199535369873,"z":0.0},{"x":-25.090600967407228,"y":-5.390700817108154,"z":0.0},{"x":-25.090600967407228,"y":-9.431751251220704,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-26.420650482177736,-2.6425018310546877,0.0]},{"label":"C","location":[-26.42435073852539,-1.6466007232666016,0.0]},{"label":"C","location":[-27.433452606201173,-2.6295013427734377,0.0]},{"label":"C","location":[-27.435951232910158,-1.6466007232666016,0.0]},{"label":"C","location":[-28.42955207824707,-1.1019001007080079,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-27.081501007080079,-6.1389007568359379,0.0]},{"label":"C","location":[-27.085201263427736,-5.142999649047852,0.0]},{"label":"C","location":[-28.094301223754884,-6.125999450683594,0.0]},{"label":"C","location":[-28.0968017578125,-5.142999649047852,0.0]},{"label":"C","location":[-28.63170051574707,-4.765199661254883,0.0]},{"label":"C","location":[-26.218502044677736,-4.642499923706055,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]},{"type":1,"atoms":[1,5]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-27.209402084350587,-9.762901306152344,0.0]},{"label":"C","location":[-27.213102340698243,-8.767000198364258,0.0]},{"label":"C","location":[-28.222103118896486,-9.750001907348633,0.0]},{"label":"C","location":[-28.22460174560547,-8.767000198364258,0.0]},{"label":"C","location":[-28.759601593017579,-8.264101028442383,0.0]},{"label":"C","location":[-26.632802963256837,-8.138900756835938,0.0]},{"label":"C","location":[-26.09060287475586,-10.724601745605469,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]},{"type":1,"atoms":[5,1]},{"type":1,"atoms":[6,0]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-35.646697998046878,2.6405763626098635,0.0]},{"label":"C","location":[-35.581398010253909,1.1593761444091797,0.0]},{"label":"C","location":[-36.041595458984378,1.8810768127441407,0.0]},{"label":"C","location":[-34.726295471191409,1.1970767974853516,0.0]},{"label":"C","location":[-34.79149627685547,2.678175926208496,0.0]},{"label":"C","location":[-34.331298828125,1.9564762115478516,0.0]},{"label":"C","location":[-31.4435977935791,1.4730768203735352,0.0]},{"label":"C","location":[-31.6177978515625,2.945376396179199,0.0]},{"label":"C","location":[-31.955698013305665,2.1589765548706056,0.0]},{"label":"C","location":[-30.767797470092775,3.0459766387939455,0.0]},{"label":"C","location":[-30.593597412109376,1.5736761093139649,0.0]},{"label":"C","location":[-30.25569725036621,2.3600759506225588,0.0]},{"label":"C","location":[-39.82659912109375,3.3058767318725588,0.0]},{"label":"C","location":[-38.462799072265628,2.724276542663574,0.0]},{"label":"C","location":[-38.97679901123047,3.40877628326416,0.0]},{"label":"C","location":[-38.79859924316406,1.936976432800293,0.0]},{"label":"C","location":[-40.16230010986328,2.5185766220092775,0.0]},{"label":"C","location":[-39.648399353027347,1.834075927734375,0.0]},{"label":"C","location":[-39.92939758300781,4.15567684173584,0.0]},{"label":"C","location":[-38.743896484375,5.045876502990723,0.0]},{"label":"C","location":[-39.07969665527344,4.258576393127441,0.0]},{"label":"C","location":[-39.25779724121094,5.730376243591309,0.0]},{"label":"C","location":[-40.443397521972659,4.840176582336426,0.0]},{"label":"C","location":[-40.10759735107422,5.627476692199707,0.0]},{"label":"C","location":[-39.024898529052737,7.367476463317871,0.0]},{"label":"C","location":[-40.21049880981445,6.477276802062988,0.0]},{"label":"C","location":[-39.36069869995117,6.58017635345459,0.0]},{"label":"C","location":[-40.72439956665039,7.161776542663574,0.0]},{"label":"C","location":[-39.53889846801758,8.051976203918457,0.0]},{"label":"C","location":[-40.38859939575195,7.9490766525268559,0.0]},{"label":"C","location":[-26.090599060058595,3.9019765853881838,0.0]},{"label":"C","location":[-27.4341983795166,4.528576850891113,0.0]},{"label":"C","location":[-26.581499099731447,4.603075981140137,0.0]},{"label":"C","location":[-27.795997619628908,3.7527761459350588,0.0]},{"label":"C","location":[-26.452299118041993,3.1261768341064455,0.0]},{"label":"C","location":[-27.30499839782715,3.051576614379883,0.0]},{"label":"C","location":[-27.999698638916017,6.082476615905762,0.0]},{"label":"C","location":[-26.656097412109376,5.455876350402832,0.0]},{"label":"C","location":[-27.508798599243165,5.3812761306762699,0.0]},{"label":"C","location":[-26.29429817199707,6.231575965881348,0.0]},{"label":"C","location":[-27.637998580932618,6.858176231384277,0.0]},{"label":"C","location":[-26.785297393798829,6.93277645111084,0.0]},{"label":"C","location":[-28.20349884033203,8.412076950073243,0.0]},{"label":"C","location":[-26.859798431396486,7.7854766845703129,0.0]},{"label":"C","location":[-27.71259880065918,7.71087646484375,0.0]},{"label":"C","location":[-26.498098373413087,8.56127643585205,0.0]},{"label":"C","location":[-27.841697692871095,9.187875747680664,0.0]},{"label":"C","location":[-26.988998413085939,9.262475967407227,0.0]},{"label":"C","location":[-36.697296142578128,8.779876708984375,0.0]},{"label":"C","location":[-35.56079864501953,9.731976509094239,0.0]},{"label":"C","location":[-36.403900146484378,9.583976745605469,0.0]},{"label":"C","location":[-35.01110076904297,9.075876235961914,0.0]},{"label":"C","location":[-36.14759826660156,8.123676300048829,0.0]},{"label":"C","location":[-35.30449676513672,8.271677017211914,0.0]},{"label":"C","location":[-32.196800231933597,10.106976509094239,0.0]},{"label":"C","location":[-30.8815975189209,9.422776222229004,0.0]},{"label":"C","location":[-31.341697692871095,10.144577026367188,0.0]},{"label":"C","location":[-31.27659797668457,8.663375854492188,0.0]},{"label":"C","location":[-32.591796875,9.347576141357422,0.0]},{"label":"C","location":[-32.13169860839844,8.625776290893555,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":2,"atoms":[56,54]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,59]},{"type":1,"atoms":[59,57]},{"type":2,"atoms":[57,55]},{"type":1,"atoms":[55,56]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[55,42]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[-13.630500793457032,6.039877891540527,0.0]},{"label":"C","location":[-14.078300476074219,5.264078140258789,0.0]},{"label":"C","location":[-13.182600975036621,5.264078140258789,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[-15.856000900268555,-8.223875999450684,0.0]},{"label":"C","location":[-15.783302307128907,-9.773575782775879,0.0]},{"label":"C","location":[-16.26700210571289,-9.019676208496094,0.0]},{"label":"C","location":[-14.888601303100586,-9.731575965881348,0.0]},{"label":"C","location":[-14.961301803588868,-8.181876182556153,0.0]},{"label":"C","location":[-14.477602005004883,-8.935675621032715,0.0]},{"label":"C","location":[-11.544900894165039,-9.434775352478028,0.0]},{"label":"C","location":[-11.745101928710938,-7.89637565612793,0.0]},{"label":"C","location":[-12.089101791381836,-8.723376274108887,0.0]},{"label":"C","location":[-10.856801986694336,-7.780876159667969,0.0]},{"label":"C","location":[-10.656702041625977,-9.319275856018067,0.0]},{"label":"C","location":[-10.312702178955079,-8.492276191711426,0.0]},{"label":"C","location":[-20.186702728271486,-7.601375579833984,0.0]},{"label":"C","location":[-18.76500129699707,-8.222576141357422,0.0]},{"label":"C","location":[-19.29650115966797,-7.501575469970703,0.0]},{"label":"C","location":[-19.123703002929689,-9.043375968933106,0.0]},{"label":"C","location":[-20.54530143737793,-8.422175407409668,0.0]},{"label":"C","location":[-20.01380157470703,-9.143176078796387,0.0]},{"label":"C","location":[-20.286502838134767,-6.711276054382324,0.0]},{"label":"C","location":[-19.037700653076173,-5.790676116943359,0.0]},{"label":"C","location":[-19.39630126953125,-6.611475944519043,0.0]},{"label":"C","location":[-19.569202423095704,-5.069675445556641,0.0]},{"label":"C","location":[-20.81800079345703,-5.9902753829956059,0.0]},{"label":"C","location":[-20.459300994873048,-5.169475555419922,0.0]},{"label":"C","location":[-19.310401916503908,-3.358776092529297,0.0]},{"label":"C","location":[-20.559101104736329,-4.279376029968262,0.0]},{"label":"C","location":[-19.669002532958986,-4.1795759201049809,0.0]},{"label":"C","location":[-21.09060287475586,-3.558375358581543,0.0]},{"label":"C","location":[-19.841901779174806,-2.637876033782959,0.0]},{"label":"C","location":[-20.73200225830078,-2.737675666809082,0.0]},{"label":"C","location":[-6.17030143737793,-6.824675559997559,0.0]},{"label":"C","location":[-7.719001770019531,-6.734175682067871,0.0]},{"label":"C","location":[-6.918500900268555,-6.332375526428223,0.0]},{"label":"C","location":[-7.77130126953125,-7.628376007080078,0.0]},{"label":"C","location":[-6.222501754760742,-7.718875885009766,0.0]},{"label":"C","location":[-7.023101806640625,-8.120676040649414,0.0]},{"label":"C","location":[-8.869102478027344,-5.441275596618652,0.0]},{"label":"C","location":[-7.320301055908203,-5.5318756103515629,0.0]},{"label":"C","location":[-8.120901107788086,-5.933675765991211,0.0]},{"label":"C","location":[-7.268102645874023,-4.637676239013672,0.0]},{"label":"C","location":[-8.816801071166993,-4.547175407409668,0.0]},{"label":"C","location":[-8.016302108764649,-4.145276069641113,0.0]},{"label":"C","location":[-9.966901779174805,-3.2542762756347658,0.0]},{"label":"C","location":[-8.418102264404297,-3.344776153564453,0.0]},{"label":"C","location":[-9.21870231628418,-3.746575355529785,0.0]},{"label":"C","location":[-8.365901947021485,-2.450575828552246,0.0]},{"label":"C","location":[-9.914602279663086,-2.3600759506225588,0.0]},{"label":"C","location":[-9.11410140991211,-1.9582757949829102,0.0]},{"label":"C","location":[-16.9934024810791,-2.2977757453918459,0.0]},{"label":"C","location":[-15.635902404785157,-1.5467758178710938,0.0]},{"label":"C","location":[-16.531402587890626,-1.5303759574890137,0.0]},{"label":"C","location":[-15.202301025390625,-2.3304758071899416,0.0]},{"label":"C","location":[-16.559701919555665,-3.081575870513916,0.0]},{"label":"C","location":[-15.664201736450196,-3.0978755950927736,0.0]},{"label":"C","location":[-12.735702514648438,-2.108475685119629,0.0]},{"label":"C","location":[-12.31180191040039,-3.4944753646850588,0.0]},{"label":"C","location":[-12.020301818847657,-2.6474757194519045,0.0]},{"label":"C","location":[-13.207401275634766,-3.4788761138916017,0.0]},{"label":"C","location":[-13.469402313232422,-2.622375965118408,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[0.0,1.1703004837036133,0.0]},{"label":"C","location":[0.8274993896484375,0.8275003433227539,0.0]},{"label":"C","location":[1.1702995300292969,9.5367431640625e-7,0.0]},{"label":"C","location":[-0.8275032043457031,0.8275003433227539,0.0]},{"label":"C","location":[-1.1703033447265626,9.5367431640625e-7,0.0]},{"label":"C","location":[-0.8275032043457031,-0.8274993896484375,0.0]},{"label":"C","location":[0.0,-1.1702995300292969,0.0]},{"label":"C","location":[0.8274993896484375,-0.8274993896484375,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":35.554100036621097,"y":11.332690238952637,"z":0.0}},"spine":{"pos":[{"x":34.554100036621097,"y":17.61530303955078,"z":0.0},{"x":34.554100036621097,"y":5.050076961517334,"z":0.0}]},"tails":{"pos":[{"x":34.054100036621097,"y":17.61530303955078,"z":0.0},{"x":34.054100036621097,"y":5.050076961517334,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":17.133800506591798,"y":5.050076961517334,"z":0.0}},"spine":{"pos":[{"x":16.133800506591798,"y":9.329853057861329,"z":0.0},{"x":16.133800506591798,"y":0.7703008651733398,"z":0.0}]},"tails":{"pos":[{"x":15.633800506591797,"y":9.329853057861329,"z":0.0},{"x":15.633800506591797,"y":4.788802146911621,"z":0.0},{"x":15.633800506591797,"y":0.7703008651733398,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":15.633800506591797,"y":17.61530303955078,"z":0.0},{"x":31.158401489257814,"y":17.61530303955078,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[14.633800506591797,0.0,0.0]},{"label":"C","location":[14.63010025024414,0.9959011077880859,0.0]},{"label":"C","location":[13.621000289916993,0.01300048828125,0.0]},{"label":"C","location":[13.618499755859375,0.9959011077880859,0.0]},{"label":"C","location":[12.624900817871094,1.5406017303466797,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[13.77079963684082,4.04060173034668,0.0]},{"label":"C","location":[13.767099380493164,5.036502838134766,0.0]},{"label":"C","location":[12.757999420166016,4.053503036499023,0.0]},{"label":"C","location":[12.755499839782715,5.036502838134766,0.0]},{"label":"C","location":[12.220600128173829,5.414302825927734,0.0]},{"label":"C","location":[14.63379955291748,5.5370025634765629,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]},{"type":1,"atoms":[1,5]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[13.51500129699707,8.998703002929688,0.0]},{"label":"C","location":[13.511301040649414,9.994604110717774,0.0]},{"label":"C","location":[12.502300262451172,9.011602401733399,0.0]},{"label":"C","location":[12.499801635742188,9.994604110717774,0.0]},{"label":"C","location":[11.964801788330079,10.497503280639649,0.0]},{"label":"C","location":[14.09160041809082,10.622703552246094,0.0]},{"label":"C","location":[14.633800506591797,8.037002563476563,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[4,3]},{"type":1,"atoms":[5,1]},{"type":1,"atoms":[6,0]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[5.077700614929199,14.603903770446778,0.0]},{"label":"C","location":[5.143000602722168,13.122703552246094,0.0]},{"label":"C","location":[4.682801246643066,13.844404220581055,0.0]},{"label":"C","location":[5.998101234436035,13.160404205322266,0.0]},{"label":"C","location":[5.932900428771973,14.64150333404541,0.0]},{"label":"C","location":[6.393099784851074,13.919803619384766,0.0]},{"label":"C","location":[9.280800819396973,13.43640422821045,0.0]},{"label":"C","location":[9.106600761413575,14.908703804016114,0.0]},{"label":"C","location":[8.76870059967041,14.12230396270752,0.0]},{"label":"C","location":[9.9566011428833,15.00930404663086,0.0]},{"label":"C","location":[10.1308012008667,13.537003517150879,0.0]},{"label":"C","location":[10.468701362609864,14.323403358459473,0.0]},{"label":"C","location":[0.8977994918823242,15.269204139709473,0.0]},{"label":"C","location":[2.261599540710449,14.687603950500489,0.0]},{"label":"C","location":[1.7475996017456055,15.372103691101075,0.0]},{"label":"C","location":[1.9258012771606446,13.900303840637207,0.0]},{"label":"C","location":[0.5621004104614258,14.481904029846192,0.0]},{"label":"C","location":[1.0760011672973633,13.797403335571289,0.0]},{"label":"C","location":[0.7950010299682617,16.119003295898439,0.0]},{"label":"C","location":[1.9805002212524415,17.009204864501954,0.0]},{"label":"C","location":[1.644700050354004,16.221904754638673,0.0]},{"label":"C","location":[1.4666013717651368,17.693702697753908,0.0]},{"label":"C","location":[0.28100013732910159,16.803504943847658,0.0]},{"label":"C","location":[0.6168003082275391,17.590805053710939,0.0]},{"label":"C","location":[1.6995000839233399,19.33080291748047,0.0]},{"label":"C","location":[0.5139007568359375,18.44060516357422,0.0]},{"label":"C","location":[1.3636999130249024,18.543502807617189,0.0]},{"label":"C","location":[0.0,19.125102996826173,0.0]},{"label":"C","location":[1.185500144958496,20.015304565429689,0.0]},{"label":"C","location":[0.3358001708984375,19.912403106689454,0.0]},{"label":"C","location":[14.63379955291748,15.865303993225098,0.0]},{"label":"C","location":[13.290200233459473,16.491905212402345,0.0]},{"label":"C","location":[14.142899513244629,16.566402435302736,0.0]},{"label":"C","location":[12.928400993347168,15.716103553771973,0.0]},{"label":"C","location":[14.272099494934082,15.08950424194336,0.0]},{"label":"C","location":[13.419400215148926,15.014904022216797,0.0]},{"label":"C","location":[12.724699974060059,18.04580307006836,0.0]},{"label":"C","location":[14.0683012008667,17.419204711914064,0.0]},{"label":"C","location":[13.21560001373291,17.3446044921875,0.0]},{"label":"C","location":[14.430100440979004,18.194904327392579,0.0]},{"label":"C","location":[13.086400032043457,18.821502685546876,0.0]},{"label":"C","location":[13.939101219177246,18.896102905273439,0.0]},{"label":"C","location":[12.520899772644043,20.375404357910158,0.0]},{"label":"C","location":[13.86460018157959,19.748804092407228,0.0]},{"label":"C","location":[13.011799812316895,19.674203872680665,0.0]},{"label":"C","location":[14.226300239562989,20.52460479736328,0.0]},{"label":"C","location":[12.88270092010498,21.151203155517579,0.0]},{"label":"C","location":[13.735400199890137,21.22580337524414,0.0]},{"label":"C","location":[4.027100563049316,20.74320411682129,0.0]},{"label":"C","location":[5.163599967956543,21.69530487060547,0.0]},{"label":"C","location":[4.320500373840332,21.547304153442384,0.0]},{"label":"C","location":[5.713299751281738,21.039203643798829,0.0]},{"label":"C","location":[4.576800346374512,20.087003707885743,0.0]},{"label":"C","location":[5.419899940490723,20.235004425048829,0.0]},{"label":"C","location":[8.527600288391114,22.07030487060547,0.0]},{"label":"C","location":[9.842801094055176,21.386104583740236,0.0]},{"label":"C","location":[9.38270092010498,22.1079044342041,0.0]},{"label":"C","location":[9.447800636291504,20.6267032623291,0.0]},{"label":"C","location":[8.132599830627442,21.310903549194337,0.0]},{"label":"C","location":[8.592700004577637,20.58910369873047,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":2,"atoms":[56,54]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,59]},{"type":1,"atoms":[59,57]},{"type":2,"atoms":[57,55]},{"type":1,"atoms":[55,56]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[55,42]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[32.606201171875,18.003204345703126,0.0]},{"label":"C","location":[32.15840148925781,17.22740364074707,0.0]},{"label":"C","location":[33.054100036621097,17.22740364074707,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[23.36840057373047,2.478177070617676,0.0]},{"label":"C","location":[23.44110107421875,0.9284772872924805,0.0]},{"label":"C","location":[22.957401275634767,1.6823768615722657,0.0]},{"label":"C","location":[24.335800170898439,0.9704771041870117,0.0]},{"label":"C","location":[24.263099670410158,2.520176887512207,0.0]},{"label":"C","location":[24.74679946899414,1.7663774490356446,0.0]},{"label":"C","location":[27.679500579833986,1.267277717590332,0.0]},{"label":"C","location":[27.47930145263672,2.8056774139404299,0.0]},{"label":"C","location":[27.135299682617189,1.9786767959594727,0.0]},{"label":"C","location":[28.367599487304689,2.9211769104003908,0.0]},{"label":"C","location":[28.567699432373048,1.382777214050293,0.0]},{"label":"C","location":[28.911701202392579,2.2097768783569338,0.0]},{"label":"C","location":[19.037700653076173,3.100677490234375,0.0]},{"label":"C","location":[20.459400177001954,2.4794769287109377,0.0]},{"label":"C","location":[19.927900314331056,3.2004776000976564,0.0]},{"label":"C","location":[20.10070037841797,1.658677101135254,0.0]},{"label":"C","location":[18.679100036621095,2.2798776626586916,0.0]},{"label":"C","location":[19.210601806640626,1.5588769912719727,0.0]},{"label":"C","location":[18.93790054321289,3.990777015686035,0.0]},{"label":"C","location":[20.18670082092285,4.911376953125,0.0]},{"label":"C","location":[19.828102111816408,4.090577125549316,0.0]},{"label":"C","location":[19.655200958251954,5.632377624511719,0.0]},{"label":"C","location":[18.406400680541993,4.711777687072754,0.0]},{"label":"C","location":[18.765100479125978,5.5325775146484379,0.0]},{"label":"C","location":[19.91400146484375,7.3432769775390629,0.0]},{"label":"C","location":[18.665300369262697,6.422677040100098,0.0]},{"label":"C","location":[19.555400848388673,6.522477149963379,0.0]},{"label":"C","location":[18.133800506591798,7.143677711486816,0.0]},{"label":"C","location":[19.38249969482422,8.064176559448243,0.0]},{"label":"C","location":[18.492401123046876,7.964377403259277,0.0]},{"label":"C","location":[33.054100036621097,3.877377510070801,0.0]},{"label":"C","location":[31.505401611328126,3.9678773880004885,0.0]},{"label":"C","location":[32.30590057373047,4.369677543640137,0.0]},{"label":"C","location":[31.453102111816408,3.0736770629882814,0.0]},{"label":"C","location":[33.00189971923828,2.9831771850585939,0.0]},{"label":"C","location":[32.20130157470703,2.5813770294189455,0.0]},{"label":"C","location":[30.355300903320314,5.260777473449707,0.0]},{"label":"C","location":[31.904102325439454,5.170177459716797,0.0]},{"label":"C","location":[31.103500366210939,4.768377304077148,0.0]},{"label":"C","location":[31.956298828125,6.0643768310546879,0.0]},{"label":"C","location":[30.40760040283203,6.154877662658691,0.0]},{"label":"C","location":[31.208099365234376,6.556777000427246,0.0]},{"label":"C","location":[29.25749969482422,7.447776794433594,0.0]},{"label":"C","location":[30.80630111694336,7.357276916503906,0.0]},{"label":"C","location":[30.005699157714845,6.955477714538574,0.0]},{"label":"C","location":[30.858501434326173,8.251477241516114,0.0]},{"label":"C","location":[29.309799194335939,8.3419771194458,0.0]},{"label":"C","location":[30.110301971435548,8.74377727508545,0.0]},{"label":"C","location":[22.230998992919923,8.404277801513672,0.0]},{"label":"C","location":[23.5885009765625,9.155277252197266,0.0]},{"label":"C","location":[22.69300079345703,9.171676635742188,0.0]},{"label":"C","location":[24.02210235595703,8.371577262878418,0.0]},{"label":"C","location":[22.66469955444336,7.620477199554443,0.0]},{"label":"C","location":[23.560199737548829,7.604177474975586,0.0]},{"label":"C","location":[26.48870086669922,8.59357738494873,0.0]},{"label":"C","location":[26.912601470947267,7.207577705383301,0.0]},{"label":"C","location":[27.2041015625,8.054576873779297,0.0]},{"label":"C","location":[26.01700210571289,7.223176956176758,0.0]},{"label":"C","location":[25.755001068115236,8.07967758178711,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[37.724403381347659,12.502989768981934,0.0]},{"label":"C","location":[38.551902770996097,12.160189628601075,0.0]},{"label":"C","location":[38.89470291137695,11.332690238952637,0.0]},{"label":"C","location":[36.89690017700195,12.160189628601075,0.0]},{"label":"C","location":[36.554100036621097,11.332690238952637,0.0]},{"label":"C","location":[36.89690017700195,10.505189895629883,0.0]},{"label":"C","location":[37.724403381347659,10.162389755249024,0.0]},{"label":"C","location":[38.551902770996097,10.505189895629883,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway8.ket b/api/tests/integration/tests/reaction/ref/pathway8.ket index 605a344d91..4db87af454 100644 --- a/api/tests/integration/tests/reaction/ref/pathway8.ket +++ b/api/tests/integration/tests/reaction/ref/pathway8.ket @@ -1 +1 @@ -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-2.206700325012207,"y":0.0,"z":0.0}},"spine":{"pos":[{"x":-4.706700325012207,"y":5.310450077056885,"z":0.0},{"x":-4.706700325012207,"y":-5.310450077056885,"z":0.0}]},"tails":{"pos":[{"x":-5.206700325012207,"y":5.310450077056885,"z":0.0},{"x":-5.206700325012207,"y":-5.310450077056885,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-11.221100807189942,"y":5.310450553894043,"z":0.0},{"x":-8.221100807189942,"y":5.310450077056885,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-11.221100807189942,"y":-5.310449600219727,"z":0.0},{"x":-8.221100807189942,"y":-5.310450077056885,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":-31.009601593017579,"y":5.310450553894043,"z":0.0},{"x":-28.009601593017579,"y":5.310450553894043,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":-28.15290069580078,"y":-5.310449600219727,"z":0.0}},"spine":{"pos":[{"x":-30.65290069580078,"y":-3.4282000064849855,"z":0.0},{"x":-30.65290069580078,"y":-7.192699432373047,"z":0.0}]},"tails":{"pos":[{"x":-31.15290069580078,"y":-3.4282000064849855,"z":0.0},{"x":-31.15290069580078,"y":-7.192699432373047,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[-33.01885223388672,-2.663750648498535,0.0]},{"label":"C","location":[-32.52205276489258,-4.192649841308594,0.0]},{"label":"C","location":[-32.21505355834961,-3.253350257873535,0.0]},{"label":"C","location":[-33.51555252075195,-4.192649841308594,0.0]},{"label":"C","location":[-33.82275390625,-3.253350257873535,0.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]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[-33.88490295410156,-6.6927490234375,0.0]},{"label":"C","location":[-33.88490295410156,-7.6927490234375,0.0]},{"label":"C","location":[-33.01890182495117,-8.1927490234375,0.0]},{"label":"C","location":[-32.15290069580078,-7.6927490234375,0.0]},{"label":"C","location":[-32.15290069580078,-6.6927490234375,0.0]},{"label":"C","location":[-33.01890182495117,-6.192649841308594,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[-21.78459930419922,2.296751022338867,0.0]},{"label":"C","location":[-21.71929931640625,0.8143510818481445,0.0]},{"label":"C","location":[-22.179800033569337,1.5366506576538087,0.0]},{"label":"C","location":[-20.86349868774414,0.85205078125,0.0]},{"label":"C","location":[-20.92879867553711,2.334351062774658,0.0]},{"label":"C","location":[-20.46820068359375,1.612051010131836,0.0]},{"label":"C","location":[-17.57830047607422,1.1283512115478516,0.0]},{"label":"C","location":[-17.752599716186525,2.6017508506774904,0.0]},{"label":"C","location":[-18.090801239013673,1.8147506713867188,0.0]},{"label":"C","location":[-16.901901245117189,2.702450752258301,0.0]},{"label":"C","location":[-16.72760009765625,1.2289505004882813,0.0]},{"label":"C","location":[-16.389400482177736,2.015951156616211,0.0]},{"label":"C","location":[-25.96780014038086,2.9625511169433595,0.0]},{"label":"C","location":[-24.6028995513916,2.380451202392578,0.0]},{"label":"C","location":[-25.117300033569337,3.0655508041381838,0.0]},{"label":"C","location":[-24.93899917602539,1.5925512313842774,0.0]},{"label":"C","location":[-26.303699493408204,2.1746511459350588,0.0]},{"label":"C","location":[-25.789400100708009,1.4895505905151368,0.0]},{"label":"C","location":[-26.070600509643556,3.81295108795166,0.0]},{"label":"C","location":[-24.884199142456056,4.703850746154785,0.0]},{"label":"C","location":[-25.220298767089845,3.9159507751464845,0.0]},{"label":"C","location":[-25.398500442504884,5.388950824737549,0.0]},{"label":"C","location":[-26.584999084472658,4.498051166534424,0.0]},{"label":"C","location":[-26.249000549316408,5.285951137542725,0.0]},{"label":"C","location":[-25.1653995513916,7.027251243591309,0.0]},{"label":"C","location":[-26.351999282836915,6.136351108551025,0.0]},{"label":"C","location":[-25.50149917602539,6.239351272583008,0.0]},{"label":"C","location":[-26.866300582885743,6.821451187133789,0.0]},{"label":"C","location":[-25.679800033569337,7.712350845336914,0.0]},{"label":"C","location":[-26.53019905090332,7.60935115814209,0.0]},{"label":"C","location":[-12.221099853515625,3.559051036834717,0.0]},{"label":"C","location":[-13.565699577331543,4.186151027679443,0.0]},{"label":"C","location":[-12.71239948272705,4.260750770568848,0.0]},{"label":"C","location":[-13.927800178527832,3.4097509384155275,0.0]},{"label":"C","location":[-12.583099365234375,2.782650947570801,0.0]},{"label":"C","location":[-13.436399459838868,2.7080512046813967,0.0]},{"label":"C","location":[-14.131699562072754,5.741250991821289,0.0]},{"label":"C","location":[-12.786999702453614,5.1141510009765629,0.0]},{"label":"C","location":[-13.640399932861329,5.03955078125,0.0]},{"label":"C","location":[-12.425000190734864,5.890450954437256,0.0]},{"label":"C","location":[-13.769700050354004,6.517550945281982,0.0]},{"label":"C","location":[-12.916299819946289,6.592250823974609,0.0]},{"label":"C","location":[-14.335599899291993,8.072650909423829,0.0]},{"label":"C","location":[-12.990900039672852,7.445651054382324,0.0]},{"label":"C","location":[-13.844399452209473,7.370950698852539,0.0]},{"label":"C","location":[-12.628899574279786,8.222050666809082,0.0]},{"label":"C","location":[-13.973599433898926,8.849050521850586,0.0]},{"label":"C","location":[-13.120200157165528,8.923750877380371,0.0]},{"label":"C","location":[-22.836000442504884,8.440751075744629,0.0]},{"label":"C","location":[-21.698699951171876,9.393651008605957,0.0]},{"label":"C","location":[-22.542400360107423,9.245450973510743,0.0]},{"label":"C","location":[-21.148500442504884,8.737051010131836,0.0]},{"label":"C","location":[-22.285900115966798,7.784050941467285,0.0]},{"label":"C","location":[-21.44219970703125,7.932150840759277,0.0]},{"label":"C","location":[-18.332000732421876,9.768951416015625,0.0]},{"label":"C","location":[-17.01580047607422,9.084151268005371,0.0]},{"label":"C","location":[-17.476299285888673,9.806550979614258,0.0]},{"label":"C","location":[-17.41109848022461,8.324151039123536,0.0]},{"label":"C","location":[-18.727298736572267,9.008951187133789,0.0]},{"label":"C","location":[-18.26689910888672,8.286550521850586,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":2,"atoms":[56,54]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,59]},{"type":1,"atoms":[59,57]},{"type":2,"atoms":[57,55]},{"type":1,"atoms":[55,56]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[55,42]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[-33.73990249633789,5.81035041809082,0.0]},{"label":"C","location":[-32.00960159301758,5.810850620269775,0.0]},{"label":"C","location":[-32.873199462890628,6.310450553894043,0.0]},{"label":"C","location":[-32.00960159301758,4.809950351715088,0.0]},{"label":"C","location":[-33.73990249633789,4.805450439453125,0.0]},{"label":"C","location":[-32.871002197265628,4.310450553894043,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[-21.91429901123047,-7.884349822998047,0.0]},{"label":"C","location":[-21.84149742126465,-9.435249328613282,0.0]},{"label":"C","location":[-22.325597763061525,-8.680747985839844,0.0]},{"label":"C","location":[-20.94609832763672,-9.393148422241211,0.0]},{"label":"C","location":[-21.018898010253908,-7.842248916625977,0.0]},{"label":"C","location":[-20.53479766845703,-8.596649169921875,0.0]},{"label":"C","location":[-17.59979820251465,-9.096149444580079,0.0]},{"label":"C","location":[-17.80019760131836,-7.556549072265625,0.0]},{"label":"C","location":[-18.144397735595704,-8.384248733520508,0.0]},{"label":"C","location":[-16.911197662353517,-7.440948486328125,0.0]},{"label":"C","location":[-16.71089744567871,-8.980548858642579,0.0]},{"label":"C","location":[-16.366697311401368,-8.152948379516602,0.0]},{"label":"C","location":[-26.24829864501953,-7.261348724365234,0.0]},{"label":"C","location":[-24.825498580932618,-7.883049011230469,0.0]},{"label":"C","location":[-25.357398986816408,-7.161449432373047,0.0]},{"label":"C","location":[-25.184497833251954,-8.704448699951172,0.0]},{"label":"C","location":[-26.60719871520996,-8.082748413085938,0.0]},{"label":"C","location":[-26.075298309326173,-8.80434799194336,0.0]},{"label":"C","location":[-26.34819793701172,-6.370548248291016,0.0]},{"label":"C","location":[-25.098398208618165,-5.449249267578125,0.0]},{"label":"C","location":[-25.457298278808595,-6.270648956298828,0.0]},{"label":"C","location":[-25.63039779663086,-4.727648735046387,0.0]},{"label":"C","location":[-26.880098342895509,-5.648948669433594,0.0]},{"label":"C","location":[-26.52109718322754,-4.827548980712891,0.0]},{"label":"C","location":[-25.37129783630371,-3.015448570251465,0.0]},{"label":"C","location":[-26.62099838256836,-3.936748504638672,0.0]},{"label":"C","location":[-25.73019790649414,-3.8368492126464845,0.0]},{"label":"C","location":[-27.15289878845215,-3.21514892578125,0.0]},{"label":"C","location":[-25.903297424316408,-2.2939491271972658,0.0]},{"label":"C","location":[-26.794097900390626,-2.393848419189453,0.0]},{"label":"C","location":[-12.221097946166993,-6.484048843383789,0.0]},{"label":"C","location":[-13.770998001098633,-6.393449783325195,0.0]},{"label":"C","location":[-12.969797134399414,-5.9913482666015629,0.0]},{"label":"C","location":[-13.823297500610352,-7.288349151611328,0.0]},{"label":"C","location":[-12.273298263549805,-7.378948211669922,0.0]},{"label":"C","location":[-13.07449722290039,-7.781049728393555,0.0]},{"label":"C","location":[-14.921897888183594,-5.099549293518066,0.0]},{"label":"C","location":[-13.371898651123047,-5.190248489379883,0.0]},{"label":"C","location":[-14.173198699951172,-5.592349052429199,0.0]},{"label":"C","location":[-13.319698333740235,-4.29534912109375,0.0]},{"label":"C","location":[-14.869598388671875,-4.20474910736084,0.0]},{"label":"C","location":[-14.068498611450196,-3.802549362182617,0.0]},{"label":"C","location":[-16.020597457885743,-2.910848617553711,0.0]},{"label":"C","location":[-14.470598220825196,-3.001448631286621,0.0]},{"label":"C","location":[-15.271797180175782,-3.4035491943359377,0.0]},{"label":"C","location":[-14.418397903442383,-2.1065492630004885,0.0]},{"label":"C","location":[-15.968297958374024,-2.015949249267578,0.0]},{"label":"C","location":[-15.167098999023438,-1.6138486862182618,0.0]},{"label":"C","location":[-23.05259895324707,-1.953648567199707,0.0]},{"label":"C","location":[-21.693998336791993,-1.2020492553710938,0.0]},{"label":"C","location":[-22.590198516845704,-1.1856489181518555,0.0]},{"label":"C","location":[-21.26009750366211,-1.986349105834961,0.0]},{"label":"C","location":[-22.618497848510743,-2.738048553466797,0.0]},{"label":"C","location":[-21.72229766845703,-2.7543487548828127,0.0]},{"label":"C","location":[-18.7914981842041,-1.7641487121582032,0.0]},{"label":"C","location":[-18.367298126220704,-3.1512489318847658,0.0]},{"label":"C","location":[-18.075597763061525,-2.303548812866211,0.0]},{"label":"C","location":[-19.26359748840332,-3.135648727416992,0.0]},{"label":"C","location":[-19.525798797607423,-2.278449058532715,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[-7.214550018310547,4.877950668334961,0.0]},{"label":"C","location":[-6.213250160217285,4.877950668334961,0.0]},{"label":"C","location":[-6.713850021362305,5.742950439453125,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[-6.206700801849365,-5.808000087738037,0.0]},{"label":"C","location":[-6.210400581359863,-4.812900066375732,0.0]},{"label":"C","location":[-7.218600749969482,-5.79509973526001,0.0]},{"label":"C","location":[-7.221100807189941,-4.812900066375732,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[-1.206700325012207,-0.5011997222900391,0.0]},{"label":"C","location":[-1.2065000534057618,0.5012998580932617,0.0]},{"label":"C","location":[-0.5012998580932617,1.2065000534057618,0.0]},{"label":"C","location":[-0.5010995864868164,-1.2066001892089844,0.0]},{"label":"C","location":[0.5012998580932617,-1.2066001892089844,0.0]},{"label":"C","location":[1.206700325012207,-0.5011997222900391,0.0]},{"label":"C","location":[1.2066001892089844,0.5012998580932617,0.0]},{"label":"C","location":[0.5012998580932617,1.2066001892089844,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.6194000244140627,"y":4.124800205230713,"z":0.0},{"x":4.1194000244140629,"y":4.124800205230713,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":27.17820167541504,"y":19.806150436401368,"z":0.0}},"spine":{"pos":[{"x":26.17820167541504,"y":25.366600036621095,"z":0.0},{"x":26.17820167541504,"y":14.245699882507325,"z":0.0}]},"tails":{"pos":[{"x":25.67820167541504,"y":25.366600036621095,"z":0.0},{"x":25.67820167541504,"y":14.245699882507325,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":21.163801193237306,"y":14.24570083618164,"z":0.0},{"x":22.676902770996095,"y":14.245699882507325,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.7320003509521486,"y":14.24570083618164,"z":0.0},{"x":4.5186004638671879,"y":14.24570083618164,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":21.163801193237306,"y":25.366600036621095,"z":0.0},{"x":22.663801193237306,"y":25.366600036621095,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.232000350952148,"y":25.366600036621095,"z":0.0}},"spine":{"pos":[{"x":3.2320003509521486,"y":27.498849868774415,"z":0.0},{"x":3.2320003509521486,"y":23.234352111816408,"z":0.0}]},"tails":{"pos":[{"x":2.7320003509521486,"y":27.498849868774415,"z":0.0},{"x":2.7320003509521486,"y":23.234352111816408,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.9282002449035645,23.998802185058595,0.0]},{"label":"C","location":[1.4250001907348633,22.46990394592285,0.0]},{"label":"C","location":[1.7320001125335694,23.409202575683595,0.0]},{"label":"C","location":[0.4315004348754883,22.46990394592285,0.0]},{"label":"C","location":[0.12430000305175781,23.409202575683595,0.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]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.0,27.99880027770996,0.0]},{"label":"C","location":[0.0,26.99880027770996,0.0]},{"label":"C","location":[0.8659999966621399,26.49880027770996,0.0]},{"label":"C","location":[1.7320001125335694,26.99880027770996,0.0]},{"label":"C","location":[1.7320001125335694,27.99880027770996,0.0]},{"label":"C","location":[0.8659999966621399,28.498899459838868,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[10.600299835205079,11.232000350952149,0.0]},{"label":"C","location":[10.665599822998047,9.749600410461426,0.0]},{"label":"C","location":[10.205100059509278,10.47189998626709,0.0]},{"label":"C","location":[11.521400451660157,9.787300109863282,0.0]},{"label":"C","location":[11.456100463867188,11.269599914550782,0.0]},{"label":"C","location":[11.91670036315918,10.547300338745118,0.0]},{"label":"C","location":[14.806600570678711,10.063600540161133,0.0]},{"label":"C","location":[14.63230037689209,11.53700065612793,0.0]},{"label":"C","location":[14.294099807739258,10.75,0.0]},{"label":"C","location":[15.482999801635743,11.637700080871582,0.0]},{"label":"C","location":[15.657299995422364,10.164199829101563,0.0]},{"label":"C","location":[15.995500564575196,10.951200485229493,0.0]},{"label":"C","location":[6.417099952697754,11.89780044555664,0.0]},{"label":"C","location":[7.782000541687012,11.31570053100586,0.0]},{"label":"C","location":[7.267600059509277,12.000800132751465,0.0]},{"label":"C","location":[7.445899963378906,10.527800559997559,0.0]},{"label":"C","location":[6.081200122833252,11.10990047454834,0.0]},{"label":"C","location":[6.5954999923706059,10.424799919128418,0.0]},{"label":"C","location":[6.314300537109375,12.748200416564942,0.0]},{"label":"C","location":[7.500699996948242,13.639100074768067,0.0]},{"label":"C","location":[7.164600372314453,12.851200103759766,0.0]},{"label":"C","location":[6.986400604248047,14.324199676513672,0.0]},{"label":"C","location":[5.799900054931641,13.433300018310547,0.0]},{"label":"C","location":[6.135900497436523,14.221200942993164,0.0]},{"label":"C","location":[7.219500541687012,15.96250057220459,0.0]},{"label":"C","location":[6.032900333404541,15.071599960327149,0.0]},{"label":"C","location":[6.883399963378906,15.174600601196289,0.0]},{"label":"C","location":[5.5186004638671879,15.75670051574707,0.0]},{"label":"C","location":[6.705100059509277,16.647600173950197,0.0]},{"label":"C","location":[5.854700088500977,16.544599533081056,0.0]},{"label":"C","location":[20.163799285888673,12.494300842285157,0.0]},{"label":"C","location":[18.81920051574707,13.121400833129883,0.0]},{"label":"C","location":[19.672500610351564,13.196000099182129,0.0]},{"label":"C","location":[18.45709991455078,12.345000267028809,0.0]},{"label":"C","location":[19.801799774169923,11.717900276184082,0.0]},{"label":"C","location":[18.948501586914064,11.643301010131836,0.0]},{"label":"C","location":[18.25320053100586,14.67650032043457,0.0]},{"label":"C","location":[19.597900390625,14.049400329589844,0.0]},{"label":"C","location":[18.74449920654297,13.974800109863282,0.0]},{"label":"C","location":[19.95989990234375,14.825700759887696,0.0]},{"label":"C","location":[18.61520004272461,15.452800750732422,0.0]},{"label":"C","location":[19.46860122680664,15.52750015258789,0.0]},{"label":"C","location":[18.049301147460939,17.00790023803711,0.0]},{"label":"C","location":[19.394001007080079,16.380901336669923,0.0]},{"label":"C","location":[18.54050064086914,16.30620002746582,0.0]},{"label":"C","location":[19.756000518798829,17.15730094909668,0.0]},{"label":"C","location":[18.411300659179689,17.784299850463868,0.0]},{"label":"C","location":[19.264699935913087,17.85900115966797,0.0]},{"label":"C","location":[9.548900604248047,17.375999450683595,0.0]},{"label":"C","location":[10.686200141906739,18.328899383544923,0.0]},{"label":"C","location":[9.842500686645508,18.180700302124025,0.0]},{"label":"C","location":[11.236400604248047,17.672300338745118,0.0]},{"label":"C","location":[10.099000930786133,16.71929931640625,0.0]},{"label":"C","location":[10.942700386047364,16.867401123046876,0.0]},{"label":"C","location":[14.052900314331055,18.704200744628908,0.0]},{"label":"C","location":[15.369100570678711,18.019399642944337,0.0]},{"label":"C","location":[14.908599853515625,18.74180030822754,0.0]},{"label":"C","location":[14.973800659179688,17.2593994140625,0.0]},{"label":"C","location":[13.657600402832032,17.94420051574707,0.0]},{"label":"C","location":[14.118000030517579,17.221799850463868,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":2,"atoms":[56,54]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,59]},{"type":1,"atoms":[59,57]},{"type":2,"atoms":[57,55]},{"type":1,"atoms":[55,56]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[55,42]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[0.00170135498046875,14.745601654052735,0.0]},{"label":"C","location":[1.7320013046264649,14.746101379394532,0.0]},{"label":"C","location":[0.8684015274047852,15.245701789855957,0.0]},{"label":"C","location":[1.7320013046264649,13.745201110839844,0.0]},{"label":"C","location":[0.00170135498046875,13.740701675415039,0.0]},{"label":"C","location":[0.8706011772155762,13.245701789855957,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[10.470600128173829,22.792699813842775,0.0]},{"label":"C","location":[10.543401718139649,21.24180030822754,0.0]},{"label":"C","location":[10.059301376342774,21.996301651000978,0.0]},{"label":"C","location":[11.438800811767579,21.28390121459961,0.0]},{"label":"C","location":[11.36600112915039,22.834800720214845,0.0]},{"label":"C","location":[11.850101470947266,22.080400466918947,0.0]},{"label":"C","location":[14.785100936889649,21.580900192260743,0.0]},{"label":"C","location":[14.584701538085938,23.120500564575197,0.0]},{"label":"C","location":[14.240501403808594,22.292800903320314,0.0]},{"label":"C","location":[15.473701477050782,23.236101150512697,0.0]},{"label":"C","location":[15.674001693725586,21.696500778198243,0.0]},{"label":"C","location":[16.01820182800293,22.52410125732422,0.0]},{"label":"C","location":[6.136600494384766,23.415700912475587,0.0]},{"label":"C","location":[7.55940055847168,22.79400062561035,0.0]},{"label":"C","location":[7.027500152587891,23.515600204467775,0.0]},{"label":"C","location":[7.200401306152344,21.97260093688965,0.0]},{"label":"C","location":[5.777700424194336,22.594301223754884,0.0]},{"label":"C","location":[6.309600830078125,21.87270164489746,0.0]},{"label":"C","location":[6.036701202392578,24.306501388549806,0.0]},{"label":"C","location":[7.286500930786133,25.227800369262697,0.0]},{"label":"C","location":[6.927600860595703,24.406400680541993,0.0]},{"label":"C","location":[6.7545013427734379,25.94940185546875,0.0]},{"label":"C","location":[5.504800796508789,25.028100967407228,0.0]},{"label":"C","location":[5.863801956176758,25.84950065612793,0.0]},{"label":"C","location":[7.013601303100586,27.661602020263673,0.0]},{"label":"C","location":[5.7639007568359379,26.74030113220215,0.0]},{"label":"C","location":[6.654701232910156,26.840200424194337,0.0]},{"label":"C","location":[5.232000350952148,27.46190071105957,0.0]},{"label":"C","location":[6.481601715087891,28.383100509643556,0.0]},{"label":"C","location":[5.590801239013672,28.283201217651368,0.0]},{"label":"C","location":[20.163801193237306,24.19300079345703,0.0]},{"label":"C","location":[18.613901138305665,24.283599853515626,0.0]},{"label":"C","location":[19.415102005004884,24.685701370239259,0.0]},{"label":"C","location":[18.561601638793947,23.388700485229493,0.0]},{"label":"C","location":[20.111600875854493,23.2981014251709,0.0]},{"label":"C","location":[19.310401916503908,22.895999908447267,0.0]},{"label":"C","location":[17.463001251220704,25.577499389648439,0.0]},{"label":"C","location":[19.01300048828125,25.486801147460939,0.0]},{"label":"C","location":[18.211700439453126,25.084701538085939,0.0]},{"label":"C","location":[19.065200805664064,26.38170051574707,0.0]},{"label":"C","location":[17.515300750732423,26.472301483154298,0.0]},{"label":"C","location":[18.3164005279541,26.874500274658204,0.0]},{"label":"C","location":[16.364301681518556,27.76620101928711,0.0]},{"label":"C","location":[17.9143009185791,27.675601959228517,0.0]},{"label":"C","location":[17.113101959228517,27.273500442504884,0.0]},{"label":"C","location":[17.966501235961915,28.570499420166017,0.0]},{"label":"C","location":[16.416601181030275,28.661100387573243,0.0]},{"label":"C","location":[17.21780014038086,29.063201904296876,0.0]},{"label":"C","location":[9.332300186157227,28.723400115966798,0.0]},{"label":"C","location":[10.690900802612305,29.475000381469728,0.0]},{"label":"C","location":[9.794700622558594,29.49140167236328,0.0]},{"label":"C","location":[11.124801635742188,28.69070053100586,0.0]},{"label":"C","location":[9.766401290893555,27.939001083374025,0.0]},{"label":"C","location":[10.662601470947266,27.922700881958009,0.0]},{"label":"C","location":[13.593400955200196,28.912900924682618,0.0]},{"label":"C","location":[14.017601013183594,27.525800704956056,0.0]},{"label":"C","location":[14.309301376342774,28.37350082397461,0.0]},{"label":"C","location":[13.121301651000977,27.541400909423829,0.0]},{"label":"C","location":[12.859100341796875,28.398601531982423,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[0.8097000122070313,4.89484977722168,0.0]},{"label":"C","location":[1.3101005554199219,3.3547496795654299,0.0]},{"label":"C","location":[1.6194000244140626,4.3009490966796879,0.0]},{"label":"C","location":[0.3094005584716797,3.3547496795654299,0.0]},{"label":"C","location":[0.0,4.3009490966796879,0.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]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[23.676902770996095,13.813199996948243,0.0]},{"label":"C","location":[24.678203582763673,13.813199996948243,0.0]},{"label":"C","location":[24.177602767944337,14.678199768066407,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[24.67820167541504,24.869050979614259,0.0]},{"label":"C","location":[24.674501419067384,25.864151000976564,0.0]},{"label":"C","location":[23.666301727294923,24.88195037841797,0.0]},{"label":"C","location":[23.663801193237306,25.864151000976564,0.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":[10.357999801635743,1.5508995056152344,0.0]},{"label":"C","location":[10.430801391601563,0.0,0.0]},{"label":"C","location":[9.946701049804688,0.7545013427734375,0.0]},{"label":"C","location":[11.326200485229493,0.04210090637207031,0.0]},{"label":"C","location":[11.253400802612305,1.5930004119873047,0.0]},{"label":"C","location":[11.73750114440918,0.8386001586914063,0.0]},{"label":"C","location":[14.672500610351563,0.3390998840332031,0.0]},{"label":"C","location":[14.472101211547852,1.8787002563476563,0.0]},{"label":"C","location":[14.127901077270508,1.0510005950927735,0.0]},{"label":"C","location":[15.361101150512696,1.9943008422851563,0.0]},{"label":"C","location":[15.5614013671875,0.4547004699707031,0.0]},{"label":"C","location":[15.905601501464844,1.2823009490966797,0.0]},{"label":"C","location":[6.02400016784668,2.173900604248047,0.0]},{"label":"C","location":[7.446800231933594,1.5522003173828126,0.0]},{"label":"C","location":[6.914899826049805,2.2737998962402345,0.0]},{"label":"C","location":[7.087800979614258,0.7308006286621094,0.0]},{"label":"C","location":[5.66510009765625,1.3525009155273438,0.0]},{"label":"C","location":[6.197000503540039,0.6309013366699219,0.0]},{"label":"C","location":[5.924100875854492,3.0647010803222658,0.0]},{"label":"C","location":[7.173900604248047,3.9860000610351564,0.0]},{"label":"C","location":[6.815000534057617,3.164600372314453,0.0]},{"label":"C","location":[6.641901016235352,4.7076005935668949,0.0]},{"label":"C","location":[5.392200469970703,3.7863006591796877,0.0]},{"label":"C","location":[5.751201629638672,4.607700347900391,0.0]},{"label":"C","location":[6.9010009765625,6.419800758361816,0.0]},{"label":"C","location":[5.651300430297852,5.498500823974609,0.0]},{"label":"C","location":[6.54210090637207,5.598400115966797,0.0]},{"label":"C","location":[5.1194000244140629,6.220100402832031,0.0]},{"label":"C","location":[6.369001388549805,7.141300201416016,0.0]},{"label":"C","location":[5.478200912475586,7.041400909423828,0.0]},{"label":"C","location":[20.05120086669922,2.951200485229492,0.0]},{"label":"C","location":[18.501300811767579,3.041799545288086,0.0]},{"label":"C","location":[19.302501678466798,3.4439010620117189,0.0]},{"label":"C","location":[18.44900131225586,2.146900177001953,0.0]},{"label":"C","location":[19.999000549316408,2.0563011169433595,0.0]},{"label":"C","location":[19.19780158996582,1.6541996002197266,0.0]},{"label":"C","location":[17.350400924682618,4.335700035095215,0.0]},{"label":"C","location":[18.900400161743165,4.245000839233398,0.0]},{"label":"C","location":[18.09910011291504,3.842900276184082,0.0]},{"label":"C","location":[18.952600479125978,5.139900207519531,0.0]},{"label":"C","location":[17.402700424194337,5.230500221252441,0.0]},{"label":"C","location":[18.203800201416017,5.632699966430664,0.0]},{"label":"C","location":[16.25170135498047,6.52440071105957,0.0]},{"label":"C","location":[17.801700592041017,6.43380069732666,0.0]},{"label":"C","location":[17.00050163269043,6.031700134277344,0.0]},{"label":"C","location":[17.853900909423829,7.328700065612793,0.0]},{"label":"C","location":[16.304000854492189,7.419300079345703,0.0]},{"label":"C","location":[17.105199813842775,7.8214006423950199,0.0]},{"label":"C","location":[9.21969985961914,7.481600761413574,0.0]},{"label":"C","location":[10.578300476074219,8.233200073242188,0.0]},{"label":"C","location":[9.682100296020508,8.249600410461426,0.0]},{"label":"C","location":[11.012201309204102,7.44890022277832,0.0]},{"label":"C","location":[9.653800964355469,6.697200775146484,0.0]},{"label":"C","location":[10.55000114440918,6.680900573730469,0.0]},{"label":"C","location":[13.48080062866211,7.671100616455078,0.0]},{"label":"C","location":[13.905000686645508,6.284000396728516,0.0]},{"label":"C","location":[14.196701049804688,7.13170051574707,0.0]},{"label":"C","location":[13.00870132446289,6.299600601196289,0.0]},{"label":"C","location":[12.746500015258789,7.156800270080566,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[28.17820167541504,19.304950714111329,0.0]},{"label":"C","location":[28.178401947021486,20.307449340820314,0.0]},{"label":"C","location":[28.883602142333986,21.012649536132814,0.0]},{"label":"C","location":[28.88380241394043,18.59954833984375,0.0]},{"label":"C","location":[29.886201858520509,18.59954833984375,0.0]},{"label":"C","location":[30.591602325439454,19.304950714111329,0.0]},{"label":"C","location":[30.591503143310548,20.307449340820314,0.0]},{"label":"C","location":[29.886201858520509,21.01274871826172,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]}} \ No newline at end of file diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index 2bbf41cffe..c8ba9234db 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -21,11 +21,12 @@ #include #include +#include +#include +#include #include #include #include -#include -#include #include "reaction/pathway_reaction.h" @@ -43,11 +44,19 @@ namespace indigo void make(); private: + static constexpr float MARGIN = 1.f; + static constexpr float ARROW_HEAD_WIDTH = 2.5f; + static constexpr float ARROW_TAIL_LENGTH = 0.5f; + static constexpr float ARROW_LENGTH = ARROW_TAIL_LENGTH + ARROW_TAIL_LENGTH; + static constexpr float HORIZONTAL_SPACING = 3.5f; + static constexpr float VERTICAL_SPACING = 2.5f; + static constexpr float MULTIPATHWAY_VERTICAL_SPACING = 1.5f; + struct PathwayLayoutItem { PathwayLayoutItem(PathwayReaction& pwr, int nodeIdx, int reactantIdx = -1) - : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), x(0.0), y(0.0), ancestor(this), thread(nullptr), - children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr), reaction(pwr) + : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), ancestor(this), thread(nullptr), children(), + parent(nullptr), nextSibling(nullptr), prevSibling(nullptr), reaction(pwr) { auto& rn = reaction.getReactionNode(nodeIdx); auto& sr = reaction.getReaction(rn.reactionIdx); @@ -68,6 +77,10 @@ namespace indigo auto& mol = reaction.getMolecule(pidx); Rect2f bbox; mol.getBoundingBox(bbox); + if (molecules.size()) + { + width += MARGIN; + } molecules.push_back(std::make_pair(pidx, bbox)); width += bbox.width(); // add some spacing for plus height = std::max(bbox.height(), height); @@ -119,19 +132,23 @@ namespace indigo [](float acc, const std::pair& r) { return acc + r.second.width(); }); float spacing = molecules.size() > 1 ? (width - totalWidth) / (molecules.size() - 1) : (width - totalWidth) / 2; - float currentX = x; - float currentY = y; + float currentX = bbox.left(); + float currentY = bbox.bottom(); for (auto& mol_desc : molecules) { auto& mol = reaction.getMolecule(mol_desc.first); - std::cout << "mol index: " << mol_desc.first << std::endl; - Vec2f item_offset(currentX - mol_desc.second.center().x, currentY - mol_desc.second.center().y); + Vec2f item_offset(currentX - mol_desc.second.left(), currentY - mol_desc.second.bottom()); mol.offsetCoordinates(Vec3f(item_offset.x, item_offset.y, 0)); currentX += mol_desc.second.width() + spacing; } } } + void setXY(float x, float y) + { + bbox = Rect2f(Vec2f(x - width, y - height / 2), Vec2f(x, y + height / 2)); + } + // required for the layout algorithm float width, height; std::vector children; @@ -143,13 +160,16 @@ namespace indigo // computed fields int number; float prelim, mod, shift, change; - float x, y; PathwayLayoutItem* ancestor; PathwayLayoutItem* thread; // other data std::vector> molecules; PathwayReaction& reaction; + Rect2f bbox; + + private: + // float x, y; }; struct PathwayLayoutRootItem @@ -162,16 +182,11 @@ namespace indigo std::vector li_items; }; - std::vector traverse(PathwayLayoutItem* root); - - void dumpLayoutItem(const PathwayLayout::PathwayLayoutItem& li) - { - std::cout << "Layout Item: " << li.x << " " << li.y << " " << li.width << " " << li.height << std::endl; - } + void traverse(PathwayLayoutItem* root, std::function node_processor); float spacing(PathwayLayoutItem* top, PathwayLayoutItem* bottom, bool siblings) { - return 1.0f + (top->height + bottom->height) / 2.0f; + return VERTICAL_SPACING + (top->height + bottom->height) / 2.0f; } void updateDepths(int depth, PathwayLayoutItem* item); diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index bbf87c0b66..9c3da1c171 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -19,6 +19,7 @@ #include #include "layout/pathway_layout.h" +#include "molecule/ket_commons.h" using namespace indigo; @@ -32,7 +33,6 @@ void PathwayLayout::make() float yShift = 0; for (auto rri : roots) { - std::cout << "Root node: " << rri << std::endl; auto& li_root = _layoutRootItems.emplace_back(rri); PathwayLayoutItem* root = &_layoutItems[rri]; _depths.clear(); @@ -42,50 +42,29 @@ void PathwayLayout::make() firstWalk(root, 0, 1); determineDepths(); secondWalk(root, nullptr, -root->prelim, 0); - li_root.li_items = traverse(root); - std::cout << "Number of items: " << li_root.li_items.size() << std::endl; + + traverse(root, [&li_root](PathwayLayoutItem* item) { li_root.li_items.push_back(item); }); + // calculating bounding box for the one pathway auto& li_items = li_root.li_items; Rect2f pw_bbox; for (auto i = 0; i < li_items.size(); ++i) { auto& li = *li_items[i]; - Rect2f item_bbox(Vec2f(li.x - li.width / 2, li.y - li.height / 2), Vec2f(li.x + li.width / 2, li.y + li.height / 2)); - std::cout << "bbox: " << item_bbox.left() << " " << item_bbox.bottom() << " " << item_bbox.right() << " " << item_bbox.top() << std::endl; if (i) - pw_bbox.extend(item_bbox); + pw_bbox.extend(li.bbox); else - pw_bbox = item_bbox; + pw_bbox = li.bbox; } li_root.bbox = pw_bbox; - if (rri == 5) - { - _log_file << "" - << std::endl; - for (auto i = 0; i < li_items.size(); ++i) - { - auto& li = *li_items[i]; - Rect2f item_bbox(Vec2f(li.x - li.width / 2, li.y - li.height / 2), Vec2f(li.x + li.width / 2, li.y + li.height / 2)); - _log_file << "" << std::endl; - } - - _log_file << "" << std::endl; - _log_file.close(); - } - for (auto i = 0; i < li_items.size(); ++i) { auto& li = *li_items[i]; - li.x -= pw_bbox.left(); - li.y -= pw_bbox.bottom() + yShift; + li.bbox.offset(Vec2f(-pw_bbox.left(), -pw_bbox.bottom() + yShift)); } - yShift += pw_bbox.height(); + yShift += pw_bbox.height() + MULTIPATHWAY_VERTICAL_SPACING; } - applyLayout(); } @@ -121,12 +100,11 @@ void PathwayLayout::buildLayoutTree() void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) { - float d = item->width + 1.0f; + float d = item->width + HORIZONTAL_SPACING; if (_depths.size() <= depth) _depths.resize(3 * depth / 2); _depths[depth] = std::max(_depths[depth], d); _maxDepth = std::max(_maxDepth, depth); - std::cout << "Depth: " << depth << " width: " << _depths[depth] << std::endl; } void PathwayLayout::determineDepths() @@ -175,29 +153,58 @@ void PathwayLayout::firstWalk(PathwayLayoutItem* n, int num, int depth) void PathwayLayout::secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth) { - n->y = n->prelim + m; - - n->x = -(_shifts[depth] + _depths[depth + 1] / 2); - - std::cout << "depth:" << depth << " n->x " << n->x << " width:" << n->width << std::endl; - + n->setXY(-_shifts[depth], n->prelim + m); for (PathwayLayoutItem* c = n->getFirstChild(); c != nullptr; c = c->nextSibling) - { secondWalk(c, n, m + n->mod, depth + 1); - } - n->clear(); } void PathwayLayout::applyLayout() { // upload coordinates back to the reaction + _reaction.meta().resetReactionData(); for (auto& li_root : _layoutRootItems) { - std::cout << " root:" << li_root.root_index << " count:" << li_root.li_items.size() << std::endl; auto& li_items = li_root.li_items; for (auto li : li_items) li->applyLayout(); + + for (auto li : li_items) + { + // connect reactants with products + if (!li->children.empty()) + { + Vec2f head = li->bbox.leftMiddle(); + head.x -= MARGIN; + std::vector tails, arrows; + arrows.push_back(head); + for (auto c : li->children) + { + Vec2f tail = c->bbox.rightMiddle(); + auto tail_it = std::lower_bound(tails.begin(), tails.end(), tail, [](const Vec2f& a, const Vec2f& b) { return a.y > b.y; }); + tails.insert(tail_it, tail); + } + auto rigt_most_x = std::max_element(tails.begin(), tails.end(), [](const Vec2f& a, const Vec2f& b) { return a.x < b.x; })->x; + rigt_most_x += MARGIN; + + std::for_each(tails.begin(), tails.end(), [rigt_most_x](Vec2f& v) { v.x = rigt_most_x; }); + arrows.insert(arrows.end(), tails.begin(), tails.end()); + + // add spines + if (tails.size() > 1) + { + Vec2f spineTop(tails.front().x + ARROW_TAIL_LENGTH, tails.front().y); + Vec2f spineBottom(tails.back().x + ARROW_TAIL_LENGTH, tails.back().y); + arrows.push_back(spineBottom); + arrows.push_back(spineTop); + _reaction.meta().addMetaObject(new KETReactionMultitailArrow(arrows.begin(), arrows.end())); + } + else if (tails.size()) + { + _reaction.meta().addMetaObject(new KETReactionArrow(KETReactionArrow::EOpenAngle, tails.front(), head)); + } + } + } } } @@ -288,22 +295,20 @@ PathwayLayout::PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim return (vim->ancestor->parent == p) ? vim->ancestor : a; } -std::vector PathwayLayout::traverse(PathwayLayoutItem* root) +void PathwayLayout::traverse(PathwayLayoutItem* root, std::function node_processor) { - std::vector result; std::stack stack; if (root != nullptr) - { stack.push(root); - } while (!stack.empty()) { PathwayLayoutItem* node = stack.top(); + // call lambda here stack.pop(); - result.push_back(node); + node_processor(node); std::for_each(node->children.rbegin(), node->children.rend(), [&stack](PathwayLayoutItem* child) { stack.push(child); }); } - return result; + // return result; } diff --git a/core/indigo-core/layout/src/reaction_layout.cpp b/core/indigo-core/layout/src/reaction_layout.cpp index f365fdefd4..23b39ae5a0 100644 --- a/core/indigo-core/layout/src/reaction_layout.cpp +++ b/core/indigo-core/layout/src/reaction_layout.cpp @@ -43,6 +43,7 @@ void ReactionLayout::fixLayout() Vec2f rmax{Vec2f::min_coord(), Vec2f::min_coord()}, pmin{Vec2f::max_coord(), Vec2f::max_coord()}; Rect2f bb; // Calculate rightTop of reactant bounding box + for (int i = _r.reactantBegin(); i != _r.reactantEnd(); i = _r.reactantNext(i)) { _r.getBaseMolecule(i).getBoundingBox(bb); diff --git a/core/indigo-core/reaction/pathway_reaction.h b/core/indigo-core/reaction/pathway_reaction.h index 025478d617..d63e86836f 100644 --- a/core/indigo-core/reaction/pathway_reaction.h +++ b/core/indigo-core/reaction/pathway_reaction.h @@ -24,7 +24,7 @@ #endif #include "base_cpp/array.h" -#include "reaction/base_reaction.h" +#include "reaction/reaction.h" #include namespace indigo @@ -136,6 +136,12 @@ namespace indigo return static_cast(_reactions.size()); } + Reaction& asReaction() override + { + _rootReaction.clone(*this); + return _rootReaction; + } + ReactionNode& addReactionNode() { ReactionNode rn; @@ -171,6 +177,7 @@ namespace indigo ObjArray _reactionNodes; PtrArray _molecules; ObjArray _reactions; + Reaction _rootReaction; }; } // namespace indigo diff --git a/core/indigo-core/reaction/pathway_reaction_builder.h b/core/indigo-core/reaction/pathway_reaction_builder.h index 44dcc91c6b..d281e46cfa 100644 --- a/core/indigo-core/reaction/pathway_reaction_builder.h +++ b/core/indigo-core/reaction/pathway_reaction_builder.h @@ -24,14 +24,13 @@ #pragma warning(disable : 4251) #endif +#include +#include #include #include #include #include #include -#include -#include -#include #include "base_cpp/exception.h" #include "molecule/ket_commons.h" @@ -52,15 +51,12 @@ namespace indigo DECL_ERROR; private: - struct ReactionInchiDescriptor { - // std::unordered_set reactants; std::vector products; // useful to collect it here to avoid look them up in the reaction object std::vector productIndexes; std::vector reactantIndexes; - // std::map> successor; // productIndexes <-> successor }; void buildInchiDescriptors(std::deque& reactions); @@ -68,11 +64,10 @@ namespace indigo auto findSuccessorReactions(int reactionIdx); void buildReactions(std::deque& reactions); - std::vector _reactionInchiDescriptors; std::unordered_map> _reactantToReactions; std::unique_ptr _pathwayReaction; - std::unordered_map< std::pair, int, pair_hash> _moleculeMapping; + std::unordered_map, int, pair_hash> _moleculeMapping; }; } // namespace indigo diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 3761922a26..2fa45750e4 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -65,7 +65,7 @@ auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) std::inserter(intersection, intersection.begin()), [](const auto& a, const auto& b) { return a.first < b.first; }); for (auto& [key, values] : intersection) - values.insert(values.end(), intersection.at(key).begin(), intersection.at(key).end()); + values.insert(values.end(), reactionReactantIndexes.at(key).begin(), reactionReactantIndexes.at(key).end()); matchedReactions = std::move(intersection); // we need at least one reaction where all products are reactants @@ -151,19 +151,13 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) auto matching_successor = findSuccessorReactions(i); // iterate over products of the reaction auto& productIndexes = _reactionInchiDescriptors[i].productIndexes; - for (auto j = 0; j < productIndexes.size(); ++j) - { - auto pidx = productIndexes[j]; - int mol_idx = matching_successor.empty() - ? _pathwayReaction->addMolecule(reactions[i].getBaseMolecule(pidx).asMolecule()) - : _moleculeMapping.at(std::make_pair(matching_successor.begin()->first, matching_successor.begin()->second[j])); - _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, pidx), std::forward_as_tuple(mol_idx)); - } auto& rn = _pathwayReaction->getReactionNode(i); - - for (auto& [j, val] : matching_successor) // [j, val] - j is the index of the matched sucessor reaction, val is the vector of reactant indexes + for (auto m_it = matching_successor.begin(); + m_it != matching_successor.end();) // [j, val] - j is the index of the matched sucessor reaction, val is the vector of reactant indexes { + auto j = m_it->first; + auto& val = m_it->second; Array val_arr; val_arr.copy(val); if (rn.successorReactions.size() == 0) @@ -179,6 +173,7 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) } if (!found) { + m_it++; rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); rnj.precursorReactionsIndexes.push(i); for (auto ridx : val) @@ -186,16 +181,27 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) } else { + m_it = matching_successor.erase(m_it); // it's impossible that a reactant has multiple precursors. // we can handle this case if needed. } } else { - // only one successor reaction is allowed for a reaction. + m_it = matching_successor.erase(m_it); + // only one successor reaction is allowed for a reaction. // we can handle this case if needed. } } + + for (auto j = 0; j < productIndexes.size(); ++j) + { + auto pidx = productIndexes[j]; + int mol_idx = matching_successor.empty() + ? _pathwayReaction->addMolecule(reactions[i].getBaseMolecule(pidx).asMolecule()) + : _moleculeMapping.at(std::make_pair(matching_successor.begin()->first, matching_successor.begin()->second[j])); + _moleculeMapping.emplace(std::piecewise_construct, std::forward_as_tuple(i, pidx), std::forward_as_tuple(mol_idx)); + } } } @@ -207,7 +213,21 @@ std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(st auto& rr = _pathwayReaction->getRootReactions(); PathwayLayout pl(*_pathwayReaction); pl.make(); + if (rr.size()) + { + auto& first_root = _pathwayReaction->getReaction(rr.back()); + for (auto& idx : first_root.reactantIndexes) + { + auto& mol = _pathwayReaction->getMolecule(idx); + _pathwayReaction->addReactantCopy(mol, 0, 0); + } + + for (auto& idx : first_root.productIndexes) + { + auto& mol = _pathwayReaction->getMolecule(idx); + _pathwayReaction->addProductCopy(mol, 0, 0); + } + } - std::cout << "root nodes: " << rr.size() << std::endl; return std::move(_pathwayReaction); } \ No newline at end of file diff --git a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp index 9bf7744203..5fc23181d6 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp @@ -40,7 +40,7 @@ void PathwayReactionJsonSaver::saveReaction(PathwayReaction& pwr) auto& molecule = pwr.getMolecule(i); merged->mergeWithMolecule(molecule, 0, 0); } - + merged->meta().clone(pwr.meta()); rapidjson::StringBuffer buffer; JsonWriter writer(pretty_json); writer.Reset(buffer); @@ -48,43 +48,4 @@ void PathwayReactionJsonSaver::saveReaction(PathwayReaction& pwr) moleculeSaver.add_stereo_desc = add_stereo_desc; moleculeSaver.saveMolecule(*merged, writer); _output.printf("%s", buffer.GetString()); - - // auto reaction = std::make_unique(); - //reaction->clone(rxn); - - //std::vector> points; - //std::vector> arrows; - //// std::tie(points, arrows) = reaction->makeTreePoints(); - //// Ensure the same order across different platforms. - //std::sort(points.begin(), points.end()); - - //for (auto& p : points) - //{ - // auto& molecule = reaction->getBaseMolecule(p.first); - // Rect2f box; - // molecule.getBoundingBox(box); - // auto offset = box.center(); - // offset.negate(); - // offset.add(p.second); - // for (int j = molecule.vertexBegin(); j != molecule.vertexEnd(); j = molecule.vertexNext(j)) - // { - // Vec3f& xyz = molecule.getAtomXyz(j); - // xyz.add(offset); - // } - // merged->mergeWithMolecule(molecule, 0, 0); - //} - - //for (auto& a : arrows) - // if (a.size() > 2) - // merged->meta().addMetaObject(new KETReactionMultitailArrow(a.begin(), a.end())); - // else if (a.size() == 2) - // merged->meta().addMetaObject(new KETReactionArrow(KETReactionArrow::EOpenAngle, a.back(), a.front())); - - //rapidjson::StringBuffer buffer; - //JsonWriter writer(pretty_json); - //writer.Reset(buffer); - //MoleculeJsonSaver moleculeSaver(_output); - //moleculeSaver.add_stereo_desc = add_stereo_desc; - //moleculeSaver.saveMolecule(*merged, writer); - //_output.printf("%s", buffer.GetString()); } diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 455a80b135..c2cd27f850 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1058,7 +1058,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 0167a3f18dc74ec3be4601e5e3cd0c5d7725e7d5 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 19:55:48 +0200 Subject: [PATCH 13/25] clang format --- api/c/indigo/src/indigo_layout.cpp | 3 ++- api/c/indigo/src/indigo_savers.cpp | 4 ++-- core/indigo-core/molecule/ket_commons.h | 1 - core/indigo-core/molecule/src/base_molecule.cpp | 2 +- core/indigo-core/molecule/src/metadata_storage.cpp | 11 ++++++----- core/indigo-core/reaction/base_reaction.h | 2 ++ .../reaction/reaction_multistep_detector.h | 4 ++-- core/indigo-core/reaction/src/base_reaction.cpp | 6 ++++++ .../indigo-core/reaction/src/reaction_auto_loader.cpp | 2 +- .../indigo-core/reaction/src/reaction_json_loader.cpp | 2 +- .../reaction/src/reaction_multistep_detector.cpp | 5 ++--- 11 files changed, 25 insertions(+), 17 deletions(-) diff --git a/api/c/indigo/src/indigo_layout.cpp b/api/c/indigo/src/indigo_layout.cpp index c662aade0b..d27ff4aa0d 100644 --- a/api/c/indigo/src/indigo_layout.cpp +++ b/api/c/indigo/src/indigo_layout.cpp @@ -101,7 +101,8 @@ CEXPORT int indigoLayout(int object) else if (IndigoBaseReaction::is(obj)) { BaseReaction& rxn = obj.getBaseReaction(); - bool no_layout = rxn.intermediateCount() || rxn.specialConditionsCount() || rxn.meta().getNonChemicalMetaCount(); + bool no_layout = rxn.intermediateCount() || rxn.specialConditionsCount() || rxn.meta().getNonChemicalMetaCount() || + obj.type == IndigoObject::PATHWAY_REACTION || rxn.multitaleCount(); if (!no_layout) { ReactionLayout rl(rxn, self.smart_layout); diff --git a/api/c/indigo/src/indigo_savers.cpp b/api/c/indigo/src/indigo_savers.cpp index 481f02c1a8..5538b79a2c 100644 --- a/api/c/indigo/src/indigo_savers.cpp +++ b/api/c/indigo/src/indigo_savers.cpp @@ -32,14 +32,14 @@ #include "molecule/sequence_saver.h" #include "molecule/smiles_saver.h" #include "reaction/canonical_rsmiles_saver.h" +#include "reaction/pathway_reaction.h" +#include "reaction/pathway_reaction_json_saver.h" #include "reaction/reaction_cdxml_saver.h" #include "reaction/reaction_cml_saver.h" #include "reaction/reaction_json_saver.h" -#include "reaction/pathway_reaction_json_saver.h" #include "reaction/rsmiles_saver.h" #include "reaction/rxnfile_loader.h" #include "reaction/rxnfile_saver.h" -#include "reaction/pathway_reaction.h" #include diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 6416fdeeb6..65d47c37f1 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -484,7 +484,6 @@ namespace indigo if (sorted_pair.first > sorted_pair.second) std::swap(sorted_pair.first, sorted_pair.second); auto c_val = pih(sorted_pair); - std::cout << "hash:" << c_val << std::endl; return c_val; } }; diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index efaf7e93d3..cb4f1af3e9 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -4483,7 +4483,7 @@ void BaseMolecule::setBondCIP(int bond_idx, CIPDesc cip) void BaseMolecule::offsetCoordinates(const Vec3f& offset) { - for (int i = 0; i < _xyz.size(); i++) + for (int i = 0; i < _xyz.size(); i++) _xyz[i].add(offset); } diff --git a/core/indigo-core/molecule/src/metadata_storage.cpp b/core/indigo-core/molecule/src/metadata_storage.cpp index 0bdc3e7c75..fe94c7fcdb 100644 --- a/core/indigo-core/molecule/src/metadata_storage.cpp +++ b/core/indigo-core/molecule/src/metadata_storage.cpp @@ -30,8 +30,8 @@ int MetaDataStorage::addMetaObject(MetaObject* pobj) _image_indexes.push() = index; break; case KETReactionMultitailArrow::CID: - _multi_tail_indexes.push() = index; - break; + _multi_tail_indexes.push() = index; + break; default: break; } @@ -108,8 +108,8 @@ int MetaDataStorage::getMetaCount(uint32_t meta_type) const return _image_indexes.size(); break; case KETReactionMultitailArrow::CID: - return _multi_tail_indexes.size(); - break; + return _multi_tail_indexes.size(); + break; default: break; } @@ -123,7 +123,8 @@ void MetaDataStorage::resetReactionData() _multi_tail_indexes.clear(); for (int i = _meta_data.size() - 1; i >= 0; i--) { - if (_meta_data[i]->_class_id == KETReactionArrow::CID || _meta_data[i]->_class_id == KETReactionPlus::CID || _meta_data[i]->_class_id == KETReactionMultitailArrow::CID) + if (_meta_data[i]->_class_id == KETReactionArrow::CID || _meta_data[i]->_class_id == KETReactionPlus::CID || + _meta_data[i]->_class_id == KETReactionMultitailArrow::CID) _meta_data.remove(i); } } diff --git a/core/indigo-core/reaction/base_reaction.h b/core/indigo-core/reaction/base_reaction.h index 9f9d03dc8c..80197f38f6 100644 --- a/core/indigo-core/reaction/base_reaction.h +++ b/core/indigo-core/reaction/base_reaction.h @@ -218,6 +218,8 @@ namespace indigo return _intermediateCount; } + int multitaleCount() const; + int reactantsCount() const { return _reactantCount; diff --git a/core/indigo-core/reaction/reaction_multistep_detector.h b/core/indigo-core/reaction/reaction_multistep_detector.h index c99d33d968..121b498899 100644 --- a/core/indigo-core/reaction/reaction_multistep_detector.h +++ b/core/indigo-core/reaction/reaction_multistep_detector.h @@ -24,9 +24,9 @@ #pragma warning(disable : 4251) #endif -#include -#include #include +#include +#include #include "base_cpp/exception.h" #include "molecule/ket_commons.h" diff --git a/core/indigo-core/reaction/src/base_reaction.cpp b/core/indigo-core/reaction/src/base_reaction.cpp index e773372645..94d4541cbe 100644 --- a/core/indigo-core/reaction/src/base_reaction.cpp +++ b/core/indigo-core/reaction/src/base_reaction.cpp @@ -19,6 +19,7 @@ #include "reaction/base_reaction.h" #include "base_cpp/tlscont.h" #include "molecule/molecule_dearom.h" +#include "molecule/ket_commons.h" using namespace indigo; @@ -493,3 +494,8 @@ MetaDataStorage& BaseReaction::meta() { return _meta; } + +int BaseReaction::multitaleCount() const +{ + return _meta.getMetaCount(KETReactionMultitailArrow::CID); +} diff --git a/core/indigo-core/reaction/src/reaction_auto_loader.cpp b/core/indigo-core/reaction/src/reaction_auto_loader.cpp index 3017d7ef32..3aee36dd19 100644 --- a/core/indigo-core/reaction/src/reaction_auto_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_auto_loader.cpp @@ -24,6 +24,7 @@ #include "reaction/icr_loader.h" #include "reaction/icr_saver.h" #include "reaction/pathway_reaction.h" +#include "reaction/pathway_reaction_builder.h" #include "reaction/query_reaction.h" #include "reaction/reaction.h" #include "reaction/reaction_cdxml_loader.h" @@ -31,7 +32,6 @@ #include "reaction/reaction_json_loader.h" #include "reaction/rsmiles_loader.h" #include "reaction/rxnfile_loader.h" -#include "reaction/pathway_reaction_builder.h" using namespace indigo; diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index b3daeb8dfd..bfec827047 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -74,7 +74,7 @@ void ReactionJsonLoader::loadReaction(BaseReaction& rxn) rxn.meta().clone(_pmol->meta()); _pmol->meta().resetMetaData(); - int arrow_count = rxn.meta().getMetaCount(KETReactionArrow::CID); + int arrow_count = rxn.meta().getMetaCount(KETReactionArrow::CID) + rxn.meta().getMetaCount(KETReactionMultitailArrow::CID); if (arrow_count == 0) throw Error("No arrow in the reaction"); diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index a97aefab86..5468ace8d7 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -45,10 +45,9 @@ ReactionMultistepDetector::ReactionMultistepDetector(BaseMolecule& bmol) : _bmol JsonWriter writer(true); writer.Reset(buffer); std::string str_json; - StringOutput output( str_json ); + StringOutput output(str_json); MoleculeJsonSaver moleculeSaver(output); moleculeSaver.saveMolecule(bmol, writer); - std::cout << str_json << std::endl; } void ReactionMultistepDetector::buildReaction(BaseReaction& rxn) @@ -291,7 +290,7 @@ void ReactionMultistepDetector::buildReaction(BaseReaction& rxn) } 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) + const FLOAT_INT_PAIRS& mol_lefts, const FLOAT_INT_PAIRS& mol_rights, std::pair& connection) { auto plus_pos_y = std::make_pair(plus_pos.y, 0); auto plus_pos_x = std::make_pair(plus_pos.x, 0); From 34064a405b49d3443f2b25caff57a6e5d73b7f13 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 19:58:42 +0200 Subject: [PATCH 14/25] clang format --- core/indigo-core/reaction/src/base_reaction.cpp | 2 +- core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/reaction/src/base_reaction.cpp b/core/indigo-core/reaction/src/base_reaction.cpp index 94d4541cbe..0af7c3ea6c 100644 --- a/core/indigo-core/reaction/src/base_reaction.cpp +++ b/core/indigo-core/reaction/src/base_reaction.cpp @@ -18,8 +18,8 @@ #include "reaction/base_reaction.h" #include "base_cpp/tlscont.h" -#include "molecule/molecule_dearom.h" #include "molecule/ket_commons.h" +#include "molecule/molecule_dearom.h" using namespace indigo; diff --git a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp index 5fc23181d6..1d65ebcc2c 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_json_saver.cpp @@ -37,8 +37,8 @@ void PathwayReactionJsonSaver::saveReaction(PathwayReaction& pwr) auto merged = std::make_unique(); for (int i = 0; i < pwr.getMoleculeCount(); ++i) { - auto& molecule = pwr.getMolecule(i); - merged->mergeWithMolecule(molecule, 0, 0); + auto& molecule = pwr.getMolecule(i); + merged->mergeWithMolecule(molecule, 0, 0); } merged->meta().clone(pwr.meta()); rapidjson::StringBuffer buffer; From 019615478c1cdb90e259de375ab5248e87026bc8 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 20:02:37 +0200 Subject: [PATCH 15/25] clang format --- api/tests/integration/tests/reaction/pathway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tests/integration/tests/reaction/pathway.py b/api/tests/integration/tests/reaction/pathway.py index d7a8abe9fa..ce462ea0c5 100644 --- a/api/tests/integration/tests/reaction/pathway.py +++ b/api/tests/integration/tests/reaction/pathway.py @@ -42,7 +42,7 @@ def find_diff(a, b): # file.write(rxn_txt) rxn_ref = open(os.path.join(ref_path, filename) + ".ket", "r").read() - + diff = find_diff(rxn_ref, rxn_txt) if not diff: print(filename + ".rdf:SUCCEED") From 372d4bcbfe33d3163f21263ef6f2c60cc052132d Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 20:29:07 +0200 Subject: [PATCH 16/25] constructor fix --- core/indigo-core/common/base_cpp/obj_array.h | 10 ++++++++++ .../reaction/src/pathway_reaction_builder.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core/indigo-core/common/base_cpp/obj_array.h b/core/indigo-core/common/base_cpp/obj_array.h index 3cfdcc05a7..bf18d8d56c 100644 --- a/core/indigo-core/common/base_cpp/obj_array.h +++ b/core/indigo-core/common/base_cpp/obj_array.h @@ -92,6 +92,16 @@ namespace indigo return _array.top(); } + template + T& push(A a, B& b) + { + void* addr = &_array.push(); + + new (addr) T(a, b); + + return _array.top(); + } + template T& push(A& a, B& b, C& c) { diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 2fa45750e4..c72be6433e 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -174,7 +174,7 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) if (!found) { m_it++; - rn.successorReactions.push(PathwayReaction::SuccessorReaction(j, val_arr)); + rn.successorReactions.push(j, val_arr); rnj.precursorReactionsIndexes.push(i); for (auto ridx : val) rnj.successorReactants.insert(ridx); From 11c3e7b2b4d52c30a115acd9ffb815bfcd853df2 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 20:41:34 +0200 Subject: [PATCH 17/25] const fix --- core/indigo-core/reaction/src/pathway_reaction_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index c72be6433e..9b0161db3e 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -210,7 +210,7 @@ std::unique_ptr PathwayReactionBuilder::buildPathwayReaction(st buildInchiDescriptors(reactions); buildNodes(reactions); buildReactions(reactions); - auto& rr = _pathwayReaction->getRootReactions(); + const auto& rr = _pathwayReaction->getRootReactions(); PathwayLayout pl(*_pathwayReaction); pl.make(); if (rr.size()) From c63b0113b19ac69c78e05da83e968f16793bc848 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 20:58:38 +0200 Subject: [PATCH 18/25] int fix --- core/indigo-core/layout/src/pathway_layout.cpp | 4 ++-- core/indigo-core/reaction/src/pathway_reaction_builder.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index 9c3da1c171..ed38ae054c 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -48,7 +48,7 @@ void PathwayLayout::make() // calculating bounding box for the one pathway auto& li_items = li_root.li_items; Rect2f pw_bbox; - for (auto i = 0; i < li_items.size(); ++i) + for (size_t i = 0; i < li_items.size(); ++i) { auto& li = *li_items[i]; if (i) @@ -58,7 +58,7 @@ void PathwayLayout::make() } li_root.bbox = pw_bbox; - for (auto i = 0; i < li_items.size(); ++i) + for (size_t i = 0; i < li_items.size(); ++i) { auto& li = *li_items[i]; li.bbox.offset(Vec2f(-pw_bbox.left(), -pw_bbox.bottom() + yShift)); diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index 9b0161db3e..edda457076 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -81,7 +81,7 @@ auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) void PathwayReactionBuilder::buildReactions(std::deque& reactions) { - for (int i = 0; i < _reactionInchiDescriptors.size(); ++i) + for (size_t i = 0; i < _reactionInchiDescriptors.size(); ++i) { auto& rid = _reactionInchiDescriptors[i]; auto [sri, sr] = _pathwayReaction->addReaction(); From 64cbed1dbac81995aaf2fdc40a3dcc80562241ef Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 21:05:59 +0200 Subject: [PATCH 19/25] comments fix --- core/indigo-core/layout/pathway_layout.h | 4 ++-- .../reaction/src/reaction_multistep_detector.cpp | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index c8ba9234db..bb3dc56499 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -55,7 +55,7 @@ namespace indigo struct PathwayLayoutItem { PathwayLayoutItem(PathwayReaction& pwr, int nodeIdx, int reactantIdx = -1) - : number(-2), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), ancestor(this), thread(nullptr), children(), + : number(-1), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), ancestor(this), thread(nullptr), children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr), reaction(pwr) { auto& rn = reaction.getReactionNode(nodeIdx); @@ -119,7 +119,7 @@ namespace indigo void clear() { - number = -2; + number = -1; prelim = mod = shift = change = 0.0; ancestor = thread = nullptr; } diff --git a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp index 5468ace8d7..e7e1977ac0 100644 --- a/core/indigo-core/reaction/src/reaction_multistep_detector.cpp +++ b/core/indigo-core/reaction/src/reaction_multistep_detector.cpp @@ -37,17 +37,8 @@ ReactionMultistepDetector::~ReactionMultistepDetector() { } -#include "molecule/molecule_json_saver.h" - ReactionMultistepDetector::ReactionMultistepDetector(BaseMolecule& bmol) : _bmol(bmol) { - rapidjson::StringBuffer buffer; - JsonWriter writer(true); - writer.Reset(buffer); - std::string str_json; - StringOutput output(str_json); - MoleculeJsonSaver moleculeSaver(output); - moleculeSaver.saveMolecule(bmol, writer); } void ReactionMultistepDetector::buildReaction(BaseReaction& rxn) From 172a14d62e17aa594aa07fdc828f637a42b62d7c Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 21:18:01 +0200 Subject: [PATCH 20/25] comments fix --- .../reaction/src/pathway_reaction_builder.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index edda457076..db117151fe 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -81,20 +81,22 @@ auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) void PathwayReactionBuilder::buildReactions(std::deque& reactions) { - for (size_t i = 0; i < _reactionInchiDescriptors.size(); ++i) + for (int i = 0; i < _reactionInchiDescriptors.size(); ++i) { auto& rid = _reactionInchiDescriptors[i]; auto [sri, sr] = _pathwayReaction->addReaction(); for (auto rci : rid.reactantIndexes) { - auto mol_idx = _moleculeMapping.at(std::make_pair(i, rci)); - sr.reactantIndexes.push(mol_idx); + auto rit = _moleculeMapping.find(std::make_pair(i, rci)); + if (rit != _moleculeMapping.end()) + sr.reactantIndexes.push(rit->second); } for (auto pid : rid.productIndexes) { - auto mol_idx = _moleculeMapping.at(std::make_pair(i, pid)); - sr.productIndexes.push(mol_idx); + auto pit = _moleculeMapping.find(std::make_pair(i, pid)); + if (pit != _moleculeMapping.end()) + sr.productIndexes.push(pit->second); } } } From 170434f6c4007843a03b046ee76b25f576522927 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 21:39:45 +0200 Subject: [PATCH 21/25] int fix --- core/indigo-core/layout/src/pathway_layout.cpp | 2 +- .../indigo-core/reaction/src/pathway_reaction_builder.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index ed38ae054c..a7d2ddf6d5 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -101,7 +101,7 @@ void PathwayLayout::buildLayoutTree() void PathwayLayout::updateDepths(int depth, PathwayLayoutItem* item) { float d = item->width + HORIZONTAL_SPACING; - if (_depths.size() <= depth) + if ((int)_depths.size() <= depth) _depths.resize(3 * depth / 2); _depths[depth] = std::max(_depths[depth], d); _maxDepth = std::max(_maxDepth, depth); diff --git a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp index db117151fe..5c93130df7 100644 --- a/core/indigo-core/reaction/src/pathway_reaction_builder.cpp +++ b/core/indigo-core/reaction/src/pathway_reaction_builder.cpp @@ -81,7 +81,7 @@ auto PathwayReactionBuilder::findSuccessorReactions(int reactionIdx) void PathwayReactionBuilder::buildReactions(std::deque& reactions) { - for (int i = 0; i < _reactionInchiDescriptors.size(); ++i) + for (int i = 0; i < (int)_reactionInchiDescriptors.size(); ++i) { auto& rid = _reactionInchiDescriptors[i]; auto [sri, sr] = _pathwayReaction->addReaction(); @@ -106,7 +106,7 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio _reactionInchiDescriptors.clear(); InchiWrapper inchiWrapper; Array inchi, inchiKey; - for (int i = 0; i < reactions.size(); ++i) + for (int i = 0; i < (int)reactions.size(); ++i) { // add empty reaction nodes meanwhile calculating inchiKeys for reactants and products _pathwayReaction->addReactionNode(); @@ -147,7 +147,7 @@ void PathwayReactionBuilder::buildInchiDescriptors(std::deque& reactio void PathwayReactionBuilder::buildNodes(std::deque& reactions) { // find all reactants of a reaction that match the products of the current reaction - for (auto i = 0; i < _reactionInchiDescriptors.size(); i++) + for (int i = 0; i < (int)_reactionInchiDescriptors.size(); i++) { // looking for the reaction continuation auto matching_successor = findSuccessorReactions(i); @@ -196,7 +196,7 @@ void PathwayReactionBuilder::buildNodes(std::deque& reactions) } } - for (auto j = 0; j < productIndexes.size(); ++j) + for (int j = 0; j < (int)productIndexes.size(); ++j) { auto pidx = productIndexes[j]; int mol_idx = matching_successor.empty() From 0ac349301d5da94932e4f6b7e44ab74f2f7eb4e0 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 22:16:35 +0200 Subject: [PATCH 22/25] missing refs --- api/tests/integration/tests/reaction/ref/pathway10.ket | 1 + api/tests/integration/tests/reaction/ref/pathway9.ket | 1 + 2 files changed, 2 insertions(+) create mode 100644 api/tests/integration/tests/reaction/ref/pathway10.ket create mode 100644 api/tests/integration/tests/reaction/ref/pathway9.ket diff --git a/api/tests/integration/tests/reaction/ref/pathway10.ket b/api/tests/integration/tests/reaction/ref/pathway10.ket new file mode 100644 index 0000000000..3a9f9a0bbc --- /dev/null +++ b/api/tests/integration/tests/reaction/ref/pathway10.ket @@ -0,0 +1 @@ +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":14.06869888305664,"y":7.232524871826172,"z":0.0}},"spine":{"pos":[{"x":13.06869888305664,"y":11.472174644470215,"z":0.0},{"x":13.06869888305664,"y":2.992875099182129,"z":0.0}]},"tails":{"pos":[{"x":12.56869888305664,"y":11.472174644470215,"z":0.0},{"x":12.56869888305664,"y":2.992875099182129,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.23029899597168,"y":2.992875099182129,"z":0.0}},"spine":{"pos":[{"x":3.2302989959716799,"y":5.134649753570557,"z":0.0},{"x":3.2302989959716799,"y":0.851099967956543,"z":0.0}]},"tails":{"pos":[{"x":2.7302989959716799,"y":5.134649753570557,"z":0.0},{"x":2.7302989959716799,"y":0.851099967956543,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":5.860099792480469,"y":11.472174644470215,"z":0.0}},"spine":{"pos":[{"x":3.2302989959716799,"y":13.607199668884278,"z":0.0},{"x":3.2302989959716799,"y":9.337149620056153,"z":0.0}]},"tails":{"pos":[{"x":2.7302989959716799,"y":13.607199668884278,"z":0.0},{"x":2.7302989959716799,"y":9.337149620056153,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[1.730299472808838,0.0,0.0]},{"label":"C","location":[1.7265992164611817,0.9950997829437256,0.0]},{"label":"C","location":[0.718299388885498,0.01289987564086914,0.0]},{"label":"C","location":[0.7157993316650391,0.9950997829437256,0.0]},{"label":"F","location":[0.008699417114257813,1.702199935913086,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[3,4]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.7289981842041016,4.202199935913086,0.0]},{"label":"C","location":[1.7302980422973633,4.202199935913086,0.0]},{"label":"C","location":[1.2296981811523438,5.067099571228027,0.0]},{"label":"Cl","location":[1.2296981811523438,6.067099571228027,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[2,3]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[0.9206981658935547,10.107199668884278,0.0]},{"label":"C","location":[1.421098232269287,8.567100524902344,0.0]},{"label":"C","location":[1.7302985191345215,9.513299942016602,0.0]},{"label":"C","location":[0.42029857635498049,8.567100524902344,0.0]},{"label":"C","location":[0.11099815368652344,9.513299942016602,0.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]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[0.0,14.107100486755371,0.0]},{"label":"C","location":[1.730299472808838,14.107601165771485,0.0]},{"label":"C","location":[0.8667998313903809,14.607200622558594,0.0]},{"label":"C","location":[1.730299472808838,13.106700897216797,0.0]},{"label":"C","location":[0.0,13.102200508117676,0.0]},{"label":"C","location":[0.8689999580383301,12.607200622558594,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[7.849699020385742,1.7228245735168458,0.0]},{"label":"C","location":[8.850898742675782,1.7228245735168458,0.0]},{"label":"C","location":[8.350399017333985,2.5878243446350099,0.0]},{"label":"O","location":[8.609199523925782,3.5537242889404299,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[2,3]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[9.836698532104493,11.972175598144532,0.0]},{"label":"C","location":[9.836698532104493,10.972175598144532,0.0]},{"label":"C","location":[10.702698707580567,10.472175598144532,0.0]},{"label":"C","location":[11.56869888305664,10.972175598144532,0.0]},{"label":"C","location":[11.56869888305664,11.972175598144532,0.0]},{"label":"C","location":[10.702698707580567,12.472175598144532,0.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]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[10.865299224853516,1.7228245735168458,0.0]},{"label":"C","location":[10.86159896850586,2.717924118041992,0.0]},{"label":"C","location":[9.853399276733399,1.7357244491577149,0.0]},{"label":"C","location":[9.850898742675782,2.717924118041992,0.0]},{"label":"N","location":[11.56869888305664,3.4250245094299318,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[1,4]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[6.040099143981934,3.262925624847412,0.0]},{"label":"C","location":[6.540499687194824,1.722825527191162,0.0]},{"label":"C","location":[6.849699020385742,2.669125556945801,0.0]},{"label":"C","location":[5.539699554443359,1.722825527191162,0.0]},{"label":"C","location":[5.23029899597168,2.669125556945801,0.0]},{"label":"S","location":[6.040099143981934,4.262925624847412,0.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]},{"type":1,"atoms":[0,5]}]},"mol8":{"type":"molecule","atoms":[{"label":"C","location":[7.87449836730957,10.472174644470215,0.0]},{"label":"C","location":[7.870798110961914,11.46727466583252,0.0]},{"label":"C","location":[6.862598419189453,10.485074996948243,0.0]},{"label":"C","location":[6.860099792480469,11.46727466583252,0.0]},{"label":"P","location":[8.836698532104493,11.72607421875,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[2,0]},{"type":1,"atoms":[1,4]}]},"mol9":{"type":"molecule","atoms":[{"label":"O","location":[19.5054988861084,8.640325546264649,0.0]},{"label":"O","location":[19.5054988861084,6.765225410461426,0.0]},{"label":"O","location":[17.686098098754884,5.824725151062012,0.0]},{"label":"O","location":[15.866598129272461,6.765125274658203,0.0]},{"label":"O","location":[17.680498123168947,8.640325546264649,0.0]},{"label":"O","location":[15.06869888305664,8.046025276184082,0.0]},{"label":"C","location":[18.595699310302736,8.181224822998047,0.0],"stereoLabel":"abs"},{"label":"C","location":[18.595699310302736,7.229825496673584,0.0],"stereoLabel":"abs"},{"label":"C","location":[17.680498123168947,6.765125274658203,0.0],"stereoLabel":"abs"},{"label":"C","location":[16.770898818969728,7.229625225067139,0.0],"stereoLabel":"abs"},{"label":"C","location":[16.770898818969728,8.18112564086914,0.0],"stereoLabel":"abs"},{"label":"C","location":[15.866598129272461,8.640125274658204,0.0]}],"bonds":[{"type":1,"atoms":[5,11]},{"type":1,"atoms":[10,4]},{"type":1,"atoms":[4,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11],"stereo":1},{"type":1,"atoms":[6,0],"stereo":6},{"type":1,"atoms":[7,1],"stereo":6},{"type":1,"atoms":[8,2],"stereo":6},{"type":1,"atoms":[9,3],"stereo":6}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/reaction/ref/pathway9.ket b/api/tests/integration/tests/reaction/ref/pathway9.ket new file mode 100644 index 0000000000..2400b7e8c4 --- /dev/null +++ b/api/tests/integration/tests/reaction/ref/pathway9.ket @@ -0,0 +1 @@ +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"$ref":"mol10"},{"$ref":"mol11"},{"$ref":"mol12"},{"$ref":"mol13"},{"$ref":"mol14"},{"$ref":"mol15"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.6194000244140627,"y":4.124800205230713,"z":0.0},{"x":4.1194000244140629,"y":4.124800205230713,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":27.17820167541504,"y":19.806150436401368,"z":0.0}},"spine":{"pos":[{"x":26.17820167541504,"y":25.366600036621095,"z":0.0},{"x":26.17820167541504,"y":14.245699882507325,"z":0.0}]},"tails":{"pos":[{"x":25.67820167541504,"y":25.366600036621095,"z":0.0},{"x":25.67820167541504,"y":14.245699882507325,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":21.163801193237306,"y":14.24570083618164,"z":0.0},{"x":22.676902770996095,"y":14.245699882507325,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":2.7320003509521486,"y":14.24570083618164,"z":0.0},{"x":4.5186004638671879,"y":14.24570083618164,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":21.163801193237306,"y":25.366600036621095,"z":0.0},{"x":22.663801193237306,"y":25.366600036621095,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.232000350952148,"y":25.366600036621095,"z":0.0}},"spine":{"pos":[{"x":3.2320003509521486,"y":27.498849868774415,"z":0.0},{"x":3.2320003509521486,"y":23.234352111816408,"z":0.0}]},"tails":{"pos":[{"x":2.7320003509521486,"y":27.498849868774415,"z":0.0},{"x":2.7320003509521486,"y":23.234352111816408,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":10.887200355529786,"y":37.020423889160159,"z":0.0}},"spine":{"pos":[{"x":9.887200355529786,"y":41.77939987182617,"z":0.0},{"x":9.887200355529786,"y":32.26144790649414,"z":0.0}]},"tails":{"pos":[{"x":9.387200355529786,"y":41.77939987182617,"z":0.0},{"x":9.387200355529786,"y":37.15544891357422,"z":0.0},{"x":9.387200355529786,"y":32.26144790649414,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":4.789100646972656,"y":41.77939987182617,"z":0.0}},"spine":{"pos":[{"x":3.230299949645996,"y":43.91444778442383,"z":0.0},{"x":3.230299949645996,"y":39.64434814453125,"z":0.0}]},"tails":{"pos":[{"x":2.730299949645996,"y":43.91444778442383,"z":0.0},{"x":2.730299949645996,"y":39.64434814453125,"z":0.0}]},"zOrder":0}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.9282002449035645,23.998802185058595,0.0]},{"label":"C","location":[1.4250001907348633,22.46990394592285,0.0]},{"label":"C","location":[1.7320001125335694,23.409202575683595,0.0]},{"label":"C","location":[0.4315004348754883,22.46990394592285,0.0]},{"label":"C","location":[0.12430000305175781,23.409202575683595,0.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]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[0.0,27.99880027770996,0.0]},{"label":"C","location":[0.0,26.99880027770996,0.0]},{"label":"C","location":[0.8659999966621399,26.49880027770996,0.0]},{"label":"C","location":[1.7320001125335694,26.99880027770996,0.0]},{"label":"C","location":[1.7320001125335694,27.99880027770996,0.0]},{"label":"C","location":[0.8659999966621399,28.498899459838868,0.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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[10.600299835205079,11.232000350952149,0.0]},{"label":"C","location":[10.665599822998047,9.749600410461426,0.0]},{"label":"C","location":[10.205100059509278,10.47189998626709,0.0]},{"label":"C","location":[11.521400451660157,9.787300109863282,0.0]},{"label":"C","location":[11.456100463867188,11.269599914550782,0.0]},{"label":"C","location":[11.91670036315918,10.547300338745118,0.0]},{"label":"C","location":[14.806600570678711,10.063600540161133,0.0]},{"label":"C","location":[14.63230037689209,11.53700065612793,0.0]},{"label":"C","location":[14.294099807739258,10.75,0.0]},{"label":"C","location":[15.482999801635743,11.637700080871582,0.0]},{"label":"C","location":[15.657299995422364,10.164199829101563,0.0]},{"label":"C","location":[15.995500564575196,10.951200485229493,0.0]},{"label":"C","location":[6.417099952697754,11.89780044555664,0.0]},{"label":"C","location":[7.782000541687012,11.31570053100586,0.0]},{"label":"C","location":[7.267600059509277,12.000800132751465,0.0]},{"label":"C","location":[7.445899963378906,10.527800559997559,0.0]},{"label":"C","location":[6.081200122833252,11.10990047454834,0.0]},{"label":"C","location":[6.5954999923706059,10.424799919128418,0.0]},{"label":"C","location":[6.314300537109375,12.748200416564942,0.0]},{"label":"C","location":[7.500699996948242,13.639100074768067,0.0]},{"label":"C","location":[7.164600372314453,12.851200103759766,0.0]},{"label":"C","location":[6.986400604248047,14.324199676513672,0.0]},{"label":"C","location":[5.799900054931641,13.433300018310547,0.0]},{"label":"C","location":[6.135900497436523,14.221200942993164,0.0]},{"label":"C","location":[7.219500541687012,15.96250057220459,0.0]},{"label":"C","location":[6.032900333404541,15.071599960327149,0.0]},{"label":"C","location":[6.883399963378906,15.174600601196289,0.0]},{"label":"C","location":[5.5186004638671879,15.75670051574707,0.0]},{"label":"C","location":[6.705100059509277,16.647600173950197,0.0]},{"label":"C","location":[5.854700088500977,16.544599533081056,0.0]},{"label":"C","location":[20.163799285888673,12.494300842285157,0.0]},{"label":"C","location":[18.81920051574707,13.121400833129883,0.0]},{"label":"C","location":[19.672500610351564,13.196000099182129,0.0]},{"label":"C","location":[18.45709991455078,12.345000267028809,0.0]},{"label":"C","location":[19.801799774169923,11.717900276184082,0.0]},{"label":"C","location":[18.948501586914064,11.643301010131836,0.0]},{"label":"C","location":[18.25320053100586,14.67650032043457,0.0]},{"label":"C","location":[19.597900390625,14.049400329589844,0.0]},{"label":"C","location":[18.74449920654297,13.974800109863282,0.0]},{"label":"C","location":[19.95989990234375,14.825700759887696,0.0]},{"label":"C","location":[18.61520004272461,15.452800750732422,0.0]},{"label":"C","location":[19.46860122680664,15.52750015258789,0.0]},{"label":"C","location":[18.049301147460939,17.00790023803711,0.0]},{"label":"C","location":[19.394001007080079,16.380901336669923,0.0]},{"label":"C","location":[18.54050064086914,16.30620002746582,0.0]},{"label":"C","location":[19.756000518798829,17.15730094909668,0.0]},{"label":"C","location":[18.411300659179689,17.784299850463868,0.0]},{"label":"C","location":[19.264699935913087,17.85900115966797,0.0]},{"label":"C","location":[9.548900604248047,17.375999450683595,0.0]},{"label":"C","location":[10.686200141906739,18.328899383544923,0.0]},{"label":"C","location":[9.842500686645508,18.180700302124025,0.0]},{"label":"C","location":[11.236400604248047,17.672300338745118,0.0]},{"label":"C","location":[10.099000930786133,16.71929931640625,0.0]},{"label":"C","location":[10.942700386047364,16.867401123046876,0.0]},{"label":"C","location":[14.052900314331055,18.704200744628908,0.0]},{"label":"C","location":[15.369100570678711,18.019399642944337,0.0]},{"label":"C","location":[14.908599853515625,18.74180030822754,0.0]},{"label":"C","location":[14.973800659179688,17.2593994140625,0.0]},{"label":"C","location":[13.657600402832032,17.94420051574707,0.0]},{"label":"C","location":[14.118000030517579,17.221799850463868,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":2,"atoms":[56,54]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,59]},{"type":1,"atoms":[59,57]},{"type":2,"atoms":[57,55]},{"type":1,"atoms":[55,56]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[55,42]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[0.00170135498046875,14.745601654052735,0.0]},{"label":"C","location":[1.7320013046264649,14.746101379394532,0.0]},{"label":"C","location":[0.8684015274047852,15.245701789855957,0.0]},{"label":"C","location":[1.7320013046264649,13.745201110839844,0.0]},{"label":"C","location":[0.00170135498046875,13.740701675415039,0.0]},{"label":"C","location":[0.8706011772155762,13.245701789855957,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[10.470600128173829,22.792699813842775,0.0]},{"label":"C","location":[10.543401718139649,21.24180030822754,0.0]},{"label":"C","location":[10.059301376342774,21.996301651000978,0.0]},{"label":"C","location":[11.438800811767579,21.28390121459961,0.0]},{"label":"C","location":[11.36600112915039,22.834800720214845,0.0]},{"label":"C","location":[11.850101470947266,22.080400466918947,0.0]},{"label":"C","location":[14.785100936889649,21.580900192260743,0.0]},{"label":"C","location":[14.584701538085938,23.120500564575197,0.0]},{"label":"C","location":[14.240501403808594,22.292800903320314,0.0]},{"label":"C","location":[15.473701477050782,23.236101150512697,0.0]},{"label":"C","location":[15.674001693725586,21.696500778198243,0.0]},{"label":"C","location":[16.01820182800293,22.52410125732422,0.0]},{"label":"C","location":[6.136600494384766,23.415700912475587,0.0]},{"label":"C","location":[7.55940055847168,22.79400062561035,0.0]},{"label":"C","location":[7.027500152587891,23.515600204467775,0.0]},{"label":"C","location":[7.200401306152344,21.97260093688965,0.0]},{"label":"C","location":[5.777700424194336,22.594301223754884,0.0]},{"label":"C","location":[6.309600830078125,21.87270164489746,0.0]},{"label":"C","location":[6.036701202392578,24.306501388549806,0.0]},{"label":"C","location":[7.286500930786133,25.227800369262697,0.0]},{"label":"C","location":[6.927600860595703,24.406400680541993,0.0]},{"label":"C","location":[6.7545013427734379,25.94940185546875,0.0]},{"label":"C","location":[5.504800796508789,25.028100967407228,0.0]},{"label":"C","location":[5.863801956176758,25.84950065612793,0.0]},{"label":"C","location":[7.013601303100586,27.661602020263673,0.0]},{"label":"C","location":[5.7639007568359379,26.74030113220215,0.0]},{"label":"C","location":[6.654701232910156,26.840200424194337,0.0]},{"label":"C","location":[5.232000350952148,27.46190071105957,0.0]},{"label":"C","location":[6.481601715087891,28.383100509643556,0.0]},{"label":"C","location":[5.590801239013672,28.283201217651368,0.0]},{"label":"C","location":[20.163801193237306,24.19300079345703,0.0]},{"label":"C","location":[18.613901138305665,24.283599853515626,0.0]},{"label":"C","location":[19.415102005004884,24.685701370239259,0.0]},{"label":"C","location":[18.561601638793947,23.388700485229493,0.0]},{"label":"C","location":[20.111600875854493,23.2981014251709,0.0]},{"label":"C","location":[19.310401916503908,22.895999908447267,0.0]},{"label":"C","location":[17.463001251220704,25.577499389648439,0.0]},{"label":"C","location":[19.01300048828125,25.486801147460939,0.0]},{"label":"C","location":[18.211700439453126,25.084701538085939,0.0]},{"label":"C","location":[19.065200805664064,26.38170051574707,0.0]},{"label":"C","location":[17.515300750732423,26.472301483154298,0.0]},{"label":"C","location":[18.3164005279541,26.874500274658204,0.0]},{"label":"C","location":[16.364301681518556,27.76620101928711,0.0]},{"label":"C","location":[17.9143009185791,27.675601959228517,0.0]},{"label":"C","location":[17.113101959228517,27.273500442504884,0.0]},{"label":"C","location":[17.966501235961915,28.570499420166017,0.0]},{"label":"C","location":[16.416601181030275,28.661100387573243,0.0]},{"label":"C","location":[17.21780014038086,29.063201904296876,0.0]},{"label":"C","location":[9.332300186157227,28.723400115966798,0.0]},{"label":"C","location":[10.690900802612305,29.475000381469728,0.0]},{"label":"C","location":[9.794700622558594,29.49140167236328,0.0]},{"label":"C","location":[11.124801635742188,28.69070053100586,0.0]},{"label":"C","location":[9.766401290893555,27.939001083374025,0.0]},{"label":"C","location":[10.662601470947266,27.922700881958009,0.0]},{"label":"C","location":[13.593400955200196,28.912900924682618,0.0]},{"label":"C","location":[14.017601013183594,27.525800704956056,0.0]},{"label":"C","location":[14.309301376342774,28.37350082397461,0.0]},{"label":"C","location":[13.121301651000977,27.541400909423829,0.0]},{"label":"C","location":[12.859100341796875,28.398601531982423,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[0.8097000122070313,4.89484977722168,0.0]},{"label":"C","location":[1.3101005554199219,3.3547496795654299,0.0]},{"label":"C","location":[1.6194000244140626,4.3009490966796879,0.0]},{"label":"C","location":[0.3094005584716797,3.3547496795654299,0.0]},{"label":"C","location":[0.0,4.3009490966796879,0.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]}]},"mol6":{"type":"molecule","atoms":[{"label":"C","location":[23.676902770996095,13.813199996948243,0.0]},{"label":"C","location":[24.678203582763673,13.813199996948243,0.0]},{"label":"C","location":[24.177602767944337,14.678199768066407,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,0]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[24.67820167541504,24.869050979614259,0.0]},{"label":"C","location":[24.674501419067384,25.864151000976564,0.0]},{"label":"C","location":[23.666301727294923,24.88195037841797,0.0]},{"label":"C","location":[23.663801193237306,25.864151000976564,0.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":[0.0,40.1442985534668,0.0]},{"label":"C","location":[1.730299949645996,40.144798278808597,0.0]},{"label":"C","location":[0.8668000102043152,40.64440155029297,0.0]},{"label":"C","location":[1.730299949645996,39.143798828125,0.0]},{"label":"C","location":[0.0,39.13929748535156,0.0]},{"label":"C","location":[0.8690000176429749,38.6442985534668,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[0.9205999374389648,44.68449783325195,0.0]},{"label":"C","location":[1.4210000038146973,43.1443977355957,0.0]},{"label":"C","location":[1.730299949645996,44.0906982421875,0.0]},{"label":"C","location":[0.4203000068664551,43.1443977355957,0.0]},{"label":"C","location":[0.1108999252319336,44.0906982421875,0.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":"C","location":[5.789100646972656,42.27939987182617,0.0]},{"label":"C","location":[5.789100646972656,41.27939987182617,0.0]},{"label":"C","location":[6.6551008224487309,40.77939987182617,0.0]},{"label":"C","location":[7.521200180053711,41.27939987182617,0.0]},{"label":"C","location":[7.521200180053711,42.27939987182617,0.0]},{"label":"C","location":[6.6551008224487309,42.77939987182617,0.0]},{"label":"C","location":[8.387200355529786,42.77939987182617,0.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]},{"type":1,"atoms":[4,6]}]},"mol11":{"type":"molecule","atoms":[{"label":"C","location":[7.387200355529785,32.531497955322269,0.0]},{"label":"C","location":[7.887600898742676,30.991397857666017,0.0]},{"label":"C","location":[8.19680118560791,31.937698364257814,0.0]},{"label":"C","location":[6.8867998123168949,30.991397857666017,0.0]},{"label":"C","location":[6.577500343322754,31.937698364257814,0.0]},{"label":"C","location":[7.387200355529785,33.531497955322269,0.0]},{"label":"C","location":[8.387200355529786,33.531497955322269,0.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]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]}]},"mol12":{"type":"molecule","atoms":[{"label":"C","location":[6.196199893951416,37.661895751953128,0.0]},{"label":"C","location":[6.980099678039551,38.279396057128909,0.0]},{"label":"C","location":[7.953099727630615,38.0568962097168,0.0]},{"label":"C","location":[8.387199401855469,37.161094665527347,0.0]},{"label":"C","location":[6.201699733734131,36.65469741821289,0.0]},{"label":"C","location":[7.953799724578857,36.253997802734378,0.0]},{"label":"C","location":[6.980099678039551,36.031497955322269,0.0]},{"label":"C","location":[5.230299949645996,37.92069625854492,0.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]},{"type":1,"atoms":[0,7]}]},"mol13":{"type":"molecule","atoms":[{"label":"C","location":[10.357999801635743,1.5508995056152344,0.0]},{"label":"C","location":[10.430801391601563,0.0,0.0]},{"label":"C","location":[9.946701049804688,0.7545013427734375,0.0]},{"label":"C","location":[11.326200485229493,0.04210090637207031,0.0]},{"label":"C","location":[11.253400802612305,1.5930004119873047,0.0]},{"label":"C","location":[11.73750114440918,0.8386001586914063,0.0]},{"label":"C","location":[14.672500610351563,0.3390998840332031,0.0]},{"label":"C","location":[14.472101211547852,1.8787002563476563,0.0]},{"label":"C","location":[14.127901077270508,1.0510005950927735,0.0]},{"label":"C","location":[15.361101150512696,1.9943008422851563,0.0]},{"label":"C","location":[15.5614013671875,0.4547004699707031,0.0]},{"label":"C","location":[15.905601501464844,1.2823009490966797,0.0]},{"label":"C","location":[6.02400016784668,2.173900604248047,0.0]},{"label":"C","location":[7.446800231933594,1.5522003173828126,0.0]},{"label":"C","location":[6.914899826049805,2.2737998962402345,0.0]},{"label":"C","location":[7.087800979614258,0.7308006286621094,0.0]},{"label":"C","location":[5.66510009765625,1.3525009155273438,0.0]},{"label":"C","location":[6.197000503540039,0.6309013366699219,0.0]},{"label":"C","location":[5.924100875854492,3.0647010803222658,0.0]},{"label":"C","location":[7.173900604248047,3.9860000610351564,0.0]},{"label":"C","location":[6.815000534057617,3.164600372314453,0.0]},{"label":"C","location":[6.641901016235352,4.7076005935668949,0.0]},{"label":"C","location":[5.392200469970703,3.7863006591796877,0.0]},{"label":"C","location":[5.751201629638672,4.607700347900391,0.0]},{"label":"C","location":[6.9010009765625,6.419800758361816,0.0]},{"label":"C","location":[5.651300430297852,5.498500823974609,0.0]},{"label":"C","location":[6.54210090637207,5.598400115966797,0.0]},{"label":"C","location":[5.1194000244140629,6.220100402832031,0.0]},{"label":"C","location":[6.369001388549805,7.141300201416016,0.0]},{"label":"C","location":[5.478200912475586,7.041400909423828,0.0]},{"label":"C","location":[20.05120086669922,2.951200485229492,0.0]},{"label":"C","location":[18.501300811767579,3.041799545288086,0.0]},{"label":"C","location":[19.302501678466798,3.4439010620117189,0.0]},{"label":"C","location":[18.44900131225586,2.146900177001953,0.0]},{"label":"C","location":[19.999000549316408,2.0563011169433595,0.0]},{"label":"C","location":[19.19780158996582,1.6541996002197266,0.0]},{"label":"C","location":[17.350400924682618,4.335700035095215,0.0]},{"label":"C","location":[18.900400161743165,4.245000839233398,0.0]},{"label":"C","location":[18.09910011291504,3.842900276184082,0.0]},{"label":"C","location":[18.952600479125978,5.139900207519531,0.0]},{"label":"C","location":[17.402700424194337,5.230500221252441,0.0]},{"label":"C","location":[18.203800201416017,5.632699966430664,0.0]},{"label":"C","location":[16.25170135498047,6.52440071105957,0.0]},{"label":"C","location":[17.801700592041017,6.43380069732666,0.0]},{"label":"C","location":[17.00050163269043,6.031700134277344,0.0]},{"label":"C","location":[17.853900909423829,7.328700065612793,0.0]},{"label":"C","location":[16.304000854492189,7.419300079345703,0.0]},{"label":"C","location":[17.105199813842775,7.8214006423950199,0.0]},{"label":"C","location":[9.21969985961914,7.481600761413574,0.0]},{"label":"C","location":[10.578300476074219,8.233200073242188,0.0]},{"label":"C","location":[9.682100296020508,8.249600410461426,0.0]},{"label":"C","location":[11.012201309204102,7.44890022277832,0.0]},{"label":"C","location":[9.653800964355469,6.697200775146484,0.0]},{"label":"C","location":[10.55000114440918,6.680900573730469,0.0]},{"label":"C","location":[13.48080062866211,7.671100616455078,0.0]},{"label":"C","location":[13.905000686645508,6.284000396728516,0.0]},{"label":"C","location":[14.196701049804688,7.13170051574707,0.0]},{"label":"C","location":[13.00870132446289,6.299600601196289,0.0]},{"label":"C","location":[12.746500015258789,7.156800270080566,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[8,6]},{"type":1,"atoms":[6,10]},{"type":2,"atoms":[10,11]},{"type":1,"atoms":[11,9]},{"type":2,"atoms":[9,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[5,8]},{"type":2,"atoms":[14,12]},{"type":1,"atoms":[12,16]},{"type":2,"atoms":[16,17]},{"type":1,"atoms":[17,15]},{"type":2,"atoms":[15,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[13,2]},{"type":2,"atoms":[20,18]},{"type":1,"atoms":[18,22]},{"type":2,"atoms":[22,23]},{"type":1,"atoms":[23,21]},{"type":2,"atoms":[21,19]},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[18,12]},{"type":1,"atoms":[20,14]},{"type":2,"atoms":[26,24]},{"type":1,"atoms":[24,28]},{"type":2,"atoms":[28,29]},{"type":1,"atoms":[29,27]},{"type":2,"atoms":[27,25]},{"type":1,"atoms":[25,26]},{"type":1,"atoms":[21,26]},{"type":1,"atoms":[23,25]},{"type":2,"atoms":[32,30]},{"type":1,"atoms":[30,34]},{"type":2,"atoms":[34,35]},{"type":1,"atoms":[35,33]},{"type":2,"atoms":[33,31]},{"type":1,"atoms":[31,32]},{"type":1,"atoms":[11,33]},{"type":2,"atoms":[38,36]},{"type":1,"atoms":[36,40]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[41,39]},{"type":2,"atoms":[39,37]},{"type":1,"atoms":[37,38]},{"type":2,"atoms":[44,42]},{"type":1,"atoms":[42,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,45]},{"type":2,"atoms":[45,43]},{"type":1,"atoms":[43,44]},{"type":1,"atoms":[38,31]},{"type":1,"atoms":[37,32]},{"type":1,"atoms":[44,40]},{"type":1,"atoms":[43,41]},{"type":2,"atoms":[50,48]},{"type":1,"atoms":[48,52]},{"type":2,"atoms":[52,53]},{"type":1,"atoms":[53,51]},{"type":2,"atoms":[51,49]},{"type":1,"atoms":[49,50]},{"type":1,"atoms":[24,48]},{"type":1,"atoms":[54,58]},{"type":2,"atoms":[58,57]},{"type":1,"atoms":[57,55]},{"type":2,"atoms":[55,56]},{"type":1,"atoms":[56,54]},{"type":1,"atoms":[51,58]},{"type":1,"atoms":[56,46]}]},"mol14":{"type":"molecule","atoms":[{"label":"C","location":[28.17820167541504,19.304950714111329,0.0]},{"label":"C","location":[28.178401947021486,20.307449340820314,0.0]},{"label":"C","location":[28.883602142333986,21.012649536132814,0.0]},{"label":"C","location":[28.88380241394043,18.59954833984375,0.0]},{"label":"C","location":[29.886201858520509,18.59954833984375,0.0]},{"label":"C","location":[30.591602325439454,19.304950714111329,0.0]},{"label":"C","location":[30.591503143310548,20.307449340820314,0.0]},{"label":"C","location":[29.886201858520509,21.01274871826172,0.0]}],"bonds":[{"type":1,"atoms":[1,0]},{"type":1,"atoms":[0,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,2]},{"type":1,"atoms":[2,1]}]},"mol15":{"type":"molecule","atoms":[{"label":"C","location":[12.753199577331543,37.87387466430664,0.0]},{"label":"C","location":[14.483498573303223,37.87437438964844,0.0]},{"label":"C","location":[13.619999885559082,38.37397384643555,0.0]},{"label":"C","location":[14.483498573303223,36.87347412109375,0.0]},{"label":"C","location":[12.753199577331543,36.86897277832031,0.0]},{"label":"C","location":[13.622199058532715,36.37397384643555,0.0]},{"label":"C","location":[11.887200355529786,36.36897277832031,0.0]},{"label":"C","location":[12.915099143981934,35.666873931884769,0.0]},{"label":"C","location":[15.190600395202637,36.16637420654297,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":1,"atoms":[0,4]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[4,6]},{"type":2,"atoms":[5,7]},{"type":1,"atoms":[3,8]}]}} \ No newline at end of file From 18b2fb215bbaff93800406b4339c6c4c43807e90 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 3 Sep 2024 23:19:08 +0200 Subject: [PATCH 23/25] update refs --- api/tests/integration/ref/reaction/pathway.py.out | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/tests/integration/ref/reaction/pathway.py.out b/api/tests/integration/ref/reaction/pathway.py.out index b8d0f02aff..c4790116ae 100644 --- a/api/tests/integration/ref/reaction/pathway.py.out +++ b/api/tests/integration/ref/reaction/pathway.py.out @@ -6,3 +6,5 @@ pathway5.rdf:SUCCEED pathway6.rdf:SUCCEED pathway7.rdf:SUCCEED pathway8.rdf:SUCCEED +pathway9.rdf:SUCCEED +pathway10.rdf:SUCCEED From c7d3f42fcc2be6d0fb779d2ed5b9d030c19d8ab2 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Wed, 4 Sep 2024 17:23:50 +0200 Subject: [PATCH 24/25] refactor --- core/indigo-core/layout/pathway_layout.h | 90 ++++---- .../indigo-core/layout/src/pathway_layout.cpp | 217 +++++++++--------- 2 files changed, 153 insertions(+), 154 deletions(-) diff --git a/core/indigo-core/layout/pathway_layout.h b/core/indigo-core/layout/pathway_layout.h index bb3dc56499..67f44e5492 100644 --- a/core/indigo-core/layout/pathway_layout.h +++ b/core/indigo-core/layout/pathway_layout.h @@ -32,12 +32,17 @@ namespace indigo { + // The algorithm is based on the following paper: + // https://www.researchgate.net/publication/30508504_Improving_Walker's_Algorithm_to_Run_in_Linear_Time + // The original Walker's algorithm is described here: + // https://www.researchgate.net/publication/220853707_An_Optimal_Algorithm_for_Computing_the_Trees_of_a_Directed_Graph + class PathwayLayout { DECL_ERROR; public: - PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0), _log_file("pathway.svg") + PathwayLayout(PathwayReaction& reaction) : _reaction(reaction), _depths(10, 0), _maxDepth(0) { } @@ -55,46 +60,44 @@ namespace indigo struct PathwayLayoutItem { PathwayLayoutItem(PathwayReaction& pwr, int nodeIdx, int reactantIdx = -1) - : number(-1), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), ancestor(this), thread(nullptr), children(), + : levelTree(-1), prelim(0.0), mod(0.0), shift(0.0), change(0.0), width(0.0), height(0.0), ancestor(this), thread(nullptr), children(), parent(nullptr), nextSibling(nullptr), prevSibling(nullptr), reaction(pwr) { - auto& rn = reaction.getReactionNode(nodeIdx); - auto& sr = reaction.getReaction(rn.reactionIdx); + auto& reactionNode = reaction.getReactionNode(nodeIdx); + auto& simpleReaction = reaction.getReaction(reactionNode.reactionIdx); // create as a final reactant child if (reactantIdx != -1) { auto& mol = reaction.getMolecule(reactantIdx); - Rect2f bbox; - mol.getBoundingBox(bbox); - molecules.push_back(std::make_pair(reactantIdx, bbox)); - width = bbox.width(); - height = bbox.height(); + Rect2f boundingBox; + mol.getBoundingBox(boundingBox); + molecules.push_back(std::make_pair(reactantIdx, boundingBox)); + width = boundingBox.width(); + height = boundingBox.height(); } else { - for (auto pidx : sr.productIndexes) + for (auto pidx : simpleReaction.productIndexes) { auto& mol = reaction.getMolecule(pidx); - Rect2f bbox; - mol.getBoundingBox(bbox); + Rect2f boundingBox; + mol.getBoundingBox(boundingBox); if (molecules.size()) - { width += MARGIN; - } - molecules.push_back(std::make_pair(pidx, bbox)); - width += bbox.width(); // add some spacing for plus - height = std::max(bbox.height(), height); + molecules.push_back(std::make_pair(pidx, boundingBox)); + width += boundingBox.width(); // add some spacing for plus + height = std::max(boundingBox.height(), height); } // add precursors free reactants as children - for (int i = 0; i < sr.reactantIndexes.size(); ++i) + for (int i = 0; i < simpleReaction.reactantIndexes.size(); ++i) { // check if it is a final reactant - if (!rn.successorReactants.find(i)) + if (!reactionNode.successorReactants.find(i)) { - auto ridx = sr.reactantIndexes[i]; - reactants_no_precursors.emplace_back(reaction, nodeIdx, ridx); - PathwayLayoutItem* item = &reactants_no_precursors.back(); + auto ridx = simpleReaction.reactantIndexes[i]; + reactantsNoPrecursors.emplace_back(reaction, nodeIdx, ridx); + PathwayLayoutItem* item = &reactantsNoPrecursors.back(); children.push_back(item); item->parent = this; if (children.size() > 1) @@ -119,7 +122,7 @@ namespace indigo void clear() { - number = -1; + levelTree = -1; prelim = mod = shift = change = 0.0; ancestor = thread = nullptr; } @@ -132,8 +135,8 @@ namespace indigo [](float acc, const std::pair& r) { return acc + r.second.width(); }); float spacing = molecules.size() > 1 ? (width - totalWidth) / (molecules.size() - 1) : (width - totalWidth) / 2; - float currentX = bbox.left(); - float currentY = bbox.bottom(); + float currentX = boundingBox.left(); + float currentY = boundingBox.bottom(); for (auto& mol_desc : molecules) { auto& mol = reaction.getMolecule(mol_desc.first); @@ -146,19 +149,19 @@ namespace indigo void setXY(float x, float y) { - bbox = Rect2f(Vec2f(x - width, y - height / 2), Vec2f(x, y + height / 2)); + boundingBox = Rect2f(Vec2f(x - width, y - height / 2), Vec2f(x, y + height / 2)); } // required for the layout algorithm float width, height; std::vector children; - std::list reactants_no_precursors; + std::list reactantsNoPrecursors; PathwayLayoutItem* parent; PathwayLayoutItem* nextSibling; PathwayLayoutItem* prevSibling; // computed fields - int number; + int levelTree; float prelim, mod, shift, change; PathwayLayoutItem* ancestor; PathwayLayoutItem* thread; @@ -166,20 +169,17 @@ namespace indigo // other data std::vector> molecules; PathwayReaction& reaction; - Rect2f bbox; - - private: - // float x, y; + Rect2f boundingBox; }; struct PathwayLayoutRootItem { - PathwayLayoutRootItem(int root) : root_index(root) + PathwayLayoutRootItem(int root) : rootIndex(root) { } - int root_index; - Rect2f bbox; - std::vector li_items; + int rootIndex; + Rect2f boundingBox; + std::vector layoutItems; }; void traverse(PathwayLayoutItem* root, std::function node_processor); @@ -195,21 +195,21 @@ namespace indigo void buildLayoutTree(); - void firstWalk(PathwayLayoutItem* n, int num, int depth); + void firstWalk(PathwayLayoutItem* node, int num, int depth); - PathwayLayoutItem* apportion(PathwayLayoutItem* v, PathwayLayoutItem* a); + PathwayLayoutItem* apportion(PathwayLayoutItem* currentNode, PathwayLayoutItem* ancestorNode); - PathwayLayoutItem* nextTop(PathwayLayoutItem* n); + PathwayLayoutItem* nextTop(PathwayLayoutItem* node); - PathwayLayoutItem* nextBottom(PathwayLayoutItem* n); + PathwayLayoutItem* nextBottom(PathwayLayoutItem* node); - void moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, float shift); + void moveSubtree(PathwayLayoutItem* parent, PathwayLayoutItem* wp, float shift); - void executeShifts(PathwayLayoutItem* n); + void executeShifts(PathwayLayoutItem* node); - PathwayLayoutItem* ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a); + PathwayLayoutItem* ancestor(PathwayLayoutItem* node1, PathwayLayoutItem* node2, PathwayLayoutItem* ancestor); - void secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth); + void secondWalk(PathwayLayoutItem* node, PathwayLayoutItem* parent, float modifier, int depth); void applyLayout(); @@ -220,9 +220,7 @@ namespace indigo PathwayReaction& _reaction; std::vector _layoutItems; std::vector _layoutRootItems; - std::ofstream _log_file; }; - } #endif diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index a7d2ddf6d5..f0d450689a 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -31,10 +31,10 @@ void PathwayLayout::make() auto roots = _reaction.getRootReactions(); _layoutRootItems.reserve(roots.size()); float yShift = 0; - for (auto rri : roots) + for (auto rootIndexes : roots) { - auto& li_root = _layoutRootItems.emplace_back(rri); - PathwayLayoutItem* root = &_layoutItems[rri]; + auto& rootItem = _layoutRootItems.emplace_back(rootIndexes); + PathwayLayoutItem* root = &_layoutItems[rootIndexes]; _depths.clear(); _depths.resize(10, 0); _maxDepth = 0; @@ -43,27 +43,27 @@ void PathwayLayout::make() determineDepths(); secondWalk(root, nullptr, -root->prelim, 0); - traverse(root, [&li_root](PathwayLayoutItem* item) { li_root.li_items.push_back(item); }); + traverse(root, [&rootItem](PathwayLayoutItem* item) { rootItem.layoutItems.push_back(item); }); // calculating bounding box for the one pathway - auto& li_items = li_root.li_items; - Rect2f pw_bbox; - for (size_t i = 0; i < li_items.size(); ++i) + auto& layoutItems = rootItem.layoutItems; + Rect2f pathwayBoundingBox; + for (size_t i = 0; i < layoutItems.size(); ++i) { - auto& li = *li_items[i]; + auto& layoutItem = *layoutItems[i]; if (i) - pw_bbox.extend(li.bbox); + pathwayBoundingBox.extend(layoutItem.boundingBox); else - pw_bbox = li.bbox; + pathwayBoundingBox = layoutItem.boundingBox; } - li_root.bbox = pw_bbox; - for (size_t i = 0; i < li_items.size(); ++i) + rootItem.boundingBox = pathwayBoundingBox; + for (size_t i = 0; i < layoutItems.size(); ++i) { - auto& li = *li_items[i]; - li.bbox.offset(Vec2f(-pw_bbox.left(), -pw_bbox.bottom() + yShift)); + auto& layoutItem = *layoutItems[i]; + layoutItem.boundingBox.offset(Vec2f(-pathwayBoundingBox.left(), -pathwayBoundingBox.bottom() + yShift)); } - yShift += pw_bbox.height() + MULTIPATHWAY_VERTICAL_SPACING; + yShift += pathwayBoundingBox.height() + MULTIPATHWAY_VERTICAL_SPACING; } applyLayout(); } @@ -79,21 +79,21 @@ void PathwayLayout::buildLayoutTree() // fill layout tree for (int i = 0; i < _reaction.getReactionNodeCount(); ++i) { - auto& rn = _reaction.getReactionNode(i); + auto& reactionNode = _reaction.getReactionNode(i); - auto& cur_li = _layoutItems[i]; + auto& currentLayoutItem = _layoutItems[i]; // add successor reactants to layout items - for (int j : rn.precursorReactionsIndexes) + for (int j : reactionNode.precursorReactionsIndexes) { - auto& prec_li = _layoutItems[j]; - auto last_child = cur_li.getLastChild(); - if (last_child != nullptr) + auto& precursorLayoutItem = _layoutItems[j]; + auto lastChild = currentLayoutItem.getLastChild(); + if (lastChild != nullptr) { - last_child->nextSibling = &prec_li; - prec_li.prevSibling = last_child; + lastChild->nextSibling = &precursorLayoutItem; + precursorLayoutItem.prevSibling = lastChild; } - cur_li.children.push_back(&prec_li); - prec_li.parent = &cur_li; + currentLayoutItem.children.push_back(&precursorLayoutItem); + precursorLayoutItem.parent = ¤tLayoutItem; } } } @@ -114,73 +114,73 @@ void PathwayLayout::determineDepths() _shifts[i] += _shifts[i - 1]; } -void PathwayLayout::firstWalk(PathwayLayoutItem* n, int num, int depth) +void PathwayLayout::firstWalk(PathwayLayoutItem* node, int level, int depth) { - n->number = num; - updateDepths(depth, n); + node->levelTree = level; + updateDepths(depth, node); - if (n->children.empty()) + if (node->children.empty()) { - PathwayLayoutItem* l = n->prevSibling; - n->prelim = (l == nullptr) ? 0 : (l->prelim + spacing(l, n, true)); + PathwayLayoutItem* layoutItem = node->prevSibling; + node->prelim = (layoutItem == nullptr) ? 0 : (layoutItem->prelim + spacing(layoutItem, node, true)); } else { - PathwayLayoutItem* topMost = n->getFirstChild(); - PathwayLayoutItem* bottomMost = n->getLastChild(); + PathwayLayoutItem* topMost = node->getFirstChild(); + PathwayLayoutItem* bottomMost = node->getLastChild(); PathwayLayoutItem* defaultAncestor = topMost; - for (auto c : n->children) + for (auto child : node->children) { - firstWalk(c, num++, depth + 1); - defaultAncestor = apportion(c, defaultAncestor); + firstWalk(child, level++, depth + 1); + defaultAncestor = apportion(child, defaultAncestor); } - executeShifts(n); + executeShifts(node); float midpoint = (topMost->prelim + bottomMost->prelim) / 2.0f; - PathwayLayoutItem* top = n->prevSibling; + PathwayLayoutItem* top = node->prevSibling; if (top != nullptr) { - n->prelim = top->prelim + spacing(top, n, true); - n->mod = n->prelim - midpoint; + node->prelim = top->prelim + spacing(top, node, true); + node->mod = node->prelim - midpoint; } else { - n->prelim = midpoint; + node->prelim = midpoint; } } } -void PathwayLayout::secondWalk(PathwayLayoutItem* n, PathwayLayoutItem* p, float m, int depth) +void PathwayLayout::secondWalk(PathwayLayoutItem* node, PathwayLayoutItem* parent, float modifier, int depth) { - n->setXY(-_shifts[depth], n->prelim + m); - for (PathwayLayoutItem* c = n->getFirstChild(); c != nullptr; c = c->nextSibling) - secondWalk(c, n, m + n->mod, depth + 1); - n->clear(); + node->setXY(-_shifts[depth], node->prelim + modifier); + for (PathwayLayoutItem* child = node->getFirstChild(); child != nullptr; child = child->nextSibling) + secondWalk(child, node, modifier + node->mod, depth + 1); + node->clear(); } void PathwayLayout::applyLayout() { // upload coordinates back to the reaction _reaction.meta().resetReactionData(); - for (auto& li_root : _layoutRootItems) + for (auto& rootItem : _layoutRootItems) { - auto& li_items = li_root.li_items; - for (auto li : li_items) - li->applyLayout(); + auto& layoutItems = rootItem.layoutItems; + for (auto layoutItem : layoutItems) + layoutItem->applyLayout(); - for (auto li : li_items) + for (auto layoutItem : layoutItems) { // connect reactants with products - if (!li->children.empty()) + if (!layoutItem->children.empty()) { - Vec2f head = li->bbox.leftMiddle(); + Vec2f head = layoutItem->boundingBox.leftMiddle(); head.x -= MARGIN; std::vector tails, arrows; arrows.push_back(head); - for (auto c : li->children) + for (auto child : layoutItem->children) { - Vec2f tail = c->bbox.rightMiddle(); + Vec2f tail = child->boundingBox.rightMiddle(); auto tail_it = std::lower_bound(tails.begin(), tails.end(), tail, [](const Vec2f& a, const Vec2f& b) { return a.y > b.y; }); tails.insert(tail_it, tail); } @@ -208,91 +208,92 @@ void PathwayLayout::applyLayout() } } -PathwayLayout::PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* v, PathwayLayoutItem* a) +PathwayLayout::PathwayLayoutItem* PathwayLayout::apportion(PathwayLayoutItem* currentNode, PathwayLayoutItem* ancestorNode) { - PathwayLayoutItem* w = v->prevSibling; - if (w != nullptr) + PathwayLayoutItem* previousSibling = currentNode->prevSibling; + if (previousSibling != nullptr) { - PathwayLayoutItem *vip = v, *vim = w, *vop = v, *vom = v->parent->getFirstChild(); - float sip = vip->mod, sim = vim->mod, sop = vop->mod, som = vom->mod; - PathwayLayoutItem* nr = nextBottom(vim); - PathwayLayoutItem* nl = nextTop(vip); + PathwayLayoutItem *innerNode = currentNode, *siblingInner = previousSibling, *outerNode = currentNode, + *siblingOuter = currentNode->parent->getFirstChild(); + float modInner = innerNode->mod, modSiblingInner = siblingInner->mod, modOuter = outerNode->mod, modSiblingOuter = siblingOuter->mod; + PathwayLayoutItem* nextLower = nextBottom(siblingInner); + PathwayLayoutItem* nextUpper = nextTop(innerNode); - while (nr != nullptr && nl != nullptr) + while (nextLower != nullptr && nextUpper != nullptr) { - vim = nr; - vip = nl; - vom = nextTop(vom); - vop = nextBottom(vop); - vop->ancestor = v; - float shift = (vim->prelim + sim) - (vip->prelim + sip) + spacing(vim, vip, false); + siblingInner = nextLower; + innerNode = nextUpper; + siblingOuter = nextTop(siblingOuter); + outerNode = nextBottom(outerNode); + outerNode->ancestor = currentNode; + float shift = (siblingInner->prelim + modSiblingInner) - (innerNode->prelim + modInner) + spacing(siblingInner, innerNode, false); if (shift > 0) { - moveSubtree(ancestor(vim, v, a), v, shift); - sip += shift; - sop += shift; + moveSubtree(ancestor(siblingInner, currentNode, ancestorNode), currentNode, shift); + modInner += shift; + modOuter += shift; } - sim += vim->mod; - sip += vip->mod; - som += vom->mod; - sop += vop->mod; + modSiblingInner += siblingInner->mod; + modInner += innerNode->mod; + modSiblingOuter += siblingOuter->mod; + modOuter += outerNode->mod; - nr = nextBottom(vim); - nl = nextTop(vip); + nextLower = nextBottom(siblingInner); + nextUpper = nextTop(innerNode); } - if (nr != nullptr && nextBottom(vop) == nullptr) + if (nextLower != nullptr && nextBottom(outerNode) == nullptr) { - vop->thread = nr; - vop->mod += sim - sop; + outerNode->thread = nextLower; + outerNode->mod += modSiblingInner - modOuter; } - if (nl != nullptr && nextTop(vom) == nullptr) + if (nextUpper != nullptr && nextTop(siblingOuter) == nullptr) { - vom->thread = nl; - vom->mod += sip - som; - a = v; + siblingOuter->thread = nextUpper; + siblingOuter->mod += modInner - modSiblingOuter; + ancestorNode = currentNode; } } - return a; + return ancestorNode; } -void PathwayLayout::moveSubtree(PathwayLayoutItem* wm, PathwayLayoutItem* wp, float shift) +void PathwayLayout::moveSubtree(PathwayLayoutItem* parent, PathwayLayoutItem* child, float shift) { - float subtrees = static_cast(wp->number - wm->number); - wp->change -= shift / subtrees; - wp->shift += shift; - wm->change += shift / subtrees; - wp->prelim += shift; - wp->mod += shift; + float subtrees = static_cast(child->levelTree - parent->levelTree); + child->change -= shift / subtrees; + child->shift += shift; + parent->change += shift / subtrees; + child->prelim += shift; + child->mod += shift; } -void PathwayLayout::executeShifts(PathwayLayoutItem* n) +void PathwayLayout::executeShifts(PathwayLayoutItem* node) { float shift = 0, change = 0; - for (PathwayLayoutItem* c = n->getLastChild(); c != nullptr; c = c->prevSibling) + for (PathwayLayoutItem* child = node->getLastChild(); child != nullptr; child = child->prevSibling) { - c->prelim += shift; - c->mod += shift; - change += c->change; - shift += c->shift + change; + child->prelim += shift; + child->mod += shift; + change += child->change; + shift += child->shift + change; } } -PathwayLayout::PathwayLayoutItem* PathwayLayout::nextTop(PathwayLayoutItem* n) +PathwayLayout::PathwayLayoutItem* PathwayLayout::nextTop(PathwayLayoutItem* node) { - PathwayLayoutItem* c = n->getFirstChild(); - return (c != nullptr) ? c : n->thread; + PathwayLayoutItem* child = node->getFirstChild(); + return (child != nullptr) ? child : node->thread; } -PathwayLayout::PathwayLayoutItem* PathwayLayout::nextBottom(PathwayLayoutItem* n) +PathwayLayout::PathwayLayoutItem* PathwayLayout::nextBottom(PathwayLayoutItem* node) { - PathwayLayoutItem* c = n->getLastChild(); - return (c != nullptr) ? c : n->thread; + PathwayLayoutItem* child = node->getLastChild(); + return (child != nullptr) ? child : node->thread; } -PathwayLayout::PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* vim, PathwayLayoutItem* v, PathwayLayoutItem* a) +PathwayLayout::PathwayLayoutItem* PathwayLayout::ancestor(PathwayLayoutItem* node1, PathwayLayoutItem* node2, PathwayLayoutItem* ancestor) { - PathwayLayoutItem* p = v->parent; - return (vim->ancestor->parent == p) ? vim->ancestor : a; + PathwayLayoutItem* p = node2->parent; + return (node1->ancestor->parent == p) ? node1->ancestor : ancestor; } void PathwayLayout::traverse(PathwayLayoutItem* root, std::function node_processor) From e92d7a3d46844985dfaf409dfde99842557e7a9f Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Wed, 4 Sep 2024 17:44:38 +0200 Subject: [PATCH 25/25] refactor --- core/indigo-core/layout/src/pathway_layout.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index f0d450689a..6e5b445f57 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -311,5 +311,4 @@ void PathwayLayout::traverse(PathwayLayoutItem* root, std::functionchildren.rbegin(), node->children.rend(), [&stack](PathwayLayoutItem* child) { stack.push(child); }); } - // return result; }