From 439a9b8c1985592e915159fe56c177e811a94aef Mon Sep 17 00:00:00 2001 From: even1024 Date: Sun, 26 May 2024 14:17:32 +0200 Subject: [PATCH 01/39] ket text step1 --- core/indigo-core/molecule/ket_commons.h | 14 +++++++------- core/indigo-core/molecule/molecule_cdxml_loader.h | 4 ++-- .../molecule/src/molecule_cdxml_loader.cpp | 4 ++-- .../molecule/src/molecule_cdxml_saver.cpp | 2 +- .../molecule/src/molecule_json_loader.cpp | 9 ++++----- .../molecule/src/molecule_json_saver.cpp | 6 +++--- .../reaction/src/reaction_cdxml_loader.cpp | 2 +- .../reaction/src/reaction_json_loader.cpp | 2 +- core/render2d/render_item_aux.h | 2 +- core/render2d/src/render_item_aux.cpp | 4 ++-- 10 files changed, 24 insertions(+), 25 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 3ab81a27b0..7783c368bb 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -122,7 +122,7 @@ namespace indigo const std::unordered_map KTextStylesMap{ {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; - struct KETTextLine + struct KETTextParagraph { std::string text; std::map styles; @@ -130,10 +130,10 @@ namespace indigo static const std::uint32_t CID = "KET text object"_hash; - KETTextObject(const Vec3f& pos, const std::string& content) : MetaObject(CID) + KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID) { using namespace rapidjson; - _pos = pos; + _bbox = bbox; _content = content; Document data; data.Parse(content.c_str()); @@ -142,7 +142,7 @@ namespace indigo Value& blocks = data["blocks"]; for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) { - KETTextLine text_line; + KETTextParagraph text_line; if (blocks[i].HasMember("text")) { text_line.text = blocks[i]["text"].GetString(); @@ -199,12 +199,12 @@ namespace indigo MetaObject* clone() const override { - return new KETTextObject(_pos, _content); + return new KETTextObject(_bbox, _content); } std::string _content; - std::list _block; - Vec3f _pos; + std::list _block; + Rect2f _bbox; }; class KETReactionArrow : public MetaObject diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index de53741bdb..5510af26fd 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -806,7 +806,7 @@ namespace indigo std::vector nodes; std::vector bonds; std::vector brackets; - std::vector> text_objects; + std::vector> text_objects; static const int SCALE = 30; @@ -821,7 +821,7 @@ namespace indigo void _parseBond(CdxmlBond& bond, BaseCDXProperty& prop); void _parseBracket(CdxmlBracket& bracket, BaseCDXProperty& prop); - void _parseText(BaseCDXElement& elem, std::vector>& text_parsed); + void _parseText(BaseCDXElement& elem, std::vector>& text_parsed); void _parseLabel(BaseCDXElement& elem, std::string& label); void _parseGraphic(BaseCDXElement& elem); diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index faa10fae2f..e3bd5fa3a3 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1530,7 +1530,7 @@ void MoleculeCdxmlLoader::_parseLabel(BaseCDXElement& elem, std::string& label) } } -void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) +void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) { Vec3f text_pos; auto text_coordinates_lambda = [&text_pos, this](const std::string& data) { this->parsePos(data, text_pos); }; @@ -1664,7 +1664,7 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vectorNewElement("t"); _current->LinkEndChild(t); diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 390eb4fbd9..99af2117b1 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1805,11 +1805,10 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat else if (sobj.HasMember("content") && sobj.HasMember("position")) { std::string content = sobj["content"].GetString(); - Vec3f text_origin; - text_origin.x = sobj["position"]["x"].GetFloat(); - text_origin.y = sobj["position"]["y"].GetFloat(); - text_origin.z = sobj["position"]["z"].GetFloat(); - meta_interface.addMetaObject(new KETTextObject(text_origin, content)); + Vec2f v1(sobj["position"]["x"].GetFloat(), sobj["position"]["y"].GetFloat()); + Vec2f v2(v1); + Rect2f text_box(v1, v2); + meta_interface.addMetaObject(new KETTextObject(text_box, content)); } } } diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 1074cb1cc1..a738450f82 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -1835,11 +1835,11 @@ void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, MetaDataStorage& meta) writer.Key("position"); writer.StartObject(); writer.Key("x"); - writer.Double(simple_obj->_pos.x); + writer.Double(simple_obj->_bbox.left()); writer.Key("y"); - writer.Double(simple_obj->_pos.y); + writer.Double(simple_obj->_bbox.top()); writer.Key("z"); - writer.Double(simple_obj->_pos.z); + writer.Double(0.0); writer.EndObject(); // end position writer.EndObject(); // end data writer.EndObject(); // end node diff --git a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp index f914067511..db2f390283 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp @@ -206,7 +206,7 @@ void ReactionCdxmlLoader::loadReaction(BaseReaction& rxn) { auto& text = (KETTextObject&)_pmol->meta().getMetaObject(KETTextObject::CID, i); int idx = rxn.meta().addMetaObject(text.clone()); - rxn.addSpecialCondition(idx, Rect2f(Vec2f(text._pos.x, text._pos.y), Vec2f(text._pos.x, text._pos.y))); + rxn.addSpecialCondition(idx, Rect2f(Vec2f(text._bbox.left(), text._bbox.top()), Vec2f(text._bbox.left(), text._bbox.top()))); } } _cdxml_elements.erase(elem_it); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 001063ed4f..f5a1d4ab77 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -492,7 +492,7 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) for (int i = 0; i < rxn.meta().getMetaCount(KETTextObject::CID); ++i) { auto& text = (const KETTextObject&)rxn.meta().getMetaObject(KETTextObject::CID, i); - Rect2f bbox(Vec2f(text._pos.x, text._pos.y), Vec2f(text._pos.x, text._pos.y)); // change to real text box later + Rect2f bbox(Vec2f(text._bbox.left(), text._bbox.top()), Vec2f(text._bbox.left(), text._bbox.top())); // change to real text box later components.emplace_back(bbox, ReactionFragmentType::TEXT, nullptr); } diff --git a/core/render2d/render_item_aux.h b/core/render2d/render_item_aux.h index a66f38f17f..8fd2a7427b 100644 --- a/core/render2d/render_item_aux.h +++ b/core/render2d/render_item_aux.h @@ -104,7 +104,7 @@ namespace indigo void _drawArrow(const KETReactionArrow& ar); void _renderIdle(); void _renderSimpleObject(const KETSimpleObject& simple); - float _getMaxHeight(const KETTextObject::KETTextLine& tl); + float _getMaxHeight(const KETTextObject::KETTextParagraph& tl); }; } // namespace indigo diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index f42657a3ac..da4ed907d5 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -315,7 +315,7 @@ void RenderItemAuxiliary::_drawMeta(bool idle) TextItem ti; ti.size = KETDefaultFontSize / KETFontScaleFactor; // default size ti.ritype = RenderItem::RIT_TITLE; - Vec2f text_origin(ko._pos.x, ko._pos.y); + Vec2f text_origin(ko._bbox.left(), ko._bbox.top()); scale(text_origin); for (auto& kvp : text_item.styles) { @@ -450,7 +450,7 @@ void RenderItemAuxiliary::init() { } -float RenderItemAuxiliary::_getMaxHeight(const KETTextObject::KETTextLine& tl) +float RenderItemAuxiliary::_getMaxHeight(const KETTextObject::KETTextParagraph& tl) { int first_index = -1; int second_index = -1; From 693f21e92126acfe8b337d7e2ce12dbfe29678fa Mon Sep 17 00:00:00 2001 From: even1024 Date: Sun, 26 May 2024 19:06:26 +0200 Subject: [PATCH 02/39] ket text step2 --- .../molecule/molecule_cdxml_loader.h | 9 +++++---- core/indigo-core/molecule/src/ket_commons.cpp | 1 - .../molecule/src/molecule_cdxml_loader.cpp | 20 ++++++++++--------- utils/indigo-depict/main.c | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index 5510af26fd..a79f3a9f61 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -132,7 +132,8 @@ namespace indigo AutoInt id; std::string label; AutoInt element; - Vec3f pos; + Vec2f pos; + Vec3f pos3d; int type; AutoInt isotope; AutoInt charge; @@ -796,7 +797,7 @@ namespace indigo static void applyDispatcher(BaseCDXProperty& prop, const std::unordered_map>& dispatcher); void parseCDXMLAttributes(BaseCDXProperty& prop); void parseBBox(const std::string& data, Rect2f& bbox); - void parsePos(const std::string& data, Vec3f& bbox); + void parsePos(const std::string& data, Vec2f& bbox); void parseSeg(const std::string& data, Vec2f& v1, Vec2f& v2); StereocentersOptions stereochemistry_options; @@ -848,8 +849,8 @@ namespace indigo std::unordered_map _id_to_bond_index; std::vector _fragment_nodes; std::vector _pluses; - std::vector, int>> _arrows; - std::vector, int>> _graphic_arrows; + std::vector, int>> _arrows; + std::vector, int>> _graphic_arrows; std::vector, int>> _primitives; std::vector _stereo_centers; diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 4cf1389cb7..f446970549 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -130,7 +130,6 @@ namespace indigo } return res; } - } #ifdef _MSC_VER diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index e3bd5fa3a3..b691f3b0fc 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -660,7 +660,7 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n { auto it = std::upper_bound(fragment_node.inner_nodes.cbegin(), fragment_node.inner_nodes.cend(), fragment_node.id, [](int a, int b) { return a > b; }); - if (nodes[i].pos.x == 0 && nodes[i].pos.y == 0 && nodes[i].pos.z == 0) // if no coord - copy from parent + if (nodes[i].pos.x == 0 && nodes[i].pos.y == 0 ) // if no coord - copy from parent nodes[i].pos = fragment_node.pos; fragment_node.inner_nodes.insert(it, nodes[i].id); } @@ -1324,14 +1324,13 @@ void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, BaseCDXProperty& prop) applyDispatcher(prop, bond_dispatcher); } -void MoleculeCdxmlLoader::parsePos(const std::string& data, Vec3f& pos) +void MoleculeCdxmlLoader::parsePos(const std::string& data, Vec2f& pos) { std::vector coords = split(data, ' '); if (coords.size() >= 2) { pos.x = std::stof(coords[0]); pos.y = std::stof(coords[1]); - pos.z = 0; if (this->_has_bounding_box) { pos.x -= this->cdxml_bbox.left(); @@ -1466,7 +1465,7 @@ void MoleculeCdxmlLoader::_parseGraphic(BaseCDXElement& elem) default: break; } - _graphic_arrows.push_back(std::make_pair(std::make_pair(Vec3f(tail.x, tail.y, 0), Vec3f(head.x, head.y, 0)), ar_type)); + _graphic_arrows.push_back(std::make_pair(std::make_pair(tail, head), ar_type)); } } break; @@ -1496,9 +1495,9 @@ void MoleculeCdxmlLoader::_parseArrow(BaseCDXElement& elem) { Rect2f text_bbox; auto arrow_bbox_lambda = [&text_bbox, this](const std::string& data) { this->parseBBox(data, text_bbox); }; - Vec3f begin_pos; + Vec2f begin_pos; auto arrow_begin_lambda = [&begin_pos, this](const std::string& data) { this->parsePos(data, begin_pos); }; - Vec3f end_pos; + Vec2f end_pos; auto arrow_end_lambda = [&end_pos, this](const std::string& data) { this->parsePos(data, end_pos); }; std::string fill_type; auto fill_type_lambda = [&fill_type](const std::string& data) { fill_type = data; }; @@ -1532,7 +1531,7 @@ void MoleculeCdxmlLoader::_parseLabel(BaseCDXElement& elem, std::string& label) void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) { - Vec3f text_pos; + Vec2f text_pos; auto text_coordinates_lambda = [&text_pos, this](const std::string& data) { this->parsePos(data, text_pos); }; Rect2f text_bbox; @@ -1656,9 +1655,12 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector 0 && text_bbox.height() > 0) - tpos.set(text_bbox.center().x, text_bbox.center().y, 0); + { + text_pos.set(text_bbox.center().x, text_bbox.center().y); + text_bbox.copy(Rect2f(text_pos, text_pos)); + } else + text_bbox.copy(Rect2f(text_pos, text_pos)); std::string txt = s.GetString(); if (!is_valid_utf8(txt)) diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index dc776994d8..c2f44db376 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1050,7 +1050,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 82222c2088431051c944834c107488161c8dc8e8 Mon Sep 17 00:00:00 2001 From: even1024 Date: Sun, 26 May 2024 20:04:58 +0200 Subject: [PATCH 03/39] ket text step3 --- core/indigo-core/molecule/molecule_json_loader.h | 3 ++- .../indigo-core/molecule/src/molecule_json_loader.cpp | 11 +++++++---- utils/indigo-depict/main.c | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/indigo-core/molecule/molecule_json_loader.h b/core/indigo-core/molecule/molecule_json_loader.h index 835543d4e1..68c8666cba 100644 --- a/core/indigo-core/molecule/molecule_json_loader.h +++ b/core/indigo-core/molecule/molecule_json_loader.h @@ -122,7 +122,8 @@ namespace indigo Molecule* _pmol; QueryMolecule* _pqmol; std::vector _stereo_centers; - unsigned int components_count; + std::string _ket_version; + unsigned int _components_count; }; } // namespace indigo diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 99af2117b1..23223348e9 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -23,8 +23,11 @@ IMPL_ERROR(MoleculeJsonLoader, "molecule json loader"); MoleculeJsonLoader::MoleculeJsonLoader(Document& ket) : _mol_array(kArrayType), _mol_nodes(_mol_array), _meta_objects(kArrayType), _templates(kArrayType), _monomer_array(kArrayType), - _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), components_count(0) + _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), _components_count(0) { + if (ket.HasMember("ket_version")) + _ket_version = ket["ket_version"].GetString(); + Value& root = ket["root"]; Value& nodes = root["nodes"]; @@ -89,7 +92,7 @@ MoleculeJsonLoader::MoleculeJsonLoader(Document& ket) MoleculeJsonLoader::MoleculeJsonLoader(Value& mol_nodes) : _mol_nodes(mol_nodes), _meta_objects(kArrayType), _templates(kArrayType), _monomer_array(kArrayType), _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), ignore_no_chiral_flag(false), skip_3d_chirality(false), treat_x_as_pseudoatom(false), treat_stereo_as(0), - components_count(0) + _components_count(0) { } @@ -890,11 +893,11 @@ void MoleculeJsonLoader::parseSGroups(const rapidjson::Value& sgroups, BaseMolec if (_pqmol) { _pqmol->components.expandFill(_pqmol->components.size() + atoms.Size(), 0); - components_count++; + _components_count++; for (rapidjson::SizeType j = 0; j < atoms.Size(); ++j) { int atom_idx = atoms[j].GetInt(); - _pqmol->components[atom_idx] = components_count; + _pqmol->components[atom_idx] = _components_count; } } else diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index c2f44db376..dc776994d8 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -1050,7 +1050,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 61e04e02c1288bf306fb82548975161e1531da25 Mon Sep 17 00:00:00 2001 From: even1024 Date: Sun, 26 May 2024 21:19:30 +0200 Subject: [PATCH 04/39] ket text step4 --- core/indigo-core/common/math/algebra.h | 2 +- core/indigo-core/molecule/ket_commons.h | 10 +++++++++- core/indigo-core/molecule/src/molecule_json_loader.cpp | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 73283f9470..d401cae54c 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -309,7 +309,7 @@ namespace indigo _rightTop.max(b._rightTop); } - inline void copy(Rect2f& other) + inline void copy(const Rect2f& other) { _leftBottom = other._leftBottom; _rightTop = other._rightTop; diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 7783c368bb..e0d33070a8 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -130,6 +130,14 @@ namespace indigo static const std::uint32_t CID = "KET text object"_hash; + KETTextObject(const KETTextObject& other) + : MetaObject(CID) + { + _bbox.copy(other._bbox); + _content = other._content; + _block = other._block; + } + KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID) { using namespace rapidjson; @@ -199,7 +207,7 @@ namespace indigo MetaObject* clone() const override { - return new KETTextObject(_bbox, _content); + return new KETTextObject(*this); } std::string _content; diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 23223348e9..906c3121da 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1814,6 +1814,10 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat meta_interface.addMetaObject(new KETTextObject(text_box, content)); } } + else if (node_type == "text") + { + + } } else if (node_type == "arrow") { From 15b6e3df4b3746ce7a2c7820ac298d55673770a5 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 27 May 2024 19:39:08 +0200 Subject: [PATCH 05/39] ket text step5 --- core/indigo-core/molecule/ket_commons.h | 52 +++++++++++++++++-- .../molecule/src/molecule_json_loader.cpp | 4 +- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index e0d33070a8..5ac93ee260 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -41,6 +41,11 @@ namespace indigo const auto KETFontSuperscriptStr = "SUPERSCRIPT"; const auto KETFontSubscriptStr = "SUBSCRIPT"; const auto KETFontCustomSizeStr = "CUSTOM_FONT_SIZE"; + const auto KETAlignmentLeft = "left"; + const auto KETAlignmentRight = "right"; + const auto KETAlignmentCenter = "center"; + const auto KETAlignmentJustify = "justify"; + const uint8_t KETReactantArea = 0; const uint8_t KETReagentUpArea = 1; const uint8_t KETReagentDownArea = 2; @@ -102,6 +107,7 @@ namespace indigo EKETRectangle, EKETLine }; + int _mode; std::pair _coordinates; }; @@ -119,9 +125,36 @@ namespace indigo EFontSize = 5 }; + enum class TextAlignment : int + { + ELeft, + ERight, + ECenter, + EJustify + }; + + const std::unordered_map KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, + {KETAlignmentRight, TextAlignment::ERight}, + {KETAlignmentCenter, TextAlignment::ECenter}, + {KETAlignmentJustify, TextAlignment::EJustify}}; + const std::unordered_map KTextStylesMap{ {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; + struct KETTextIndent + { + float left; + float right; + float first_line; + }; + + struct KETTextFont + { + std::string family; + int size; + uint32_t color; + }; + struct KETTextParagraph { std::string text; @@ -130,15 +163,14 @@ namespace indigo static const std::uint32_t CID = "KET text object"_hash; - KETTextObject(const KETTextObject& other) - : MetaObject(CID) + KETTextObject(const KETTextObject& other) : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font} { _bbox.copy(other._bbox); _content = other._content; _block = other._block; } - KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID) + KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} { using namespace rapidjson; _bbox = bbox; @@ -205,6 +237,17 @@ namespace indigo } } + KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + { + using namespace rapidjson; + auto& bbox = text_obj["bounding_box"]; + Vec2f v1(bbox["x"].GetFloat(), bbox["y"].GetFloat()); + Vec2f v2(v1); + v2.add(Vec2f(bbox["width"].GetFloat(), bbox["height"].GetFloat())); + _bbox.copy(Rect2f(v1, v2)); + + } + MetaObject* clone() const override { return new KETTextObject(*this); @@ -213,6 +256,9 @@ namespace indigo std::string _content; std::list _block; Rect2f _bbox; + KETTextIndent _indent; + KETTextFont _font; + TextAlignment _alignment; }; class KETReactionArrow : public MetaObject diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 906c3121da..ee17f8d192 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1815,9 +1815,7 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat } } else if (node_type == "text") - { - - } + meta_interface.addMetaObject(new KETTextObject(mobj)); } else if (node_type == "arrow") { From f931c8d2e2a6c6e8acb1fcf6217a7095c2872a13 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 29 May 2024 13:19:43 +0200 Subject: [PATCH 06/39] ket text step6 --- core/indigo-core/molecule/ket_commons.h | 56 ++++++++++++++++--------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 5ac93ee260..72874d14b9 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -114,6 +114,7 @@ namespace indigo class KETTextObject : public MetaObject { + public: enum { @@ -134,9 +135,9 @@ namespace indigo }; const std::unordered_map KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, - {KETAlignmentRight, TextAlignment::ERight}, - {KETAlignmentCenter, TextAlignment::ECenter}, - {KETAlignmentJustify, TextAlignment::EJustify}}; + {KETAlignmentRight, TextAlignment::ERight}, + {KETAlignmentCenter, TextAlignment::ECenter}, + {KETAlignmentJustify, TextAlignment::EJustify}}; const std::unordered_map KTextStylesMap{ {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; @@ -163,11 +164,17 @@ namespace indigo static const std::uint32_t CID = "KET text object"_hash; - KETTextObject(const KETTextObject& other) : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font} + std::string _content; + std::list _block; + Rect2f _bbox; + KETTextIndent _indent; + KETTextFont _font; + TextAlignment _alignment; + + KETTextObject(const KETTextObject& other) + : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font}, _bbox(other._bbox), _content(other._content), + _block(other._block) { - _bbox.copy(other._bbox); - _content = other._content; - _block = other._block; } KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} @@ -240,25 +247,36 @@ namespace indigo KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} { using namespace rapidjson; - auto& bbox = text_obj["bounding_box"]; - Vec2f v1(bbox["x"].GetFloat(), bbox["y"].GetFloat()); - Vec2f v2(v1); - v2.add(Vec2f(bbox["width"].GetFloat(), bbox["height"].GetFloat())); - _bbox.copy(Rect2f(v1, v2)); + auto bbox_lambda = [this](const Value& bbox_val) { + Vec2f v1(bbox_val["x"].GetFloat(), bbox_val["y"].GetFloat()); + Vec2f v2(v1); + v2.add(Vec2f(bbox_val["width"].GetFloat(), bbox_val["height"].GetFloat())); + _bbox.copy(Rect2f(v1, v2)); + }; + + auto alignment_lambda = [this](const Value& align_val) { + auto ta_it = KTextAlignmentsMap.find(align_val.GetString()); + if (ta_it != KTextAlignmentsMap.end()) + _alignment = ta_it->second; + }; + + std::unordered_map> node_dispatcher = { + {"bounding_box", bbox_lambda}, + {"alignment", alignment_lambda}}; + + for (auto kvp_it = text_obj.MemberBegin(); kvp_it != text_obj.MemberEnd(); ++kvp_it) + { + auto disp_it = node_dispatcher.find(kvp_it->name.GetString()); + if (disp_it != node_dispatcher.end()) + disp_it->second(kvp_it->value); + } } MetaObject* clone() const override { return new KETTextObject(*this); } - - std::string _content; - std::list _block; - Rect2f _bbox; - KETTextIndent _indent; - KETTextFont _font; - TextAlignment _alignment; }; class KETReactionArrow : public MetaObject From 20d8abd47308e9838b327faed83a54fa1348a555 Mon Sep 17 00:00:00 2001 From: even1024 Date: Sat, 1 Jun 2024 09:47:50 +0200 Subject: [PATCH 07/39] ket text step7 --- core/indigo-core/molecule/ket_commons.h | 260 ++++++++++++------ core/indigo-core/molecule/src/ket_commons.cpp | 116 ++++++++ 2 files changed, 287 insertions(+), 89 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 72874d14b9..507550e81f 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -114,7 +114,6 @@ namespace indigo class KETTextObject : public MetaObject { - public: enum { @@ -134,12 +133,17 @@ namespace indigo EJustify }; - const std::unordered_map KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, - {KETAlignmentRight, TextAlignment::ERight}, - {KETAlignmentCenter, TextAlignment::ECenter}, - {KETAlignmentJustify, TextAlignment::EJustify}}; + using TextAlignMap = const std::unordered_map; + using StrIntMap = const std::unordered_map; + using DispatchMapKVP = std::unordered_map>; + using DispatchMapVal = std::unordered_map>; + + TextAlignMap KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, + {KETAlignmentRight, TextAlignment::ERight}, + {KETAlignmentCenter, TextAlignment::ECenter}, + {KETAlignmentJustify, TextAlignment::EJustify}}; - const std::unordered_map KTextStylesMap{ + StrIntMap KTextStylesMap{ {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; struct KETTextIndent @@ -151,14 +155,32 @@ namespace indigo struct KETTextFont { + KETTextFont() : size(0), color(0) + { + } std::string family; int size; uint32_t color; }; + struct KETTextStyle + { + KETTextStyle() : bold(false), italic(false), subscript(false), superscript(false) + { + } + bool bold; + bool italic; + bool subscript; + bool superscript; + }; + struct KETTextParagraph { std::string text; + KETTextStyle style; + KETTextFont font; + TextAlignment alignment; + KETTextIndent indent; std::map styles; }; @@ -170,109 +192,169 @@ namespace indigo KETTextIndent _indent; KETTextFont _font; TextAlignment _alignment; + KETTextStyle _style; - KETTextObject(const KETTextObject& other) - : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font}, _bbox(other._bbox), _content(other._content), - _block(other._block) + static void applyDispatcher(const rapidjson::Value& val, const DispatchMapKVP& disp_map) { + for (auto kvp_it = val.MemberBegin(); kvp_it != val.MemberEnd(); ++kvp_it) + { + auto disp_it = disp_map.find(kvp_it->name.GetString()); + if (disp_it != disp_map.end()) + disp_it->second(kvp_it->name.GetString(), kvp_it->value); + } } - KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + static void applyDispatcher(const rapidjson::Value& val, const DispatchMapVal& disp_map) { - using namespace rapidjson; - _bbox = bbox; - _content = content; - Document data; - data.Parse(content.c_str()); - if (data.HasMember("blocks")) + for (auto kvp_it = val.MemberBegin(); kvp_it != val.MemberEnd(); ++kvp_it) { - Value& blocks = data["blocks"]; - for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) + auto disp_it = disp_map.find(kvp_it->name.GetString()); + if (disp_it != disp_map.end()) + disp_it->second(kvp_it->value); + } + } + + static auto floatLambda(float& val) + { + return [&val](const rapidjson::Value& float_val) { val = float_val.GetFloat(); }; + } + + static auto intLambda(int& val) + { + return [&val](const rapidjson::Value& int_val) { val = int_val.GetInt(); }; + } + + static auto strLambda(std::string& str) + { + return [&str](const rapidjson::Value& str_val) { str = str_val.GetString(); }; + } + + static auto colorLambda(uint32_t& color) + { + return [&color](const rapidjson::Value& color_str) { + std::string color_string = color_str.GetString(); + if (color_string.length() == 7 && color_string[0] == '#') + color = std::stoul(color_string.substr(1), nullptr, 16); + }; + } + + auto alignLambda(TextAlignment& alignment) + { + return [this, &alignment](const std::string&, const rapidjson::Value& align_val) { + auto ta_it = KTextAlignmentsMap.find(align_val.GetString()); + if (ta_it != KTextAlignmentsMap.end()) + alignment = ta_it->second; + }; + } + + auto styleLambda(KETTextStyle& style) + { + return [this, &style](const std::string& key, const rapidjson::Value& style_val) { + std::string style_name = key; + std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); + auto ta_it = KTextStylesMap.find(style_name); + if (ta_it != KTextStylesMap.end()) { - KETTextParagraph text_line; - if (blocks[i].HasMember("text")) + bool bval = style_val.GetBool(); + switch (ta_it->second) { - text_line.text = blocks[i]["text"].GetString(); - text_line.styles.emplace(0, std::initializer_list>{}); - text_line.styles.emplace(text_line.text.size(), std::initializer_list>{}); - if (blocks[i].HasMember("inlineStyleRanges")) - { - Value& style_ranges = blocks[i]["inlineStyleRanges"]; - for (rapidjson::SizeType j = 0; j < style_ranges.Size(); ++j) - { - int style_begin = style_ranges[j]["offset"].GetInt(); - int style_end = style_begin + style_ranges[j]["length"].GetInt(); - int style_code = -1; - - std::string style = style_ranges[j]["style"].GetString(); - auto it = KTextStylesMap.find(style); - if (it != KTextStylesMap.end()) - { - style_code = it->second; - } - else - { - const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; - const std::string KCustomFontUnits = "px"; - if (style.find(KCustomFontSize) == 0) - { - style_code = - std::stoi(style.substr(KCustomFontSize.size(), style.size() - KCustomFontSize.size() - KCustomFontUnits.size())); - } - } - const auto it_begin = text_line.styles.find(style_begin); - const auto it_end = text_line.styles.find(style_end); - - if (it_begin == text_line.styles.end()) - text_line.styles.emplace(style_begin, std::initializer_list>{{style_code, true}}); - else - { - it_begin->second.emplace(style_code, true); - } - - if (it_end == text_line.styles.end()) - text_line.styles.emplace(style_end, std::initializer_list>{{style_code, false}}); - else - { - it_end->second.emplace(style_code, false); - } - } - } + case EBold: + style.bold = bval; + break; + case EItalic: + style.italic = bval; + break; + case ESubScript: + style.subscript = bval; + break; + case ESuperScript: + style.superscript = bval; + break; + default: + break; } - _block.push_back(text_line); } - } + }; } - KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + auto styleLambda(FONT_STYLE_SET& style) { - using namespace rapidjson; - auto bbox_lambda = [this](const Value& bbox_val) { - Vec2f v1(bbox_val["x"].GetFloat(), bbox_val["y"].GetFloat()); - Vec2f v2(v1); - v2.add(Vec2f(bbox_val["width"].GetFloat(), bbox_val["height"].GetFloat())); - _bbox.copy(Rect2f(v1, v2)); - }; + return [this, &style](const std::string& key, const rapidjson::Value& style_val) { + std::string style_name = key; + std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); + auto ta_it = KTextStylesMap.find(style_name); + if (ta_it != KTextStylesMap.end()) + style.emplace(ta_it->second, style_val.GetBool()); + }; + } - auto alignment_lambda = [this](const Value& align_val) { - auto ta_it = KTextAlignmentsMap.find(align_val.GetString()); - if (ta_it != KTextAlignmentsMap.end()) - _alignment = ta_it->second; + static auto indentLambda(KETTextIndent& indent) + { + return [&indent](const std::string&, const rapidjson::Value& indent_val) { + std::unordered_map> indent_dispatcher = { + {"first_line", floatLambda(indent.first_line)}, {"left", floatLambda(indent.left)}, {"right", floatLambda(indent.right)}}; + + for (auto indent_it = indent_val.MemberBegin(); indent_it != indent_val.MemberEnd(); ++indent_it) + { + auto ind_it = indent_dispatcher.find(indent_it->name.GetString()); + if (ind_it != indent_dispatcher.end()) + ind_it->second(indent_it->value); + } }; + } + static auto fontLambda(KETTextFont& font) + { + return [&font](const std::string&, const rapidjson::Value& font_val) { + DispatchMapVal font_dispatcher = {{"family", strLambda(font.family)}, {"size", intLambda(font.size)}, {"color", colorLambda(font.color)}}; + applyDispatcher(font_val, font_dispatcher); + }; + } + + auto partsLambda(KETTextParagraph& paragraph) + { + return [this, ¶graph](const std::string&, const rapidjson::Value& parts) { + auto text_lambda = [¶graph](const std::string&, const rapidjson::Value& text_val) { paragraph.text += text_val.GetString(); }; + auto style_lambda = [this, ¶graph](const std::string& key, const rapidjson::Value& style_val) + { + std::string style_name = key; + std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); + auto ta_it = KTextStylesMap.find(style_name); + if (ta_it != KTextStylesMap.end()) + { + bool bval = style_val.GetBool(); + switch (ta_it->second) + { + case EBold: + break; + case EItalic: + break; + case ESubScript: + break; + case ESuperScript: + break; + default: + break; + } + } + }; + for (const auto& part : parts.GetArray()) + { - std::unordered_map> node_dispatcher = { - {"bounding_box", bbox_lambda}, - {"alignment", alignment_lambda}}; + } + }; + } - for (auto kvp_it = text_obj.MemberBegin(); kvp_it != text_obj.MemberEnd(); ++kvp_it) - { - auto disp_it = node_dispatcher.find(kvp_it->name.GetString()); - if (disp_it != node_dispatcher.end()) - disp_it->second(kvp_it->value); - } + KETTextObject(const KETTextObject& other) + : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font}, _bbox(other._bbox), _content(other._content), + _block(other._block) + { } + KETTextObject(const Rect2f& bbox, const std::string& content); + + KETTextObject(const rapidjson::Value& text_obj); + MetaObject* clone() const override { return new KETTextObject(*this); diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index f446970549..97a0dd0da4 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -130,6 +130,122 @@ namespace indigo } return res; } + + KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + { + using namespace rapidjson; + _bbox = bbox; + _content = content; + Document data; + data.Parse(content.c_str()); + if (data.HasMember("blocks")) + { + Value& blocks = data["blocks"]; + for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) + { + KETTextParagraph text_line; + if (blocks[i].HasMember("text")) + { + text_line.text = blocks[i]["text"].GetString(); + text_line.styles.emplace(0, std::initializer_list>{}); + text_line.styles.emplace(text_line.text.size(), std::initializer_list>{}); + if (blocks[i].HasMember("inlineStyleRanges")) + { + Value& style_ranges = blocks[i]["inlineStyleRanges"]; + for (rapidjson::SizeType j = 0; j < style_ranges.Size(); ++j) + { + int style_begin = style_ranges[j]["offset"].GetInt(); + int style_end = style_begin + style_ranges[j]["length"].GetInt(); + int style_code = -1; + + std::string style = style_ranges[j]["style"].GetString(); + auto it = KTextStylesMap.find(style); + if (it != KTextStylesMap.end()) + { + style_code = it->second; + } + else + { + const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; + const std::string KCustomFontUnits = "px"; + if (style.find(KCustomFontSize) == 0) + { + style_code = + std::stoi(style.substr(KCustomFontSize.size(), style.size() - KCustomFontSize.size() - KCustomFontUnits.size())); + } + } + const auto it_begin = text_line.styles.find(style_begin); + const auto it_end = text_line.styles.find(style_end); + + if (it_begin == text_line.styles.end()) + text_line.styles.emplace(style_begin, std::initializer_list>{{style_code, true}}); + else + { + it_begin->second.emplace(style_code, true); + } + + if (it_end == text_line.styles.end()) + text_line.styles.emplace(style_end, std::initializer_list>{{style_code, false}}); + else + { + it_end->second.emplace(style_code, false); + } + } + } + } + _block.push_back(text_line); + } + } + } + + KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + { + using namespace rapidjson; + + auto bbox_lambda = [this](const std::string&, const Value& bbox_val) { + Vec2f v1(bbox_val["x"].GetFloat(), bbox_val["y"].GetFloat()); + Vec2f v2(v1); + v2.add(Vec2f(bbox_val["width"].GetFloat(), bbox_val["height"].GetFloat())); + _bbox.copy(Rect2f(v1, v2)); + }; + + auto paragraphs_lambda = [this](const std::string&, const Value& paragraphs_val) { + for (const auto& paragraph : paragraphs_val.GetArray()) + { + KETTextParagraph text_line; + auto style_lambda = styleLambda(text_line.style); + DispatchMapKVP paragraph_dispatcher = { + {"alignment", alignLambda(text_line.alignment)}, + {"bold", style_lambda}, + {"italic", style_lambda}, + {"subscript", style_lambda}, + {"superscript", style_lambda}, + {"indent", indentLambda(text_line.indent)}, + {"font", fontLambda(text_line.font)}, + {"parts", partsLambda(text_line)}}; + + applyDispatcher(paragraph, paragraph_dispatcher); + _block.push_back(text_line); + } + }; + + auto style_lambda = styleLambda(_style); + + DispatchMapKVP text_obj_dispatcher = { + {"bounding_box", bbox_lambda}, + {"alignment", alignLambda(_alignment)}, + {"bold", style_lambda}, + {"italic", style_lambda}, + {"subscript", style_lambda}, + {"superscript", style_lambda}, + {"indent", indentLambda(_indent)}, + {"font", fontLambda(_font)}, + {"paragraphs", paragraphs_lambda} + }; + applyDispatcher(text_obj, text_obj_dispatcher); + } + + } #ifdef _MSC_VER From 76a7d20aff3f3ca836bd16abd6c6996d3281693b Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 3 Jun 2024 00:43:06 +0200 Subject: [PATCH 08/39] ket text step8 --- core/indigo-core/molecule/ket_commons.h | 109 +++++++++++------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 507550e81f..000d0294da 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -148,9 +148,9 @@ namespace indigo struct KETTextIndent { - float left; - float right; - float first_line; + std::optional left; + std::optional right; + std::optional first_line; }; struct KETTextFont @@ -158,30 +158,34 @@ namespace indigo KETTextFont() : size(0), color(0) { } - std::string family; - int size; - uint32_t color; + std::optional family; + std::optional size; + std::optional color; }; struct KETTextStyle { - KETTextStyle() : bold(false), italic(false), subscript(false), superscript(false) + KETTextStyle() { } - bool bold; - bool italic; - bool subscript; - bool superscript; + std::optional bold; + std::optional italic; + std::optional subscript; + std::optional superscript; }; struct KETTextParagraph { + KETTextParagraph() + { + } std::string text; - KETTextStyle style; - KETTextFont font; - TextAlignment alignment; - KETTextIndent indent; + std::optional style; + std::optional font; + std::optional alignment; + std::optional indent; std::map styles; + std::map fonts; }; static const std::uint32_t CID = "KET text object"_hash; @@ -189,10 +193,10 @@ namespace indigo std::string _content; std::list _block; Rect2f _bbox; - KETTextIndent _indent; - KETTextFont _font; - TextAlignment _alignment; - KETTextStyle _style; + std::optional _indent; + std::optional _font; + std::optional _alignment; + std::optional _style; static void applyDispatcher(const rapidjson::Value& val, const DispatchMapKVP& disp_map) { @@ -214,22 +218,22 @@ namespace indigo } } - static auto floatLambda(float& val) + static auto floatLambda(std::optional& val) { return [&val](const rapidjson::Value& float_val) { val = float_val.GetFloat(); }; } - static auto intLambda(int& val) + static auto intLambda(std::optional& val) { return [&val](const rapidjson::Value& int_val) { val = int_val.GetInt(); }; } - static auto strLambda(std::string& str) + static auto strLambda(std::optional& str) { return [&str](const rapidjson::Value& str_val) { str = str_val.GetString(); }; } - static auto colorLambda(uint32_t& color) + static auto colorLambda(std::optional& color) { return [&color](const rapidjson::Value& color_str) { std::string color_string = color_str.GetString(); @@ -238,7 +242,7 @@ namespace indigo }; } - auto alignLambda(TextAlignment& alignment) + auto alignLambda(std::optional& alignment) { return [this, &alignment](const std::string&, const rapidjson::Value& align_val) { auto ta_it = KTextAlignmentsMap.find(align_val.GetString()); @@ -247,7 +251,7 @@ namespace indigo }; } - auto styleLambda(KETTextStyle& style) + auto styleLambda(std::optional& style) { return [this, &style](const std::string& key, const rapidjson::Value& style_val) { std::string style_name = key; @@ -256,19 +260,20 @@ namespace indigo if (ta_it != KTextStylesMap.end()) { bool bval = style_val.GetBool(); + style = KETTextStyle(); switch (ta_it->second) { case EBold: - style.bold = bval; + style.value().bold = bval; break; case EItalic: - style.italic = bval; + style.value().italic = bval; break; case ESubScript: - style.subscript = bval; + style.value().subscript = bval; break; case ESuperScript: - style.superscript = bval; + style.value().superscript = bval; break; default: break; @@ -288,11 +293,11 @@ namespace indigo }; } - static auto indentLambda(KETTextIndent& indent) + static auto indentLambda(std::optional& indent) { return [&indent](const std::string&, const rapidjson::Value& indent_val) { std::unordered_map> indent_dispatcher = { - {"first_line", floatLambda(indent.first_line)}, {"left", floatLambda(indent.left)}, {"right", floatLambda(indent.right)}}; + {"first_line", floatLambda(indent.value().first_line)}, {"left", floatLambda(indent.value().left)}, {"right", floatLambda(indent.value().right)}}; for (auto indent_it = indent_val.MemberBegin(); indent_it != indent_val.MemberEnd(); ++indent_it) { @@ -303,10 +308,12 @@ namespace indigo }; } - static auto fontLambda(KETTextFont& font) + static auto fontLambda(std::optional& font) { return [&font](const std::string&, const rapidjson::Value& font_val) { - DispatchMapVal font_dispatcher = {{"family", strLambda(font.family)}, {"size", intLambda(font.size)}, {"color", colorLambda(font.color)}}; + font = KETTextFont(); + DispatchMapVal font_dispatcher = { + {"family", strLambda(font.value().family)}, {"size", intLambda(font.value().size)}, {"color", colorLambda(font.value().color)}}; applyDispatcher(font_val, font_dispatcher); }; } @@ -314,33 +321,21 @@ namespace indigo auto partsLambda(KETTextParagraph& paragraph) { return [this, ¶graph](const std::string&, const rapidjson::Value& parts) { - auto text_lambda = [¶graph](const std::string&, const rapidjson::Value& text_val) { paragraph.text += text_val.GetString(); }; - auto style_lambda = [this, ¶graph](const std::string& key, const rapidjson::Value& style_val) + for (const auto& part : parts.GetArray()) { - std::string style_name = key; - std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); - auto ta_it = KTextStylesMap.find(style_name); - if (ta_it != KTextStylesMap.end()) + std::string text; + FONT_STYLE_SET fss; + auto text_lambda = [&text](const std::string&, const rapidjson::Value& text_val) { text = text_val.GetString(); }; + auto style_lambda = styleLambda(fss); + DispatchMapKVP paragraph_dispatcher = { + {"text", text_lambda}, {"bold", style_lambda}, {"italic", style_lambda}, {"subscript", style_lambda}, {"superscript", style_lambda}, + }; + applyDispatcher(part, paragraph_dispatcher); + if (text.size()) { - bool bval = style_val.GetBool(); - switch (ta_it->second) - { - case EBold: - break; - case EItalic: - break; - case ESubScript: - break; - case ESuperScript: - break; - default: - break; - } + paragraph.styles.emplace(paragraph.text.size(), fss); + paragraph.text += text; } - }; - for (const auto& part : parts.GetArray()) - { - } }; } From 366fdb696bc1675229eaee887840290a01b07ad1 Mon Sep 17 00:00:00 2001 From: even1024 Date: Fri, 7 Jun 2024 10:12:27 +0200 Subject: [PATCH 09/39] ket text step9 --- core/indigo-core/molecule/ket_commons.h | 228 +++++++++++------- core/indigo-core/molecule/src/ket_commons.cpp | 81 +++---- .../molecule/src/molecule_cdxml_saver.cpp | 22 +- core/render2d/src/render_item_aux.cpp | 25 +- 4 files changed, 204 insertions(+), 152 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 000d0294da..241550c32d 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "common/math/algebra.h" #include "graph/graph.h" @@ -52,15 +53,90 @@ namespace indigo const uint8_t KETProductArea = 3; const Vec2f MIN_MOL_SIZE = {0.5, 0.5}; + struct KETFontStyle + { + enum class FontStyle : int + { + ENone, + EBold, + EItalic, + ESuperScript, + ESubScript, + EFamily, + ESize, + EColor + }; + + KETFontStyle(const FontStyle fs, std::variant val = std::monostate{}) : _font_style(fs), _val(val) + { + } + + KETFontStyle() : _font_style(FontStyle::ENone) + { + } + + KETFontStyle(const KETFontStyle& other) : _font_style(other._font_style), _val(other._val) + { + } + + operator int() const + { + return static_cast(_font_style); + } + + operator FontStyle() const + { + return _font_style; + } + + FontStyle getFontStyle() const + { + return _font_style; + } + + std::optional getString() const + { + if (auto str = std::get_if(&_val)) + return *str; + return std::nullopt; + } + + std::optional getUInt() const + { + if (auto val = std::get_if(&_val)) + return *val; + return std::nullopt; + } + + void setFontStyle( FontStyle fs ) + { + _font_style = fs; + } + + void setValue(const std::string& val) + { + _val = val; + } + + void setValue(uint32_t val) + { + _val = val; + } + + private: + FontStyle _font_style; + std::variant _val; + }; + struct compareFunction { - bool operator()(const std::pair& a, const std::pair& b) const + bool operator()(const std::pair& a, const std::pair& b) const { - return a.second == b.second ? a.first < b.first : a.second < b.second; + return a.second == b.second ? static_cast(a.first) < static_cast(b.first) : a.second < b.second; } }; - using FONT_STYLE_SET = std::set, compareFunction>; + using FONT_STYLE_SET = std::set, compareFunction>; constexpr std::uint32_t string_hash(char const* s, std::size_t count) { @@ -115,16 +191,6 @@ namespace indigo class KETTextObject : public MetaObject { public: - enum - { - EPlain = 0, - EBold = 1, - EItalic = 2, - ESuperScript = 3, - ESubScript = 4, - EFontSize = 5 - }; - enum class TextAlignment : int { ELeft, @@ -135,6 +201,7 @@ namespace indigo using TextAlignMap = const std::unordered_map; using StrIntMap = const std::unordered_map; + using FontStyleMap = const std::unordered_map; using DispatchMapKVP = std::unordered_map>; using DispatchMapVal = std::unordered_map>; @@ -143,8 +210,18 @@ namespace indigo {KETAlignmentCenter, TextAlignment::ECenter}, {KETAlignmentJustify, TextAlignment::EJustify}}; - StrIntMap KTextStylesMap{ - {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; + FontStyleMap KTextStylesMap{{KETFontBoldStr, KETFontStyle::FontStyle::EBold}, + {KETFontItalicStr, KETFontStyle::FontStyle::EItalic}, + {KETFontSuperscriptStr, KETFontStyle::FontStyle::ESuperScript}, + {KETFontSubscriptStr, KETFontStyle::FontStyle::ESubScript}}; + + const std::unordered_map KTextFontStylesMap{{"bold", KETFontStyle::FontStyle::EBold}, + {"italic ", KETFontStyle::FontStyle::EItalic}, + {"superscript", KETFontStyle::FontStyle::ESuperScript}, + {"subscript", KETFontStyle::FontStyle::ESubScript}, + {"family", KETFontStyle::FontStyle::EFamily}, + {"size", KETFontStyle::FontStyle::ESize}, + {"color", KETFontStyle::FontStyle::EColor}}; struct KETTextIndent { @@ -153,39 +230,16 @@ namespace indigo std::optional first_line; }; - struct KETTextFont - { - KETTextFont() : size(0), color(0) - { - } - std::optional family; - std::optional size; - std::optional color; - }; - - struct KETTextStyle - { - KETTextStyle() - { - } - std::optional bold; - std::optional italic; - std::optional subscript; - std::optional superscript; - }; - struct KETTextParagraph { KETTextParagraph() { } std::string text; - std::optional style; - std::optional font; + FONT_STYLE_SET font_style; std::optional alignment; std::optional indent; - std::map styles; - std::map fonts; + std::map font_styles; }; static const std::uint32_t CID = "KET text object"_hash; @@ -194,9 +248,8 @@ namespace indigo std::list _block; Rect2f _bbox; std::optional _indent; - std::optional _font; std::optional _alignment; - std::optional _style; + FONT_STYLE_SET _font_style; static void applyDispatcher(const rapidjson::Value& val, const DispatchMapKVP& disp_map) { @@ -233,15 +286,6 @@ namespace indigo return [&str](const rapidjson::Value& str_val) { str = str_val.GetString(); }; } - static auto colorLambda(std::optional& color) - { - return [&color](const rapidjson::Value& color_str) { - std::string color_string = color_str.GetString(); - if (color_string.length() == 7 && color_string[0] == '#') - color = std::stoul(color_string.substr(1), nullptr, 16); - }; - } - auto alignLambda(std::optional& alignment) { return [this, &alignment](const std::string&, const rapidjson::Value& align_val) { @@ -251,45 +295,51 @@ namespace indigo }; } - auto styleLambda(std::optional& style) + auto styleLambda(FONT_STYLE_SET& fs) { - return [this, &style](const std::string& key, const rapidjson::Value& style_val) { + return [this, &fs](const std::string& key, const rapidjson::Value& style_val) { std::string style_name = key; std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); auto ta_it = KTextStylesMap.find(style_name); if (ta_it != KTextStylesMap.end()) + fs.emplace(ta_it->second, style_val.GetBool()); + }; + } + + static auto colorLambda(FONT_STYLE_SET& fs, bool bval) + { + return [&fs, bval](const rapidjson::Value& color_str) { + std::string color_string = color_str.GetString(); + if (color_string.length() == 7 && color_string[0] == '#') { - bool bval = style_val.GetBool(); - style = KETTextStyle(); - switch (ta_it->second) - { - case EBold: - style.value().bold = bval; - break; - case EItalic: - style.value().italic = bval; - break; - case ESubScript: - style.value().subscript = bval; - break; - case ESuperScript: - style.value().superscript = bval; - break; - default: - break; - } + fs.emplace(std::piecewise_construct, + std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, std::stoul(color_string.substr(1), nullptr, 16)), + std::forward_as_tuple(bval)); } }; } - auto styleLambda(FONT_STYLE_SET& style) + static auto fontFamilyLambda(FONT_STYLE_SET& fs, bool bval) { - return [this, &style](const std::string& key, const rapidjson::Value& style_val) { - std::string style_name = key; - std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); - auto ta_it = KTextStylesMap.find(style_name); - if (ta_it != KTextStylesMap.end()) - style.emplace(ta_it->second, style_val.GetBool()); + return [&fs, bval](const rapidjson::Value& val) { + if (val.IsString()) + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), std::forward_as_tuple(bval)); + }; + } + + static auto fontSizeLambda(FONT_STYLE_SET& fs, bool bval) + { + return [&fs, bval](const rapidjson::Value& val) { + if (val.IsInt()) + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), std::forward_as_tuple(bval)); + }; + } + + auto fontLambda(FONT_STYLE_SET& fs, bool bval = true) + { + return [&fs, bval](const std::string&, const rapidjson::Value& font_val) { + DispatchMapVal font_dispatcher = {{"family", fontFamilyLambda(fs, bval)}, {"size", fontSizeLambda(fs, bval)}, {"color", colorLambda(fs, bval)}}; + applyDispatcher(font_val, font_dispatcher); }; } @@ -297,7 +347,9 @@ namespace indigo { return [&indent](const std::string&, const rapidjson::Value& indent_val) { std::unordered_map> indent_dispatcher = { - {"first_line", floatLambda(indent.value().first_line)}, {"left", floatLambda(indent.value().left)}, {"right", floatLambda(indent.value().right)}}; + {"first_line", floatLambda(indent.value().first_line)}, + {"left", floatLambda(indent.value().left)}, + {"right", floatLambda(indent.value().right)}}; for (auto indent_it = indent_val.MemberBegin(); indent_it != indent_val.MemberEnd(); ++indent_it) { @@ -308,16 +360,6 @@ namespace indigo }; } - static auto fontLambda(std::optional& font) - { - return [&font](const std::string&, const rapidjson::Value& font_val) { - font = KETTextFont(); - DispatchMapVal font_dispatcher = { - {"family", strLambda(font.value().family)}, {"size", intLambda(font.value().size)}, {"color", colorLambda(font.value().color)}}; - applyDispatcher(font_val, font_dispatcher); - }; - } - auto partsLambda(KETTextParagraph& paragraph) { return [this, ¶graph](const std::string&, const rapidjson::Value& parts) { @@ -333,7 +375,7 @@ namespace indigo applyDispatcher(part, paragraph_dispatcher); if (text.size()) { - paragraph.styles.emplace(paragraph.text.size(), fss); + paragraph.font_styles.emplace(paragraph.text.size(), fss); paragraph.text += text; } } @@ -341,8 +383,8 @@ namespace indigo } KETTextObject(const KETTextObject& other) - : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font{other._font}, _bbox(other._bbox), _content(other._content), - _block(other._block) + : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font_style{other._font_style}, _bbox(other._bbox), + _content(other._content), _block(other._block) { } diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 97a0dd0da4..3ade426900 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -131,7 +131,7 @@ namespace indigo return res; } - KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_style{} { using namespace rapidjson; _bbox = bbox; @@ -147,8 +147,8 @@ namespace indigo if (blocks[i].HasMember("text")) { text_line.text = blocks[i]["text"].GetString(); - text_line.styles.emplace(0, std::initializer_list>{}); - text_line.styles.emplace(text_line.text.size(), std::initializer_list>{}); + text_line.font_styles.emplace(0, std::initializer_list>{{}}); + text_line.font_styles.emplace(text_line.text.size(), std::initializer_list>{{}}); if (blocks[i].HasMember("inlineStyleRanges")) { Value& style_ranges = blocks[i]["inlineStyleRanges"]; @@ -156,39 +156,39 @@ namespace indigo { int style_begin = style_ranges[j]["offset"].GetInt(); int style_end = style_begin + style_ranges[j]["length"].GetInt(); - int style_code = -1; std::string style = style_ranges[j]["style"].GetString(); + KETFontStyle ket_fs; auto it = KTextStylesMap.find(style); if (it != KTextStylesMap.end()) - { - style_code = it->second; - } + ket_fs.setFontStyle( it->second ); else { const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; const std::string KCustomFontUnits = "px"; if (style.find(KCustomFontSize) == 0) { - style_code = - std::stoi(style.substr(KCustomFontSize.size(), style.size() - KCustomFontSize.size() - KCustomFontUnits.size())); + ket_fs.setFontStyle( KETFontStyle::FontStyle::ESize ); + ket_fs.setValue( + std::stoi(style.substr(KCustomFontSize.size(), style.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); } } - const auto it_begin = text_line.styles.find(style_begin); - const auto it_end = text_line.styles.find(style_end); - if (it_begin == text_line.styles.end()) - text_line.styles.emplace(style_begin, std::initializer_list>{{style_code, true}}); + const auto it_begin = text_line.font_styles.find(style_begin); + const auto it_end = text_line.font_styles.find(style_end); + + if (it_begin == text_line.font_styles.end()) + text_line.font_styles.emplace(style_begin, std::initializer_list>{{ket_fs, true}}); else { - it_begin->second.emplace(style_code, true); + it_begin->second.emplace(ket_fs, true); } - if (it_end == text_line.styles.end()) - text_line.styles.emplace(style_end, std::initializer_list>{{style_code, false}}); + if (it_end == text_line.font_styles.end()) + text_line.font_styles.emplace(style_end, std::initializer_list>{{ket_fs, false}}); else { - it_end->second.emplace(style_code, false); + it_end->second.emplace(ket_fs, false); } } } @@ -198,7 +198,7 @@ namespace indigo } } - KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font{} + KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_style{} { using namespace rapidjson; @@ -213,39 +213,36 @@ namespace indigo for (const auto& paragraph : paragraphs_val.GetArray()) { KETTextParagraph text_line; - auto style_lambda = styleLambda(text_line.style); - DispatchMapKVP paragraph_dispatcher = { - {"alignment", alignLambda(text_line.alignment)}, - {"bold", style_lambda}, - {"italic", style_lambda}, - {"subscript", style_lambda}, - {"superscript", style_lambda}, - {"indent", indentLambda(text_line.indent)}, - {"font", fontLambda(text_line.font)}, - {"parts", partsLambda(text_line)}}; + auto style_lambda = styleLambda(text_line.font_style); + DispatchMapKVP paragraph_dispatcher = {{"alignment", alignLambda(text_line.alignment)}, + {"bold", style_lambda}, + {"italic", style_lambda}, + {"subscript", style_lambda}, + {"superscript", style_lambda}, + {"indent", indentLambda(text_line.indent)}, + {"font", fontLambda(text_line.font_style)}, + {"parts", partsLambda(text_line)}}; applyDispatcher(paragraph, paragraph_dispatcher); _block.push_back(text_line); } }; - auto style_lambda = styleLambda(_style); - - DispatchMapKVP text_obj_dispatcher = { - {"bounding_box", bbox_lambda}, - {"alignment", alignLambda(_alignment)}, - {"bold", style_lambda}, - {"italic", style_lambda}, - {"subscript", style_lambda}, - {"superscript", style_lambda}, - {"indent", indentLambda(_indent)}, - {"font", fontLambda(_font)}, - {"paragraphs", paragraphs_lambda} - }; + auto style_lambda = styleLambda(_font_style); + + DispatchMapKVP text_obj_dispatcher = {{"bounding_box", bbox_lambda}, + {"alignment", alignLambda(_alignment)}, + {"bold", style_lambda}, + {"italic", style_lambda}, + {"subscript", style_lambda}, + {"superscript", style_lambda}, + {"indent", indentLambda(_indent)}, + {"font", fontLambda(_font_style)}, + {"paragraphs", paragraphs_lambda}}; + applyDispatcher(text_obj, text_obj_dispatcher); } - } #ifdef _MSC_VER diff --git a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp index 57ff05c794..e1e166a28f 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp @@ -1473,7 +1473,7 @@ void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) t->SetAttribute("p", pos_str.c_str()); t->SetAttribute("Justification", "Left"); t->SetAttribute("InterpretChemically", "no"); - for (auto& kvp : text_item.styles) + for (auto& kvp : text_item.font_styles) { if (is_first_index) { @@ -1491,24 +1491,30 @@ void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) auto sub_text = text_item.text.substr(first_index, second_index - first_index); for (const auto& text_style : current_styles) { - switch (text_style.first) + switch (static_cast(text_style.first)) { - case KETTextObject::EPlain: + case KETFontStyle::FontStyle::ENone: break; - case KETTextObject::EBold: + case KETFontStyle::FontStyle::EBold: font_face.is_bold = text_style.second; break; - case KETTextObject::EItalic: + case KETFontStyle::FontStyle::EItalic: font_face.is_italic = text_style.second; break; - case KETTextObject::ESuperScript: + case KETFontStyle::FontStyle::ESuperScript: font_face.is_superscript = text_style.second; break; - case KETTextObject::ESubScript: + case KETFontStyle::FontStyle::ESubScript: font_face.is_subscript = text_style.second; break; + case KETFontStyle::FontStyle::ESize: { + font_size = static_cast(KETDefaultFontSize); + auto sz_val = text_style.first.getUInt(); + if (text_style.second && sz_val.has_value()) + font_size = sz_val.value(); + } + break; default: - font_size = text_style.second ? text_style.first : static_cast(KETDefaultFontSize); break; } } diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index da4ed907d5..65e58c6464 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -264,23 +264,30 @@ void RenderItemAuxiliary::fillKETStyle(TextItem& ti, const FONT_STYLE_SET& style { for (const auto& text_style : style_set) { - switch (text_style.first) + switch (static_cast(text_style.first)) { - case KETTextObject::EBold: + case KETFontStyle::FontStyle::EBold: ti.bold = text_style.second; break; - case KETTextObject::EItalic: + case KETFontStyle::FontStyle::EItalic: ti.italic = text_style.second; break; - case KETTextObject::ESuperScript: + case KETFontStyle::FontStyle::ESuperScript: ti.script_type = text_style.second ? 1 : 0; break; - case KETTextObject::ESubScript: + case KETFontStyle::FontStyle::ESubScript: ti.script_type = text_style.second ? 2 : 0; break; - default: - ti.size = text_style.second ? text_style.first : KETDefaultFontSize; + case KETFontStyle::FontStyle::ESize: + { + ti.size = KETDefaultFontSize; + auto sz_val = text_style.first.getUInt(); + if (text_style.second && sz_val.has_value()) + ti.size = sz_val.value(); ti.size /= KETFontScaleFactor; + } + break; + default: break; } } @@ -317,7 +324,7 @@ void RenderItemAuxiliary::_drawMeta(bool idle) ti.ritype = RenderItem::RIT_TITLE; Vec2f text_origin(ko._bbox.left(), ko._bbox.top()); scale(text_origin); - for (auto& kvp : text_item.styles) + for (auto& kvp : text_item.font_styles) { if (first_index == -1) { @@ -459,7 +466,7 @@ float RenderItemAuxiliary::_getMaxHeight(const KETTextObject::KETTextParagraph& TextItem ti; ti.size = KETDefaultFontSize / KETFontScaleFactor; // default size ti.ritype = RenderItem::RIT_TITLE; - for (auto& kvp : tl.styles) + for (auto& kvp : tl.font_styles) { if (first_index == -1) { From 54bc06ff20835e2119cd241d26df5178f50c116c Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 2 Jul 2024 21:52:10 +0200 Subject: [PATCH 10/39] conflict fix --- core/indigo-core/molecule/src/molecule_json_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 92bb1116df..1aae1813b2 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -23,7 +23,7 @@ IMPL_ERROR(MoleculeJsonLoader, "molecule json loader"); MoleculeJsonLoader::MoleculeJsonLoader(Document& ket) : _mol_array(kArrayType), _mol_nodes(_mol_array), _meta_objects(kArrayType), _templates(kArrayType), _monomer_array(kArrayType), - _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), components_count(0), _is_library(false) + _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), _components_count(0), _is_library(false) { if (ket.HasMember("ket_version")) _ket_version = ket["ket_version"].GetString(); From 5533d1b64ae1d473ea6975aca7f727a76b724542 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 3 Jul 2024 22:27:42 +0200 Subject: [PATCH 11/39] text ket --- core/indigo-core/molecule/ket_commons.h | 49 +++++-- .../molecule/molecule_json_saver.h | 66 ++++++++- core/indigo-core/molecule/src/ket_commons.cpp | 8 +- .../molecule/src/molecule_cdxml_saver.cpp | 4 +- .../molecule/src/molecule_json_loader.cpp | 10 ++ .../molecule/src/molecule_json_saver.cpp | 137 +++++++++++------- .../reaction/src/reaction_cdxml_loader.cpp | 3 +- .../reaction/src/reaction_json_loader.cpp | 3 +- core/render2d/src/render_item_aux.cpp | 4 +- 9 files changed, 207 insertions(+), 77 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 3ebb79e5d4..af75193483 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -108,7 +108,7 @@ namespace indigo return std::nullopt; } - void setFontStyle( FontStyle fs ) + void setFontStyle(FontStyle fs) { _font_style = fs; } @@ -244,13 +244,6 @@ namespace indigo static const std::uint32_t CID = "KET text object"_hash; - std::string _content; - std::list _block; - Rect2f _bbox; - std::optional _indent; - std::optional _alignment; - FONT_STYLE_SET _font_style; - static void applyDispatcher(const rapidjson::Value& val, const DispatchMapKVP& disp_map) { for (auto kvp_it = val.MemberBegin(); kvp_it != val.MemberEnd(); ++kvp_it) @@ -383,7 +376,7 @@ namespace indigo } KETTextObject(const KETTextObject& other) - : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font_style{other._font_style}, _bbox(other._bbox), + : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font_styles{other._font_styles}, _bbox(other._bbox), _content(other._content), _block(other._block) { } @@ -396,6 +389,44 @@ namespace indigo { return new KETTextObject(*this); } + + auto indent() const + { + return _indent; + } + + auto alignment() const + { + return _alignment; + } + + const auto& boundingBox() const + { + return _bbox; + } + + const auto& block() const + { + return _block; + } + + const auto& content() const + { + return _content; + } + + const auto& fontStyles() const + { + return _font_styles; + } + + private: + std::string _content; + std::list _block; + Rect2f _bbox; + std::optional _indent; + std::optional _alignment; + FONT_STYLE_SET _font_styles; }; class KETReactionArrow : public MetaObject diff --git a/core/indigo-core/molecule/molecule_json_saver.h b/core/indigo-core/molecule/molecule_json_saver.h index 5a28b0ecd1..a5e6a99e7c 100644 --- a/core/indigo-core/molecule/molecule_json_saver.h +++ b/core/indigo-core/molecule/molecule_json_saver.h @@ -173,6 +173,62 @@ namespace indigo _writer.Flush(); } + void WritePoint( const Vec2f& point ) + { + if (pretty_json) + { + _pretty_writer.StartObject(); + _pretty_writer.Key("x"); + _pretty_writer.Double(point.x); + _pretty_writer.Key("y"); + _pretty_writer.Double(point.y); + _pretty_writer.Key("z"); + _pretty_writer.Double(0.0); + _pretty_writer.EndObject(); // end position + } + else + { + _writer.StartObject(); + _writer.Key("x"); + _writer.Double(point.x); + _writer.Key("y"); + _writer.Double(point.y); + _writer.Key("z"); + _writer.Double(0.0); + _writer.EndObject(); // end position + } + } + + void WriteRect(const Rect2f& rect) + { + if (pretty_json) + { + _pretty_writer.StartObject(); + _pretty_writer.Key("x"); + _pretty_writer.Double(rect.left()); + _pretty_writer.Key("y"); + _pretty_writer.Double(rect.top()); + _pretty_writer.Key("width"); + _pretty_writer.Double(rect.width()); + _pretty_writer.Key("height"); + _pretty_writer.Double(rect.height()); + _pretty_writer.EndObject(); + } + else + { + _writer.StartObject(); + _writer.Key("x"); + _writer.Double(rect.left()); + _writer.Key("y"); + _writer.Double(rect.top()); + _writer.Key("width"); + _writer.Double(rect.width()); + _writer.Key("height"); + _writer.Double(rect.height()); + _writer.EndObject(); + } + } + private: bool pretty_json; rapidjson::Writer _writer; @@ -186,14 +242,20 @@ namespace indigo void saveMolecule(BaseMolecule& bmol); void saveMolecule(BaseMolecule& bmol, JsonWriter& writer); - static void saveMetaData(JsonWriter& writer, MetaDataStorage& meta); + static void saveMetaData(JsonWriter& writer, const MetaDataStorage& meta); + static void saveTextV1(JsonWriter& writer, const KETTextObject& text_obj); + static void saveTextV2(JsonWriter& writer, const KETTextObject& text_obj); + static void saveAlignment(JsonWriter& writer, KETTextObject::TextAlignment alignment); + static void saveIndent(JsonWriter& writer, const KETTextObject::KETTextIndent& indent); + static void saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& fss); + static std::string monomerId(const TGroup& tg); static std::string monomerKETClass(const std::string& class_name); static std::string monomerHELMClass(const std::string& class_name); bool add_stereo_desc; bool pretty_json; - bool use_native_precision; // TODO: Remove option and use_native_precision allways - have to fix a lot of UTs + bool use_native_precision; // TODO: Remove option and use_native_precision always - have to fix a lot of UTs protected: void saveRoot(BaseMolecule& mol, JsonWriter& writer); diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 3ade426900..358af76098 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -131,7 +131,7 @@ namespace indigo return res; } - KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_style{} + KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_styles{} { using namespace rapidjson; _bbox = bbox; @@ -198,7 +198,7 @@ namespace indigo } } - KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_style{} + KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_styles{} { using namespace rapidjson; @@ -228,7 +228,7 @@ namespace indigo } }; - auto style_lambda = styleLambda(_font_style); + auto style_lambda = styleLambda(_font_styles); DispatchMapKVP text_obj_dispatcher = {{"bounding_box", bbox_lambda}, {"alignment", alignLambda(_alignment)}, @@ -237,7 +237,7 @@ namespace indigo {"subscript", style_lambda}, {"superscript", style_lambda}, {"indent", indentLambda(_indent)}, - {"font", fontLambda(_font_style)}, + {"font", fontLambda(_font_styles)}, {"paragraphs", paragraphs_lambda}}; applyDispatcher(text_obj, text_obj_dispatcher); diff --git a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp index 8696c26656..f03f31f042 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp @@ -1418,14 +1418,14 @@ void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) // double text_offset_y = 0; int font_size = static_cast(KETDefaultFontSize); CDXMLFontStyle font_face(0); - for (auto& text_item : ko._block) + for (auto& text_item : ko.block()) { bool is_first_index = true; size_t first_index = 0; size_t second_index = 0; // double text_offset_x = 0; FONT_STYLE_SET current_styles; - Vec2f text_origin(ko._bbox.left(), ko._bbox.top()); + Vec2f text_origin(ko.boundingBox().left(), ko.boundingBox().top()); std::string pos_str = std::to_string(_bond_length * text_origin.x) + " " + std::to_string(-_bond_length * text_origin.y); XMLElement* t = _doc->NewElement("t"); _current->LinkEndChild(t); diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 1aae1813b2..a944b3b04f 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1843,6 +1843,16 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat std::string content = sobj["content"].GetString(); Vec2f v1(sobj["position"]["x"].GetFloat(), sobj["position"]["y"].GetFloat()); Vec2f v2(v1); + if (sobj.HasMember("pos")) + { + auto pos_array = sobj["pos"].GetArray(); + if (pos_array.Size() == 4) + { + auto rb = pos_array[2].GetObject(); + v2.x = rb["x"].GetFloat(); + v2.y = rb["y"].GetFloat(); + } + } Rect2f text_box(v1, v2); meta_interface.addMetaObject(new KETTextObject(text_box, content)); } diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 20e774d6ec..9fde7153fb 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -1734,7 +1734,7 @@ void MoleculeJsonSaver::saveMolecule(BaseMolecule& bmol) _output.printf("%s", result.str().c_str()); } -void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, MetaDataStorage& meta) +void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, const MetaDataStorage& meta) { static const std::unordered_map _arrow_type2string = { {ReactionComponent::ARROW_BASIC, "open-angle"}, @@ -1774,24 +1774,8 @@ void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, MetaDataStorage& meta) // arrow coordinates writer.Key("pos"); writer.StartArray(); - writer.StartObject(); - writer.Key("x"); - writer.Double(ar._begin.x); - writer.Key("y"); - writer.Double(ar._begin.y); - writer.Key("z"); - writer.Double(0); - writer.EndObject(); - - writer.StartObject(); - writer.Key("x"); - writer.Double(ar._end.x); - writer.Key("y"); - writer.Double(ar._end.y); - writer.Key("z"); - writer.Double(0); - writer.EndObject(); - + writer.WritePoint(ar._begin); + writer.WritePoint(ar._end); writer.EndArray(); // arrow coordinates writer.EndObject(); // end data writer.EndObject(); // end node @@ -1833,29 +1817,9 @@ void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, MetaDataStorage& meta) } writer.Key("pos"); writer.StartArray(); - auto& coords = simple_obj->_coordinates; - - // point1 - writer.StartObject(); - writer.Key("x"); - writer.Double(coords.first.x); - writer.Key("y"); - writer.Double(coords.first.y); - writer.Key("z"); - writer.Double(0); - writer.EndObject(); - - // point2 - writer.StartObject(); - writer.Key("x"); - writer.Double(coords.second.x); - writer.Key("y"); - writer.Double(coords.second.y); - writer.Key("z"); - writer.Double(0); - writer.EndObject(); - + writer.WritePoint(coords.first); + writer.WritePoint(coords.second); writer.EndArray(); // end data @@ -1865,27 +1829,88 @@ void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, MetaDataStorage& meta) break; } case KETTextObject::CID: { - auto simple_obj = (KETTextObject*)pobj; + auto ptext_obj = (KETTextObject*)pobj; writer.StartObject(); writer.Key("type"); writer.String("text"); - writer.Key("data"); - writer.StartObject(); - writer.Key("content"); - writer.String(simple_obj->_content.c_str()); - writer.Key("position"); - writer.StartObject(); - writer.Key("x"); - writer.Double(simple_obj->_bbox.left()); - writer.Key("y"); - writer.Double(simple_obj->_bbox.top()); - writer.Key("z"); - writer.Double(0.0); - writer.EndObject(); // end position - writer.EndObject(); // end data + saveTextV1(writer, *ptext_obj); + saveTextV2(writer, *ptext_obj); writer.EndObject(); // end node break; } } } } + +void MoleculeJsonSaver::saveTextV1(JsonWriter& writer, const KETTextObject& text_obj) +{ + writer.Key("data"); + writer.StartObject(); + writer.Key("content"); + writer.String(text_obj.content().c_str()); + writer.Key("position"); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.Key("pos"); + writer.StartArray(); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().leftBottom()); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().rightBottom()); + writer.WritePoint(text_obj.boundingBox().rightTop()); + writer.EndArray(); + writer.EndObject(); +} + +void MoleculeJsonSaver::saveTextV2(JsonWriter& writer, const KETTextObject& text_obj) +{ + writer.Key("bounding_box"); + writer.StartObject(); + writer.WriteRect(text_obj.boundingBox()); + if (text_obj.alignment().has_value()) + saveAlignment(writer, text_obj.alignment().value()); + if (text_obj.indent().has_value()) + saveIndent(writer, text_obj.indent().value()); + writer.EndObject(); +} + +void MoleculeJsonSaver::saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& fss) +{ + +} + +void MoleculeJsonSaver::saveIndent(JsonWriter& writer, const KETTextObject::KETTextIndent& indent) +{ + if (indent.first_line.has_value()) + { + } + + if (indent.left.has_value()) + { + } + + if (indent.right.has_value()) + { + } +} + +void MoleculeJsonSaver::saveAlignment(JsonWriter& writer, KETTextObject::TextAlignment alignment) +{ + std::string alignment_str; + switch (alignment) + { + case KETTextObject::TextAlignment::ELeft: + alignment_str = KETAlignmentLeft; + break; + case KETTextObject::TextAlignment::ERight: + alignment_str = KETAlignmentRight; + break; + case KETTextObject::TextAlignment::ECenter: + alignment_str = KETAlignmentCenter; + break; + case KETTextObject::TextAlignment::EJustify: + alignment_str = KETAlignmentJustify; + break; + } + writer.Key("alignment"); + writer.String(alignment_str.c_str()); +} diff --git a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp index db2f390283..a574c0a3da 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp @@ -206,7 +206,8 @@ void ReactionCdxmlLoader::loadReaction(BaseReaction& rxn) { auto& text = (KETTextObject&)_pmol->meta().getMetaObject(KETTextObject::CID, i); int idx = rxn.meta().addMetaObject(text.clone()); - rxn.addSpecialCondition(idx, Rect2f(Vec2f(text._bbox.left(), text._bbox.top()), Vec2f(text._bbox.left(), text._bbox.top()))); + rxn.addSpecialCondition( + idx, Rect2f(Vec2f(text.boundingBox().left(), text.boundingBox().top()), Vec2f(text.boundingBox().left(), text.boundingBox().top()))); } } _cdxml_elements.erase(elem_it); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index f5a1d4ab77..73b31cafb6 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -492,7 +492,8 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) for (int i = 0; i < rxn.meta().getMetaCount(KETTextObject::CID); ++i) { auto& text = (const KETTextObject&)rxn.meta().getMetaObject(KETTextObject::CID, i); - Rect2f bbox(Vec2f(text._bbox.left(), text._bbox.top()), Vec2f(text._bbox.left(), text._bbox.top())); // change to real text box later + Rect2f bbox(Vec2f(text.boundingBox().left(), text.boundingBox().top()), + Vec2f(text.boundingBox().left(), text.boundingBox().top())); // change to real text box later components.emplace_back(bbox, ReactionFragmentType::TEXT, nullptr); } diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index 65e58c6464..1e28c2f4b2 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -312,7 +312,7 @@ void RenderItemAuxiliary::_drawMeta(bool idle) case KETTextObject::CID: { const KETTextObject& ko = static_cast(mobj); double text_offset_y = 0; - for (auto& text_item : ko._block) + for (auto& text_item : ko.block()) { float text_max_height = _getMaxHeight(text_item); int first_index = -1; @@ -322,7 +322,7 @@ void RenderItemAuxiliary::_drawMeta(bool idle) TextItem ti; ti.size = KETDefaultFontSize / KETFontScaleFactor; // default size ti.ritype = RenderItem::RIT_TITLE; - Vec2f text_origin(ko._bbox.left(), ko._bbox.top()); + Vec2f text_origin(ko.boundingBox().left(), ko.boundingBox().top()); scale(text_origin); for (auto& kvp : text_item.font_styles) { From 45f54ab2c5dca558c2c6e2e345870ef3fa57d619 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 09:45:45 +0200 Subject: [PATCH 12/39] ket text step11 --- api/c/indigo/src/indigo.cpp | 3 + api/c/indigo/src/indigo_internal.h | 3 + api/c/indigo/src/indigo_options.cpp | 14 +- core/indigo-core/molecule/ket_commons.h | 87 +++++--- .../molecule/molecule_json_saver.h | 17 +- core/indigo-core/molecule/src/ket_commons.cpp | 105 +++++++--- .../molecule/src/molecule_cdxml_loader.cpp | 10 +- .../molecule/src/molecule_json_saver.cpp | 198 ++++++++++++++++-- .../reaction/reaction_json_saver.h | 1 + .../reaction/src/reaction_json_saver.cpp | 3 +- 10 files changed, 356 insertions(+), 85 deletions(-) diff --git a/api/c/indigo/src/indigo.cpp b/api/c/indigo/src/indigo.cpp index 9c87d9d859..2fb1234774 100644 --- a/api/c/indigo/src/indigo.cpp +++ b/api/c/indigo/src/indigo.cpp @@ -105,6 +105,7 @@ void Indigo::init() deco_save_ap_bond_orders = false; deco_ignore_errors = true; molfile_saving_mode = 0; + ket_saving_version = {1,0,0}; dearomatize_on_load = false; smiles_saving_format = SmilesSaver::SMILES_MODE::SMILES_CHEMAXON; molfile_saving_no_chiral = false; @@ -204,12 +205,14 @@ void Indigo::initMoleculeJsonSaver(MoleculeJsonSaver& saver) saver.add_stereo_desc = json_saving_add_stereo_desc; saver.pretty_json = json_saving_pretty; saver.use_native_precision = json_use_native_precision; + saver.ket_version = ket_saving_version; } void Indigo::initReactionJsonSaver(ReactionJsonSaver& saver) { saver.add_stereo_desc = json_saving_add_stereo_desc; saver.pretty_json = json_saving_pretty; + saver.ket_version = ket_saving_version; } void Indigo::initRxnfileSaver(RxnfileSaver& saver) diff --git a/api/c/indigo/src/indigo_internal.h b/api/c/indigo/src/indigo_internal.h index c4d5505c76..969cb57761 100644 --- a/api/c/indigo/src/indigo_internal.h +++ b/api/c/indigo/src/indigo_internal.h @@ -44,6 +44,8 @@ #include "molecule/molecule_stereocenter_options.h" #include "molecule/molecule_tautomer.h" #include "molecule/smiles_saver.h" +#include "molecule/molecule_json_saver.h" + #include "option_manager.h" /* When Indigo internal code is used dynamically the INDIGO_VERSION define @@ -312,6 +314,7 @@ class DLLEXPORT Indigo bool deco_ignore_errors; int molfile_saving_mode; // MolfileSaver::MODE_***, default is zero + KETVersion ket_saving_version; bool dearomatize_on_load; SmilesSaver::SMILES_MODE smiles_saving_format; bool molfile_saving_no_chiral; diff --git a/api/c/indigo/src/indigo_options.cpp b/api/c/indigo/src/indigo_options.cpp index e48af77123..13e4509558 100644 --- a/api/c/indigo/src/indigo_options.cpp +++ b/api/c/indigo/src/indigo_options.cpp @@ -18,7 +18,6 @@ #include "indigo_internal.h" #include "molecule/molfile_saver.h" -#include "molecule/smiles_saver.h" static void setStrValue(const char* source, char* dest, int len) { @@ -39,6 +38,18 @@ static void indigoGetMolfileSavingMode(Array& value) MolfileSaver::saveFormatMode(self.molfile_saving_mode, value); } +static void indigoGetJsonSavingVersion(Array& value) +{ + Indigo& self = indigoGetInstance(); + MoleculeJsonSaver::saveFormatMode(self.ket_saving_version, value); +} + +static void indigoSetJsonSavingVersion(const char* version) +{ + Indigo& self = indigoGetInstance(); + MoleculeJsonSaver::parseFormatMode(version, self.ket_saving_version); +} + static void indigoSetSmilesSavingFormat(const char* mode) { Indigo& self = indigoGetInstance(); @@ -281,6 +292,7 @@ void IndigoOptionHandlerSetter::setBasicOptionHandlers(const qword id) mgr->setOptionHandlerBool("deco-save-ap-bond-orders", SETTER_GETTER_BOOL_OPTION(indigo.deco_save_ap_bond_orders)); mgr->setOptionHandlerBool("deco-ignore-errors", SETTER_GETTER_BOOL_OPTION(indigo.deco_ignore_errors)); mgr->setOptionHandlerString("molfile-saving-mode", indigoSetMolfileSavingMode, indigoGetMolfileSavingMode); + mgr->setOptionHandlerString("ket-saving-version", indigoSetJsonSavingVersion, indigoGetJsonSavingVersion); mgr->setOptionHandlerString("smiles-saving-format", indigoSetSmilesSavingFormat, indigoGetSmilesSavingFormat); mgr->setOptionHandlerInt("molfile-saving-no-chiral", SETTER_GETTER_INT_OPTION(indigo.molfile_saving_no_chiral)); diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index af75193483..9563e97395 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -37,11 +37,20 @@ namespace indigo { const double KETDefaultFontSize = 13; const double KETFontScaleFactor = 47; - const auto KETFontBoldStr = "BOLD"; - const auto KETFontItalicStr = "ITALIC"; - const auto KETFontSuperscriptStr = "SUPERSCRIPT"; - const auto KETFontSubscriptStr = "SUBSCRIPT"; - const auto KETFontCustomSizeStr = "CUSTOM_FONT_SIZE"; + const auto KETFontBoldStrV1 = "BOLD"; + const auto KETFontItalicStrV1 = "ITALIC"; + const auto KETFontSuperscriptStrV1 = "SUPERSCRIPT"; + const auto KETFontSubscriptStrV1 = "SUBSCRIPT"; + const auto KETFontCustomSizeStrV1 = "CUSTOM_FONT_SIZE"; + + const auto KETFontBoldStr = "bold"; + const auto KETFontItalicStr = "italic"; + const auto KETFontSuperscriptStr = "superscript"; + const auto KETFontSubscriptStr = "subscript"; + const auto KETFontSizeStr = "size"; + const auto KETFontColorStr = "color"; + const auto KETFontFamilyStr = "family"; + const auto KETAlignmentLeft = "left"; const auto KETAlignmentRight = "right"; const auto KETAlignmentCenter = "center"; @@ -53,6 +62,23 @@ namespace indigo const uint8_t KETProductArea = 3; const Vec2f MIN_MOL_SIZE = {0.5, 0.5}; + struct KETVersion + { + int major; + int minor; + int patch; + }; + + const KETVersion KETVersion1 = {1, 0, 0}; + const KETVersion KETVersion2 = {2, 0, 0}; + + enum class KETVersionIndex : int + { + EMajor, + EMinor, + EPatch + }; + struct KETFontStyle { enum class FontStyle : int @@ -123,6 +149,11 @@ namespace indigo _val = val; } + bool hasValue() const + { + return _val.index() != 0; + } + private: FontStyle _font_style; std::variant _val; @@ -138,6 +169,8 @@ namespace indigo using FONT_STYLE_SET = std::set, compareFunction>; + FONT_STYLE_SET& operator+=(FONT_STYLE_SET& lhs, const FONT_STYLE_SET& rhs); + constexpr std::uint32_t string_hash(char const* s, std::size_t count) { return ((count ? string_hash(s, count - 1) : 2166136261u) ^ s[count]) * 16777619u; @@ -205,23 +238,13 @@ namespace indigo using DispatchMapKVP = std::unordered_map>; using DispatchMapVal = std::unordered_map>; - TextAlignMap KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, - {KETAlignmentRight, TextAlignment::ERight}, - {KETAlignmentCenter, TextAlignment::ECenter}, - {KETAlignmentJustify, TextAlignment::EJustify}}; + static const TextAlignMap& textAlignmentMap(); + + static const FontStyleMap& textStyleMapV1(); - FontStyleMap KTextStylesMap{{KETFontBoldStr, KETFontStyle::FontStyle::EBold}, - {KETFontItalicStr, KETFontStyle::FontStyle::EItalic}, - {KETFontSuperscriptStr, KETFontStyle::FontStyle::ESuperScript}, - {KETFontSubscriptStr, KETFontStyle::FontStyle::ESubScript}}; + static const FontStyleMap& textStyleMap(); - const std::unordered_map KTextFontStylesMap{{"bold", KETFontStyle::FontStyle::EBold}, - {"italic ", KETFontStyle::FontStyle::EItalic}, - {"superscript", KETFontStyle::FontStyle::ESuperScript}, - {"subscript", KETFontStyle::FontStyle::ESubScript}, - {"family", KETFontStyle::FontStyle::EFamily}, - {"size", KETFontStyle::FontStyle::ESize}, - {"color", KETFontStyle::FontStyle::EColor}}; + static KETFontStyle::FontStyle textStyleByName(const std::string& style_name); struct KETTextIndent { @@ -282,8 +305,8 @@ namespace indigo auto alignLambda(std::optional& alignment) { return [this, &alignment](const std::string&, const rapidjson::Value& align_val) { - auto ta_it = KTextAlignmentsMap.find(align_val.GetString()); - if (ta_it != KTextAlignmentsMap.end()) + auto ta_it = textAlignmentMap().find(align_val.GetString()); + if (ta_it != textAlignmentMap().end()) alignment = ta_it->second; }; } @@ -293,9 +316,9 @@ namespace indigo return [this, &fs](const std::string& key, const rapidjson::Value& style_val) { std::string style_name = key; std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); - auto ta_it = KTextStylesMap.find(style_name); - if (ta_it != KTextStylesMap.end()) - fs.emplace(ta_it->second, style_val.GetBool()); + auto style = textStyleByName(style_name); + if (style != KETFontStyle::FontStyle::ENone) + fs.emplace(style, style_val.GetBool()); }; } @@ -306,7 +329,7 @@ namespace indigo if (color_string.length() == 7 && color_string[0] == '#') { fs.emplace(std::piecewise_construct, - std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, std::stoul(color_string.substr(1), nullptr, 16)), + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, std::stoul(color_string.substr(1), nullptr, 16)), std::forward_as_tuple(bval)); } }; @@ -324,14 +347,15 @@ namespace indigo { return [&fs, bval](const rapidjson::Value& val) { if (val.IsInt()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), std::forward_as_tuple(bval)); + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, val.GetInt()), std::forward_as_tuple(bval)); }; } auto fontLambda(FONT_STYLE_SET& fs, bool bval = true) { return [&fs, bval](const std::string&, const rapidjson::Value& font_val) { - DispatchMapVal font_dispatcher = {{"family", fontFamilyLambda(fs, bval)}, {"size", fontSizeLambda(fs, bval)}, {"color", colorLambda(fs, bval)}}; + DispatchMapVal font_dispatcher = { + {KETFontFamilyStr, fontFamilyLambda(fs, bval)}, {KETFontSizeStr, fontSizeLambda(fs, bval)}, {KETFontColorStr, colorLambda(fs, bval)}}; applyDispatcher(font_val, font_dispatcher); }; } @@ -363,7 +387,12 @@ namespace indigo auto text_lambda = [&text](const std::string&, const rapidjson::Value& text_val) { text = text_val.GetString(); }; auto style_lambda = styleLambda(fss); DispatchMapKVP paragraph_dispatcher = { - {"text", text_lambda}, {"bold", style_lambda}, {"italic", style_lambda}, {"subscript", style_lambda}, {"superscript", style_lambda}, + {"text", text_lambda}, + {KETFontBoldStr, style_lambda}, + {KETFontItalicStr, style_lambda}, + {KETFontSubscriptStr, style_lambda}, + {KETFontSuperscriptStr, style_lambda}, + {"font", fontLambda(fss)} }; applyDispatcher(part, paragraph_dispatcher); if (text.size()) diff --git a/core/indigo-core/molecule/molecule_json_saver.h b/core/indigo-core/molecule/molecule_json_saver.h index a5e6a99e7c..5df8417318 100644 --- a/core/indigo-core/molecule/molecule_json_saver.h +++ b/core/indigo-core/molecule/molecule_json_saver.h @@ -155,6 +155,11 @@ namespace indigo return pretty_json ? _pretty_writer.String(str) : _writer.String(str); } + bool String(const std::string& str) + { + return String(str.c_str()); + } + bool Key(const Ch* const& str) { return pretty_json ? _pretty_writer.Key(str) : _writer.Key(str); @@ -173,7 +178,7 @@ namespace indigo _writer.Flush(); } - void WritePoint( const Vec2f& point ) + void WritePoint(const Vec2f& point) { if (pretty_json) { @@ -241,13 +246,18 @@ namespace indigo explicit MoleculeJsonSaver(Output& output); void saveMolecule(BaseMolecule& bmol); void saveMolecule(BaseMolecule& bmol, JsonWriter& writer); + void saveMetaData(JsonWriter& writer, const MetaDataStorage& meta); + + static void parseFormatMode(const char* version_str, KETVersion& version); + static void saveFormatMode(KETVersion& version, Array& output); - static void saveMetaData(JsonWriter& writer, const MetaDataStorage& meta); static void saveTextV1(JsonWriter& writer, const KETTextObject& text_obj); - static void saveTextV2(JsonWriter& writer, const KETTextObject& text_obj); + static void saveText(JsonWriter& writer, const KETTextObject& text_obj); static void saveAlignment(JsonWriter& writer, KETTextObject::TextAlignment alignment); static void saveIndent(JsonWriter& writer, const KETTextObject::KETTextIndent& indent); static void saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& fss); + static void saveParagraphs(JsonWriter& writer, const std::list& paragraphs); + static void saveParts(JsonWriter& writer, const std::map& fss_map, const std::string& text); static std::string monomerId(const TGroup& tg); static std::string monomerKETClass(const std::string& class_name); @@ -256,6 +266,7 @@ namespace indigo bool add_stereo_desc; bool pretty_json; bool use_native_precision; // TODO: Remove option and use_native_precision always - have to fix a lot of UTs + KETVersion ket_version; protected: void saveRoot(BaseMolecule& mol, JsonWriter& writer); diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 358af76098..0cdcc3b8f0 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -25,6 +25,25 @@ namespace indigo { + FONT_STYLE_SET& operator+=(FONT_STYLE_SET& lhs, const FONT_STYLE_SET& rhs) + { + for (const auto& fs : rhs) + { + if (fs.second) + { + if (!lhs.count(fs)) + lhs.insert(fs); + } + else + { + auto it = lhs.find(std::make_pair(fs.first, true)); + if (it != lhs.end()) + lhs.erase(it); + } + } + return lhs; + } + uint8_t getPointSide(const Vec2f& point, const Vec2f& beg, const Vec2f& end) { uint8_t bit_mask = 0; @@ -131,7 +150,48 @@ namespace indigo return res; } - KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_styles{} + const KETTextObject::TextAlignMap& KETTextObject::textAlignmentMap() + { + static TextAlignMap KTextAlignmentsMap{{KETAlignmentLeft, TextAlignment::ELeft}, + {KETAlignmentRight, TextAlignment::ERight}, + {KETAlignmentCenter, TextAlignment::ECenter}, + {KETAlignmentJustify, TextAlignment::EJustify}}; + return KTextAlignmentsMap; + } + + const KETTextObject::FontStyleMap& KETTextObject::textStyleMapV1() + { + static const FontStyleMap KTextStylesMap{{KETFontBoldStrV1, KETFontStyle::FontStyle::EBold}, + {KETFontItalicStrV1, KETFontStyle::FontStyle::EItalic}, + {KETFontSuperscriptStrV1, KETFontStyle::FontStyle::ESuperScript}, + {KETFontSubscriptStrV1, KETFontStyle::FontStyle::ESubScript}}; + return KTextStylesMap; + } + + const KETTextObject::FontStyleMap& KETTextObject::textStyleMap() + { + static const FontStyleMap KTextFontStylesMap{{KETFontBoldStr, KETFontStyle::FontStyle::EBold}, + {KETFontItalicStr, KETFontStyle::FontStyle::EItalic}, + {KETFontSuperscriptStr, KETFontStyle::FontStyle::ESuperScript}, + {KETFontSubscriptStr, KETFontStyle::FontStyle::ESubScript}, + {KETFontFamilyStr, KETFontStyle::FontStyle::EFamily}, + {KETFontSizeStr, KETFontStyle::FontStyle::ESize}, + {KETFontColorStr, KETFontStyle::FontStyle::EColor}}; + return KTextFontStylesMap; + } + + KETFontStyle::FontStyle KETTextObject::textStyleByName(const std::string& style_name) + { + auto style_it = textStyleMap().find(style_name); + if (style_it != textStyleMap().end()) + return style_it->second; + style_it = textStyleMapV1().find(style_name); + if (style_it != textStyleMapV1().end()) + return style_it->second; + return KETFontStyle::FontStyle::ENone; + } + + KETTextObject::KETTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment{}, _indent{}, _font_styles{} { using namespace rapidjson; _bbox = bbox; @@ -157,20 +217,21 @@ namespace indigo int style_begin = style_ranges[j]["offset"].GetInt(); int style_end = style_begin + style_ranges[j]["length"].GetInt(); - std::string style = style_ranges[j]["style"].GetString(); + std::string style_name = style_ranges[j]["style"].GetString(); KETFontStyle ket_fs; - auto it = KTextStylesMap.find(style); - if (it != KTextStylesMap.end()) - ket_fs.setFontStyle( it->second ); + + auto style = textStyleByName(style_name); + if (style != KETFontStyle::FontStyle::ENone) + ket_fs.setFontStyle(style); else { const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; const std::string KCustomFontUnits = "px"; - if (style.find(KCustomFontSize) == 0) + if (style_name.find(KCustomFontSize) == 0) { - ket_fs.setFontStyle( KETFontStyle::FontStyle::ESize ); - ket_fs.setValue( - std::stoi(style.substr(KCustomFontSize.size(), style.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); + ket_fs.setFontStyle(KETFontStyle::FontStyle::ESize); + ket_fs.setValue(std::stoi( + style_name.substr(KCustomFontSize.size(), style_name.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); } } @@ -180,16 +241,12 @@ namespace indigo if (it_begin == text_line.font_styles.end()) text_line.font_styles.emplace(style_begin, std::initializer_list>{{ket_fs, true}}); else - { it_begin->second.emplace(ket_fs, true); - } if (it_end == text_line.font_styles.end()) text_line.font_styles.emplace(style_end, std::initializer_list>{{ket_fs, false}}); else - { it_end->second.emplace(ket_fs, false); - } } } } @@ -198,7 +255,7 @@ namespace indigo } } - KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment(TextAlignment::ELeft), _indent{}, _font_styles{} + KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment{}, _indent{}, _font_styles{} { using namespace rapidjson; @@ -215,10 +272,10 @@ namespace indigo KETTextParagraph text_line; auto style_lambda = styleLambda(text_line.font_style); DispatchMapKVP paragraph_dispatcher = {{"alignment", alignLambda(text_line.alignment)}, - {"bold", style_lambda}, - {"italic", style_lambda}, - {"subscript", style_lambda}, - {"superscript", style_lambda}, + {KETFontBoldStr, style_lambda}, + {KETFontItalicStr, style_lambda}, + {KETFontSubscriptStr, style_lambda}, + {KETFontSuperscriptStr, style_lambda}, {"indent", indentLambda(text_line.indent)}, {"font", fontLambda(text_line.font_style)}, {"parts", partsLambda(text_line)}}; @@ -230,15 +287,9 @@ namespace indigo auto style_lambda = styleLambda(_font_styles); - DispatchMapKVP text_obj_dispatcher = {{"bounding_box", bbox_lambda}, - {"alignment", alignLambda(_alignment)}, - {"bold", style_lambda}, - {"italic", style_lambda}, - {"subscript", style_lambda}, - {"superscript", style_lambda}, - {"indent", indentLambda(_indent)}, - {"font", fontLambda(_font_styles)}, - {"paragraphs", paragraphs_lambda}}; + DispatchMapKVP text_obj_dispatcher = {{"bounding_box", bbox_lambda}, {"alignment", alignLambda(_alignment)}, {KETFontBoldStr, style_lambda}, + {KETFontItalicStr, style_lambda}, {KETFontSubscriptStr, style_lambda}, {KETFontSuperscriptStr, style_lambda}, + {"indent", indentLambda(_indent)}, {"font", fontLambda(_font_styles)}, {"paragraphs", paragraphs_lambda}}; applyDispatcher(text_obj, text_obj_dispatcher); } diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index b691f3b0fc..a9fdafa7db 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1604,16 +1604,16 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector 0 && (int)font_size != KETDefaultFontSize) - ket_text_style.styles.push_back(std::string(KETFontCustomSizeStr) + "_" + std::to_string((int)ceil(font_size)) + "px"); + ket_text_style.styles.push_back(std::string(KETFontCustomSizeStrV1) + "_" + std::to_string((int)ceil(font_size)) + "px"); } } diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 9fde7153fb..0e0b486911 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -71,10 +71,38 @@ void printMappings(Array& mapping) } MoleculeJsonSaver::MoleculeJsonSaver(Output& output) - : _output(output), _pmol(nullptr), _pqmol(nullptr), add_stereo_desc(false), pretty_json(false), use_native_precision(false) + : _output(output), _pmol(nullptr), _pqmol(nullptr), add_stereo_desc(false), pretty_json(false), use_native_precision(false), ket_version(KETVersion2) { } +void MoleculeJsonSaver::parseFormatMode(const char* version_str, KETVersion& version) +{ + auto version_data = split(version_str, '.'); + for (int i = 0; i < version_data.size(); ++i) + { + int val = std::stoi(version_data[i]); + switch (static_cast(i)) + { + case KETVersionIndex::EMajor: + version.major = val; + break; + case KETVersionIndex::EMinor: + version.minor = val; + break; + case KETVersionIndex::EPatch: + version.patch = val; + break; + } + } +} + +void MoleculeJsonSaver::saveFormatMode(KETVersion& version, Array& output) +{ + std::string ver; + ver += std::to_string(version.major) + "." + std::to_string(version.minor) + "." + std::to_string(version.patch); + output.readString(ver.c_str(), true); +} + void MoleculeJsonSaver::_checkSGroupIndices(BaseMolecule& mol, Array& sgs_list) { QS_DEF(Array, orig_ids); @@ -1417,6 +1445,16 @@ void MoleculeJsonSaver::saveRoot(BaseMolecule& mol, JsonWriter& writer) QS_DEF(Array, buf); ArrayOutput out(buf); writer.StartObject(); + + // save KET version + if (ket_version.major > KETVersion1.major) + { + writer.Key("ket_version"); + Array version_str; + saveFormatMode(ket_version, version_str); + writer.String(version_str.ptr()); + } + writer.Key("root"); writer.StartObject(); writer.Key("nodes"); @@ -1833,8 +1871,10 @@ void MoleculeJsonSaver::saveMetaData(JsonWriter& writer, const MetaDataStorage& writer.StartObject(); writer.Key("type"); writer.String("text"); - saveTextV1(writer, *ptext_obj); - saveTextV2(writer, *ptext_obj); + if (ket_version.major == KETVersion1.major) + saveTextV1(writer, *ptext_obj); + else + saveText(writer, *ptext_obj); writer.EndObject(); // end node break; } @@ -1850,46 +1890,166 @@ void MoleculeJsonSaver::saveTextV1(JsonWriter& writer, const KETTextObject& text writer.String(text_obj.content().c_str()); writer.Key("position"); writer.WritePoint(text_obj.boundingBox().leftTop()); - writer.Key("pos"); - writer.StartArray(); - writer.WritePoint(text_obj.boundingBox().leftTop()); - writer.WritePoint(text_obj.boundingBox().leftBottom()); - writer.WritePoint(text_obj.boundingBox().leftTop()); - writer.WritePoint(text_obj.boundingBox().rightBottom()); - writer.WritePoint(text_obj.boundingBox().rightTop()); - writer.EndArray(); - writer.EndObject(); + if (text_obj.boundingBox().width() > 0 && text_obj.boundingBox().height() > 0) + { + writer.Key("pos"); + writer.StartArray(); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().leftBottom()); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().rightBottom()); + writer.WritePoint(text_obj.boundingBox().rightTop()); + writer.EndArray(); + writer.EndObject(); + } } -void MoleculeJsonSaver::saveTextV2(JsonWriter& writer, const KETTextObject& text_obj) +void MoleculeJsonSaver::saveText(JsonWriter& writer, const KETTextObject& text_obj) { writer.Key("bounding_box"); - writer.StartObject(); writer.WriteRect(text_obj.boundingBox()); if (text_obj.alignment().has_value()) saveAlignment(writer, text_obj.alignment().value()); if (text_obj.indent().has_value()) saveIndent(writer, text_obj.indent().value()); - writer.EndObject(); + if (text_obj.fontStyles().size()) + saveFontStyles(writer, text_obj.fontStyles()); + if (text_obj.block().size()) + saveParagraphs(writer, text_obj.block()); } void MoleculeJsonSaver::saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& fss) { + std::vector>> font_fields; + for (auto& fs : fss) + { + switch (fs.first.getFontStyle()) + { + case KETFontStyle::FontStyle::EBold: + writer.Key(KETFontBoldStr); + writer.Bool(fs.second); + break; + case KETFontStyle::FontStyle::EItalic: + writer.Key(KETFontItalicStr); + writer.Bool(fs.second); + break; + case KETFontStyle::FontStyle::ESubScript: + writer.Key(KETFontSubscriptStr); + writer.Bool(fs.second); + break; + case KETFontStyle::FontStyle::ESuperScript: + writer.Key(KETFontSuperscriptStr); + writer.Bool(fs.second); + break; + case KETFontStyle::FontStyle::ENone: + // default style + break; + default: + if (fs.second) + font_fields.push_back(std::ref(fs)); + break; + } + } + if (font_fields.size()) + { + writer.Key("font"); + writer.StartObject(); + for (auto& fs_ref : font_fields) + { + auto& fs_font = fs_ref.get(); + if (fs_font.second && fs_font.first.hasValue()) + switch (fs_font.first.getFontStyle()) + { + case KETFontStyle::FontStyle::EColor: + writer.Key(KETFontColorStr); + writer.Uint(fs_font.first.getUInt().value()); + break; + case KETFontStyle::FontStyle::EFamily: + writer.Key(KETFontFamilyStr); + writer.String(fs_font.first.getString().value()); + break; + case KETFontStyle::FontStyle::ESize: + writer.Key(KETFontSizeStr); + writer.Uint(fs_font.first.getUInt().value()); + break; + } + break; + } + writer.EndObject(); + } } -void MoleculeJsonSaver::saveIndent(JsonWriter& writer, const KETTextObject::KETTextIndent& indent) +void MoleculeJsonSaver::saveParagraphs(JsonWriter& writer, const std::list& paragraphs) { - if (indent.first_line.has_value()) + writer.Key("paragraphs"); + writer.StartArray(); + for (const auto& paragraph : paragraphs) { + writer.StartObject(); + if (paragraph.alignment.has_value()) + saveAlignment(writer, paragraph.alignment.value()); + if (paragraph.indent.has_value()) + saveIndent(writer, paragraph.indent.value()); + if (paragraph.font_style.size()) + saveFontStyles(writer, paragraph.font_style); + if (paragraph.font_styles.size()) + saveParts(writer, paragraph.font_styles, paragraph.text); + writer.EndObject(); } + writer.EndArray(); +} - if (indent.left.has_value()) +void MoleculeJsonSaver::saveParts(JsonWriter& writer, const std::map& fss_map, const std::string& text) +{ + if (fss_map.size() > 1) { + std::string_view text_view = std::string_view(text); + writer.Key("parts"); + writer.StartArray(); + FONT_STYLE_SET fss; + for (auto it_fss_kvp = fss_map.begin(); it_fss_kvp != std::prev(fss_map.end()); ++it_fss_kvp) + { + writer.StartObject(); + auto next_it = std::next(it_fss_kvp); + auto text_part = text_view.substr(it_fss_kvp->first, next_it->first - it_fss_kvp->first); + writer.Key("text"); + writer.String(std::string(text_part).c_str()); + if (it_fss_kvp->second.size()) + { + fss += it_fss_kvp->second; + saveFontStyles(writer, fss); + } + writer.EndObject(); + } + writer.EndArray(); } +} - if (indent.right.has_value()) +void MoleculeJsonSaver::saveIndent(JsonWriter& writer, const KETTextObject::KETTextIndent& indent) +{ + if (indent.first_line.has_value() || indent.left.has_value() || indent.right.has_value()) { + writer.Key("indent"); + writer.StartObject(); + if (indent.first_line.has_value()) + { + writer.Key("first_line"); + writer.Double(indent.first_line.value()); + } + + if (indent.left.has_value()) + { + writer.Key("left"); + writer.Double(indent.first_line.value()); + } + + if (indent.right.has_value()) + { + writer.Key("right"); + writer.Double(indent.first_line.value()); + } + writer.EndObject(); } } diff --git a/core/indigo-core/reaction/reaction_json_saver.h b/core/indigo-core/reaction/reaction_json_saver.h index e019b125a9..13dc5e4b91 100644 --- a/core/indigo-core/reaction/reaction_json_saver.h +++ b/core/indigo-core/reaction/reaction_json_saver.h @@ -45,6 +45,7 @@ namespace indigo void saveReactionWithMetaData(BaseReaction& rxn, BaseMolecule& merged, MoleculeJsonSaver& json_saver); bool add_stereo_desc; bool pretty_json; + KETVersion ket_version; DECL_ERROR; protected: diff --git a/core/indigo-core/reaction/src/reaction_json_saver.cpp b/core/indigo-core/reaction/src/reaction_json_saver.cpp index 9a1a73683e..bae1195d47 100644 --- a/core/indigo-core/reaction/src/reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_json_saver.cpp @@ -72,7 +72,7 @@ void ReactionJsonSaver::_getBounds(BaseMolecule& mol, Vec2f& min_vec, Vec2f& max max_vec.scale(scale); } -ReactionJsonSaver::ReactionJsonSaver(Output& output) : _output(output), add_stereo_desc(false), pretty_json(false) +ReactionJsonSaver::ReactionJsonSaver(Output& output) : _output(output), add_stereo_desc(false), pretty_json(false), ket_version{1, 0, 0} { } @@ -250,6 +250,7 @@ void ReactionJsonSaver::saveReaction(BaseReaction& rxn) { MoleculeJsonSaver json_saver(_output); json_saver.add_stereo_desc = add_stereo_desc; + json_saver.ket_version = ket_version; std::unique_ptr merged; if (rxn.isQueryReaction()) { From 87f83dfe59cb8da96e54bc61e2db2a8a0a137770 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 09:53:06 +0200 Subject: [PATCH 13/39] ket text step11 --- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index a9fdafa7db..196ed774b0 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -660,7 +660,7 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n { auto it = std::upper_bound(fragment_node.inner_nodes.cbegin(), fragment_node.inner_nodes.cend(), fragment_node.id, [](int a, int b) { return a > b; }); - if (nodes[i].pos.x == 0 && nodes[i].pos.y == 0 ) // if no coord - copy from parent + if (nodes[i].pos.x == 0 && nodes[i].pos.y == 0) // if no coord - copy from parent nodes[i].pos = fragment_node.pos; fragment_node.inner_nodes.insert(it, nodes[i].id); } @@ -1659,7 +1659,8 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector Date: Mon, 8 Jul 2024 09:56:13 +0200 Subject: [PATCH 14/39] ket text step11 --- api/c/indigo/src/indigo.cpp | 2 +- api/c/indigo/src/indigo_internal.h | 2 +- core/indigo-core/molecule/ket_commons.h | 14 ++++++-------- core/render2d/src/render_item_aux.cpp | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/api/c/indigo/src/indigo.cpp b/api/c/indigo/src/indigo.cpp index 2fb1234774..c4be737692 100644 --- a/api/c/indigo/src/indigo.cpp +++ b/api/c/indigo/src/indigo.cpp @@ -105,7 +105,7 @@ void Indigo::init() deco_save_ap_bond_orders = false; deco_ignore_errors = true; molfile_saving_mode = 0; - ket_saving_version = {1,0,0}; + ket_saving_version = {1, 0, 0}; dearomatize_on_load = false; smiles_saving_format = SmilesSaver::SMILES_MODE::SMILES_CHEMAXON; molfile_saving_no_chiral = false; diff --git a/api/c/indigo/src/indigo_internal.h b/api/c/indigo/src/indigo_internal.h index 969cb57761..c081d7c44d 100644 --- a/api/c/indigo/src/indigo_internal.h +++ b/api/c/indigo/src/indigo_internal.h @@ -39,12 +39,12 @@ #include "molecule/molecule_fingerprint.h" #include "molecule/molecule_gross_formula.h" #include "molecule/molecule_ionize.h" +#include "molecule/molecule_json_saver.h" #include "molecule/molecule_mass_options.h" #include "molecule/molecule_standardize_options.h" #include "molecule/molecule_stereocenter_options.h" #include "molecule/molecule_tautomer.h" #include "molecule/smiles_saver.h" -#include "molecule/molecule_json_saver.h" #include "option_manager.h" diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 9563e97395..c7836427c0 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -386,14 +386,12 @@ namespace indigo FONT_STYLE_SET fss; auto text_lambda = [&text](const std::string&, const rapidjson::Value& text_val) { text = text_val.GetString(); }; auto style_lambda = styleLambda(fss); - DispatchMapKVP paragraph_dispatcher = { - {"text", text_lambda}, - {KETFontBoldStr, style_lambda}, - {KETFontItalicStr, style_lambda}, - {KETFontSubscriptStr, style_lambda}, - {KETFontSuperscriptStr, style_lambda}, - {"font", fontLambda(fss)} - }; + DispatchMapKVP paragraph_dispatcher = {{"text", text_lambda}, + {KETFontBoldStr, style_lambda}, + {KETFontItalicStr, style_lambda}, + {KETFontSubscriptStr, style_lambda}, + {KETFontSuperscriptStr, style_lambda}, + {"font", fontLambda(fss)}}; applyDispatcher(part, paragraph_dispatcher); if (text.size()) { diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index 1e28c2f4b2..c4fc972f3d 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -278,8 +278,7 @@ void RenderItemAuxiliary::fillKETStyle(TextItem& ti, const FONT_STYLE_SET& style case KETFontStyle::FontStyle::ESubScript: ti.script_type = text_style.second ? 2 : 0; break; - case KETFontStyle::FontStyle::ESize: - { + case KETFontStyle::FontStyle::ESize: { ti.size = KETDefaultFontSize; auto sz_val = text_style.first.getUInt(); if (text_style.second && sz_val.has_value()) From a500c3f1e6bc2b40ece5dcad0ac17ee8d6842099 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 10:39:12 +0200 Subject: [PATCH 15/39] ket text step11 --- core/indigo-core/molecule/src/molecule_json_saver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 0e0b486911..abe6dbf543 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -78,7 +78,7 @@ MoleculeJsonSaver::MoleculeJsonSaver(Output& output) void MoleculeJsonSaver::parseFormatMode(const char* version_str, KETVersion& version) { auto version_data = split(version_str, '.'); - for (int i = 0; i < version_data.size(); ++i) + for (auto i = 0; i < version_data.size(); ++i) { int val = std::stoi(version_data[i]); switch (static_cast(i)) From d7891e7ce8726fe83513aee1f26e2d4c96742ed1 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 11:38:15 +0200 Subject: [PATCH 16/39] ket text step11 --- core/indigo-core/molecule/ket_commons.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index c7836427c0..34f758c8bc 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -347,7 +347,7 @@ namespace indigo { return [&fs, bval](const rapidjson::Value& val) { if (val.IsInt()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, val.GetInt()), std::forward_as_tuple(bval)); + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, val.GetUint()), std::forward_as_tuple(bval)); }; } From f16ada2494e0943d38ce6b6c4e1a62e76f613256 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 12:56:45 +0200 Subject: [PATCH 17/39] ket text step11 --- core/indigo-core/molecule/ket_commons.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 34f758c8bc..c05e86c715 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -81,6 +81,7 @@ namespace indigo struct KETFontStyle { + using KETFontVal = std::variant; enum class FontStyle : int { ENone, @@ -93,7 +94,7 @@ namespace indigo EColor }; - KETFontStyle(const FontStyle fs, std::variant val = std::monostate{}) : _font_style(fs), _val(val) + KETFontStyle(const FontStyle fs, KETFontVal val = std::monostate{}) : _font_style(fs), _val(val) { } @@ -329,7 +330,7 @@ namespace indigo if (color_string.length() == 7 && color_string[0] == '#') { fs.emplace(std::piecewise_construct, - std::forward_as_tuple(KETFontStyle::FontStyle::EColor, std::stoul(color_string.substr(1), nullptr, 16)), + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, KETFontStyle::KETFontVal(std::stoul(color_string.substr(1), nullptr, 16))), std::forward_as_tuple(bval)); } }; @@ -347,7 +348,8 @@ namespace indigo { return [&fs, bval](const rapidjson::Value& val) { if (val.IsInt()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, val.GetUint()), std::forward_as_tuple(bval)); + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, KETFontStyle::KETFontVal(val.GetUint())), + std::forward_as_tuple(bval)); }; } From a1bf896e5032abd26e2a0dba095d946977b3476c Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 12:58:31 +0200 Subject: [PATCH 18/39] ket text step11 --- core/indigo-core/molecule/ket_commons.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index c05e86c715..cf774f83ed 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -329,9 +329,10 @@ namespace indigo std::string color_string = color_str.GetString(); if (color_string.length() == 7 && color_string[0] == '#') { - fs.emplace(std::piecewise_construct, - std::forward_as_tuple(KETFontStyle::FontStyle::EColor, KETFontStyle::KETFontVal(std::stoul(color_string.substr(1), nullptr, 16))), - std::forward_as_tuple(bval)); + fs.emplace( + std::piecewise_construct, + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, KETFontStyle::KETFontVal(std::stoul(color_string.substr(1), nullptr, 16))), + std::forward_as_tuple(bval)); } }; } From 65d03abb4ce3bbc420699ce6477c5d7f7451cbe4 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 8 Jul 2024 14:18:28 +0200 Subject: [PATCH 19/39] ket text step11 --- core/indigo-core/molecule/ket_commons.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index cf774f83ed..0fdcde19a8 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -329,10 +329,9 @@ namespace indigo std::string color_string = color_str.GetString(); if (color_string.length() == 7 && color_string[0] == '#') { - fs.emplace( - std::piecewise_construct, - std::forward_as_tuple(KETFontStyle::FontStyle::EColor, KETFontStyle::KETFontVal(std::stoul(color_string.substr(1), nullptr, 16))), - std::forward_as_tuple(bval)); + fs.emplace(std::piecewise_construct, + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, static_cast(std::stoul(color_string.substr(1), nullptr, 16))), + std::forward_as_tuple(bval)); } }; } @@ -349,7 +348,7 @@ namespace indigo { return [&fs, bval](const rapidjson::Value& val) { if (val.IsInt()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, KETFontStyle::KETFontVal(val.GetUint())), + fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(val.GetUint())), std::forward_as_tuple(bval)); }; } From 578be0a1faf0569d3cd2fa9fa8589ed3dc05a487 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Tue, 9 Jul 2024 03:42:13 +0200 Subject: [PATCH 20/39] ket text step11 --- core/indigo-core/molecule/src/molecule_json_saver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index abe6dbf543..dd161ed5e1 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -78,7 +78,7 @@ MoleculeJsonSaver::MoleculeJsonSaver(Output& output) void MoleculeJsonSaver::parseFormatMode(const char* version_str, KETVersion& version) { auto version_data = split(version_str, '.'); - for (auto i = 0; i < version_data.size(); ++i) + for (size_t i = 0; i < version_data.size(); ++i) { int val = std::stoi(version_data[i]); switch (static_cast(i)) From c864063f7b51f738da215d469eee8d30a8a3d8ad Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Sun, 14 Jul 2024 19:59:39 +0200 Subject: [PATCH 21/39] no errors --- core/indigo-core/molecule/src/molecule_json_saver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index dd161ed5e1..389c8133b6 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -1900,8 +1900,8 @@ void MoleculeJsonSaver::saveTextV1(JsonWriter& writer, const KETTextObject& text writer.WritePoint(text_obj.boundingBox().rightBottom()); writer.WritePoint(text_obj.boundingBox().rightTop()); writer.EndArray(); - writer.EndObject(); } + writer.EndObject(); } void MoleculeJsonSaver::saveText(JsonWriter& writer, const KETTextObject& text_obj) From 6fc92414621f13c5dbc90e6278c01f73e87e2739 Mon Sep 17 00:00:00 2001 From: even1024 Date: Fri, 23 Feb 2024 11:02:00 +0100 Subject: [PATCH 22/39] cr --- .../molecule/src/molecule_cdxml_loader.cpp | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index faa10fae2f..84e6ad5953 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1571,50 +1571,56 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vectorhasContent(); text_style = text_style->nextSiblingElement()) { std::string text_element = text_style->name(); - auto& ket_text_line = ket_text_lines.back(); if (text_element == "s") { - std::string label_part = text_style->getText(); - if (label_part == "+") + std::string style_text = text_style->getText(); + if (style_text == "+") { _pluses.push_back(text_bbox.center()); return; } - ket_text_line.text_styles.emplace_back(); - auto& ket_text_style = ket_text_line.text_styles.back(); + auto lines = split(style_text, '\n'); + for (int i = 0; i < lines.size(); ++i) + { + const auto& label_part = lines[i]; + auto& ket_text_line = ket_text_lines.back(); + ket_text_line.text_styles.emplace_back(); + auto& ket_text_style = ket_text_line.text_styles.back(); - auto initial_size = label_part.size(); - label_part.erase(std::remove_if(label_part.begin(), label_part.end(), [](auto ch) { return (ch == '\n' || ch == '\r'); }), label_part.end()); - if (initial_size > label_part.size()) // line break - ket_text_lines.emplace_back(); + auto initial_size = label_part.size(); - ket_text_style.offset = ket_text_line.text.size(); - ket_text_style.size = label_part.size(); - ket_text_line.text += label_part; + ket_text_style.offset = ket_text_line.text.size(); + ket_text_style.size = label_part.size(); + ket_text_line.text += label_part; - font_face = 0; - font_size = 0.0; - applyDispatcher(*text_style->firstProperty().get(), style_dispatcher); + font_face = 0; + font_size = 0.0; + auto style = text_style->firstProperty(); + applyDispatcher(*style, style_dispatcher); - CDXMLFontStyle fs(font_face); - if (font_face == KCDXMLChemicalFontStyle) - { - // special case - } - else - { - if (fs.is_bold) - ket_text_style.styles.push_back(KETFontBoldStr); - if (fs.is_italic) - ket_text_style.styles.push_back(KETFontItalicStr); - if (fs.is_superscript) - ket_text_style.styles.push_back(KETFontSuperscriptStr); - if (fs.is_subscript) - ket_text_style.styles.push_back(KETFontSubscriptStr); + CDXMLFontStyle fs(font_face); + if (font_face == KCDXMLChemicalFontStyle) + { + // special case + } + else + { + if (fs.is_bold) + ket_text_style.styles.push_back(KETFontBoldStr); + if (fs.is_italic) + ket_text_style.styles.push_back(KETFontItalicStr); + if (fs.is_superscript) + ket_text_style.styles.push_back(KETFontSuperscriptStr); + if (fs.is_subscript) + ket_text_style.styles.push_back(KETFontSubscriptStr); + } + if (font_size > 0 && (int)font_size != KETDefaultFontSize) + ket_text_style.styles.push_back(std::string(KETFontCustomSizeStr) + "_" + std::to_string((int)ceil(font_size)) + "px"); + + if (i < lines.size() - 1) + ket_text_lines.emplace_back(); } - if (font_size > 0 && (int)font_size != KETDefaultFontSize) - ket_text_style.styles.push_back(std::string(KETFontCustomSizeStr) + "_" + std::to_string((int)ceil(font_size)) + "px"); } } From 2573be6ac0dcd4127099c4f5f8e134ec357fec40 Mon Sep 17 00:00:00 2001 From: even1024 Date: Fri, 23 Feb 2024 11:36:07 +0100 Subject: [PATCH 23/39] line cr --- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 84e6ad5953..c1408b7029 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1581,7 +1581,7 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector Date: Mon, 15 Jul 2024 01:17:29 +0200 Subject: [PATCH 24/39] tests fix --- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 2 +- utils/indigo-depict/main.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 4d120234b0..f259ce2d3e 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1580,7 +1580,7 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector Date: Thu, 18 Jul 2024 11:55:57 +0200 Subject: [PATCH 25/39] tests fix --- core/indigo-core/molecule/ket_commons.h | 82 ++-- .../molecule/molecule_cdxml_loader.h | 59 ++- .../molecule/molecule_json_loader.h | 2 +- core/indigo-core/molecule/src/ket_commons.cpp | 97 ++-- .../molecule/src/molecule_cdxml_loader.cpp | 426 ++++++++++++------ .../molecule/src/molecule_json_loader.cpp | 8 +- .../molecule/src/molecule_json_saver.cpp | 10 +- 7 files changed, 463 insertions(+), 221 deletions(-) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 0fdcde19a8..ecd4a2a068 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -312,52 +312,53 @@ namespace indigo }; } - auto styleLambda(FONT_STYLE_SET& fs) + auto styleLambda(FONT_STYLE_SET& fss) { - return [this, &fs](const std::string& key, const rapidjson::Value& style_val) { + return [this, &fss](const std::string& key, const rapidjson::Value& style_val) { std::string style_name = key; std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); auto style = textStyleByName(style_name); if (style != KETFontStyle::FontStyle::ENone) - fs.emplace(style, style_val.GetBool()); + fss.emplace(style, style_val.GetBool()); }; } - static auto colorLambda(FONT_STYLE_SET& fs, bool bval) + static auto colorLambda(FONT_STYLE_SET& fss, bool bval) { - return [&fs, bval](const rapidjson::Value& color_str) { + return [&fss, bval](const rapidjson::Value& color_str) { std::string color_string = color_str.GetString(); - if (color_string.length() == 7 && color_string[0] == '#') + if (color_string.size() && color_string[0] == '#') { - fs.emplace(std::piecewise_construct, - std::forward_as_tuple(KETFontStyle::FontStyle::EColor, static_cast(std::stoul(color_string.substr(1), nullptr, 16))), - std::forward_as_tuple(bval)); + fss.emplace(std::piecewise_construct, + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, static_cast(std::stoul(color_string.substr(1), nullptr, 16))), + std::forward_as_tuple(bval)); } }; } - static auto fontFamilyLambda(FONT_STYLE_SET& fs, bool bval) + static auto fontFamilyLambda(FONT_STYLE_SET& fss, bool bval) { - return [&fs, bval](const rapidjson::Value& val) { + return [&fss, bval](const rapidjson::Value& val) { if (val.IsString()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), std::forward_as_tuple(bval)); + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), + std::forward_as_tuple(bval)); }; } - static auto fontSizeLambda(FONT_STYLE_SET& fs, bool bval) + static auto fontSizeLambda(FONT_STYLE_SET& fss, bool bval) { - return [&fs, bval](const rapidjson::Value& val) { + return [&fss, bval](const rapidjson::Value& val) { if (val.IsInt()) - fs.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(val.GetUint())), - std::forward_as_tuple(bval)); + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(val.GetUint())), + std::forward_as_tuple(bval)); }; } - auto fontLambda(FONT_STYLE_SET& fs, bool bval = true) + auto fontLambda(FONT_STYLE_SET& fss, bool bval = true) { - return [&fs, bval](const std::string&, const rapidjson::Value& font_val) { + return [&fss, bval](const std::string&, const rapidjson::Value& font_val) { DispatchMapVal font_dispatcher = { - {KETFontFamilyStr, fontFamilyLambda(fs, bval)}, {KETFontSizeStr, fontSizeLambda(fs, bval)}, {KETFontColorStr, colorLambda(fs, bval)}}; + {KETFontFamilyStr, fontFamilyLambda(fss, bval)}, {KETFontSizeStr, fontSizeLambda(fss, bval)}, {KETFontColorStr, colorLambda(fss, bval)}}; applyDispatcher(font_val, font_dispatcher); }; } @@ -382,11 +383,11 @@ namespace indigo auto partsLambda(KETTextParagraph& paragraph) { return [this, ¶graph](const std::string&, const rapidjson::Value& parts) { - for (const auto& part : parts.GetArray()) + for (const auto& part_val : parts.GetArray()) { - std::string text; + std::string part; FONT_STYLE_SET fss; - auto text_lambda = [&text](const std::string&, const rapidjson::Value& text_val) { text = text_val.GetString(); }; + auto text_lambda = [&part](const std::string&, const rapidjson::Value& text_val) { part = text_val.GetString(); }; auto style_lambda = styleLambda(fss); DispatchMapKVP paragraph_dispatcher = {{"text", text_lambda}, {KETFontBoldStr, style_lambda}, @@ -394,11 +395,12 @@ namespace indigo {KETFontSubscriptStr, style_lambda}, {KETFontSuperscriptStr, style_lambda}, {"font", fontLambda(fss)}}; - applyDispatcher(part, paragraph_dispatcher); - if (text.size()) + // all styles collected in fss + applyDispatcher(part_val, paragraph_dispatcher); + if (part.size()) { paragraph.font_styles.emplace(paragraph.text.size(), fss); - paragraph.text += text; + paragraph.text += part; } } }; @@ -413,27 +415,48 @@ namespace indigo KETTextObject(const Rect2f& bbox, const std::string& content); KETTextObject(const rapidjson::Value& text_obj); + KETTextObject(); MetaObject* clone() const override { return new KETTextObject(*this); } - auto indent() const + auto& indent() { return _indent; } - auto alignment() const + const auto& indent() const + { + return _indent; + } + + auto& alignment() + { + return _alignment; + } + + const auto& alignment() const { return _alignment; } + auto& boundingBox() + { + return _bbox; + } + const auto& boundingBox() const { return _bbox; } + auto& block() + { + return _block; + } + const auto& block() const { return _block; @@ -444,6 +467,11 @@ namespace indigo return _content; } + auto& fontStyles() + { + return _font_styles; + } + const auto& fontStyles() const { return _font_styles; diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index a79f3a9f61..4d512b5737 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -34,6 +34,7 @@ #include "molecule/base_molecule.h" #include "molecule/molecule_stereocenter_options.h" #include "molecule/query_molecule.h" +#include "molecule/ket_commons.h" typedef unsigned short int UINT16; typedef int INT32; @@ -796,9 +797,56 @@ namespace indigo static void applyDispatcher(BaseCDXProperty& prop, const std::unordered_map>& dispatcher); void parseCDXMLAttributes(BaseCDXProperty& prop); - void parseBBox(const std::string& data, Rect2f& bbox); - void parsePos(const std::string& data, Vec2f& bbox); - void parseSeg(const std::string& data, Vec2f& v1, Vec2f& v2); + + auto segLambda(Vec2f& v1, Vec2f& v2); + + auto bboxLambda(Rect2f& bbox); + + static auto strLambda(std::string& str) + { + return [&str](const std::string& data) { str = data; }; + } + + static auto intLambda(AutoInt& val) + { + return [&val](const std::string& data) { val = data; }; + } + + static auto floatLambda(float& val) + { + return [&val](const std::string& data) { val = std::stof(data); }; + } + + auto posLambda(Vec2f& pos) + { + return [this, &pos](const std::string& data) { + std::vector coords = split(data, ' '); + if (coords.size() >= 2) + { + pos.x = std::stof(coords[0]); + pos.y = std::stof(coords[1]); + if (_has_bounding_box) + { + pos.x -= cdxml_bbox.left(); + pos.y -= cdxml_bbox.bottom(); + } + pos.x /= SCALE; + pos.y /= -SCALE; + } + else + throw Error("Not enought coordinates"); + }; + } + + static auto intListLambda(std::vector& vals) + { + return [&vals](const std::string& data) { + std::vector str_vals = split(data, ' '); + vals.clear(); + for (auto& str : str_vals) + vals.push_back(std::stoi(str)); + }; + } StereocentersOptions stereochemistry_options; bool ignore_bad_valence; @@ -808,6 +856,9 @@ namespace indigo std::vector bonds; std::vector brackets; std::vector> text_objects; + std::vector ket_text_objects; + std::map font_table; + std::vector color_table; static const int SCALE = 30; @@ -823,6 +874,8 @@ namespace indigo void _parseBracket(CdxmlBracket& bracket, BaseCDXProperty& prop); void _parseText(BaseCDXElement& elem, std::vector>& text_parsed); + void _parseTextToKetObject(BaseCDXElement& elem, std::vector& text_objects); + void _parseLabel(BaseCDXElement& elem, std::string& label); void _parseGraphic(BaseCDXElement& elem); diff --git a/core/indigo-core/molecule/molecule_json_loader.h b/core/indigo-core/molecule/molecule_json_loader.h index 83ad0aa697..999c8333dd 100644 --- a/core/indigo-core/molecule/molecule_json_loader.h +++ b/core/indigo-core/molecule/molecule_json_loader.h @@ -77,7 +77,7 @@ namespace indigo // = ATOM_AND ('rac') // = ATOM_ANY ('any') - static void loadMetaObjects(rapidjson::Value& meta_objects, MetaDataStorage& meta); + void loadMetaObjects(rapidjson::Value& meta_objects, MetaDataStorage& meta); protected: struct EnhancedStereoCenter diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 0cdcc3b8f0..1a524c7c85 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -29,8 +29,14 @@ namespace indigo { for (const auto& fs : rhs) { - if (fs.second) + if (fs.second) // we want to turn on the style { + // remove previous switching off the style if there is one + auto it = lhs.find(std::make_pair(fs.first, false)); + if (it != lhs.end()) + lhs.erase(it); + + // check for duplicates if (!lhs.count(fs)) lhs.insert(fs); } @@ -195,66 +201,73 @@ namespace indigo { using namespace rapidjson; _bbox = bbox; - _content = content; - Document data; - data.Parse(content.c_str()); - if (data.HasMember("blocks")) + if (content.size()) { - Value& blocks = data["blocks"]; - for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) + _content = content; + Document data; + data.Parse(content.c_str()); + if (data.HasMember("blocks")) { - KETTextParagraph text_line; - if (blocks[i].HasMember("text")) + Value& blocks = data["blocks"]; + for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) { - text_line.text = blocks[i]["text"].GetString(); - text_line.font_styles.emplace(0, std::initializer_list>{{}}); - text_line.font_styles.emplace(text_line.text.size(), std::initializer_list>{{}}); - if (blocks[i].HasMember("inlineStyleRanges")) + KETTextParagraph text_line; + if (blocks[i].HasMember("text")) { - Value& style_ranges = blocks[i]["inlineStyleRanges"]; - for (rapidjson::SizeType j = 0; j < style_ranges.Size(); ++j) + text_line.text = blocks[i]["text"].GetString(); + text_line.font_styles.emplace(0, std::initializer_list>{{}}); + text_line.font_styles.emplace(text_line.text.size(), std::initializer_list>{{}}); + if (blocks[i].HasMember("inlineStyleRanges")) { - int style_begin = style_ranges[j]["offset"].GetInt(); - int style_end = style_begin + style_ranges[j]["length"].GetInt(); + Value& style_ranges = blocks[i]["inlineStyleRanges"]; + for (rapidjson::SizeType j = 0; j < style_ranges.Size(); ++j) + { + int style_begin = style_ranges[j]["offset"].GetInt(); + int style_end = style_begin + style_ranges[j]["length"].GetInt(); - std::string style_name = style_ranges[j]["style"].GetString(); - KETFontStyle ket_fs; + std::string style_name = style_ranges[j]["style"].GetString(); + KETFontStyle ket_fs; - auto style = textStyleByName(style_name); - if (style != KETFontStyle::FontStyle::ENone) - ket_fs.setFontStyle(style); - else - { - const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; - const std::string KCustomFontUnits = "px"; - if (style_name.find(KCustomFontSize) == 0) + auto style = textStyleByName(style_name); + if (style != KETFontStyle::FontStyle::ENone) + ket_fs.setFontStyle(style); + else { - ket_fs.setFontStyle(KETFontStyle::FontStyle::ESize); - ket_fs.setValue(std::stoi( - style_name.substr(KCustomFontSize.size(), style_name.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); + const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; + const std::string KCustomFontUnits = "px"; + if (style_name.find(KCustomFontSize) == 0) + { + ket_fs.setFontStyle(KETFontStyle::FontStyle::ESize); + ket_fs.setValue(std::stoi( + style_name.substr(KCustomFontSize.size(), style_name.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); + } } - } - const auto it_begin = text_line.font_styles.find(style_begin); - const auto it_end = text_line.font_styles.find(style_end); + const auto it_begin = text_line.font_styles.find(style_begin); + const auto it_end = text_line.font_styles.find(style_end); - if (it_begin == text_line.font_styles.end()) - text_line.font_styles.emplace(style_begin, std::initializer_list>{{ket_fs, true}}); - else - it_begin->second.emplace(ket_fs, true); + if (it_begin == text_line.font_styles.end()) + text_line.font_styles.emplace(style_begin, std::initializer_list>{{ket_fs, true}}); + else + it_begin->second.emplace(ket_fs, true); - if (it_end == text_line.font_styles.end()) - text_line.font_styles.emplace(style_end, std::initializer_list>{{ket_fs, false}}); - else - it_end->second.emplace(ket_fs, false); + if (it_end == text_line.font_styles.end()) + text_line.font_styles.emplace(style_end, std::initializer_list>{{ket_fs, false}}); + else + it_end->second.emplace(ket_fs, false); + } } } + _block.push_back(text_line); } - _block.push_back(text_line); } } } + KETTextObject::KETTextObject() : MetaObject(CID) + { + } + KETTextObject::KETTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment{}, _indent{}, _font_styles{} { using namespace rapidjson; diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index f259ce2d3e..83d2118732 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -22,7 +22,6 @@ #include "base_cpp/scanner.h" #include "molecule/elements.h" -#include "molecule/ket_commons.h" #include "molecule/molecule.h" #include "molecule/molecule_cdxml_loader.h" #include "molecule/molecule_scaffold_detection.h" @@ -38,19 +37,6 @@ bool is_fragment(CdxmlNode& node) return node.has_fragment || node.type == kCDXNodeType_Nickname || node.type == kCDXNodeType_Fragment; } -/*/ -static float readFloat(const char* point_str) -{ - float res = 0; - if (point_str != 0) - { - BufferScanner strscan(point_str); - res = strscan.readFloat(); - } - return res; -} -//*/ - IMPL_ERROR(MoleculeCdxmlLoader, "CDXML loader"); IMPL_ERROR(CDXMLReader, "CDXML reader"); IMPL_ERROR(CDXElement, "CDX element"); @@ -361,6 +347,40 @@ CDXReader::CDXReader(Scanner& scanner) : _scanner(scanner) scanner.readAll(_buffer); } +// lambdas + +auto MoleculeCdxmlLoader::segLambda(Vec2f& v1, Vec2f& v2) +{ + return [this, &v1, &v2](const std::string& data) { + std::vector coords = split(data, ' '); + if (coords.size() == 4) + { + v1.set(std::stof(coords[0]), std::stof(coords[1])); + v2.set(std::stof(coords[2]), std::stof(coords[3])); + if (_has_bounding_box) + { + v1.sub(cdxml_bbox.leftBottom()); + v2.sub(cdxml_bbox.leftBottom()); + } + v1.x /= SCALE; + v2.x /= SCALE; + v1.y /= -SCALE; + v2.y /= -SCALE; + } + else + throw Error("Not enought coordinates for text bounding box"); + }; +} + +auto MoleculeCdxmlLoader::bboxLambda(Rect2f& bbox) +{ + return [this, &bbox](const std::string& data) { + Vec2f v1, v2; + segLambda(v1, v2)(data); + bbox = Rect2f(v1, v2); + }; +} + MoleculeCdxmlLoader::MoleculeCdxmlLoader(Scanner& scanner, bool is_binary, bool is_fragment) : _scanner(scanner), _is_binary(is_binary), _is_fragment(is_fragment), _has_bounding_box(false), _pmol(nullptr), _pqmol(nullptr), ignore_bad_valence(false) { @@ -494,11 +514,13 @@ void MoleculeCdxmlLoader::_parseCollections(BaseMolecule& mol) for (const auto& to : text_objects) mol.meta().addMetaObject(new KETTextObject(to.first, to.second)); + for (const auto& kto : ket_text_objects) + mol.meta().addMetaObject(new KETTextObject(kto)); for (const auto& plus : _pluses) mol.meta().addMetaObject(new KETReactionPlus(plus)); - // CDX contains draphic arrow wich id dublicate arrow/ + // CDX contains graphic arrow wich id dublicate arrow/ // Search arrows for arrow with coords same as in grapic arrow and if found - remove tis arrow gecause graphic arrow contains more specific type for (const auto& g_arrow : _graphic_arrows) { @@ -611,8 +633,8 @@ void MoleculeCdxmlLoader::parseCDXMLAttributes(BaseCDXProperty& prop) std::vector coords = split(data, ' '); if (coords.size() == 4) { - this->_has_bounding_box = true; - this->cdxml_bbox = Rect2f(Vec2f(std::stof(coords[0]), std::stof(coords[1])), Vec2f(std::stof(coords[2]), std::stof(coords[3]))); + _has_bounding_box = true; + cdxml_bbox = Rect2f(Vec2f(std::stof(coords[0]), std::stof(coords[1])), Vec2f(std::stof(coords[2]), std::stof(coords[3]))); } else throw Error("Not enought coordinates for atom position"); @@ -639,6 +661,47 @@ void MoleculeCdxmlLoader::_parseCDXMLPage(BaseCDXElement& elem) _has_scheme = true; } } + else if (page_elem->value() == "colortable") + { + for (auto color_elem = page_elem->firstChildElement(); color_elem->hasContent(); color_elem = color_elem->nextSiblingElement()) + { + if (color_elem->name() == "color") + { + uint32_t cdxml_color = 0; + for (auto color_prop = color_elem->firstProperty(); color_prop->hasContent(); color_prop = color_prop->next()) + { + auto cval = static_cast(std::stof(color_prop->value()) * 0xFF); + if (color_prop->name() == "r") + cdxml_color |= cval << 16; + else if (color_prop->name() == "g") + cdxml_color |= cval << 8; + else if (color_prop->name() == "b") + cdxml_color |= cval; + } + color_table.push_back(cdxml_color); + } + } + } + else if (page_elem->value() == "fonttable") + { + for (auto font_elem = page_elem->firstChildElement(); font_elem->hasContent(); font_elem = font_elem->nextSiblingElement()) + { + if (font_elem->name() == "font") + { + int font_id = 0; + std::string font_name; + for (auto font_prop = font_elem->firstProperty(); font_prop->hasContent(); font_prop = font_prop->next()) + { + if (font_prop->name() == "id") + font_id = std::stoi(font_prop->value()); + else if (font_prop->name() == "name") + font_name = font_prop->value(); + } + if (font_id && font_name.size()) + font_table.emplace(font_id, font_name); + } + } + } } } @@ -648,12 +711,12 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n auto node_lambda = [this](BaseCDXElement& elem) { CdxmlNode node; - this->_parseNode(node, elem); + _parseNode(node, elem); _addNode(node); if (node.has_fragment) { auto inner_idx_start = nodes.size(); - this->_parseCDXMLElements(*elem.firstChildElement(), false, true); + _parseCDXMLElements(*elem.firstChildElement(), false, true); auto inner_idx_end = nodes.size(); CdxmlNode& fragment_node = nodes[inner_idx_start - 1]; for (auto i = inner_idx_start; i < inner_idx_end; ++i) @@ -669,23 +732,23 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n auto bond_lambda = [this](BaseCDXElement& elem) { CdxmlBond bond; - this->_parseBond(bond, *elem.firstProperty()); - this->bonds.push_back(bond); - this->_id_to_bond_index.emplace(bond.id, bonds.size() - 1); + _parseBond(bond, *elem.firstProperty()); + bonds.push_back(bond); + _id_to_bond_index.emplace(bond.id, bonds.size() - 1); }; auto fragment_lambda = [this, &fragment_start_idx](BaseCDXElement& elem) { fragment_start_idx = static_cast(nodes.size()); - this->_parseFragmentAttributes(*elem.firstProperty()); - this->_parseCDXMLElements(*elem.firstChildElement()); + _parseFragmentAttributes(*elem.firstProperty()); + _parseCDXMLElements(*elem.firstChildElement()); }; - auto group_lambda = [this](BaseCDXElement& elem) { this->_parseCDXMLElements(*elem.firstChildElement()); }; + auto group_lambda = [this](BaseCDXElement& elem) { _parseCDXMLElements(*elem.firstChildElement()); }; auto bracketed_lambda = [this](BaseCDXElement& elem) { CdxmlBracket bracket; - this->_parseBracket(bracket, *elem.firstProperty()); - this->brackets.push_back(bracket); + _parseBracket(bracket, *elem.firstProperty()); + brackets.push_back(bracket); }; auto text_lambda = [this, &fragment_start_idx, inside_fragment_node](BaseCDXElement& elem) { @@ -693,26 +756,29 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n { CdxmlBracket bracket; bracket.is_superatom = true; - for (size_t node_idx = fragment_start_idx; node_idx < this->nodes.size(); ++node_idx) + for (size_t node_idx = fragment_start_idx; node_idx < nodes.size(); ++node_idx) { - auto& node = this->nodes[node_idx]; + auto& node = nodes[node_idx]; if (node.type == kCDXNodeType_Element || node.type == kCDXNodeType_ElementList) { bracket.bracketed_list.push_back(node.id); } } - this->_parseLabel(elem, bracket.label); - this->brackets.push_back(bracket); + _parseLabel(elem, bracket.label); + brackets.push_back(bracket); } else - this->_parseText(elem, this->text_objects); + { + //_parseTextToKetObject(elem, ket_text_objects); + _parseText(elem, text_objects); + } }; - auto graphic_lambda = [this](BaseCDXElement& elem) { this->_parseGraphic(elem); }; + auto graphic_lambda = [this](BaseCDXElement& elem) { _parseGraphic(elem); }; - auto arrow_lambda = [this](BaseCDXElement& elem) { this->_parseArrow(elem); }; + auto arrow_lambda = [this](BaseCDXElement& elem) { _parseArrow(elem); }; - auto altgroup_lambda = [this](BaseCDXElement& elem) { this->_parseAltGroup(elem); }; + auto altgroup_lambda = [this](BaseCDXElement& elem) { _parseAltGroup(elem); }; std::unordered_map> cdxml_dispatcher = { {"n", node_lambda}, {"b", bond_lambda}, {"fragment", fragment_lambda}, {"group", group_lambda}, {"bracketedgroup", bracketed_lambda}, @@ -731,7 +797,7 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n if (no_siblings) break; } - // Text elements should be processed after all others because it behavior depends on fragment lambda + // Text elements should be processed after all others because its behavior depends on fragment lambda for (auto pelem = first_elem.copy(); pelem->hasContent(); pelem = pelem->nextSiblingElement()) { if (pelem->value() == "t") @@ -1133,17 +1199,11 @@ void MoleculeCdxmlLoader::applyDispatcher(BaseCDXProperty& prop, const std::unor void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, BaseCDXElement& elem) { // Atom parsing lambdas definition - auto id_lambda = [&node](const std::string& data) { node.id = data; }; - auto hydrogens_lambda = [&node](const std::string& data) { node.hydrogens = data; }; - auto charge_lambda = [&node](const std::string& data) { node.charge = data; }; - auto element_lambda = [&node](const std::string& data) { node.element = data; }; - auto isotope_lambda = [&node](const std::string& data) { node.isotope = data; }; auto radical_lambda = [&node](const std::string& data) { auto rd_it = kRadicalStrToId.find(data); if (rd_it != kRadicalStrToId.end()) node.radical = rd_it->second; }; - auto label_lambda = [&node](const std::string& data) { node.label = data; }; auto bond_ordering_lambda = [&node](const std::string& data) { auto vec_str = split(data, ' '); @@ -1155,8 +1215,6 @@ void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, BaseCDXElement& elem) } }; - auto pos_lambda = [&node, this](const std::string& data) { this->parsePos(data, node.pos); }; - auto stereo_lambda = [&node](const std::string& data) { node.stereo = kCIPStereochemistryCharToIndex.at(data.front()); }; auto node_type_lambda = [&node](const std::string& data) { @@ -1176,30 +1234,27 @@ void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, BaseCDXElement& elem) }; auto geometry_lambda = [&node](const std::string& data) { node.geometry = KGeometryTypeNameToInt.at(data); }; - auto enhanced_stereo_type_lambda = [&node](const std::string& data) { node.enchanced_stereo = kCDXEnhancedStereoStrToID.at(data); }; - auto enhanced_stereo_group_lambda = [&node](const std::string& data) { node.enhanced_stereo_group = data; }; - - auto alt_group_id_lambda = [&node](const std::string& data) { node.alt_group_id = data; }; - - std::unordered_map> node_dispatcher = {{"id", id_lambda}, - {"p", pos_lambda}, - {"xyz", pos_lambda}, - {"NumHydrogens", hydrogens_lambda}, - {"Charge", charge_lambda}, - {"Isotope", isotope_lambda}, - {"Radical", radical_lambda}, - {"AS", stereo_lambda}, - {"NodeType", node_type_lambda}, - {"Element", element_lambda}, - {"GenericNickname", label_lambda}, - {"ElementList", element_list_lambda}, - {"BondOrdering", bond_ordering_lambda}, - {"Geometry", geometry_lambda}, - {"EnhancedStereoType", enhanced_stereo_type_lambda}, - {"EnhancedStereoGroupNum", enhanced_stereo_group_lambda}, - {"AltGroupID", alt_group_id_lambda}}; + std::unordered_map> node_dispatcher = { + {"id", intLambda(node.id)}, + {"p", posLambda(node.pos)}, + {"xyz", posLambda(node.pos)}, + {"NumHydrogens", intLambda(node.hydrogens)}, + {"Charge", intLambda(node.charge)}, + {"Isotope", intLambda(node.isotope)}, + {"Radical", radical_lambda}, + {"AS", stereo_lambda}, + {"NodeType", node_type_lambda}, + {"Element", intLambda(node.element)}, + {"GenericNickname", strLambda(node.label)}, + {"ElementList", element_list_lambda}, + {"BondOrdering", bond_ordering_lambda}, + {"Geometry", geometry_lambda}, + {"EnhancedStereoType", enhanced_stereo_type_lambda}, + {"EnhancedStereoGroupNum", intLambda(node.enhanced_stereo_group)}, + {"AltGroupID", intLambda(node.alt_group_id)}}; + applyDispatcher(*elem.firstProperty().get(), node_dispatcher); for (auto child_elem = elem.firstChildElement(); child_elem->hasContent(); child_elem = child_elem->nextSiblingElement()) { @@ -1247,9 +1302,6 @@ void MoleculeCdxmlLoader::_addNode(CdxmlNode& node) void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, BaseCDXProperty& prop) { - auto id_lambda = [&bond](const std::string& data) { bond.id = data; }; - auto bond_begin_lambda = [&bond](const std::string& data) { bond.be.first = data; }; - auto bond_end_lambda = [&bond](const std::string& data) { bond.be.second = data; }; auto bond_order_lambda = [&bond](const std::string& data) { uint16_t bond_order = 0; for (auto order : split(data, ' ')) @@ -1311,9 +1363,9 @@ void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, BaseCDXProperty& prop) bond.topology = cdx_topology_to_topology.at(topology); }; - std::unordered_map> bond_dispatcher = {{"id", id_lambda}, - {"B", bond_begin_lambda}, - {"E", bond_end_lambda}, + std::unordered_map> bond_dispatcher = {{"id", intLambda(bond.id)}, + {"B", intLambda(bond.be.first)}, + {"E", intLambda(bond.be.second)}, {"Order", bond_order_lambda}, {"Display", bond_display_lambda}, {"Display2", bond_display2_lambda}, @@ -1324,65 +1376,17 @@ void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, BaseCDXProperty& prop) applyDispatcher(prop, bond_dispatcher); } -void MoleculeCdxmlLoader::parsePos(const std::string& data, Vec2f& pos) -{ - std::vector coords = split(data, ' '); - if (coords.size() >= 2) - { - pos.x = std::stof(coords[0]); - pos.y = std::stof(coords[1]); - if (this->_has_bounding_box) - { - pos.x -= this->cdxml_bbox.left(); - pos.y -= this->cdxml_bbox.bottom(); - } - pos.x /= SCALE; - pos.y /= -SCALE; - } - else - throw Error("Not enought coordinates"); -} - -void MoleculeCdxmlLoader::parseBBox(const std::string& data, Rect2f& bbox) -{ - Vec2f v1, v2; - parseSeg(data, v1, v2); - bbox = Rect2f(v1, v2); -} - -void MoleculeCdxmlLoader::parseSeg(const std::string& data, Vec2f& v1, Vec2f& v2) -{ - std::vector coords = split(data, ' '); - if (coords.size() == 4) - { - v1.set(std::stof(coords[0]), std::stof(coords[1])); - v2.set(std::stof(coords[2]), std::stof(coords[3])); - if (this->_has_bounding_box) - { - v1.sub(this->cdxml_bbox.leftBottom()); - v2.sub(this->cdxml_bbox.leftBottom()); - } - v1.x /= SCALE; - v2.x /= SCALE; - v1.y /= -SCALE; - v2.y /= -SCALE; - } - else - throw Error("Not enought coordinates for text bounding box"); -} - void MoleculeCdxmlLoader::_parseAltGroup(BaseCDXElement& elem) { std::vector r_labels; std::vector> r_fragments; std::pair bbox, text_frame, group_frame; - auto bbox_lambda = [&bbox, this](const std::string& data) { this->parseSeg(data, bbox.first, bbox.second); }; - auto text_frame_lambda = [&text_frame, this](const std::string& data) { this->parseSeg(data, text_frame.first, text_frame.second); }; - auto group_frame_lambda = [&group_frame, this](const std::string& data) { this->parseSeg(data, group_frame.first, group_frame.second); }; std::unordered_map> altgroup_dispatcher = { - {"BoundingBox", bbox_lambda}, {"TextFrame", text_frame_lambda}, {"GroupFrame", group_frame_lambda}}; + {"BoundingBox", segLambda(bbox.first, bbox.second)}, + {"TextFrame", segLambda(text_frame.first, text_frame.second)}, + {"GroupFrame", segLambda(group_frame.first, group_frame.second)}}; applyDispatcher(*elem.firstProperty().get(), altgroup_dispatcher); @@ -1424,8 +1428,6 @@ void MoleculeCdxmlLoader::_parseGraphic(BaseCDXElement& elem) std::pair graph_bbox; - auto graphic_bbox_lambda = [&graph_bbox, this](const std::string& data) { this->parseSeg(data, graph_bbox.first, graph_bbox.second); }; - CDXGraphicType graphic_type = kCDXGraphicType_Undefined; auto graphic_type_lambda = [&graphic_type](const std::string& data) { graphic_type = kCDXPropGraphicTypeStrToID.at(data); }; @@ -1439,8 +1441,9 @@ void MoleculeCdxmlLoader::_parseGraphic(BaseCDXElement& elem) auto head_size_lambda = [&head_size](const std::string& data) { head_size = data; }; std::unordered_map> graphic_dispatcher = { - {"SupersededBy", superseded_lambda}, {"BoundingBox", graphic_bbox_lambda}, {"GraphicType", graphic_type_lambda}, - {"SymbolType", symbol_type_lambda}, {"ArrowType", arrow_type_lambda}, {"HeadSize", head_size_lambda}}; + {"SupersededBy", superseded_lambda}, {"BoundingBox", segLambda(graph_bbox.first, graph_bbox.second)}, + {"GraphicType", graphic_type_lambda}, {"SymbolType", symbol_type_lambda}, + {"ArrowType", arrow_type_lambda}, {"HeadSize", head_size_lambda}}; applyDispatcher(*elem.firstProperty().get(), graphic_dispatcher); @@ -1494,20 +1497,15 @@ void MoleculeCdxmlLoader::_parseGraphic(BaseCDXElement& elem) void MoleculeCdxmlLoader::_parseArrow(BaseCDXElement& elem) { Rect2f text_bbox; - auto arrow_bbox_lambda = [&text_bbox, this](const std::string& data) { this->parseBBox(data, text_bbox); }; Vec2f begin_pos; - auto arrow_begin_lambda = [&begin_pos, this](const std::string& data) { this->parsePos(data, begin_pos); }; Vec2f end_pos; - auto arrow_end_lambda = [&end_pos, this](const std::string& data) { this->parsePos(data, end_pos); }; std::string fill_type; - auto fill_type_lambda = [&fill_type](const std::string& data) { fill_type = data; }; std::string arrow_head; - auto arrow_head_lambda = [&arrow_head](const std::string& data) { arrow_head = data; }; std::string head_type; - auto head_type_lambda = [&head_type](const std::string& data) { head_type = data; }; + std::unordered_map> arrow_dispatcher = { - {"BoundingBox", arrow_bbox_lambda}, {"FillType", fill_type_lambda}, {"ArrowheadHead", arrow_head_lambda}, - {"ArrowheadType", head_type_lambda}, {"Head3D", arrow_end_lambda}, {"Tail3D", arrow_begin_lambda}}; + {"BoundingBox", bboxLambda(text_bbox)}, {"FillType", strLambda(fill_type)}, {"ArrowheadHead", strLambda(arrow_head)}, + {"ArrowheadType", strLambda(head_type)}, {"Head3D", posLambda(end_pos)}, {"Tail3D", posLambda(begin_pos)}}; applyDispatcher(*elem.firstProperty().get(), arrow_dispatcher); _arrows.push_back(std::make_pair(std::make_pair(begin_pos, end_pos), 2)); @@ -1529,29 +1527,167 @@ void MoleculeCdxmlLoader::_parseLabel(BaseCDXElement& elem, std::string& label) } } -void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) +void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vector& text_objects) { Vec2f text_pos; - auto text_coordinates_lambda = [&text_pos, this](const std::string& data) { this->parsePos(data, text_pos); }; + Rect2f text_bbox; + float wwrap_val; + std::vector line_starts; + std::string label_justification, label_alignment, text_justification; + AutoInt font_id, font_color_index, font_face; + float font_size; + KETTextObject kto; + + std::unordered_map> text_dispatcher = { + {"p", posLambda(text_pos)}, + {"BoundingBox", bboxLambda(kto.boundingBox())}, + {"Justification", strLambda(text_justification)}, + {"WordWrapWidth", floatLambda(wwrap_val)}, + {"LineStarts", intListLambda(line_starts)}, + {"LabelJustification", strLambda(label_justification)}, + {"LabelAlignment", strLambda(label_alignment)}, + }; + + auto style_size_lambda = [&font_size](const std::string& data) { font_size = round(std::stof(data) * kCDXMLFonsSizeMultiplier); }; + auto style_color_lambda = [&font_color_index](const std::string& data) { + font_color_index = data; + font_color_index = font_color_index - 2; + }; + + std::unordered_map> style_dispatcher = { + {"font", intLambda(font_id)}, {"size", style_size_lambda}, {"color", style_color_lambda}, {"face", intLambda(font_face)}}; + + applyDispatcher(*elem.firstProperty().get(), text_dispatcher); + + for (auto text_style = elem.firstChildElement(); text_style->hasContent(); text_style = text_style->nextSiblingElement()) + { + std::string text_element = text_style->name(); + // "s" = parts + if (text_element == "s") + { + std::string style_text = text_style->getText(); + if (style_text == "+") + { + _pluses.push_back(text_bbox.center()); + return; + } + + // add paragraph + if (kto.block().empty()) + kto.block().push_back(KETTextObject::KETTextParagraph()); + + // break parts into separate paragraphs if CR presents + auto lines = split_with_empty(style_text, '\n'); + for (size_t i = 0; i < lines.size(); ++i) + { + if (i) + { + kto.block().push_back(KETTextObject::KETTextParagraph()); + } + + const auto& part = lines[i]; + if (part.size()) + { + // parts should be added to the last paragraph + auto& paragraph = kto.block().back(); + + FONT_STYLE_SET fss; + + font_face = 0; + font_size = 0.0; + font_id = 0; + font_color_index = -2; + auto style = text_style->firstProperty(); + applyDispatcher(*style, style_dispatcher); + + // fill fss + CDXMLFontStyle fs(font_face); + if (font_face == KCDXMLChemicalFontStyle) + { + // special case + } + else + { + if (fs.is_bold) + fss.emplace(KETFontStyle::FontStyle::EBold, true); + if (fs.is_italic) + fss.emplace(KETFontStyle::FontStyle::EBold, true); + if (fs.is_superscript) + fss.emplace(KETFontStyle::FontStyle::ESuperScript, true); + if (fs.is_superscript) + fss.emplace(KETFontStyle::FontStyle::ESubScript, true); + } + + // set fss font size + if (font_size > 0 && (int)font_size != KETDefaultFontSize) + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(font_size)), + std::forward_as_tuple(true)); + + // set fss font color + if (font_color_index >= 0 && font_color_index < color_table.size()) + { + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, color_table[font_color_index]), + std::forward_as_tuple(true)); + } + + // set fss font family + auto font_it = font_table.find(font_id); + if (font_it != font_table.end()) + { + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, font_it->second), + std::forward_as_tuple(true)); + } + + auto prev_it = paragraph.font_styles.find(paragraph.text.size()); + if (prev_it != paragraph.font_styles.end()) + prev_it->second += fss; + else + paragraph.font_styles.emplace(paragraph.text.size(), fss); + + paragraph.text += part; + // turn off the styles + FONT_STYLE_SET fss_off; + for (auto& fs_off : fss) + { + fss.emplace(fs_off.first, false); + } + if (fss.size()) + paragraph.font_styles.emplace(paragraph.text.size(), fss); + } + } + } + } + if (kto.block().size()) + { + + text_objects.push_back(kto); + } +} + +void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) +{ + Vec2f text_pos; Rect2f text_bbox; - auto text_bbox_lambda = [&text_bbox, this](const std::string& data) { this->parseBBox(data, text_bbox); }; std::string label_justification, label_alignment; auto label_justification_lambda = [&label_justification, this](const std::string& data) { label_justification = data; }; auto label_justification_alignment_lambda = [&label_alignment, this](const std::string& data) { label_alignment = data; }; - std::unordered_map> text_dispatcher = {{"p", text_coordinates_lambda}, - {"BoundingBox", text_bbox_lambda}, + std::unordered_map> text_dispatcher = {{"p", posLambda(text_pos)}, + {"BoundingBox", bboxLambda(text_bbox)}, {"LabelJustification", label_justification_lambda}, {"LabelAlignment", label_justification_alignment_lambda}}; - AutoInt font_id, font_color_id, font_face; + AutoInt font_id, font_color_index, font_face; float font_size; auto style_font_lambda = [&font_id](const std::string& data) { font_id = data; }; auto style_size_lambda = [&font_size](const std::string& data) { font_size = round(std::stof(data) * kCDXMLFonsSizeMultiplier); }; - auto style_color_lambda = [&font_color_id](const std::string& data) { font_color_id = data; }; + auto style_color_lambda = [&font_color_index](const std::string& data) { + font_color_index = data; + font_color_index = font_color_index - 2; + }; auto style_face_lambda = [&font_face](const std::string& data) { font_face = data; }; std::unordered_map> style_dispatcher = { @@ -1566,7 +1702,6 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector ket_text_lines; - ket_text_lines.emplace_back(); for (auto text_style = elem.firstChildElement(); text_style->hasContent(); text_style = text_style->nextSiblingElement()) { std::string text_element = text_style->name(); @@ -1579,6 +1714,9 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vectorfirstProperty(); applyDispatcher(*style, style_dispatcher); diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 568bf75db0..eadf036b94 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -26,7 +26,9 @@ MoleculeJsonLoader::MoleculeJsonLoader(Document& ket) _connection_array(kArrayType), _pmol(0), _pqmol(0), ignore_noncritical_query_features(false), _components_count(0), _is_library(false) { if (ket.HasMember("ket_version")) + { _ket_version = ket["ket_version"].GetString(); + } Value& root = ket["root"]; Value& nodes = root["nodes"]; @@ -1865,7 +1867,11 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat } } else if (node_type == "text") - meta_interface.addMetaObject(new KETTextObject(mobj)); + { + std::string ver2 = std::to_string(KETVersion2.major) + "." + std::to_string(KETVersion2.minor) + "." + std::to_string(KETVersion2.patch); + if (_ket_version == ver2) + meta_interface.addMetaObject(new KETTextObject(mobj)); + } } else if (node_type == "arrow") { diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 389c8133b6..7ccd08a878 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -1961,10 +1961,13 @@ void MoleculeJsonSaver::saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& if (fs_font.second && fs_font.first.hasValue()) switch (fs_font.first.getFontStyle()) { - case KETFontStyle::FontStyle::EColor: + case KETFontStyle::FontStyle::EColor: { writer.Key(KETFontColorStr); - writer.Uint(fs_font.first.getUInt().value()); - break; + std::stringstream ss; + ss << "#" << std::hex << fs_font.first.getUInt().value(); + writer.String(ss.str()); + } + break; case KETFontStyle::FontStyle::EFamily: writer.Key(KETFontFamilyStr); writer.String(fs_font.first.getString().value()); @@ -1974,7 +1977,6 @@ void MoleculeJsonSaver::saveFontStyles(JsonWriter& writer, const FONT_STYLE_SET& writer.Uint(fs_font.first.getUInt().value()); break; } - break; } writer.EndObject(); } From 1d1ddbb09cf7ea7f64a18f1baed69eebae4a6a40 Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Thu, 18 Jul 2024 11:58:28 +0200 Subject: [PATCH 26/39] tests fix --- core/indigo-core/molecule/molecule_cdxml_loader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index 4d512b5737..ba58dc70a7 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -32,9 +32,9 @@ #include "base_cpp/exception.h" #include "elements.h" #include "molecule/base_molecule.h" +#include "molecule/ket_commons.h" #include "molecule/molecule_stereocenter_options.h" #include "molecule/query_molecule.h" -#include "molecule/ket_commons.h" typedef unsigned short int UINT16; typedef int INT32; From 71cecfdd4fdf1318d14891c1db84ca1cf18debce Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Thu, 18 Jul 2024 12:30:34 +0200 Subject: [PATCH 27/39] tests fix --- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 83d2118732..7c6716a3f1 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1625,7 +1625,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto std::forward_as_tuple(true)); // set fss font color - if (font_color_index >= 0 && font_color_index < color_table.size()) + if (font_color_index >= 0 && font_color_index < static_cast(color_table.size())) { fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, color_table[font_color_index]), std::forward_as_tuple(true)); From a2c885b30560af43cda52b13e582e7ea959796cb Mon Sep 17 00:00:00 2001 From: Roman Porozhnetov Date: Mon, 29 Jul 2024 10:55:10 +0200 Subject: [PATCH 28/39] text --- core/indigo-core/molecule/src/ket_commons.cpp | 2 +- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 4 ++-- core/indigo-core/molecule/src/molecule_json_saver.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/indigo-core/molecule/src/ket_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp index 1a524c7c85..cfe9a21b2a 100644 --- a/core/indigo-core/molecule/src/ket_commons.cpp +++ b/core/indigo-core/molecule/src/ket_commons.cpp @@ -300,7 +300,7 @@ namespace indigo auto style_lambda = styleLambda(_font_styles); - DispatchMapKVP text_obj_dispatcher = {{"bounding_box", bbox_lambda}, {"alignment", alignLambda(_alignment)}, {KETFontBoldStr, style_lambda}, + DispatchMapKVP text_obj_dispatcher = {{"boundingBox", bbox_lambda}, {"alignment", alignLambda(_alignment)}, {KETFontBoldStr, style_lambda}, {KETFontItalicStr, style_lambda}, {KETFontSubscriptStr, style_lambda}, {KETFontSuperscriptStr, style_lambda}, {"indent", indentLambda(_indent)}, {"font", fontLambda(_font_styles)}, {"paragraphs", paragraphs_lambda}}; diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 7c6716a3f1..ec18966d74 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -769,8 +769,8 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n } else { - //_parseTextToKetObject(elem, ket_text_objects); - _parseText(elem, text_objects); + _parseTextToKetObject(elem, ket_text_objects); + //_parseText(elem, text_objects); } }; diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 7ccd08a878..920873ee8e 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -1906,7 +1906,7 @@ void MoleculeJsonSaver::saveTextV1(JsonWriter& writer, const KETTextObject& text void MoleculeJsonSaver::saveText(JsonWriter& writer, const KETTextObject& text_obj) { - writer.Key("bounding_box"); + writer.Key("boundingBox"); writer.WriteRect(text_obj.boundingBox()); if (text_obj.alignment().has_value()) saveAlignment(writer, text_obj.alignment().value()); From a014b340617ffc6f14af99117ed89b7f99660c94 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 9 Dec 2024 20:49:54 +0100 Subject: [PATCH 29/39] meta --- core/indigo-core/molecule/{meta_commons.h => ket_commons.h} | 0 .../molecule/src/{meta_commons.cpp => ket_commons.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename core/indigo-core/molecule/{meta_commons.h => ket_commons.h} (100%) rename core/indigo-core/molecule/src/{meta_commons.cpp => ket_commons.cpp} (100%) diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/ket_commons.h similarity index 100% rename from core/indigo-core/molecule/meta_commons.h rename to core/indigo-core/molecule/ket_commons.h diff --git a/core/indigo-core/molecule/src/meta_commons.cpp b/core/indigo-core/molecule/src/ket_commons.cpp similarity index 100% rename from core/indigo-core/molecule/src/meta_commons.cpp rename to core/indigo-core/molecule/src/ket_commons.cpp From ba6c31d170b4fc5f6bfc8d6afc41d231da749d7b Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 10 Dec 2024 01:02:52 +0100 Subject: [PATCH 30/39] merge5 --- core/indigo-core/molecule/meta_commons.h | 895 ++++++++++++++++++ .../indigo-core/molecule/src/meta_commons.cpp | 408 ++++++++ 2 files changed, 1303 insertions(+) create mode 100644 core/indigo-core/molecule/meta_commons.h create mode 100644 core/indigo-core/molecule/src/meta_commons.cpp diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/meta_commons.h new file mode 100644 index 0000000000..99304ce774 --- /dev/null +++ b/core/indigo-core/molecule/meta_commons.h @@ -0,0 +1,895 @@ +/**************************************************************************** + * 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 __meta_commons_h__ +#define __meta_commons_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/math/algebra.h" +#include "graph/graph.h" +#include "molecule/molecule_cip_calculator.h" +#include "molecule/parse_utils.h" +#include "molecule/query_molecule.h" +#include "reaction/base_reaction.h" + +namespace indigo +{ + const double KDefaultFontSize = 13; + const double KFontScaleFactor = 47; + const auto KFontBoldStrV1 = "BOLD"; + const auto KFontItalicStrV1 = "ITALIC"; + const auto KFontSuperscriptStrV1 = "SUPERSCRIPT"; + const auto KFontSubscriptStrV1 = "SUBSCRIPT"; + const auto KFontCustomSizeStrV1 = "CUSTOM_FONT_SIZE"; + const auto KImagePNG = "image/png"; + const auto KImageSVG = "image/svg+xml"; + + const auto KFontBoldStr = "bold"; + const auto KFontItalicStr = "italic"; + const auto KFontSuperscriptStr = "superscript"; + const auto KFontSubscriptStr = "subscript"; + const auto KFontSizeStr = "size"; + const auto KFontColorStr = "color"; + const auto KFontFamilyStr = "family"; + + const auto KAlignmentLeft = "left"; + const auto KAlignmentRight = "right"; + const auto KAlignmentCenter = "center"; + const auto KAlignmentJustify = "justify"; + + const uint8_t KReactantArea = 0; + const uint8_t KReagentUpArea = 1; + const uint8_t KReagentDownArea = 2; + const uint8_t KProductArea = 3; + const Vec2f MIN_MOL_SIZE = {0.5, 0.5}; + + struct KETVersion + { + int major; + int minor; + int patch; + }; + + const KETVersion KETVersion1 = {1, 0, 0}; + const KETVersion KETVersion2 = {2, 0, 0}; + + enum class KETVersionIndex : int + { + EMajor, + EMinor, + EPatch + }; + + struct KETFontStyle + { + using KETFontVal = std::variant; + enum class FontStyle : int + { + ENone, + EBold, + EItalic, + ESuperScript, + ESubScript, + EFamily, + ESize, + EColor + }; + + KETFontStyle(const FontStyle fs, KETFontVal val = std::monostate{}) : _font_style(fs), _val(val) + { + } + + KETFontStyle() : _font_style(FontStyle::ENone) + { + } + + KETFontStyle(const KETFontStyle& other) : _font_style(other._font_style), _val(other._val) + { + } + + operator int() const + { + return static_cast(_font_style); + } + + operator FontStyle() const + { + return _font_style; + } + + FontStyle getFontStyle() const + { + return _font_style; + } + + std::optional getString() const + { + if (auto str = std::get_if(&_val)) + return *str; + return std::nullopt; + } + + std::optional getUInt() const + { + if (auto val = std::get_if(&_val)) + return *val; + return std::nullopt; + } + + void setFontStyle(FontStyle fs) + { + _font_style = fs; + } + + void setValue(const std::string& val) + { + _val = val; + } + + void setValue(uint32_t val) + { + _val = val; + } + + bool hasValue() const + { + return _val.index() != 0; + } + + private: + FontStyle _font_style; + std::variant _val; + }; + + struct compareFunction + { + bool operator()(const std::pair& a, const std::pair& b) const + { + return a.second == b.second ? static_cast(a.first) < static_cast(b.first) : a.second < b.second; + } + }; + + using FONT_STYLE_SET = std::set, compareFunction>; + + FONT_STYLE_SET& operator+=(FONT_STYLE_SET& lhs, const FONT_STYLE_SET& rhs); + + constexpr std::uint32_t string_hash(char const* s, std::size_t count) + { + return ((count ? string_hash(s, count - 1) : 2166136261u) ^ s[count]) * 16777619u; + } + + constexpr std::uint32_t operator"" _hash(char const* s, std::size_t count) + { + return string_hash(s, count); + } + + uint8_t getPointSide(const Vec2f& point, const Vec2f& beg, const Vec2f& end); + + CIPDesc stringToCIP(const std::string& cip_str); + + std::string CIPToString(CIPDesc cip); + + bool isCIPSGroup(SGroup& sgroup); + + void getSGroupAtoms(BaseMolecule& mol, std::list>& neighbors); + + std::string convertAPToHELM(const std::string& atp_id_str); + + std::string convertAPFromHELM(const std::string& atp_id_str); + + class SimpleGraphicsObject : public MetaObject + { + public: + static const std::uint32_t CID = "Metadata simple object"_hash; + SimpleGraphicsObject(int mode, const std::pair& coords) : MetaObject(CID) + { + _mode = mode; + _coordinates = coords; + }; + + void getBoundingBox(Rect2f& bbox) const override + { + bbox = Rect2f(_coordinates.first, _coordinates.second); + } + + MetaObject* clone() const override + { + return new SimpleGraphicsObject(_mode, _coordinates); + } + + void offset(const Vec2f& offset) override + { + _coordinates.first += offset; + _coordinates.second += offset; + } + + enum + { + EEllipse, + ERectangle, + ELine + }; + + int _mode; + std::pair _coordinates; + }; + + struct SimpleTextStyle + { + std::size_t offset; + std::size_t size; + std::list styles; + }; + + struct SimpleTextLine + { + std::string text; + std::list text_styles; + }; + + class SimpleTextObject : public MetaObject + { + public: + enum class TextAlignment : int + { + ELeft, + ERight, + ECenter, + EJustify + }; + + using TextAlignMap = const std::unordered_map; + using StrIntMap = const std::unordered_map; + using FontStyleMap = const std::unordered_map; + using DispatchMapKVP = std::unordered_map>; + using DispatchMapVal = std::unordered_map>; + + static const TextAlignMap& textAlignmentMap(); + + static const FontStyleMap& textStyleMapV1(); + + static const FontStyleMap& textStyleMap(); + + static KETFontStyle::FontStyle textStyleByName(const std::string& style_name); + + struct KETTextIndent + { + std::optional left; + std::optional right; + std::optional first_line; + }; + + struct KETTextParagraph + { + KETTextParagraph() + { + } + std::string text; + FONT_STYLE_SET font_style; + std::optional alignment; + std::optional indent; + std::map font_styles; + }; + + static const std::uint32_t CID = "Simple text object"_hash; + + static void applyDispatcher(const rapidjson::Value& val, const DispatchMapKVP& disp_map) + { + for (auto kvp_it = val.MemberBegin(); kvp_it != val.MemberEnd(); ++kvp_it) + { + auto disp_it = disp_map.find(kvp_it->name.GetString()); + if (disp_it != disp_map.end()) + disp_it->second(kvp_it->name.GetString(), kvp_it->value); + } + } + + static void applyDispatcher(const rapidjson::Value& val, const DispatchMapVal& disp_map) + { + for (auto kvp_it = val.MemberBegin(); kvp_it != val.MemberEnd(); ++kvp_it) + { + auto disp_it = disp_map.find(kvp_it->name.GetString()); + if (disp_it != disp_map.end()) + disp_it->second(kvp_it->value); + } + } + + static auto floatLambda(std::optional& val) + { + return [&val](const rapidjson::Value& float_val) { val = float_val.GetFloat(); }; + } + + static auto intLambda(std::optional& val) + { + return [&val](const rapidjson::Value& int_val) { val = int_val.GetInt(); }; + } + + static auto strLambda(std::optional& str) + { + return [&str](const rapidjson::Value& str_val) { str = str_val.GetString(); }; + } + + auto alignLambda(std::optional& alignment) + { + return [this, &alignment](const std::string&, const rapidjson::Value& align_val) { + auto ta_it = textAlignmentMap().find(align_val.GetString()); + if (ta_it != textAlignmentMap().end()) + alignment = ta_it->second; + }; + } + + auto styleLambda(FONT_STYLE_SET& fss) + { + return [this, &fss](const std::string& key, const rapidjson::Value& style_val) { + std::string style_name = key; + std::transform(style_name.begin(), style_name.end(), style_name.begin(), [](unsigned char c) { return std::toupper(c); }); + auto style = textStyleByName(style_name); + if (style != KETFontStyle::FontStyle::ENone) + fss.emplace(style, style_val.GetBool()); + }; + } + + static auto colorLambda(FONT_STYLE_SET& fss, bool bval) + { + return [&fss, bval](const rapidjson::Value& color_str) { + std::string color_string = color_str.GetString(); + if (color_string.size() && color_string[0] == '#') + { + fss.emplace(std::piecewise_construct, + std::forward_as_tuple(KETFontStyle::FontStyle::EColor, static_cast(std::stoul(color_string.substr(1), nullptr, 16))), + std::forward_as_tuple(bval)); + } + }; + } + + static auto fontFamilyLambda(FONT_STYLE_SET& fss, bool bval) + { + return [&fss, bval](const rapidjson::Value& val) { + if (val.IsString()) + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, val.GetString()), + std::forward_as_tuple(bval)); + }; + } + + static auto fontSizeLambda(FONT_STYLE_SET& fss, bool bval) + { + return [&fss, bval](const rapidjson::Value& val) { + if (val.IsInt()) + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(val.GetUint())), + std::forward_as_tuple(bval)); + }; + } + + auto fontLambda(FONT_STYLE_SET& fss, bool bval = true) + { + return [&fss, bval](const std::string&, const rapidjson::Value& font_val) { + DispatchMapVal font_dispatcher = { + {KFontFamilyStr, fontFamilyLambda(fss, bval)}, {KFontSizeStr, fontSizeLambda(fss, bval)}, {KFontColorStr, colorLambda(fss, bval)}}; + applyDispatcher(font_val, font_dispatcher); + }; + } + + static auto indentLambda(std::optional& indent) + { + return [&indent](const std::string&, const rapidjson::Value& indent_val) { + std::unordered_map> indent_dispatcher = { + {"first_line", floatLambda(indent.value().first_line)}, + {"left", floatLambda(indent.value().left)}, + {"right", floatLambda(indent.value().right)}}; + + for (auto indent_it = indent_val.MemberBegin(); indent_it != indent_val.MemberEnd(); ++indent_it) + { + auto ind_it = indent_dispatcher.find(indent_it->name.GetString()); + if (ind_it != indent_dispatcher.end()) + ind_it->second(indent_it->value); + } + }; + } + + auto partsLambda(KETTextParagraph& paragraph) + { + return [this, ¶graph](const std::string&, const rapidjson::Value& parts) { + for (const auto& part_val : parts.GetArray()) + { + std::string part; + FONT_STYLE_SET fss; + auto text_lambda = [&part](const std::string&, const rapidjson::Value& text_val) { part = text_val.GetString(); }; + auto style_lambda = styleLambda(fss); + DispatchMapKVP paragraph_dispatcher = {{"text", text_lambda}, + {KFontBoldStr, style_lambda}, + {KFontItalicStr, style_lambda}, + {KFontSubscriptStr, style_lambda}, + {KFontSuperscriptStr, style_lambda}, + {"font", fontLambda(fss)}}; + // all styles collected in fss + applyDispatcher(part_val, paragraph_dispatcher); + if (part.size()) + { + paragraph.font_styles.emplace(paragraph.text.size(), fss); + paragraph.text += part; + } + } + }; + } + + SimpleTextObject(const SimpleTextObject& other) + : MetaObject(CID), _alignment(other._alignment), _indent(other._indent), _font_styles{other._font_styles}, _bbox(other._bbox), + _content(other._content), _block(other._block) + { + } + + SimpleTextObject(const Rect2f& bbox, const std::string& content); + + SimpleTextObject(const rapidjson::Value& text_obj); + SimpleTextObject(); + + MetaObject* clone() const override + { + return new SimpleTextObject(*this); + } + + auto& indent() + { + return _indent; + } + + const auto& indent() const + { + return _indent; + } + + auto& alignment() + { + return _alignment; + } + + const auto& alignment() const + { + return _alignment; + } + + auto& boundingBox() + { + return _bbox; + } + + const auto& boundingBox() const + { + return _bbox; + } + + auto& block() + { + return _block; + } + + const auto& block() const + { + return _block; + } + + const auto& content() const + { + return _content; + } + + auto& fontStyles() + { + return _font_styles; + } + + const auto& fontStyles() const + { + return _font_styles; + } + + void getBoundingBox(Rect2f& bbox) const override + { + bbox = _bbox; + } + + const auto& getLines() const + { + return _block; + } + + private: + + void offset(const Vec2f& offset) override + { + _bbox.offset(offset); + } + + std::string _content; + std::list _block; + Rect2f _bbox; + std::optional _indent; + std::optional _alignment; + FONT_STYLE_SET _font_styles; + }; + + class SimpleTextObjectBuilder + { + public: + SimpleTextObjectBuilder(); + void addLine(const SimpleTextLine& line); + void finalize(); + std::string getJsonString() const; + int getLineCounter() const; + + private: + rapidjson::Writer _writer; + rapidjson::StringBuffer _buffer; + int _line_counter; + }; + + class ReactionArrowObject : public MetaObject + { + public: + static const std::uint32_t CID = "Reaction arrow object"_hash; + enum + { + EOpenAngle = 2, + EFilledTriangle, + EFilledBow, + EDashedOpenAngle, + EFailed, + EBothEndsFilledTriangle, + EEquilibriumFilledHalfBow, + EEquilibriumFilledTriangle, + EEquilibriumOpenAngle, + EUnbalancedEquilibriumFilledHalfBow, + EUnbalancedEquilibriumLargeFilledHalfBow, + EUnbalancedEquilibriumOpenHalfAngle, + EUnbalancedEquilibriumFilledHalfTriangle, + EEllipticalArcFilledBow, + EEllipticalArcFilledTriangle, + EEllipticalArcOpenAngle, + EEllipticalArcOpenHalfAngle, + ERetrosynthetic + }; + + ReactionArrowObject(int arrow_type, const Vec2f& begin, const Vec2f& end, float height = 0) + : MetaObject(CID), _arrow_type(arrow_type), _begin(begin), _end(end), _height(height){}; + + MetaObject* clone() const override + { + return new ReactionArrowObject(_arrow_type, _begin, _end, _height); + } + + void getBoundingBox(Rect2f& bbox) const override + { + bbox = Rect2f(_begin, _end); + } + + int getArrowType() const + { + return _arrow_type; + } + + float getHeight() const + { + return _height; + } + + const auto& getHead() const + { + return _end; + } + + const auto& getTail() const + { + return _begin; + } + + void offset(const Vec2f& offset) override + { + _begin += offset; + _end += offset; + } + + private: + int _arrow_type; + float _height; + Vec2f _begin; + Vec2f _end; + }; + + class ReactionMultitailArrowObject : public MetaObject + { + static const int CORRECT_CONSTRUCTOR_PARAMETERS_SIZE = 5; + static const int CORRECT_HEAD_SIZE = 1; + static const int CORRECT_TAIL_SIZE = 2; + + public: + static const std::uint32_t CID = "Reaction multitail arrow object"_hash; + + static constexpr float TAIL_ARC_RADIUS = .15f; + + template + ReactionMultitailArrowObject(Iterator&& begin, Iterator&& end) : MetaObject(CID) + { + auto distanceBetweenBeginAndEnd = std::distance(begin, end); + if (distanceBetweenBeginAndEnd < CORRECT_CONSTRUCTOR_PARAMETERS_SIZE) + throw Exception("ReactionMultitailArrowObject: invalid arguments"); + + _head = *begin++; + _tails.reserve(static_cast(distanceBetweenBeginAndEnd) - CORRECT_HEAD_SIZE - CORRECT_TAIL_SIZE); + while (begin != end) + _tails.push(*begin++); + _spine_begin = _tails.pop(); + _spine_end = _tails.pop(); + } + + ReactionMultitailArrowObject(Vec2f head, const Array& tails, Vec2f spine_begin, Vec2f spine_end) + : MetaObject(CID), _head(head), _spine_begin(spine_begin), _spine_end(spine_end) + { + if (tails.size() < CORRECT_TAIL_SIZE) + throw Exception("ReactionMultitailArrowObject: invalid arguments"); + _tails.copy(tails); + } + + MetaObject* clone() const override + { + return new ReactionMultitailArrowObject(_head, _tails, _spine_begin, _spine_end); + } + + auto getHead() const + { + return _head; + } + + auto& getTails() const + { + return _tails; + } + + auto getSpineBegin() const + { + return _spine_begin; + } + + auto getSpineEnd() const + { + return _spine_end; + } + + void getBoundingBox(Rect2f& bbox) const override + { + float min_left = 0; + for (int i = 0; i < _tails.size(); ++i) + { + if (i == 0) + min_left = _tails[i].x; + else + min_left = std::min(min_left, _tails[i].x); + } + + float max_top = _spine_begin.y; + float min_bottom = _spine_end.y; + float max_right = _head.x; + bbox = Rect2f(Vec2f(min_left, max_top), Vec2f(max_right, min_bottom)); + } + + void offset(const Vec2f& offset) override + { + _head += offset; + _spine_begin += offset; + _spine_end += offset; + for (auto& tail : _tails) + tail += offset; + } + + private: + Vec2f _head; + Array _tails; + Vec2f _spine_begin, _spine_end; + }; + + class ReactionPlusObject : public MetaObject + { + public: + static const std::uint32_t CID = "Reaction plus object"_hash; + ReactionPlusObject(const Vec2f& pos) : MetaObject(CID), _pos(pos){}; + + MetaObject* clone() const override + { + return new ReactionPlusObject(_pos); + } + + enum + { + EKETEllipse, + EKETRectangle, + EKETLine + }; + const auto& getPos() const + { + return _pos; + } + + void getBoundingBox(Rect2f& bbox) const override + { + bbox = Rect2f(_pos, _pos); + } + + void offset(const Vec2f& offset) override + { + _pos += offset; + } + + private: + Vec2f _pos; + }; + + class EmbeddedImageObject : public MetaObject + { + public: + enum ImageFormat + { + EKETPNG, + EKETSVG + }; + + static const std::uint32_t CID = "Embedded image object"_hash; + EmbeddedImageObject(const Rect2f& bbox, EmbeddedImageObject::ImageFormat format, const std::string& data, bool is_base64 = true); + + MetaObject* clone() const override + { + return new EmbeddedImageObject(_bbox, _image_format, getBase64()); + } + + auto& getBoundingBox() const + { + return _bbox; + } + + std::string getBase64() const; + + const std::string& getData() const + { + return _image_data; + } + + ImageFormat getFormat() const + { + return _image_format; + } + + void getBoundingBox(Rect2f& bbox) const override + { + bbox = _bbox; + } + + void offset(const Vec2f& offset) override + { + _bbox = Rect2f(_bbox.leftBottom() + offset, _bbox.rightTop() + offset); + } + + private: + Rect2f _bbox; + std::string _image_data; + ImageFormat _image_format; + }; + + struct MolSumm + { + MolSumm() : bbox(Vec2f(0, 0), Vec2f(0, 0)), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; + MolSumm(const Rect2f& box) : bbox(box), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; + + Rect2f bbox; + std::vector indexes; + int role; + int reaction_idx; + std::vector arrows_to; + std::vector arrows_from; + }; + + struct PathwayComponent + { + int product_csb_idx; + std::vector reactant_csb_indexes; + }; + + struct ReactionComponent + { + enum + { + MOLECULE = 0, + PLUS, + ARROW_BASIC, + ARROW_FILLED_TRIANGLE, + ARROW_FILLED_BOW, + ARROW_DASHED, + ARROW_FAILED, + ARROW_BOTH_ENDS_FILLED_TRIANGLE, + ARROW_EQUILIBRIUM_FILLED_HALF_BOW, + ARROW_EQUILIBRIUM_FILLED_TRIANGLE, + ARROW_EQUILIBRIUM_OPEN_ANGLE, + ARROW_UNBALANCED_EQUILIBRIUM_FILLED_HALF_BOW, + ARROW_UNBALANCED_EQUILIBRIUM_LARGE_FILLED_HALF_BOW, + ARROW_UNBALANCED_EQUILIBRIUM_OPEN_HALF_ANGLE, + ARROW_UNBALANCED_EQUILIBRIUM_FILLED_HALF_TRIANGLE, + ARROW_ELLIPTICAL_ARC_FILLED_BOW, + ARROW_ELLIPTICAL_ARC_FILLED_TRIANGLE, + ARROW_ELLIPTICAL_ARC_OPEN_ANGLE, + ARROW_ELLIPTICAL_ARC_OPEN_HALF_ANGLE, + ARROW_RETROSYNTHETIC, + ARROW_MULTITAIL + }; + + enum + { + NOT_CONNECTED = -2, + CONNECTED = -1 + }; + + ReactionComponent(int ctype, const Rect2f& box, int idx, std::unique_ptr mol) + : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED), index(idx){}; + + int component_type; + Rect2f bbox; + std::unique_ptr molecule; + std::list::iterator summ_block_it; + int summ_block_idx; + std::vector coordinates; + int index; + }; + + // hash for pairs taken from boost library + struct pair_int_hash + { + private: + const std::hash ah; + const std::hash bh; + + public: + pair_int_hash() : ah(), bh() + { + } + size_t operator()(const std::pair& p) const + { + size_t seed = ah(p.first); + return bh(p.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + }; + + struct commutative_pair_int_hash + { + pair_int_hash pih; + + public: + size_t operator()(const std::pair& p) const + { + std::pair sorted_pair(p); + if (sorted_pair.first > sorted_pair.second) + std::swap(sorted_pair.first, sorted_pair.second); + auto c_val = pih(sorted_pair); + return c_val; + } + }; + std::string getDebugSmiles(BaseMolecule& mol); +} +#endif diff --git a/core/indigo-core/molecule/src/meta_commons.cpp b/core/indigo-core/molecule/src/meta_commons.cpp new file mode 100644 index 0000000000..b74135b7f2 --- /dev/null +++ b/core/indigo-core/molecule/src/meta_commons.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** + * 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. + ***************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push, 4) +#endif + +#include "molecule/meta_commons.h" +#include "base_cpp/output.h" +#include "base_cpp/scanner.h" +#include "molecule/monomer_commons.h" +#include "molecule/smiles_saver.h" +#include + +namespace indigo +{ + FONT_STYLE_SET& operator+=(FONT_STYLE_SET& lhs, const FONT_STYLE_SET& rhs) + { + for (const auto& fs : rhs) + { + if (fs.second) // we want to turn on the style + { + // remove previous switching off the style if there is one + auto it = lhs.find(std::make_pair(fs.first, false)); + if (it != lhs.end()) + lhs.erase(it); + + // check for duplicates + if (!lhs.count(fs)) + lhs.insert(fs); + } + else + { + auto it = lhs.find(std::make_pair(fs.first, true)); + if (it != lhs.end()) + lhs.erase(it); + } + } + return lhs; + } + + uint8_t getPointSide(const Vec2f& point, const Vec2f& beg, const Vec2f& end) + { + uint8_t bit_mask = 0; + Vec2f arrow_vec(beg); + arrow_vec.sub(end); + + Vec2f slope1(point.x, point.y); + Vec2f slope2(slope1); + slope1.sub(beg); + slope2.sub(end); + auto dt1 = Vec2f::dot(slope1, arrow_vec); + auto dt2 = Vec2f::dot(slope2, arrow_vec); + + if (std::signbit(dt1)) + bit_mask |= KReagentUpArea; + + if (std::signbit(dt2)) + bit_mask |= KReagentDownArea; + + return bit_mask; + } + + bool isCIPSGroup(SGroup& sgroup) + { + if (sgroup.sgroup_type == SGroup::SG_DATA) + { + auto& dsg = (DataSGroup&)sgroup; + return std::string(dsg.name.ptr()) == "INDIGO_CIP_DESC"; + } + return false; + } + + CIPDesc stringToCIP(const std::string& cip_str) + { + static const std::unordered_map KStringToCIP = {{"R", CIPDesc::R}, {"S", CIPDesc::S}, {"r", CIPDesc::r}, + {"s", CIPDesc::s}, {"E", CIPDesc::E}, {"Z", CIPDesc::Z}}; + auto cip_it = KStringToCIP.find(cip_str); + if (cip_it != KStringToCIP.end()) + return cip_it->second; + return CIPDesc::NONE; + } + + std::string CIPToString(CIPDesc cip) + { + static const std::unordered_map KCIPToString = {{(int)CIPDesc::R, "R"}, {(int)CIPDesc::S, "S"}, {(int)CIPDesc::r, "r"}, + {(int)CIPDesc::s, "s"}, {(int)CIPDesc::E, "E"}, {(int)CIPDesc::Z, "Z"}}; + auto cip_it = KCIPToString.find((int)cip); + std::string res; + if (cip_it != KCIPToString.end()) + res = cip_it->second; + return res; + } + + void getSGroupAtoms(BaseMolecule& mol, std::list>& neighbors) + { + for (int i = mol.sgroups.begin(); i != mol.sgroups.end(); i = mol.sgroups.next(i)) + { + SGroup& sgroup = mol.sgroups.getSGroup(i); + neighbors.push_back({}); + auto& sg_set = neighbors.back(); + for (auto atom_idx : sgroup.atoms) + sg_set.insert(atom_idx); + } + if (mol.isQueryMolecule()) + { + QueryMolecule& qmol = static_cast(mol); + qmol.getComponentNeighbors(neighbors); + } + } + + std::string convertAPToHELM(const std::string& atp_id_str) + { + if (::isupper(atp_id_str[0]) && atp_id_str.size() == 2) + { + if (atp_id_str == kLeftAttachmentPoint) + return kAttachmentPointR1; + else if (atp_id_str == kRightAttachmentPoint) + return kAttachmentPointR2; + else if (atp_id_str[1] == 'x') + return std::string("R") + std::to_string(atp_id_str[0] - 'A' + 1); + } + return atp_id_str; + } + + std::string convertAPFromHELM(const std::string& atp_id_str) + { + int id = extract_id(atp_id_str, "R"); + if (id < 0) + throw std::invalid_argument(std::string("convertAPFromHELM: prefix 'R' not found in :") + atp_id_str); + char ap_symbol = static_cast(id) + '@'; // convert number to ASCII letter + std::string res(1, ap_symbol); + switch (ap_symbol) + { + case 'A': + res += 'l'; + break; + case 'B': + res += 'r'; + break; + default: + res += 'x'; + break; + } + return res; + } + + const SimpleTextObject::TextAlignMap& SimpleTextObject::textAlignmentMap() + { + static TextAlignMap KTextAlignmentsMap{{KAlignmentLeft, TextAlignment::ELeft}, + {KAlignmentRight, TextAlignment::ERight}, + {KAlignmentCenter, TextAlignment::ECenter}, + {KAlignmentJustify, TextAlignment::EJustify}}; + return KTextAlignmentsMap; + } + + const SimpleTextObject::FontStyleMap& SimpleTextObject::textStyleMapV1() + { + static const FontStyleMap KTextStylesMap{{KFontBoldStrV1, KETFontStyle::FontStyle::EBold}, + {KFontItalicStrV1, KETFontStyle::FontStyle::EItalic}, + {KFontSuperscriptStrV1, KETFontStyle::FontStyle::ESuperScript}, + {KFontSubscriptStrV1, KETFontStyle::FontStyle::ESubScript}}; + return KTextStylesMap; + } + + const SimpleTextObject::FontStyleMap& SimpleTextObject::textStyleMap() + { + static const FontStyleMap KTextFontStylesMap{{KFontBoldStr, KETFontStyle::FontStyle::EBold}, + {KFontItalicStr, KETFontStyle::FontStyle::EItalic}, + {KFontSuperscriptStr, KETFontStyle::FontStyle::ESuperScript}, + {KFontSubscriptStr, KETFontStyle::FontStyle::ESubScript}, + {KFontFamilyStr, KETFontStyle::FontStyle::EFamily}, + {KFontSizeStr, KETFontStyle::FontStyle::ESize}, + {KFontColorStr, KETFontStyle::FontStyle::EColor}}; + return KTextFontStylesMap; + } + + KETFontStyle::FontStyle SimpleTextObject::textStyleByName(const std::string& style_name) + { + auto style_it = textStyleMap().find(style_name); + if (style_it != textStyleMap().end()) + return style_it->second; + style_it = textStyleMapV1().find(style_name); + if (style_it != textStyleMapV1().end()) + return style_it->second; + return KETFontStyle::FontStyle::ENone; + } + + SimpleTextObject::SimpleTextObject(const Rect2f& bbox, const std::string& content) : MetaObject(CID), _alignment{}, _indent{}, _font_styles{} + { + using namespace rapidjson; + _bbox = bbox; + if (content.size()) + { + _content = content; + Document data; + data.Parse(content.c_str()); + if (data.HasMember("blocks")) + { + Value& blocks = data["blocks"]; + for (rapidjson::SizeType i = 0; i < blocks.Size(); ++i) + { + KETTextParagraph text_line; + if (blocks[i].HasMember("text")) + { + text_line.text = blocks[i]["text"].GetString(); + text_line.font_styles.emplace(0, std::initializer_list>{{}}); + text_line.font_styles.emplace(text_line.text.size(), std::initializer_list>{{}}); + if (blocks[i].HasMember("inlineStyleRanges")) + { + Value& style_ranges = blocks[i]["inlineStyleRanges"]; + for (rapidjson::SizeType j = 0; j < style_ranges.Size(); ++j) + { + int style_begin = style_ranges[j]["offset"].GetInt(); + int style_end = style_begin + style_ranges[j]["length"].GetInt(); + + std::string style_name = style_ranges[j]["style"].GetString(); + KETFontStyle ket_fs; + + auto style = textStyleByName(style_name); + if (style != KETFontStyle::FontStyle::ENone) + ket_fs.setFontStyle(style); + else + { + const std::string KCustomFontSize = "CUSTOM_FONT_SIZE_"; + const std::string KCustomFontUnits = "px"; + if (style_name.find(KCustomFontSize) == 0) + { + ket_fs.setFontStyle(KETFontStyle::FontStyle::ESize); + ket_fs.setValue(std::stoi( + style_name.substr(KCustomFontSize.size(), style_name.size() - KCustomFontSize.size() - KCustomFontUnits.size()))); + } + } + + const auto it_begin = text_line.font_styles.find(style_begin); + const auto it_end = text_line.font_styles.find(style_end); + + if (it_begin == text_line.font_styles.end()) + text_line.font_styles.emplace(style_begin, std::initializer_list>{{ket_fs, true}}); + else + it_begin->second.emplace(ket_fs, true); + + if (it_end == text_line.font_styles.end()) + text_line.font_styles.emplace(style_end, std::initializer_list>{{ket_fs, false}}); + else + it_end->second.emplace(ket_fs, false); + } + } + } + _block.push_back(text_line); + } + } + } + } + + SimpleTextObject::SimpleTextObject() : MetaObject(CID) + { + } + + SimpleTextObject::SimpleTextObject(const rapidjson::Value& text_obj) : MetaObject(CID), _alignment{}, _indent{}, _font_styles{} + { + using namespace rapidjson; + + auto bbox_lambda = [this](const std::string&, const Value& bbox_val) { + Vec2f v1(bbox_val["x"].GetFloat(), bbox_val["y"].GetFloat()); + Vec2f v2(v1); + v2.add(Vec2f(bbox_val["width"].GetFloat(), bbox_val["height"].GetFloat())); + _bbox.copy(Rect2f(v1, v2)); + }; + + auto paragraphs_lambda = [this](const std::string&, const Value& paragraphs_val) { + for (const auto& paragraph : paragraphs_val.GetArray()) + { + KETTextParagraph text_line; + auto style_lambda = styleLambda(text_line.font_style); + DispatchMapKVP paragraph_dispatcher = {{"alignment", alignLambda(text_line.alignment)}, + {KFontBoldStr, style_lambda}, + {KFontItalicStr, style_lambda}, + {KFontSubscriptStr, style_lambda}, + {KFontSuperscriptStr, style_lambda}, + {"indent", indentLambda(text_line.indent)}, + {"font", fontLambda(text_line.font_style)}, + {"parts", partsLambda(text_line)}}; + + applyDispatcher(paragraph, paragraph_dispatcher); + _block.push_back(text_line); + } + }; + + auto style_lambda = styleLambda(_font_styles); + + DispatchMapKVP text_obj_dispatcher = {{"boundingBox", bbox_lambda}, {"alignment", alignLambda(_alignment)}, {KFontBoldStr, style_lambda}, + {KFontItalicStr, style_lambda}, {KFontSubscriptStr, style_lambda}, {KFontSuperscriptStr, style_lambda}, + {"indent", indentLambda(_indent)}, {"font", fontLambda(_font_styles)}, {"paragraphs", paragraphs_lambda}}; + + applyDispatcher(text_obj, text_obj_dispatcher); + } + + EmbeddedImageObject::EmbeddedImageObject(const Rect2f& bbox, EmbeddedImageObject::ImageFormat format, const std::string& data, bool is_base64) + : MetaObject(CID), _bbox(bbox), _image_format(format) + { + if (is_base64) + { + BufferScanner b64decode(data.c_str(), true); + b64decode.readAll(_image_data); + } + else + _image_data = data; + } + + std::string EmbeddedImageObject::getBase64() const + { + return base64::encode(_image_data.c_str(), _image_data.size()); + } + + std::string getDebugSmiles(BaseMolecule& mol) + { + Array out_buffer; + ArrayOutput output(out_buffer); + SmilesSaver saver(output); + saver.saveMolecule(mol.asMolecule()); + out_buffer.push('\0'); + return out_buffer.ptr(); + } + + + SimpleTextObjectBuilder::SimpleTextObjectBuilder() : _writer(_buffer), _line_counter(0) + { + } + + void SimpleTextObjectBuilder::addLine(const SimpleTextLine& line) + { + _line_counter++; + if (_buffer.GetLength() == 0) + { + _writer.StartObject(); + _writer.Key("blocks"); + _writer.StartArray(); + } + _writer.StartObject(); + _writer.Key("text"); + _writer.String(line.text.c_str()); + _writer.Key("inlineStyleRanges"); + _writer.StartArray(); + for (const auto& ts : line.text_styles) + { + for (const auto& style_str : ts.styles) + { + _writer.StartObject(); + _writer.Key("offset"); + _writer.Int(static_cast(ts.offset)); + _writer.Key("length"); + _writer.Int(static_cast(ts.size)); + _writer.Key("style"); + _writer.String(style_str.c_str()); + _writer.EndObject(); + } + } + _writer.EndArray(); + _writer.Key("entityRanges"); + _writer.StartArray(); + _writer.EndArray(); + _writer.Key("data"); + _writer.StartObject(); + _writer.EndObject(); + _writer.EndObject(); + } + + void SimpleTextObjectBuilder::finalize() + { + _writer.EndArray(); + _writer.Key("entityMap"); + _writer.StartObject(); + _writer.EndObject(); + _writer.EndObject(); + } + + std::string SimpleTextObjectBuilder::getJsonString() const + { + std::string result; + if (_buffer.GetLength() > 0) + result = _buffer.GetString(); + return result; + } + + int SimpleTextObjectBuilder::getLineCounter() const + { + return _line_counter; + } +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif From b68d830e6b9bbf2be10b77241bae27da6892ddd0 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 11 Dec 2024 15:55:22 +0100 Subject: [PATCH 31/39] first step --- core/indigo-core/layout/src/pathway_layout.cpp | 8 ++++---- core/indigo-core/molecule/molecule_cdxml_loader.h | 7 +++---- .../molecule/src/molecule_cdxml_loader.cpp | 12 +++++++----- utils/indigo-depict/main.c | 4 ++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/core/indigo-core/layout/src/pathway_layout.cpp b/core/indigo-core/layout/src/pathway_layout.cpp index 3248482254..742bc80719 100644 --- a/core/indigo-core/layout/src/pathway_layout.cpp +++ b/core/indigo-core/layout/src/pathway_layout.cpp @@ -377,12 +377,12 @@ void PathwayLayout::addMetaText(PathwayReaction::ReactionNode& node, const Vec2f // add text meta-object SimpleTextObjectBuilder tob; auto height_limit = text_height_limit; - generateTextBlocks(tob, node.name_text, KFontBoldStr, height_limit); - generateTextBlocks(tob, node.conditions_text, KFontItalicStr, height_limit); + generateTextBlocks(tob, node.name_text, KFontBoldStrV1, height_limit); + generateTextBlocks(tob, node.conditions_text, KFontItalicStrV1, height_limit); tob.finalize(); auto text_height = _text_line_height * tob.getLineCounter(); - Vec2f text_pos_tl(text_pos_bl.x, text_pos_bl.y - _text_line_height / 2.0f + text_height + _reaction_margin_size); - _reaction.meta().addMetaObject(new SimpleTextObject(Rect2f(text_pos_tl, text_pos_bl), tob.getJsonString()), true); + Vec2f text_pos_tr(text_pos_bl.x + node.text_width, text_pos_bl.y - _text_line_height / 2.0f + text_height + _reaction_margin_size); + _reaction.meta().addMetaObject(new SimpleTextObject(Rect2f(text_pos_bl, text_pos_tr), tob.getJsonString()), true); } std::vector PathwayLayout::splitText(const std::string& text, float max_width, std::function symbol_width) diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index cc80684f43..fcb6ebea5d 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -180,12 +180,11 @@ namespace indigo struct CdxmlText { - CdxmlText(const Vec3f& pos, const Vec2f& size, const std::string& text) : pos(pos), size(size), text(text) + CdxmlText(const Rect2f& bbox, const std::string& text) : bbox(bbox), text(text) { } std::string text; - Vec3f pos; - Vec2f size; + Rect2f bbox; }; class BaseCDXProperty @@ -898,7 +897,7 @@ namespace indigo void _parseBond(CdxmlBond& bond, BaseCDXProperty& prop); void _parseBracket(CdxmlBracket& bracket, BaseCDXProperty& prop); - void _parseText(BaseCDXElement& elem, std::vector>& text_parsed); + void _parseText(BaseCDXElement& elem, std::vector& text_parsed); void _parseTextToKetObject(BaseCDXElement& elem, std::vector& text_objects); void _parseLabel(BaseCDXElement& elem, std::string& label); diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 52981aaf1f..c5d0734694 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -529,17 +529,19 @@ void MoleculeCdxmlLoader::_parseCollections(BaseMolecule& mol) for (auto& brk : brackets) _addBracket(mol, brk); + for (const auto& to : text_objects) + mol.meta().addMetaObject(new SimpleTextObject(to.bbox, to.text)); for (const auto& kto : ket_text_objects) mol.meta().addMetaObject(new SimpleTextObject(kto)); for (const auto& plus : _pluses) mol.meta().addMetaObject(new ReactionPlusObject(plus)); - // CDX contains graphic arrow wich id dublicate arrow/ + // CDX contains graphic arrow with duplicate arrow id/ for (const auto& image : _images) mol.meta().addMetaObject(new EmbeddedImageObject(image.bbox, image.image_format, image.data, false)); - // Search arrows for arrow with coords same as in grapic arrow and if found - remove tis arrow gecause graphic arrow contains more specific type + // Search arrows for arrow with coords same as in graphic arrow and if found - remove tis arrow gecause graphic arrow contains more specific type for (const auto& g_arrow : _graphic_arrows) { const auto& g_arr_info = g_arrow.first; @@ -787,8 +789,8 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n } else { - _parseTextToKetObject(elem, ket_text_objects); - //_parseText(elem, text_objects); + // _parseTextToKetObject(elem, ket_text_objects); + _parseText(elem, text_objects); } }; @@ -1789,7 +1791,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto } } -void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector>& text_parsed) +void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector& text_parsed) { Vec2f text_pos; Rect2f text_bbox; diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 4773b6449d..14d7679bf5 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -868,7 +868,7 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-stereochemistry-errors", "on"); indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); - indigoSetOption("ket-saving-version", "2.0.0"); + indigoSetOption("ket-saving-version", "1.0.0"); indigoSetOptionBool("json-saving-pretty", "on"); if (parseParams(&p, argc, argv) < 0) @@ -1059,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - indigoLayout(obj); + //indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From ac2faeed3ae45dfb7f693c446c02b1da7cb30327 Mon Sep 17 00:00:00 2001 From: even1024 Date: Sun, 15 Dec 2024 23:16:00 +0100 Subject: [PATCH 32/39] second step --- core/indigo-core/molecule/meta_commons.h | 11 +++-- .../molecule/molecule_cdxml_loader.h | 42 ++++++++++++++----- .../molecule/src/base_molecule.cpp | 10 +++++ .../indigo-core/molecule/src/meta_commons.cpp | 3 +- .../molecule/src/molecule_json_loader.cpp | 2 +- .../molecule/src/molecule_json_saver.cpp | 19 ++++----- utils/indigo-depict/main.c | 6 +-- 7 files changed, 60 insertions(+), 33 deletions(-) diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/meta_commons.h index 99304ce774..1ec166361c 100644 --- a/core/indigo-core/molecule/meta_commons.h +++ b/core/indigo-core/molecule/meta_commons.h @@ -516,7 +516,6 @@ namespace indigo } private: - void offset(const Vec2f& offset) override { _bbox.offset(offset); @@ -572,7 +571,7 @@ namespace indigo }; ReactionArrowObject(int arrow_type, const Vec2f& begin, const Vec2f& end, float height = 0) - : MetaObject(CID), _arrow_type(arrow_type), _begin(begin), _end(end), _height(height){}; + : MetaObject(CID), _arrow_type(arrow_type), _begin(begin), _end(end), _height(height) {}; MetaObject* clone() const override { @@ -712,7 +711,7 @@ namespace indigo { public: static const std::uint32_t CID = "Reaction plus object"_hash; - ReactionPlusObject(const Vec2f& pos) : MetaObject(CID), _pos(pos){}; + ReactionPlusObject(const Vec2f& pos) : MetaObject(CID), _pos(pos) {}; MetaObject* clone() const override { @@ -796,8 +795,8 @@ namespace indigo struct MolSumm { - MolSumm() : bbox(Vec2f(0, 0), Vec2f(0, 0)), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; - MolSumm(const Rect2f& box) : bbox(box), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; + MolSumm() : bbox(Vec2f(0, 0), Vec2f(0, 0)), role(BaseReaction::UNDEFINED), reaction_idx(-1) {}; + MolSumm(const Rect2f& box) : bbox(box), role(BaseReaction::UNDEFINED), reaction_idx(-1) {}; Rect2f bbox; std::vector indexes; @@ -847,7 +846,7 @@ namespace indigo }; ReactionComponent(int ctype, const Rect2f& box, int idx, std::unique_ptr mol) - : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED), index(idx){}; + : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED), index(idx) {}; int component_type; Rect2f bbox; diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index fcb6ebea5d..081b7d24c8 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -19,6 +19,7 @@ #ifndef __cdxml_loader__ #define __cdxml_loader__ +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include "base_cpp/array.h" #include "base_cpp/exception.h" @@ -65,9 +65,9 @@ namespace indigo class AutoInt { public: - AutoInt() : val(0){}; + AutoInt() : val(0) {}; - AutoInt(int v) : val(v){}; + AutoInt(int v) : val(v) {}; AutoInt(const std::string& v) : val(std::stoi(v)) { @@ -122,8 +122,7 @@ namespace indigo AutoInt id; std::string label; AutoInt element; - Vec2f pos; - Vec3f pos3d; + Vec3f pos; int type; AutoInt isotope; AutoInt charge; @@ -205,7 +204,7 @@ namespace indigo public: DECL_ERROR; - CDXMLProperty(const tinyxml2::XMLAttribute* attribute) : _attribute(attribute){}; + CDXMLProperty(const tinyxml2::XMLAttribute* attribute) : _attribute(attribute) {}; virtual bool hasContent() const override { @@ -319,7 +318,7 @@ namespace indigo class CDXIdProperty : public CDXProperty { public: - CDXIdProperty(CDXElement* parent, const uint8_t* data) : CDXProperty(parent, 0, data, id_size){}; + CDXIdProperty(CDXElement* parent, const uint8_t* data) : CDXProperty(parent, 0, data, id_size) {}; std::unique_ptr copy() override { @@ -340,7 +339,7 @@ namespace indigo { public: CDXStyleProperty(CDXElement* parent, const uint8_t* data, uint8_t prop_index) - : CDXProperty(parent, 0xffff, data, sizeof(uint16_t)), _prop_index(prop_index){}; + : CDXProperty(parent, 0xffff, data, sizeof(uint16_t)), _prop_index(prop_index) {}; std::unique_ptr copy() override { @@ -392,7 +391,7 @@ namespace indigo public: DECL_ERROR; - CDXMLElement(const tinyxml2::XMLElement* xml) : _xml(xml){}; + CDXMLElement(const tinyxml2::XMLElement* xml) : _xml(xml) {}; bool hasContent() override { @@ -738,7 +737,7 @@ namespace indigo return _scanner; } - virtual ~CDXReader(){}; + virtual ~CDXReader() {}; protected: std::string _buffer; @@ -847,6 +846,29 @@ namespace indigo }; } + auto posLambda(Vec3f& pos) + { + return [this, &pos](const std::string& data) { + std::vector coords = split(data, ' '); + if (coords.size() >= 2) + { + pos.x = std::stof(coords[0]); + pos.y = std::stof(coords[1]); + pos.z = coords.size() > 2 ? std::stof(coords[2]) : -0.0f; + if (_has_bounding_box) + { + pos.x -= cdxml_bbox.left(); + pos.y -= cdxml_bbox.bottom(); + } + pos.x /= SCALE; + pos.y /= -SCALE; + pos.z /= -SCALE; + } + else + throw Error("Not enough coordinates"); + }; + } + auto hexLambda(std::string& binary) { return [this, &binary](const std::string& hex) { diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index 65381c986f..18a8f291c3 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -124,6 +124,16 @@ bool BaseMolecule::hasCoord(BaseMolecule& mol) return true; } + for (i = 0; i < mol.rgroups.getRGroupCount(); ++i) + { + RGroup& rg = mol.rgroups.getRGroup(i + 1); + for (int j = 0; j < rg.fragments.size(); ++j) + { + BaseMolecule* frag = rg.fragments[j]; + if (hasCoord(*frag)) + return true; + } + } return false; } diff --git a/core/indigo-core/molecule/src/meta_commons.cpp b/core/indigo-core/molecule/src/meta_commons.cpp index b74135b7f2..0936e6b052 100644 --- a/core/indigo-core/molecule/src/meta_commons.cpp +++ b/core/indigo-core/molecule/src/meta_commons.cpp @@ -305,7 +305,7 @@ namespace indigo auto style_lambda = styleLambda(_font_styles); DispatchMapKVP text_obj_dispatcher = {{"boundingBox", bbox_lambda}, {"alignment", alignLambda(_alignment)}, {KFontBoldStr, style_lambda}, - {KFontItalicStr, style_lambda}, {KFontSubscriptStr, style_lambda}, {KFontSuperscriptStr, style_lambda}, + {KFontItalicStr, style_lambda}, {KFontSubscriptStr, style_lambda}, {KFontSuperscriptStr, style_lambda}, {"indent", indentLambda(_indent)}, {"font", fontLambda(_font_styles)}, {"paragraphs", paragraphs_lambda}}; applyDispatcher(text_obj, text_obj_dispatcher); @@ -338,7 +338,6 @@ namespace indigo return out_buffer.ptr(); } - SimpleTextObjectBuilder::SimpleTextObjectBuilder() : _writer(_buffer), _line_counter(0) { } diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 04940011ca..ae49291375 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -1909,7 +1909,7 @@ void MoleculeJsonLoader::loadMetaObjects(rapidjson::Value& meta_objects, MetaDat rb = Vec2f(pos[2]["x"].GetFloat(), pos[2]["y"].GetFloat()); } } - meta_interface.addMetaObject(new SimpleTextObject(Rect2f(lt,rb), content)); + meta_interface.addMetaObject(new SimpleTextObject(Rect2f(lt, rb), content)); } } else if (node_type == "text") diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 145e382e21..3dc872dd49 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -2091,17 +2091,14 @@ void MoleculeJsonSaver::saveTextV1(JsonWriter& writer, const SimpleTextObject& t writer.String(text_obj.content().c_str()); writer.Key("position"); writer.WritePoint(text_obj.boundingBox().leftTop()); - if (text_obj.boundingBox().width() > 0 && text_obj.boundingBox().height() > 0) - { - writer.Key("pos"); - writer.StartArray(); - writer.WritePoint(text_obj.boundingBox().leftTop()); - writer.WritePoint(text_obj.boundingBox().leftBottom()); - writer.WritePoint(text_obj.boundingBox().leftTop()); - writer.WritePoint(text_obj.boundingBox().rightBottom()); - writer.WritePoint(text_obj.boundingBox().rightTop()); - writer.EndArray(); - } + writer.Key("pos"); + writer.StartArray(); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().leftBottom()); + writer.WritePoint(text_obj.boundingBox().leftTop()); + writer.WritePoint(text_obj.boundingBox().rightBottom()); + writer.WritePoint(text_obj.boundingBox().rightTop()); + writer.EndArray(); writer.EndObject(); } diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 14d7679bf5..fe0fa55874 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -868,7 +868,7 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-stereochemistry-errors", "on"); indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); - indigoSetOption("ket-saving-version", "1.0.0"); + //indigoSetOption("ket-saving-version", "2.0.0"); indigoSetOptionBool("json-saving-pretty", "on"); if (parseParams(&p, argc, argv) < 0) @@ -956,7 +956,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_MOL) indigoSaveMolfileToFile(obj, p.outfile); else if (p.out_ext == OEXT_KET) @@ -1059,7 +1059,7 @@ int main(int argc, char* argv[]) _prepare(obj, p.aromatization); if (p.action == ACTION_LAYOUT) { - //indigoLayout(obj); + // indigoLayout(obj); if (p.out_ext == OEXT_CML) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) From 53bdce499f90849d2fb3af5fa96eb8a2db2952a3 Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 17 Dec 2024 11:53:57 +0100 Subject: [PATCH 33/39] third step --- core/indigo-core/molecule/meta_commons.h | 10 +- .../molecule/molecule_cdxml_loader.h | 3 + .../indigo-core/molecule/src/meta_commons.cpp | 11 +- .../molecule/src/molecule_cdxml_loader.cpp | 121 +++++++++--------- .../reaction/src/reaction_cdxml_loader.cpp | 4 + core/render2d/src/render_item_aux.cpp | 35 ++++- 6 files changed, 120 insertions(+), 64 deletions(-) diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/meta_commons.h index 1ec166361c..16f69c00bf 100644 --- a/core/indigo-core/molecule/meta_commons.h +++ b/core/indigo-core/molecule/meta_commons.h @@ -144,9 +144,9 @@ namespace indigo _font_style = fs; } - void setValue(const std::string& val) + void copyValue(const KETFontStyle& other) { - _val = val; + _val = other._val; } void setValue(uint32_t val) @@ -154,6 +154,11 @@ namespace indigo _val = val; } + void setValue(const std::variant& val) + { + _val = val; + } + bool hasValue() const { return _val.index() != 0; @@ -291,6 +296,7 @@ namespace indigo FONT_STYLE_SET font_style; std::optional alignment; std::optional indent; + std::optional> line_starts; std::map font_styles; }; diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index 081b7d24c8..b8e386a865 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -896,6 +896,9 @@ namespace indigo }; } + void parseColorTable(BaseCDXElement& elem); + void parseFontTable(BaseCDXElement& elem); + StereocentersOptions stereochemistry_options; bool ignore_bad_valence; Rect2f cdxml_bbox; diff --git a/core/indigo-core/molecule/src/meta_commons.cpp b/core/indigo-core/molecule/src/meta_commons.cpp index 0936e6b052..5a8217ecca 100644 --- a/core/indigo-core/molecule/src/meta_commons.cpp +++ b/core/indigo-core/molecule/src/meta_commons.cpp @@ -41,7 +41,16 @@ namespace indigo lhs.erase(it); // check for duplicates - if (!lhs.count(fs)) + auto fs_it = lhs.find(fs); + if (fs_it != lhs.end()) + { + // Update value if it is already present + if (fs_it->first.hasValue()) + { + lhs.erase(fs_it); + lhs.insert(fs); + } + } else lhs.insert(fs); } else diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index c5d0734694..8afbfcc624 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -667,6 +667,49 @@ void MoleculeCdxmlLoader::parseCDXMLAttributes(BaseCDXProperty& prop) applyDispatcher(prop, cdxml_dispatcher); } +void MoleculeCdxmlLoader::parseColorTable(BaseCDXElement& elem) +{ + for (auto color_elem = elem.firstChildElement(); color_elem->hasContent(); color_elem = color_elem->nextSiblingElement()) + { + if (color_elem->name() == "color") + { + uint32_t cdxml_color = 0; + for (auto color_prop = color_elem->firstProperty(); color_prop->hasContent(); color_prop = color_prop->next()) + { + auto cval = static_cast(std::stof(color_prop->value()) * 0xFF); + if (color_prop->name() == "r") + cdxml_color |= cval << 16; + else if (color_prop->name() == "g") + cdxml_color |= cval << 8; + else if (color_prop->name() == "b") + cdxml_color |= cval; + } + color_table.push_back(cdxml_color); + } + } +} + +void indigo::MoleculeCdxmlLoader::parseFontTable(BaseCDXElement& elem) +{ + for (auto font_elem = elem.firstChildElement(); font_elem->hasContent(); font_elem = font_elem->nextSiblingElement()) + { + if (font_elem->name() == "font") + { + int font_id = 0; + std::string font_name; + for (auto font_prop = font_elem->firstProperty(); font_prop->hasContent(); font_prop = font_prop->next()) + { + if (font_prop->name() == "id") + font_id = std::stoi(font_prop->value()); + else if (font_prop->name() == "name") + font_name = font_prop->value(); + } + if (font_id && font_name.size()) + font_table.emplace(font_id, font_name); + } + } +} + void MoleculeCdxmlLoader::_parseCDXMLPage(BaseCDXElement& elem) { for (auto page_elem = elem.firstChildElement(); page_elem->hasContent(); page_elem = page_elem->nextSiblingElement()) @@ -682,46 +725,9 @@ void MoleculeCdxmlLoader::_parseCDXMLPage(BaseCDXElement& elem) } } else if (page_elem->value() == "colortable") - { - for (auto color_elem = page_elem->firstChildElement(); color_elem->hasContent(); color_elem = color_elem->nextSiblingElement()) - { - if (color_elem->name() == "color") - { - uint32_t cdxml_color = 0; - for (auto color_prop = color_elem->firstProperty(); color_prop->hasContent(); color_prop = color_prop->next()) - { - auto cval = static_cast(std::stof(color_prop->value()) * 0xFF); - if (color_prop->name() == "r") - cdxml_color |= cval << 16; - else if (color_prop->name() == "g") - cdxml_color |= cval << 8; - else if (color_prop->name() == "b") - cdxml_color |= cval; - } - color_table.push_back(cdxml_color); - } - } - } + parseColorTable(*page_elem); else if (page_elem->value() == "fonttable") - { - for (auto font_elem = page_elem->firstChildElement(); font_elem->hasContent(); font_elem = font_elem->nextSiblingElement()) - { - if (font_elem->name() == "font") - { - int font_id = 0; - std::string font_name; - for (auto font_prop = font_elem->firstProperty(); font_prop->hasContent(); font_prop = font_prop->next()) - { - if (font_prop->name() == "id") - font_id = std::stoi(font_prop->value()); - else if (font_prop->name() == "name") - font_name = font_prop->value(); - } - if (font_id && font_name.size()) - font_table.emplace(font_id, font_name); - } - } - } + parseFontTable(*page_elem); } } @@ -789,8 +795,8 @@ void MoleculeCdxmlLoader::_parseCDXMLElements(BaseCDXElement& first_elem, bool n } else { - // _parseTextToKetObject(elem, ket_text_objects); - _parseText(elem, text_objects); + _parseTextToKetObject(elem, ket_text_objects); + //_parseText(elem, text_objects); } }; @@ -1656,11 +1662,11 @@ void MoleculeCdxmlLoader::_parseLabel(BaseCDXElement& elem, std::string& label) void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vector& text_objects) { Vec2f text_pos; - Rect2f text_bbox; float wwrap_val; std::vector line_starts; std::string label_justification, label_alignment, text_justification; - AutoInt font_id, font_color_index, font_face; + AutoInt font_id, font_face; + std::optional font_color_index; float font_size; SimpleTextObject kto; @@ -1677,7 +1683,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto auto style_size_lambda = [&font_size](const std::string& data) { font_size = round(std::stof(data) * kCDXMLFonsSizeMultiplier); }; auto style_color_lambda = [&font_color_index](const std::string& data) { font_color_index = data; - font_color_index = font_color_index - 2; + font_color_index = font_color_index.value() - 2; }; std::unordered_map> style_dispatcher = { @@ -1694,7 +1700,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto std::string style_text = text_style->getText(); if (style_text == "+") { - _pluses.push_back(text_bbox.center()); + _pluses.push_back(kto.boundingBox().center()); return; } @@ -1707,22 +1713,24 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto for (size_t i = 0; i < lines.size(); ++i) { if (i) - { kto.block().push_back(SimpleTextObject::KETTextParagraph()); - } const auto& part = lines[i]; if (part.size()) { // parts should be added to the last paragraph auto& paragraph = kto.block().back(); + if (line_starts.size()) + { + paragraph.line_starts = line_starts; + line_starts.clear(); + } FONT_STYLE_SET fss; - font_face = 0; font_size = 0.0; font_id = 0; - font_color_index = -2; + font_color_index.reset(); auto style = text_style->firstProperty(); applyDispatcher(*style, style_dispatcher); @@ -1751,19 +1759,20 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto std::forward_as_tuple(true)); // set fss font color - if (font_color_index >= 0 && font_color_index < static_cast(color_table.size())) + if (font_color_index.has_value()) { - fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, color_table[font_color_index]), + auto fidx = font_color_index.value(); + auto font_color = fidx >= 0 && font_color_index.value() < static_cast(color_table.size()) ? color_table[font_color_index.value()] + : (fidx == -1 ? 0xFFFFFF : 0); + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, font_color), std::forward_as_tuple(true)); } // set fss font family auto font_it = font_table.find(font_id); if (font_it != font_table.end()) - { fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, font_it->second), std::forward_as_tuple(true)); - } auto prev_it = paragraph.font_styles.find(paragraph.text.size()); if (prev_it != paragraph.font_styles.end()) @@ -1785,10 +1794,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto } } if (kto.block().size()) - { - text_objects.push_back(kto); - } } void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector& text_parsed) @@ -1803,7 +1809,8 @@ void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vectorvalue() == "colortable") + loader.parseColorTable(*page_elem); + else if (page_elem->value() == "fonttable") + loader.parseFontTable(*page_elem); } for (auto id : reactants_ids) diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index 9299ee3115..0d371bd130 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -323,6 +323,11 @@ void RenderItemAuxiliary::fillKETStyle(TextItem& ti, const FONT_STYLE_SET& style ti.size /= KFontScaleFactor; } break; + case KETFontStyle::FontStyle::EColor: { + auto color_val = text_style.first.getUInt(); + if (text_style.second && color_val.has_value()) + ti.color = color_val.value(); + } default: break; } @@ -386,14 +391,34 @@ void RenderItemAuxiliary::_drawMeta(bool idle) std::wstring_convert> w2utf8; auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(text_item.text).substr(first_index, second_index - first_index)); - ti.text.readString(sub_text.c_str(), true); fillKETStyle(ti, current_styles); + ti.text.readString(sub_text.c_str(), true); _rc.setTextItemSize(ti); ti.bbp.x = static_cast(text_origin.x - ti.relpos.x + text_offset_x); ti.bbp.y = static_cast(text_origin.y - ti.relpos.y + text_max_height / 2 + text_offset_y); - _rc.drawTextItemText(ti, Vec3f(0, 0, 0), idle); - text_offset_x += ti.bbsz.x + _settings.boundExtent; + float red = (float)((ti.color >> 16) & 0xFF) / 255.0f; + float green = (float)((ti.color >> 8) & 0xFF) / 255.0f; + float blue = (float)(ti.color & 0xFF) / 255.0f; + + if (text_item.line_starts.has_value()) + { + int line_start_offset = 0; + for (auto& line_start : text_item.line_starts.value()) + { + ti.text.readString(sub_text.substr(line_start_offset, line_start - line_start_offset).c_str(), true); + line_start_offset = line_start; + _rc.drawTextItemText(ti, Vec3f(red, green, blue), idle); + ti.bbp.y += text_max_height + _settings.boundExtent; + } + text_offset_y += text_max_height * (text_item.line_starts.value().size() - 1); + } + else + { + _rc.drawTextItemText(ti, Vec3f(red, green, blue), idle); + } + + text_offset_x += ti.bbsz.x; current_styles = kvp.second; first_index = second_index; } @@ -465,6 +490,7 @@ void RenderItemAuxiliary::_drawImage(const EmbeddedImageObject& img) void RenderItemAuxiliary::_renderSimpleObject(const SimpleGraphicsObject& simple) { _rc.setLineWidth(_settings.bondLineWidth); + _rc.setSingleSource(CWC_BASE); auto v1 = simple._coordinates.first; auto v2 = simple._coordinates.second; @@ -569,7 +595,8 @@ float RenderItemAuxiliary::_getMaxHeight(const SimpleTextObject::KETTextParagrap std::wstring_convert> utf82w; std::wstring_convert> w2utf8; - auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(tl.text).substr(first_index, second_index - first_index)); + auto utf32str = utf82w.from_bytes(tl.text); + auto sub_text = w2utf8.to_bytes(utf32str.substr(first_index, second_index - first_index)); ti.text.readString(sub_text.c_str(), true); fillKETStyle(ti, current_styles); From eaa197b79fb425d9b314b50acd093d504a893a29 Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 17 Dec 2024 11:57:48 +0100 Subject: [PATCH 34/39] third step --- core/indigo-core/molecule/src/meta_commons.cpp | 3 ++- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 3 +-- utils/indigo-depict/main.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/indigo-core/molecule/src/meta_commons.cpp b/core/indigo-core/molecule/src/meta_commons.cpp index 5a8217ecca..975b316d2a 100644 --- a/core/indigo-core/molecule/src/meta_commons.cpp +++ b/core/indigo-core/molecule/src/meta_commons.cpp @@ -50,7 +50,8 @@ namespace indigo lhs.erase(fs_it); lhs.insert(fs); } - } else + } + else lhs.insert(fs); } else diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 8afbfcc624..3a563acc71 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1764,8 +1764,7 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto auto fidx = font_color_index.value(); auto font_color = fidx >= 0 && font_color_index.value() < static_cast(color_table.size()) ? color_table[font_color_index.value()] : (fidx == -1 ? 0xFFFFFF : 0); - fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, font_color), - std::forward_as_tuple(true)); + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, font_color), std::forward_as_tuple(true)); } // set fss font family diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index fe0fa55874..bcf93e234e 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -868,7 +868,7 @@ int main(int argc, char* argv[]) indigoSetOption("ignore-stereochemistry-errors", "on"); indigoSetOption("ignore-bad-valence", "on"); indigoSetOption("molfile-saving-mode", "3000"); - //indigoSetOption("ket-saving-version", "2.0.0"); + indigoSetOption("ket-saving-version", "2.0.0"); indigoSetOptionBool("json-saving-pretty", "on"); if (parseParams(&p, argc, argv) < 0) From 769456d4a2b1723a7612f73334bd499f999a5c49 Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 17 Dec 2024 12:26:14 +0100 Subject: [PATCH 35/39] third step --- core/indigo-core/molecule/meta_commons.h | 10 +++++----- core/indigo-core/molecule/molecule_cdxml_loader.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/indigo-core/molecule/meta_commons.h b/core/indigo-core/molecule/meta_commons.h index 16f69c00bf..5fc7ada9af 100644 --- a/core/indigo-core/molecule/meta_commons.h +++ b/core/indigo-core/molecule/meta_commons.h @@ -577,7 +577,7 @@ namespace indigo }; ReactionArrowObject(int arrow_type, const Vec2f& begin, const Vec2f& end, float height = 0) - : MetaObject(CID), _arrow_type(arrow_type), _begin(begin), _end(end), _height(height) {}; + : MetaObject(CID), _arrow_type(arrow_type), _begin(begin), _end(end), _height(height){}; MetaObject* clone() const override { @@ -717,7 +717,7 @@ namespace indigo { public: static const std::uint32_t CID = "Reaction plus object"_hash; - ReactionPlusObject(const Vec2f& pos) : MetaObject(CID), _pos(pos) {}; + ReactionPlusObject(const Vec2f& pos) : MetaObject(CID), _pos(pos){}; MetaObject* clone() const override { @@ -801,8 +801,8 @@ namespace indigo struct MolSumm { - MolSumm() : bbox(Vec2f(0, 0), Vec2f(0, 0)), role(BaseReaction::UNDEFINED), reaction_idx(-1) {}; - MolSumm(const Rect2f& box) : bbox(box), role(BaseReaction::UNDEFINED), reaction_idx(-1) {}; + MolSumm() : bbox(Vec2f(0, 0), Vec2f(0, 0)), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; + MolSumm(const Rect2f& box) : bbox(box), role(BaseReaction::UNDEFINED), reaction_idx(-1){}; Rect2f bbox; std::vector indexes; @@ -852,7 +852,7 @@ namespace indigo }; ReactionComponent(int ctype, const Rect2f& box, int idx, std::unique_ptr mol) - : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED), index(idx) {}; + : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED), index(idx){}; int component_type; Rect2f bbox; diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index b8e386a865..f360b887c4 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -65,9 +65,9 @@ namespace indigo class AutoInt { public: - AutoInt() : val(0) {}; + AutoInt() : val(0){}; - AutoInt(int v) : val(v) {}; + AutoInt(int v) : val(v){}; AutoInt(const std::string& v) : val(std::stoi(v)) { @@ -204,7 +204,7 @@ namespace indigo public: DECL_ERROR; - CDXMLProperty(const tinyxml2::XMLAttribute* attribute) : _attribute(attribute) {}; + CDXMLProperty(const tinyxml2::XMLAttribute* attribute) : _attribute(attribute){}; virtual bool hasContent() const override { @@ -737,7 +737,7 @@ namespace indigo return _scanner; } - virtual ~CDXReader() {}; + virtual ~CDXReader(){}; protected: std::string _buffer; From f9008e02348e0033962e28452db151bc9ae02e8a Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 18 Dec 2024 00:37:28 +0100 Subject: [PATCH 36/39] clang fix --- core/indigo-core/molecule/molecule_cdxml_loader.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index f360b887c4..0f3ba7d3a1 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -318,7 +318,7 @@ namespace indigo class CDXIdProperty : public CDXProperty { public: - CDXIdProperty(CDXElement* parent, const uint8_t* data) : CDXProperty(parent, 0, data, id_size) {}; + CDXIdProperty(CDXElement* parent, const uint8_t* data) : CDXProperty(parent, 0, data, id_size){}; std::unique_ptr copy() override { @@ -339,7 +339,7 @@ namespace indigo { public: CDXStyleProperty(CDXElement* parent, const uint8_t* data, uint8_t prop_index) - : CDXProperty(parent, 0xffff, data, sizeof(uint16_t)), _prop_index(prop_index) {}; + : CDXProperty(parent, 0xffff, data, sizeof(uint16_t)), _prop_index(prop_index){}; std::unique_ptr copy() override { @@ -391,7 +391,7 @@ namespace indigo public: DECL_ERROR; - CDXMLElement(const tinyxml2::XMLElement* xml) : _xml(xml) {}; + CDXMLElement(const tinyxml2::XMLElement* xml) : _xml(xml){}; bool hasContent() override { From 0f0e501941d4c8cb4b0511df984e074f00d734d8 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 18 Dec 2024 01:55:21 +0100 Subject: [PATCH 37/39] clang fix --- core/indigo-core/molecule/src/molecule_cdxml_loader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 3a563acc71..c9e5e6cee6 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1593,8 +1593,8 @@ void MoleculeCdxmlLoader::_parseGraphic(BaseCDXElement& elem) void MoleculeCdxmlLoader::_parseArrow(BaseCDXElement& elem) { Rect2f text_bbox; - Vec2f begin_pos; - Vec2f end_pos; + Vec3f begin_pos; + Vec3f end_pos; std::string fill_type; std::string arrow_head; std::string head_type; @@ -1638,8 +1638,7 @@ void MoleculeCdxmlLoader::_parseArrow(BaseCDXElement& elem) ar_type = ReactionComponent::ARROW_BOTH_ENDS_FILLED_TRIANGLE; } } - - _arrows[arrow_id] = (std::make_pair(std::make_pair(begin_pos, end_pos), ar_type)); + _arrows[arrow_id] = std::make_pair(std::make_pair(begin_pos, end_pos), ar_type); } } From 47c0e9b9414f964b847d84260217f1b08a482766 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 18 Dec 2024 12:01:47 +0100 Subject: [PATCH 38/39] line starts fix --- .../molecule/src/molecule_cdxml_loader.cpp | 133 ++++++++---------- core/render2d/src/render_item_aux.cpp | 46 +++--- 2 files changed, 84 insertions(+), 95 deletions(-) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index c9e5e6cee6..3edfd6b0c3 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1706,93 +1706,80 @@ void MoleculeCdxmlLoader::_parseTextToKetObject(BaseCDXElement& elem, std::vecto // add paragraph if (kto.block().empty()) kto.block().push_back(SimpleTextObject::KETTextParagraph()); + auto& paragraph = kto.block().back(); - // break parts into separate paragraphs if CR presents - auto lines = split_with_empty(style_text, '\n'); - for (size_t i = 0; i < lines.size(); ++i) + if (style_text.size()) { - if (i) - kto.block().push_back(SimpleTextObject::KETTextParagraph()); - - const auto& part = lines[i]; - if (part.size()) + FONT_STYLE_SET fss; + font_face = 0; + font_size = 0.0; + font_id = 0; + font_color_index.reset(); + auto style = text_style->firstProperty(); + applyDispatcher(*style, style_dispatcher); + + // fill fss + + CDXMLFontStyle fs(font_face); + if (font_face == KCDXMLChemicalFontStyle) { - // parts should be added to the last paragraph - auto& paragraph = kto.block().back(); - if (line_starts.size()) - { - paragraph.line_starts = line_starts; - line_starts.clear(); - } - - FONT_STYLE_SET fss; - font_face = 0; - font_size = 0.0; - font_id = 0; - font_color_index.reset(); - auto style = text_style->firstProperty(); - applyDispatcher(*style, style_dispatcher); - - // fill fss - - CDXMLFontStyle fs(font_face); - if (font_face == KCDXMLChemicalFontStyle) - { - // special case - } - else - { - if (fs.is_bold) - fss.emplace(KETFontStyle::FontStyle::EBold, true); - if (fs.is_italic) - fss.emplace(KETFontStyle::FontStyle::EBold, true); - if (fs.is_superscript) - fss.emplace(KETFontStyle::FontStyle::ESuperScript, true); - if (fs.is_superscript) - fss.emplace(KETFontStyle::FontStyle::ESubScript, true); - } + // special case + } + else + { + if (fs.is_bold) + fss.emplace(KETFontStyle::FontStyle::EBold, true); + if (fs.is_italic) + fss.emplace(KETFontStyle::FontStyle::EBold, true); + if (fs.is_superscript) + fss.emplace(KETFontStyle::FontStyle::ESuperScript, true); + if (fs.is_superscript) + fss.emplace(KETFontStyle::FontStyle::ESubScript, true); + } - // set fss font size - if (font_size > 0 && (int)font_size != KDefaultFontSize) - fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(font_size)), - std::forward_as_tuple(true)); + // set fss font size + if (font_size > 0 && (int)font_size != KDefaultFontSize) + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::ESize, static_cast(font_size)), + std::forward_as_tuple(true)); - // set fss font color - if (font_color_index.has_value()) - { - auto fidx = font_color_index.value(); - auto font_color = fidx >= 0 && font_color_index.value() < static_cast(color_table.size()) ? color_table[font_color_index.value()] - : (fidx == -1 ? 0xFFFFFF : 0); - fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, font_color), std::forward_as_tuple(true)); - } + // set fss font color + if (font_color_index.has_value()) + { + auto fidx = font_color_index.value(); + auto font_color = fidx >= 0 && font_color_index.value() < static_cast(color_table.size()) ? color_table[font_color_index.value()] + : (fidx == -1 ? 0xFFFFFF : 0); + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EColor, font_color), std::forward_as_tuple(true)); + } - // set fss font family - auto font_it = font_table.find(font_id); - if (font_it != font_table.end()) - fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, font_it->second), - std::forward_as_tuple(true)); + // set fss font family + auto font_it = font_table.find(font_id); + if (font_it != font_table.end()) + fss.emplace(std::piecewise_construct, std::forward_as_tuple(KETFontStyle::FontStyle::EFamily, font_it->second), + std::forward_as_tuple(true)); - auto prev_it = paragraph.font_styles.find(paragraph.text.size()); - if (prev_it != paragraph.font_styles.end()) - prev_it->second += fss; - else - paragraph.font_styles.emplace(paragraph.text.size(), fss); + auto prev_it = paragraph.font_styles.find(paragraph.text.size()); + if (prev_it != paragraph.font_styles.end()) + prev_it->second += fss; + else + paragraph.font_styles.emplace(paragraph.text.size(), fss); - paragraph.text += part; - // turn off the styles - FONT_STYLE_SET fss_off; - for (auto& fs_off : fss) - { - fss.emplace(fs_off.first, false); - } - if (fss.size()) - paragraph.font_styles.emplace(paragraph.text.size(), fss); + paragraph.text += style_text; + // turn off the styles + FONT_STYLE_SET fss_off; + for (auto& fs_off : fss) + { + fss.emplace(fs_off.first, false); } + if (fss.size()) + paragraph.font_styles.emplace(paragraph.text.size(), fss); } } } if (kto.block().size()) + { + kto.block().back().line_starts = line_starts; text_objects.push_back(kto); + } } void MoleculeCdxmlLoader::_parseText(BaseCDXElement& elem, std::vector& text_parsed) diff --git a/core/render2d/src/render_item_aux.cpp b/core/render2d/src/render_item_aux.cpp index 0d371bd130..4679006629 100644 --- a/core/render2d/src/render_item_aux.cpp +++ b/core/render2d/src/render_item_aux.cpp @@ -368,6 +368,7 @@ void RenderItemAuxiliary::_drawMeta(bool idle) for (auto& text_item : ko.block()) { float text_max_height = _getMaxHeight(text_item); + auto line_starts = text_item.line_starts; int first_index = -1; int second_index = -1; double text_offset_x = 0; @@ -390,34 +391,35 @@ void RenderItemAuxiliary::_drawMeta(bool idle) std::wstring_convert> utf82w; std::wstring_convert> w2utf8; - auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(text_item.text).substr(first_index, second_index - first_index)); - fillKETStyle(ti, current_styles); - ti.text.readString(sub_text.c_str(), true); - _rc.setTextItemSize(ti); - ti.bbp.x = static_cast(text_origin.x - ti.relpos.x + text_offset_x); - ti.bbp.y = static_cast(text_origin.y - ti.relpos.y + text_max_height / 2 + text_offset_y); + std::vector styled_lines; + if (line_starts.has_value() && line_starts.value().size() && line_starts.value().front() <= second_index && + line_starts.value().front() > first_index) + { + auto ls_index = line_starts.value().front(); + line_starts.value().erase(line_starts.value().begin()); + styled_lines.push_back(text_item.text.substr(first_index, ls_index - first_index)); + styled_lines.push_back(text_item.text.substr(ls_index, second_index - ls_index)); + } + else + styled_lines.push_back(text_item.text.substr(first_index, second_index - first_index)); + fillKETStyle(ti, current_styles); float red = (float)((ti.color >> 16) & 0xFF) / 255.0f; float green = (float)((ti.color >> 8) & 0xFF) / 255.0f; float blue = (float)(ti.color & 0xFF) / 255.0f; - if (text_item.line_starts.has_value()) - { - int line_start_offset = 0; - for (auto& line_start : text_item.line_starts.value()) - { - ti.text.readString(sub_text.substr(line_start_offset, line_start - line_start_offset).c_str(), true); - line_start_offset = line_start; - _rc.drawTextItemText(ti, Vec3f(red, green, blue), idle); - ti.bbp.y += text_max_height + _settings.boundExtent; - } - text_offset_y += text_max_height * (text_item.line_starts.value().size() - 1); - } - else + // check for multiple lines + for (auto& styled_text : styled_lines) { + auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(styled_text)); + ti.text.readString(sub_text.c_str(), true); + _rc.setTextItemSize(ti); + ti.bbp.x = static_cast(text_origin.x - ti.relpos.x + text_offset_x); + ti.bbp.y = static_cast(text_origin.y - ti.relpos.y + text_max_height / 2 + text_offset_y); _rc.drawTextItemText(ti, Vec3f(red, green, blue), idle); + if (styled_lines.size() > 1) + text_offset_y += text_max_height + _settings.boundExtent; } - text_offset_x += ti.bbsz.x; current_styles = kvp.second; first_index = second_index; @@ -595,8 +597,8 @@ float RenderItemAuxiliary::_getMaxHeight(const SimpleTextObject::KETTextParagrap std::wstring_convert> utf82w; std::wstring_convert> w2utf8; - auto utf32str = utf82w.from_bytes(tl.text); - auto sub_text = w2utf8.to_bytes(utf32str.substr(first_index, second_index - first_index)); + auto utf32str = utf82w.from_bytes(tl.text.substr(first_index, second_index - first_index)); + auto sub_text = w2utf8.to_bytes(utf32str); ti.text.readString(sub_text.c_str(), true); fillKETStyle(ti, current_styles); From b8c7cb22ab352aecdc492839ba0a0b6ac0340491 Mon Sep 17 00:00:00 2001 From: even1024 Date: Wed, 18 Dec 2024 12:17:12 +0100 Subject: [PATCH 39/39] line starts fix --- api/tests/integration/tests/formats/ref/pathway11.ket | 2 +- api/tests/integration/tests/formats/ref/pathway12.ket | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/tests/integration/tests/formats/ref/pathway11.ket b/api/tests/integration/tests/formats/ref/pathway11.ket index 820ce6d205..b10cab1347 100644 --- a/api/tests/integration/tests/formats/ref/pathway11.ket +++ b/api/tests/integration/tests/formats/ref/pathway11.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"},{"$ref":"mol10"},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Removal of benzoxazol-2-yl\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":26,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"group from amines\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":17,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"LAH.THF.reflux\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":14,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":77.3457260131836,"y":-11.969417572021485,"z":0.0},"pos":[{"x":77.3457260131836,"y":-11.969417572021485,"z":0.0},{"x":77.3457260131836,"y":-13.409418106079102,"z":0.0},{"x":82.20868682861328,"y":-13.409418106079102,"z":0.0},{"x":82.20868682861328,"y":-11.969417572021485,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Alkylation of amines with\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"alkyl halides\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":13,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"KOH. toluene. PTC. catalyst or\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"KI. base e.g. K2CO3\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":19,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":57.039302825927737,"y":-11.609416961669922,"z":0.0},"pos":[{"x":57.039302825927737,"y":-11.609416961669922,"z":0.0},{"x":57.039302825927737,"y":-13.409417152404786,"z":0.0},{"x":62.650413513183597,"y":-13.409417152404786,"z":0.0},{"x":62.650413513183597,"y":-11.609416961669922,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Published reaction\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":18,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Stage 1: 14 h, Copper(II)\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"chloride, Dimethylformamide,\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Dichloromethane, CK2O3 \",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Potassium carbonate | Stage 2:\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"5 h, 80 degree, acid, Dy(3+)-\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":29,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"salt C3Dy1F9O9S3,\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":17,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Dichloromethane, Acetonitrile\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":29,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":41.58322525024414,"y":-3.980682611465454,"z":0.0},"pos":[{"x":41.58322525024414,"y":-3.980682611465454,"z":0.0},{"x":41.58322525024414,"y":-7.2206830978393559,"z":0.0},{"x":47.1943359375,"y":-7.2206830978393559,"z":0.0},{"x":47.1943359375,"y":-3.980682849884033,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Addition of dihalomethane to\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"aldehyde\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":8,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"SmI2.THF\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":8,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":41.58322525024414,"y":-18.15814971923828,"z":0.0},"pos":[{"x":41.58322525024414,"y":-18.15814971923828,"z":0.0},{"x":41.58322525024414,"y":-19.5981502532959,"z":0.0},{"x":46.82026290893555,"y":-19.5981502532959,"z":0.0},{"x":46.82026290893555,"y":-18.15814971923828,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Ozonolysis\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":10,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"O3.MeOH.CH2Cl2.PPh3 or Me2S.\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"low temperature\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":15,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":24.256389617919923,"y":-20.532968521118165,"z":0.0},"pos":[{"x":24.256389617919923,"y":-20.532968521118165,"z":0.0},{"x":24.256389617919923,"y":-21.97296905517578,"z":0.0},{"x":29.493425369262697,"y":-21.97296905517578,"z":0.0},{"x":29.493425369262697,"y":-20.532968521118165,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Mitsunobu reaction\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":18,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"DEAD.or.DCAD.or.DIAD.PPh3\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":8.077838897705079,"y":-20.892969131469728,"z":0.0},"pos":[{"x":8.077838897705079,"y":-20.892969131469728,"z":0.0},{"x":8.077838897705079,"y":-21.97296905517578,"z":0.0},{"x":12.753764152526856,"y":-21.97296905517578,"z":0.0},{"x":12.753764152526856,"y":-20.892969131469728,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":13.883398056030274,"y":-22.48741340637207,"z":0.0}},"spine":{"pos":[{"x":7.383394241333008,"y":-20.35758399963379,"z":0.0},{"x":7.383394241333008,"y":-24.61724090576172,"z":0.0}]},"tails":{"pos":[{"x":6.883394241333008,"y":-20.35758399963379,"z":0.0},{"x":6.883394241333008,"y":-24.61724090576172,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":24.069353103637697,"y":-22.48741340637207,"z":0.0},{"x":31.06934928894043,"y":-22.48741340637207,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":47.38878631591797,"y":-20.112594604492189,"z":0.0}},"spine":{"pos":[{"x":40.8887825012207,"y":-17.737777709960939,"z":0.0},{"x":40.8887825012207,"y":-22.48741340637207,"z":0.0}]},"tails":{"pos":[{"x":40.3887825012207,"y":-17.737777709960939,"z":0.0},{"x":40.3887825012207,"y":-22.48741340637207,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":47.38878631591797,"y":-7.7351274490356449,"z":0.0}},"spine":{"pos":[{"x":40.8887825012207,"y":-3.80068302154541,"z":0.0},{"x":40.8887825012207,"y":-11.669571876525879,"z":0.0}]},"tails":{"pos":[{"x":40.3887825012207,"y":-3.80068302154541,"z":0.0},{"x":40.3887825012207,"y":-11.669571876525879,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":62.84486389160156,"y":-13.923861503601075,"z":0.0}},"spine":{"pos":[{"x":56.3448600769043,"y":-7.7351274490356449,"z":0.0},{"x":56.3448600769043,"y":-20.112594604492189,"z":0.0}]},"tails":{"pos":[{"x":55.8448600769043,"y":-7.7351274490356449,"z":0.0},{"x":55.8448600769043,"y":-20.112594604492189,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":76.97164916992188,"y":-13.923861503601075,"z":0.0},{"x":83.97164916992188,"y":-13.923861503601075,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[4.826539039611816,-21.107912063598634,0.0]},{"label":"C","location":[3.960906982421875,-20.6072940826416,0.0]},{"label":"C","location":[3.9617068767547609,-19.607255935668947,0.0]},{"label":"C","location":[3.0944743156433107,-21.10651206970215,0.0]},{"label":"C","location":[2.228842258453369,-20.605894088745118,0.0]},{"label":"O","location":[1.362410068511963,-21.10531234741211,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]}]},"mol1":{"type":"molecule","atoms":[{"label":"N","location":[0.4999988079071045,-25.626569747924806,0.0]},{"label":"C","location":[1.3642239570617676,-25.123554229736329,0.0]},{"label":"O","location":[1.360624074935913,-24.123525619506837,0.0]},{"label":"C","location":[2.2320497035980226,-25.62036895751953,0.0]},{"label":"C","location":[3.0962748527526857,-25.117355346679689,0.0]},{"label":"C","location":[3.9641003608703615,-25.61417007446289,0.0]},{"label":"C","location":[4.8283257484436039,-25.11095428466797,0.0]},{"label":"C","location":[4.82472562789917,-24.111125946044923,0.0]},{"label":"O","location":[5.688951015472412,-23.60791015625,0.0]},{"label":"C","location":[3.956900119781494,-23.614110946655275,0.0]},{"label":"C","location":[3.092674732208252,-24.117324829101564,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":4,"atoms":[7,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,4]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[15.945083618164063,-22.733625411987306,0.0]},{"label":"C","location":[15.944183349609375,-23.733671188354493,0.0]},{"label":"C","location":[15.077842712402344,-24.233095169067384,0.0]},{"label":"C","location":[16.809925079345704,-24.234294891357423,0.0]},{"label":"C","location":[17.67636489868164,-23.735071182250978,0.0]},{"label":"O","location":[18.54200553894043,-24.235694885253908,0.0]},{"label":"C","location":[19.408246994018556,-23.736473083496095,0.0]},{"label":"C","location":[20.27398681640625,-24.23709487915039,0.0]},{"label":"C","location":[21.14042854309082,-23.737873077392579,0.0]},{"label":"C","location":[21.141328811645509,-22.737825393676759,0.0]},{"label":"C","location":[22.00766944885254,-22.238401412963868,0.0]},{"label":"C","location":[22.008569717407228,-21.238353729248048,0.0]},{"label":"N","location":[22.874910354614259,-20.739131927490236,0.0]},{"label":"O","location":[21.142929077148439,-20.73773193359375,0.0]},{"label":"C","location":[20.27558708190918,-22.237201690673829,0.0]},{"label":"C","location":[19.409046173095704,-22.736425399780275,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":4,"atoms":[7,8]},{"type":4,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[11,12]},{"type":2,"atoms":[11,13]},{"type":4,"atoms":[9,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"Cl","location":[36.59503936767578,-17.988170623779298,0.0]},{"label":"C","location":[35.72946548461914,-17.487384796142579,0.0]},{"label":"I","location":[34.86308670043945,-17.986770629882814,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"N","location":[39.1943359375,-20.73917579650879,0.0]},{"label":"C","location":[38.327919006347659,-21.238386154174806,0.0]},{"label":"O","location":[37.46229934692383,-20.737775802612306,0.0]},{"label":"C","location":[38.327117919921878,-22.238407135009767,0.0]},{"label":"C","location":[37.46070098876953,-22.737817764282228,0.0]},{"label":"C","location":[37.45989990234375,-23.737838745117189,0.0]},{"label":"C","location":[36.593482971191409,-24.237049102783204,0.0]},{"label":"C","location":[35.72786331176758,-23.736438751220704,0.0]},{"label":"O","location":[34.861446380615237,-24.235849380493165,0.0]},{"label":"C","location":[33.995826721191409,-23.73503875732422,0.0]},{"label":"C","location":[33.12940979003906,-24.23444938659668,0.0]},{"label":"O","location":[32.263790130615237,-23.733638763427736,0.0]},{"label":"C","location":[35.72866439819336,-22.736417770385743,0.0]},{"label":"C","location":[36.5950813293457,-22.237207412719728,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":2,"atoms":[10,11]},{"type":4,"atoms":[7,12]},{"type":4,"atoms":[12,13]},{"type":4,"atoms":[13,4]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[37.46143341064453,-4.549666881561279,0.0]},{"label":"C","location":[36.59505081176758,-4.0502777099609379,0.0]},{"label":"C","location":[36.5942497253418,-3.0502989292144777,0.0]},{"label":"N","location":[35.729469299316409,-4.551066875457764,0.0]},{"label":"C","location":[34.86308670043945,-4.051677703857422,0.0]},{"label":"S","location":[33.9967041015625,-3.552288055419922,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":2,"atoms":[3,4]},{"type":2,"atoms":[4,5]}]},"mol6":{"type":"molecule","atoms":[{"label":"N","location":[34.429447174072269,-12.668888092041016,0.0]},{"label":"C","location":[35.29586410522461,-12.169480323791504,0.0]},{"label":"C","location":[36.161476135253909,-12.6702880859375,0.0]},{"label":"C","location":[37.027889251708987,-12.170880317687989,0.0]},{"label":"C","location":[37.028690338134769,-11.17086410522461,0.0]},{"label":"C","location":[36.16307830810547,-10.670255661010743,0.0]},{"label":"C","location":[35.296661376953128,-11.169464111328125,0.0]},{"label":"O","location":[34.43104934692383,-10.668855667114258,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":4,"atoms":[1,2]},{"type":4,"atoms":[2,3]},{"type":4,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":4,"atoms":[6,1]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[48.730865478515628,-7.237734317779541,0.0]},{"label":"C","location":[49.73085021972656,-7.236934661865234,0.0]},{"label":"C","location":[50.23024368286133,-6.370546817779541,0.0]},{"label":"N","location":[50.23164367675781,-8.102521896362305,0.0]},{"label":"C","location":[51.23183059692383,-8.10172176361084,0.0]},{"label":"N","location":[51.81861877441406,-7.292133808135986,0.0]},{"label":"C","location":[52.7700080871582,-7.600529193878174,0.0]},{"label":"C","location":[53.63559341430664,-7.099936485290527,0.0]},{"label":"C","location":[54.501983642578128,-7.5991291999816898,0.0]},{"label":"C","location":[54.50278091430664,-8.599114418029786,0.0]},{"label":"C","location":[53.6371955871582,-9.09970760345459,0.0]},{"label":"C","location":[52.77080535888672,-8.60051441192627,0.0]},{"label":"O","location":[51.819820404052737,-8.910510063171387,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":4,"atoms":[7,8]},{"type":4,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":4,"atoms":[12,4]},{"type":4,"atoms":[11,6]}]},"mol8":{"type":"molecule","atoms":[{"label":"N","location":[48.583229064941409,-16.86559295654297,0.0]},{"label":"C","location":[49.44965362548828,-17.36480712890625,0.0]},{"label":"O","location":[50.31528091430664,-16.864192962646486,0.0]},{"label":"C","location":[49.45045471191406,-18.364839553833009,0.0]},{"label":"C","location":[50.316680908203128,-18.864253997802736,0.0]},{"label":"C","location":[50.317481994628909,-19.864286422729493,0.0]},{"label":"C","location":[51.18390655517578,-20.363500595092775,0.0]},{"label":"C","location":[52.04973602294922,-19.862886428833009,0.0]},{"label":"O","location":[52.91596221923828,-20.362300872802736,0.0]},{"label":"C","location":[52.91676330566406,-21.362333297729493,0.0]},{"label":"C","location":[53.78318786621094,-21.861547470092775,0.0]},{"label":"O","location":[54.6488151550293,-21.360933303833009,0.0]},{"label":"C","location":[53.78398895263672,-22.86157989501953,0.0]},{"label":"Cl","location":[54.65041732788086,-23.360994338989259,0.0]},{"label":"C","location":[52.04893493652344,-18.86285400390625,0.0]},{"label":"C","location":[51.1825065612793,-18.36363983154297,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[10,12]},{"type":1,"atoms":[12,13]},{"type":4,"atoms":[7,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,4]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[70.95356750488281,-16.431081771850587,0.0]},{"label":"C","location":[71.82097625732422,-15.933477401733399,0.0]},{"label":"C","location":[72.68558502197266,-16.435882568359376,0.0]},{"label":"N","location":[71.82377624511719,-14.933469772338868,0.0]},{"label":"C","location":[70.95916748046875,-14.431065559387207,0.0]},{"label":"C","location":[70.09175872802735,-14.928669929504395,0.0]},{"label":"O","location":[70.08895874023438,-15.928677558898926,0.0]},{"label":"C","location":[69.22715759277344,-14.426265716552735,0.0]},{"label":"O","location":[68.35954284667969,-14.923869132995606,0.0]},{"label":"C","location":[67.4951400756836,-14.421464920043946,0.0]},{"label":"C","location":[67.49774169921875,-13.421457290649414,0.0]},{"label":"C","location":[66.63313293457031,-12.919053077697754,0.0]},{"label":"C","location":[65.7657241821289,-13.416657447814942,0.0]},{"label":"C","location":[64.90111541748047,-12.914253234863282,0.0]},{"label":"C","location":[64.90391540527344,-11.914244651794434,0.0]},{"label":"N","location":[64.039306640625,-11.411840438842774,0.0]},{"label":"O","location":[65.77132415771485,-11.416640281677246,0.0]},{"label":"C","location":[65.76312255859375,-14.416665077209473,0.0]},{"label":"C","location":[66.62753295898438,-14.919069290161133,0.0]},{"label":"C","location":[72.6913833618164,-14.43586540222168,0.0]},{"label":"N","location":[73.60359191894531,-14.845468521118164,0.0]},{"label":"C","location":[74.27479553222656,-14.104063034057618,0.0]},{"label":"C","location":[75.27460479736328,-14.10666275024414,0.0]},{"label":"C","location":[75.77720642089844,-13.242255210876465,0.0]},{"label":"C","location":[75.27960205078125,-12.374649047851563,0.0]},{"label":"C","location":[74.27959442138672,-12.372048377990723,0.0]},{"label":"C","location":[73.77719116210938,-13.236655235290528,0.0]},{"label":"O","location":[72.79838562011719,-13.441657066345215,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":1,"atoms":[3,19]},{"type":4,"atoms":[19,20]},{"type":4,"atoms":[20,21]},{"type":4,"atoms":[21,22]},{"type":4,"atoms":[22,23]},{"type":4,"atoms":[23,24]},{"type":4,"atoms":[24,25]},{"type":4,"atoms":[25,26]},{"type":4,"atoms":[26,27]},{"type":4,"atoms":[18,9]},{"type":4,"atoms":[27,19]},{"type":4,"atoms":[26,21]}]},"mol10":{"type":"molecule","atoms":[{"label":"C","location":[85.16609191894531,-13.4183349609375,0.0]},{"label":"C","location":[86.03173828125,-13.918960571289063,0.0]},{"label":"C","location":[86.03093719482422,-14.919013023376465,0.0]},{"label":"N","location":[86.89818572998047,-13.419734954833985,0.0]},{"label":"C","location":[87.76383209228516,-13.920360565185547,0.0]},{"label":"C","location":[88.6302719116211,-13.421134948730469,0.0]},{"label":"O","location":[88.63107299804688,-12.421082496643067,0.0]},{"label":"C","location":[89.49591827392578,-13.921760559082032,0.0]},{"label":"O","location":[90.36236572265625,-13.422534942626954,0.0]},{"label":"C","location":[91.22801208496094,-13.923160552978516,0.0]},{"label":"C","location":[91.22721099853516,-14.923213958740235,0.0]},{"label":"C","location":[92.09285736083985,-15.423839569091797,0.0]},{"label":"C","location":[92.95930480957031,-14.924613952636719,0.0]},{"label":"C","location":[93.82494354248047,-15.425239562988282,0.0]},{"label":"C","location":[94.69139099121094,-14.926013946533204,0.0]},{"label":"N","location":[95.55703735351563,-15.426639556884766,0.0]},{"label":"O","location":[94.69219207763672,-13.9259614944458,0.0]},{"label":"C","location":[92.96009826660156,-13.924561500549317,0.0]},{"label":"C","location":[92.0944595336914,-13.423934936523438,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":4,"atoms":[18,9]}]}} \ No newline at end of file +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"$ref":"mol6"},{"$ref":"mol7"},{"$ref":"mol8"},{"$ref":"mol9"},{"$ref":"mol10"},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Removal of benzoxazol-2-yl\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":26,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"group from amines\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":17,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"LAH.THF.reflux\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":14,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":77.3457260131836,"y":-11.969417572021485,"z":0.0},"pos":[{"x":77.3457260131836,"y":-11.969417572021485,"z":0.0},{"x":77.3457260131836,"y":-13.923861503601075,"z":0.0},{"x":77.3457260131836,"y":-11.969417572021485,"z":0.0},{"x":82.20868682861328,"y":-13.923861503601075,"z":0.0},{"x":82.20868682861328,"y":-11.969417572021485,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Alkylation of amines with\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"alkyl halides\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":13,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"KOH. toluene. PTC. catalyst or\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"KI. base e.g. K2CO3\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":19,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":57.039302825927737,"y":-11.609416961669922,"z":0.0},"pos":[{"x":57.039302825927737,"y":-11.609416961669922,"z":0.0},{"x":57.039302825927737,"y":-13.923861503601075,"z":0.0},{"x":57.039302825927737,"y":-11.609416961669922,"z":0.0},{"x":62.650413513183597,"y":-13.923861503601075,"z":0.0},{"x":62.650413513183597,"y":-11.609416961669922,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Published reaction\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":18,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Stage 1: 14 h, Copper(II)\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"chloride, Dimethylformamide,\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Dichloromethane, CK2O3 \",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Potassium carbonate | Stage 2:\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"5 h, 80 degree, acid, Dy(3+)-\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":29,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"salt C3Dy1F9O9S3,\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":17,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"Dichloromethane, Acetonitrile\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":29,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":41.58322525024414,"y":-3.980682611465454,"z":0.0},"pos":[{"x":41.58322525024414,"y":-3.980682611465454,"z":0.0},{"x":41.58322525024414,"y":-7.7351274490356449,"z":0.0},{"x":41.58322525024414,"y":-3.980682611465454,"z":0.0},{"x":47.1943359375,"y":-7.7351274490356449,"z":0.0},{"x":47.1943359375,"y":-3.980682611465454,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Addition of dihalomethane to\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"aldehyde\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":8,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"SmI2.THF\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":8,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":41.58322525024414,"y":-18.15814971923828,"z":0.0},"pos":[{"x":41.58322525024414,"y":-18.15814971923828,"z":0.0},{"x":41.58322525024414,"y":-20.112594604492189,"z":0.0},{"x":41.58322525024414,"y":-18.15814971923828,"z":0.0},{"x":46.82026290893555,"y":-20.112594604492189,"z":0.0},{"x":46.82026290893555,"y":-18.15814971923828,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Ozonolysis\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":10,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"O3.MeOH.CH2Cl2.PPh3 or Me2S.\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":28,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"low temperature\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":15,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":24.256389617919923,"y":-20.532968521118165,"z":0.0},"pos":[{"x":24.256389617919923,"y":-20.532968521118165,"z":0.0},{"x":24.256389617919923,"y":-22.48741340637207,"z":0.0},{"x":24.256389617919923,"y":-20.532968521118165,"z":0.0},{"x":29.493425369262697,"y":-22.48741340637207,"z":0.0},{"x":29.493425369262697,"y":-20.532968521118165,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"Mitsunobu reaction\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":18,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"DEAD.or.DCAD.or.DIAD.PPh3\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":25,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":8.077838897705079,"y":-20.892969131469728,"z":0.0},"pos":[{"x":8.077838897705079,"y":-20.892969131469728,"z":0.0},{"x":8.077838897705079,"y":-22.48741340637207,"z":0.0},{"x":8.077838897705079,"y":-20.892969131469728,"z":0.0},{"x":12.753764152526856,"y":-22.48741340637207,"z":0.0},{"x":12.753764152526856,"y":-20.892969131469728,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":13.883398056030274,"y":-22.48741340637207,"z":0.0}},"spine":{"pos":[{"x":7.383394241333008,"y":-20.35758399963379,"z":0.0},{"x":7.383394241333008,"y":-24.61724090576172,"z":0.0}]},"tails":{"pos":[{"x":6.883394241333008,"y":-20.35758399963379,"z":0.0},{"x":6.883394241333008,"y":-24.61724090576172,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":24.069353103637697,"y":-22.48741340637207,"z":0.0},{"x":31.06934928894043,"y":-22.48741340637207,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":47.38878631591797,"y":-20.112594604492189,"z":0.0}},"spine":{"pos":[{"x":40.8887825012207,"y":-17.737777709960939,"z":0.0},{"x":40.8887825012207,"y":-22.48741340637207,"z":0.0}]},"tails":{"pos":[{"x":40.3887825012207,"y":-17.737777709960939,"z":0.0},{"x":40.3887825012207,"y":-22.48741340637207,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":47.38878631591797,"y":-7.7351274490356449,"z":0.0}},"spine":{"pos":[{"x":40.8887825012207,"y":-3.80068302154541,"z":0.0},{"x":40.8887825012207,"y":-11.669571876525879,"z":0.0}]},"tails":{"pos":[{"x":40.3887825012207,"y":-3.80068302154541,"z":0.0},{"x":40.3887825012207,"y":-11.669571876525879,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":62.84486389160156,"y":-13.923861503601075,"z":0.0}},"spine":{"pos":[{"x":56.3448600769043,"y":-7.7351274490356449,"z":0.0},{"x":56.3448600769043,"y":-20.112594604492189,"z":0.0}]},"tails":{"pos":[{"x":55.8448600769043,"y":-7.7351274490356449,"z":0.0},{"x":55.8448600769043,"y":-20.112594604492189,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":76.97164916992188,"y":-13.923861503601075,"z":0.0},{"x":83.97164916992188,"y":-13.923861503601075,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[4.826539039611816,-21.107912063598634,0.0]},{"label":"C","location":[3.960906982421875,-20.6072940826416,0.0]},{"label":"C","location":[3.9617068767547609,-19.607255935668947,0.0]},{"label":"C","location":[3.0944743156433107,-21.10651206970215,0.0]},{"label":"C","location":[2.228842258453369,-20.605894088745118,0.0]},{"label":"O","location":[1.362410068511963,-21.10531234741211,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]}]},"mol1":{"type":"molecule","atoms":[{"label":"N","location":[0.4999988079071045,-25.626569747924806,0.0]},{"label":"C","location":[1.3642239570617676,-25.123554229736329,0.0]},{"label":"O","location":[1.360624074935913,-24.123525619506837,0.0]},{"label":"C","location":[2.2320497035980226,-25.62036895751953,0.0]},{"label":"C","location":[3.0962748527526857,-25.117355346679689,0.0]},{"label":"C","location":[3.9641003608703615,-25.61417007446289,0.0]},{"label":"C","location":[4.8283257484436039,-25.11095428466797,0.0]},{"label":"C","location":[4.82472562789917,-24.111125946044923,0.0]},{"label":"O","location":[5.688951015472412,-23.60791015625,0.0]},{"label":"C","location":[3.956900119781494,-23.614110946655275,0.0]},{"label":"C","location":[3.092674732208252,-24.117324829101564,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":4,"atoms":[7,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,4]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[15.945083618164063,-22.733625411987306,0.0]},{"label":"C","location":[15.944183349609375,-23.733671188354493,0.0]},{"label":"C","location":[15.077842712402344,-24.233095169067384,0.0]},{"label":"C","location":[16.809925079345704,-24.234294891357423,0.0]},{"label":"C","location":[17.67636489868164,-23.735071182250978,0.0]},{"label":"O","location":[18.54200553894043,-24.235694885253908,0.0]},{"label":"C","location":[19.408246994018556,-23.736473083496095,0.0]},{"label":"C","location":[20.27398681640625,-24.23709487915039,0.0]},{"label":"C","location":[21.14042854309082,-23.737873077392579,0.0]},{"label":"C","location":[21.141328811645509,-22.737825393676759,0.0]},{"label":"C","location":[22.00766944885254,-22.238401412963868,0.0]},{"label":"C","location":[22.008569717407228,-21.238353729248048,0.0]},{"label":"N","location":[22.874910354614259,-20.739131927490236,0.0]},{"label":"O","location":[21.142929077148439,-20.73773193359375,0.0]},{"label":"C","location":[20.27558708190918,-22.237201690673829,0.0]},{"label":"C","location":[19.409046173095704,-22.736425399780275,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":4,"atoms":[7,8]},{"type":4,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[11,12]},{"type":2,"atoms":[11,13]},{"type":4,"atoms":[9,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,6]}]},"mol3":{"type":"molecule","atoms":[{"label":"Cl","location":[36.59503936767578,-17.988170623779298,0.0]},{"label":"C","location":[35.72946548461914,-17.487384796142579,0.0]},{"label":"I","location":[34.86308670043945,-17.986770629882814,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]}]},"mol4":{"type":"molecule","atoms":[{"label":"N","location":[39.1943359375,-20.73917579650879,0.0]},{"label":"C","location":[38.327919006347659,-21.238386154174806,0.0]},{"label":"O","location":[37.46229934692383,-20.737775802612306,0.0]},{"label":"C","location":[38.327117919921878,-22.238407135009767,0.0]},{"label":"C","location":[37.46070098876953,-22.737817764282228,0.0]},{"label":"C","location":[37.45989990234375,-23.737838745117189,0.0]},{"label":"C","location":[36.593482971191409,-24.237049102783204,0.0]},{"label":"C","location":[35.72786331176758,-23.736438751220704,0.0]},{"label":"O","location":[34.861446380615237,-24.235849380493165,0.0]},{"label":"C","location":[33.995826721191409,-23.73503875732422,0.0]},{"label":"C","location":[33.12940979003906,-24.23444938659668,0.0]},{"label":"O","location":[32.263790130615237,-23.733638763427736,0.0]},{"label":"C","location":[35.72866439819336,-22.736417770385743,0.0]},{"label":"C","location":[36.5950813293457,-22.237207412719728,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":2,"atoms":[10,11]},{"type":4,"atoms":[7,12]},{"type":4,"atoms":[12,13]},{"type":4,"atoms":[13,4]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[37.46143341064453,-4.549666881561279,0.0]},{"label":"C","location":[36.59505081176758,-4.0502777099609379,0.0]},{"label":"C","location":[36.5942497253418,-3.0502989292144777,0.0]},{"label":"N","location":[35.729469299316409,-4.551066875457764,0.0]},{"label":"C","location":[34.86308670043945,-4.051677703857422,0.0]},{"label":"S","location":[33.9967041015625,-3.552288055419922,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":2,"atoms":[3,4]},{"type":2,"atoms":[4,5]}]},"mol6":{"type":"molecule","atoms":[{"label":"N","location":[34.429447174072269,-12.668888092041016,0.0]},{"label":"C","location":[35.29586410522461,-12.169480323791504,0.0]},{"label":"C","location":[36.161476135253909,-12.6702880859375,0.0]},{"label":"C","location":[37.027889251708987,-12.170880317687989,0.0]},{"label":"C","location":[37.028690338134769,-11.17086410522461,0.0]},{"label":"C","location":[36.16307830810547,-10.670255661010743,0.0]},{"label":"C","location":[35.296661376953128,-11.169464111328125,0.0]},{"label":"O","location":[34.43104934692383,-10.668855667114258,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":4,"atoms":[1,2]},{"type":4,"atoms":[2,3]},{"type":4,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":4,"atoms":[6,1]}]},"mol7":{"type":"molecule","atoms":[{"label":"C","location":[48.730865478515628,-7.237734317779541,0.0]},{"label":"C","location":[49.73085021972656,-7.236934661865234,0.0]},{"label":"C","location":[50.23024368286133,-6.370546817779541,0.0]},{"label":"N","location":[50.23164367675781,-8.102521896362305,0.0]},{"label":"C","location":[51.23183059692383,-8.10172176361084,0.0]},{"label":"N","location":[51.81861877441406,-7.292133808135986,0.0]},{"label":"C","location":[52.7700080871582,-7.600529193878174,0.0]},{"label":"C","location":[53.63559341430664,-7.099936485290527,0.0]},{"label":"C","location":[54.501983642578128,-7.5991291999816898,0.0]},{"label":"C","location":[54.50278091430664,-8.599114418029786,0.0]},{"label":"C","location":[53.6371955871582,-9.09970760345459,0.0]},{"label":"C","location":[52.77080535888672,-8.60051441192627,0.0]},{"label":"O","location":[51.819820404052737,-8.910510063171387,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":4,"atoms":[7,8]},{"type":4,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":4,"atoms":[12,4]},{"type":4,"atoms":[11,6]}]},"mol8":{"type":"molecule","atoms":[{"label":"N","location":[48.583229064941409,-16.86559295654297,0.0]},{"label":"C","location":[49.44965362548828,-17.36480712890625,0.0]},{"label":"O","location":[50.31528091430664,-16.864192962646486,0.0]},{"label":"C","location":[49.45045471191406,-18.364839553833009,0.0]},{"label":"C","location":[50.316680908203128,-18.864253997802736,0.0]},{"label":"C","location":[50.317481994628909,-19.864286422729493,0.0]},{"label":"C","location":[51.18390655517578,-20.363500595092775,0.0]},{"label":"C","location":[52.04973602294922,-19.862886428833009,0.0]},{"label":"O","location":[52.91596221923828,-20.362300872802736,0.0]},{"label":"C","location":[52.91676330566406,-21.362333297729493,0.0]},{"label":"C","location":[53.78318786621094,-21.861547470092775,0.0]},{"label":"O","location":[54.6488151550293,-21.360933303833009,0.0]},{"label":"C","location":[53.78398895263672,-22.86157989501953,0.0]},{"label":"Cl","location":[54.65041732788086,-23.360994338989259,0.0]},{"label":"C","location":[52.04893493652344,-18.86285400390625,0.0]},{"label":"C","location":[51.1825065612793,-18.36363983154297,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[10,12]},{"type":1,"atoms":[12,13]},{"type":4,"atoms":[7,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,4]}]},"mol9":{"type":"molecule","atoms":[{"label":"C","location":[70.95356750488281,-16.431081771850587,0.0]},{"label":"C","location":[71.82097625732422,-15.933477401733399,0.0]},{"label":"C","location":[72.68558502197266,-16.435882568359376,0.0]},{"label":"N","location":[71.82377624511719,-14.933469772338868,0.0]},{"label":"C","location":[70.95916748046875,-14.431065559387207,0.0]},{"label":"C","location":[70.09175872802735,-14.928669929504395,0.0]},{"label":"O","location":[70.08895874023438,-15.928677558898926,0.0]},{"label":"C","location":[69.22715759277344,-14.426265716552735,0.0]},{"label":"O","location":[68.35954284667969,-14.923869132995606,0.0]},{"label":"C","location":[67.4951400756836,-14.421464920043946,0.0]},{"label":"C","location":[67.49774169921875,-13.421457290649414,0.0]},{"label":"C","location":[66.63313293457031,-12.919053077697754,0.0]},{"label":"C","location":[65.7657241821289,-13.416657447814942,0.0]},{"label":"C","location":[64.90111541748047,-12.914253234863282,0.0]},{"label":"C","location":[64.90391540527344,-11.914244651794434,0.0]},{"label":"N","location":[64.039306640625,-11.411840438842774,0.0]},{"label":"O","location":[65.77132415771485,-11.416640281677246,0.0]},{"label":"C","location":[65.76312255859375,-14.416665077209473,0.0]},{"label":"C","location":[66.62753295898438,-14.919069290161133,0.0]},{"label":"C","location":[72.6913833618164,-14.43586540222168,0.0]},{"label":"N","location":[73.60359191894531,-14.845468521118164,0.0]},{"label":"C","location":[74.27479553222656,-14.104063034057618,0.0]},{"label":"C","location":[75.27460479736328,-14.10666275024414,0.0]},{"label":"C","location":[75.77720642089844,-13.242255210876465,0.0]},{"label":"C","location":[75.27960205078125,-12.374649047851563,0.0]},{"label":"C","location":[74.27959442138672,-12.372048377990723,0.0]},{"label":"C","location":[73.77719116210938,-13.236655235290528,0.0]},{"label":"O","location":[72.79838562011719,-13.441657066345215,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":1,"atoms":[3,19]},{"type":4,"atoms":[19,20]},{"type":4,"atoms":[20,21]},{"type":4,"atoms":[21,22]},{"type":4,"atoms":[22,23]},{"type":4,"atoms":[23,24]},{"type":4,"atoms":[24,25]},{"type":4,"atoms":[25,26]},{"type":4,"atoms":[26,27]},{"type":4,"atoms":[18,9]},{"type":4,"atoms":[27,19]},{"type":4,"atoms":[26,21]}]},"mol10":{"type":"molecule","atoms":[{"label":"C","location":[85.16609191894531,-13.4183349609375,0.0]},{"label":"C","location":[86.03173828125,-13.918960571289063,0.0]},{"label":"C","location":[86.03093719482422,-14.919013023376465,0.0]},{"label":"N","location":[86.89818572998047,-13.419734954833985,0.0]},{"label":"C","location":[87.76383209228516,-13.920360565185547,0.0]},{"label":"C","location":[88.6302719116211,-13.421134948730469,0.0]},{"label":"O","location":[88.63107299804688,-12.421082496643067,0.0]},{"label":"C","location":[89.49591827392578,-13.921760559082032,0.0]},{"label":"O","location":[90.36236572265625,-13.422534942626954,0.0]},{"label":"C","location":[91.22801208496094,-13.923160552978516,0.0]},{"label":"C","location":[91.22721099853516,-14.923213958740235,0.0]},{"label":"C","location":[92.09285736083985,-15.423839569091797,0.0]},{"label":"C","location":[92.95930480957031,-14.924613952636719,0.0]},{"label":"C","location":[93.82494354248047,-15.425239562988282,0.0]},{"label":"C","location":[94.69139099121094,-14.926013946533204,0.0]},{"label":"N","location":[95.55703735351563,-15.426639556884766,0.0]},{"label":"O","location":[94.69219207763672,-13.9259614944458,0.0]},{"label":"C","location":[92.96009826660156,-13.924561500549317,0.0]},{"label":"C","location":[92.0944595336914,-13.423934936523438,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":4,"atoms":[18,9]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/formats/ref/pathway12.ket b/api/tests/integration/tests/formats/ref/pathway12.ket index edb2fbec25..6fea7ba300 100644 --- a/api/tests/integration/tests/formats/ref/pathway12.ket +++ b/api/tests/integration/tests/formats/ref/pathway12.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"},{"$ref":"mol10"},{"$ref":"mol11"},{"$ref":"mol12"},{"$ref":"mol13"},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567...\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":37.53075408935547,"y":-7.535224914550781,"z":0.0},"pos":[{"x":37.53075408935547,"y":-7.535224914550781,"z":0.0},{"x":37.53075408935547,"y":-10.775224685668946,"z":0.0},{"x":43.14186477661133,"y":-10.775224685668946,"z":0.0},{"x":43.14186477661133,"y":-7.535224437713623,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"12\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":27.145294189453126,"y":-10.055225372314454,"z":0.0},"pos":[{"x":27.145294189453126,"y":-10.055225372314454,"z":0.0},{"x":27.145294189453126,"y":-10.775225639343262,"z":0.0},{"x":32.756404876708987,"y":-10.775225639343262,"z":0.0},{"x":32.756404876708987,"y":-10.055225372314454,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"12\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"~!@#$%^&*()_-+=?.,{}[]|\\\\/\\\"':;`\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"<>\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":16.741878509521486,"y":-3.820610284805298,"z":0.0},"pos":[{"x":16.741878509521486,"y":-3.820610284805298,"z":0.0},{"x":16.741878509521486,"y":-5.620610237121582,"z":0.0},{"x":22.352989196777345,"y":-5.620610237121582,"z":0.0},{"x":22.352989196777345,"y":-3.8206100463867189,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"AbcdefghijklmnopqrstuvWxyzabcd\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":16.741878509521486,"y":-14.84984016418457,"z":0.0},"pos":[{"x":16.741878509521486,"y":-14.84984016418457,"z":0.0},{"x":16.741878509521486,"y":-15.929840087890625,"z":0.0},{"x":22.352989196777345,"y":-15.929840087890625,"z":0.0},{"x":22.352989196777345,"y":-14.84984016418457,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"~!@#$%^&*()_-+=?.,{}[]|\\\\/\\\"':;`\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":2.6944448947906496,"y":-16.984554290771486,"z":0.0},"pos":[{"x":2.6944448947906496,"y":-16.984554290771486,"z":0.0},{"x":2.6944448947906496,"y":-18.06455421447754,"z":0.0},{"x":8.30555534362793,"y":-18.06455421447754,"z":0.0},{"x":8.30555534362793,"y":-16.984554290771486,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":24.939748764038087,"y":-25.64972496032715,"z":0.0},"pos":[{"x":24.939748764038087,"y":-25.64972496032715,"z":0.0},{"x":24.939748764038087,"y":-28.16972541809082,"z":0.0},{"x":30.550859451293947,"y":-28.16972541809082,"z":0.0},{"x":30.550859451293947,"y":-25.64972496032715,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567...\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":13.279644012451172,"y":-24.929725646972658,"z":0.0},"pos":[{"x":13.279644012451172,"y":-24.929725646972658,"z":0.0},{"x":13.279644012451172,"y":-28.16972541809082,"z":0.0},{"x":18.89075469970703,"y":-28.16972541809082,"z":0.0},{"x":18.89075469970703,"y":-24.929725646972658,"z":0.0}]}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":2.694444417953491,"y":-18.578998565673829,"z":0.0},{"x":9.69444465637207,"y":-18.578998565673829,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":22.54743194580078,"y":-16.444284439086915,"z":0.0}},"spine":{"pos":[{"x":16.047433853149415,"y":-14.309571266174317,"z":0.0},{"x":16.047433853149415,"y":-18.578998565673829,"z":0.0}]},"tails":{"pos":[{"x":15.547433853149414,"y":-14.309571266174317,"z":0.0},{"x":15.547433853149414,"y":-18.578998565673829,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":22.54743194580078,"y":-6.135055065155029,"z":0.0}},"spine":{"pos":[{"x":16.047433853149415,"y":-2.0,"z":0.0},{"x":16.047433853149415,"y":-10.270110130310059,"z":0.0}]},"tails":{"pos":[{"x":15.547433853149414,"y":-2.0,"z":0.0},{"x":15.547433853149414,"y":-6.000044822692871,"z":0.0},{"x":15.547433853149414,"y":-10.270110130310059,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":32.95085144042969,"y":-11.28966999053955,"z":0.0}},"spine":{"pos":[{"x":26.450849533081056,"y":-6.135055065155029,"z":0.0},{"x":26.450849533081056,"y":-16.444284439086915,"z":0.0}]},"tails":{"pos":[{"x":25.950849533081056,"y":-6.135055065155029,"z":0.0},{"x":25.950849533081056,"y":-16.444284439086915,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":37.53075408935547,"y":-11.28966999053955,"z":0.0},{"x":44.530757904052737,"y":-11.28966999053955,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":19.0851993560791,"y":-28.68416976928711,"z":0.0}},"spine":{"pos":[{"x":12.585199356079102,"y":-24.749725341796876,"z":0.0},{"x":12.585199356079102,"y":-32.618614196777347,"z":0.0}]},"tails":{"pos":[{"x":12.085199356079102,"y":-24.749725341796876,"z":0.0},{"x":12.085199356079102,"y":-32.618614196777347,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":24.939748764038087,"y":-28.68416976928711,"z":0.0},{"x":31.939748764038087,"y":-28.68416976928711,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.566990852355957,-18.829002380371095,0.0]},{"label":"C","location":[1.4330101013183594,-18.328994750976564,0.0]}],"bonds":[{"type":2,"atoms":[0,1]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[12.620939254760743,-13.540131568908692,0.0]},{"label":"C","location":[13.429929733276368,-14.127924919128418,0.0]},{"label":"C","location":[13.120933532714844,-15.079012870788575,0.0]},{"label":"C","location":[12.12094497680664,-15.079012870788575,0.0]},{"label":"C","location":[11.811948776245118,-14.127924919128418,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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[11.754902839660645,-18.07900619506836,0.0]},{"label":"C","location":[11.754902839660645,-19.078990936279298,0.0]},{"label":"C","location":[12.620990753173829,-19.578983306884767,0.0]},{"label":"C","location":[13.486976623535157,-19.078990936279298,0.0]},{"label":"C","location":[13.486976623535157,-18.07900619506836,0.0]},{"label":"C","location":[12.620990753173829,-17.579011917114259,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]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[14.352989196777344,-1.75,0.0]},{"label":"C","location":[13.486888885498047,-2.25,0.0]},{"label":"C","location":[12.620888710021973,-1.75,0.0]},{"label":"C","location":[11.754888534545899,-2.25,0.0]},{"label":"C","location":[10.888888359069825,-1.75,0.0]}],"bonds":[{"type":2,"atoms":[1,0]},{"type":2,"atoms":[2,1]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[4,3]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[11.7557954788208,-5.500100135803223,0.0]},{"label":"C","location":[13.486083984375,-5.499699592590332,0.0]},{"label":"C","location":[12.622590065002442,-5.000000953674316,0.0]},{"label":"C","location":[13.486083984375,-6.500592231750488,0.0]},{"label":"C","location":[11.7557954788208,-6.505091667175293,0.0]},{"label":"C","location":[12.624690055847168,-7.000090599060059,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]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[12.621038436889649,-9.500088691711426,0.0]},{"label":"C","location":[13.121353149414063,-11.040129661560059,0.0]},{"label":"C","location":[13.430660247802735,-10.093903541564942,0.0]},{"label":"C","location":[12.120625495910645,-11.040129661560059,0.0]},{"label":"C","location":[11.811217308044434,-10.093903541564942,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.748519897460939,-6.567529678344727,0.0]},{"label":"C","location":[24.7497615814209,-6.567529678344727,0.0]},{"label":"C","location":[24.249191284179689,-5.702579498291016,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.756404876708986,-16.941797256469728,0.0]},{"label":"C","location":[24.752704620361329,-15.946769714355469,0.0]},{"label":"C","location":[23.74437713623047,-16.928796768188478,0.0]},{"label":"C","location":[23.74187660217285,-15.946769714355469,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":[34.145294189453128,-10.7832670211792,0.0]},{"label":"C","location":[34.92919921875,-10.16565990447998,0.0]},{"label":"C","location":[35.90220642089844,-10.388262748718262,0.0]},{"label":"C","location":[36.33631134033203,-11.284070014953614,0.0]},{"label":"C","location":[34.150794982910159,-11.790474891662598,0.0]},{"label":"C","location":[35.90290832519531,-12.19107723236084,0.0]},{"label":"C","location":[34.92919921875,-12.413680076599121,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]}]},"mol9":{"type":"molecule","atoms":[{"label":"N","location":[2.6617696285247804,-21.502716064453126,0.0]},{"label":"C","location":[3.528186082839966,-22.001922607421876,0.0]},{"label":"O","location":[4.393802642822266,-21.501319885253908,0.0]},{"label":"C","location":[3.5289859771728517,-23.001937866210939,0.0]},{"label":"C","location":[4.39520263671875,-23.501358032226564,0.0]},{"label":"C","location":[4.396002769470215,-24.501373291015626,0.0]},{"label":"C","location":[5.262418746948242,-25.000579833984376,0.0]},{"label":"C","location":[6.128235816955566,-24.499969482421876,0.0]},{"label":"O","location":[6.994552135467529,-24.999374389648439,0.0]},{"label":"C","location":[6.995352268218994,-25.99950408935547,0.0]},{"label":"C","location":[7.86176872253418,-26.49871063232422,0.0]},{"label":"O","location":[8.727384567260743,-25.99810028076172,0.0]},{"label":"C","location":[7.8625688552856449,-27.498733520507814,0.0]},{"label":"Cl","location":[8.728984832763672,-27.998138427734376,0.0]},{"label":"C","location":[6.127435684204102,-23.499954223632814,0.0]},{"label":"C","location":[5.261018753051758,-23.00074005126953,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[10,12]},{"type":1,"atoms":[12,13]},{"type":4,"atoms":[7,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,4]}]},"mol10":{"type":"molecule","atoms":[{"label":"C","location":[0.5,-32.113059997558597,0.0]},{"label":"C","location":[1.3656139373779297,-32.61376953125,0.0]},{"label":"C","location":[1.3648128509521485,-33.61377716064453,0.0]},{"label":"N","location":[2.232027053833008,-32.114463806152347,0.0]},{"label":"C","location":[3.097738265991211,-32.615074157714847,0.0]},{"label":"C","location":[3.964151382446289,-32.11585998535156,0.0]},{"label":"O","location":[3.9649505615234377,-31.1158447265625,0.0]},{"label":"C","location":[4.829765319824219,-32.61656951904297,0.0]},{"label":"O","location":[5.696178436279297,-32.11726379394531,0.0]},{"label":"C","location":[6.561788558959961,-32.61787414550781,0.0]},{"label":"C","location":[6.5609893798828129,-33.61798095703125,0.0]},{"label":"C","location":[7.426702499389648,-34.11858367919922,0.0]},{"label":"C","location":[8.293115615844727,-33.61937713623047,0.0]},{"label":"C","location":[9.158727645874024,-34.11998748779297,0.0]},{"label":"C","location":[10.025140762329102,-33.62078094482422,0.0]},{"label":"N","location":[10.890754699707032,-34.12138366699219,0.0]},{"label":"O","location":[10.02593994140625,-32.62067413330078,0.0]},{"label":"C","location":[8.293916702270508,-32.61936950683594,0.0]},{"label":"C","location":[7.428302764892578,-32.11865997314453,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":4,"atoms":[18,9]}]},"mol11":{"type":"molecule","atoms":[{"label":"F","location":[20.279644012451173,-29.682788848876954,0.0]},{"label":"C","location":[21.146060943603517,-29.183582305908204,0.0]},{"label":"C","location":[22.011676788330079,-29.684192657470704,0.0]},{"label":"C","location":[22.878089904785158,-29.18478012084961,0.0]},{"label":"F","location":[23.74370574951172,-29.685588836669923,0.0]},{"label":"C","location":[22.878890991210939,-28.184764862060548,0.0]},{"label":"Br","location":[23.745304107666017,-27.685558319091798,0.0]},{"label":"C","location":[22.013275146484376,-27.684162139892579,0.0]},{"label":"C","location":[21.146862030029298,-28.18356704711914,0.0]},{"label":"F","location":[20.281246185302736,-27.682758331298829,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":4,"atoms":[1,2]},{"type":4,"atoms":[2,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[3,5]},{"type":1,"atoms":[5,6]},{"type":4,"atoms":[5,7]},{"type":4,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[8,1]}]},"mol12":{"type":"molecule","atoms":[{"label":"C","location":[45.72520065307617,-11.790976524353028,0.0]},{"label":"C","location":[45.72540283203125,-10.788464546203614,0.0]},{"label":"C","location":[46.430511474609378,-10.083159446716309,0.0]},{"label":"C","location":[46.43070983886719,-12.496281623840332,0.0]},{"label":"C","location":[47.4331169128418,-12.496281623840332,0.0]},{"label":"C","location":[48.138526916503909,-11.790976524353028,0.0]},{"label":"C","location":[48.138423919677737,-10.788464546203614,0.0]},{"label":"C","location":[47.4331169128418,-10.08305835723877,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]}]},"mol13":{"type":"molecule","atoms":[{"label":"C","location":[35.73244094848633,-28.435138702392579,0.0]},{"label":"C","location":[34.8660888671875,-28.93460464477539,0.0]},{"label":"C","location":[34.00054168701172,-28.43374252319336,0.0]},{"label":"Cl","location":[33.134193420410159,-28.933109283447267,0.0]}],"bonds":[{"type":2,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,3]}]}} \ No newline at end of file +{"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"},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567...\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":37.53075408935547,"y":-7.535224914550781,"z":0.0},"pos":[{"x":37.53075408935547,"y":-7.535224914550781,"z":0.0},{"x":37.53075408935547,"y":-11.28966999053955,"z":0.0},{"x":37.53075408935547,"y":-7.535224914550781,"z":0.0},{"x":43.14186477661133,"y":-11.28966999053955,"z":0.0},{"x":43.14186477661133,"y":-7.535224914550781,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"12\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":27.145294189453126,"y":-10.055225372314454,"z":0.0},"pos":[{"x":27.145294189453126,"y":-10.055225372314454,"z":0.0},{"x":27.145294189453126,"y":-11.28966999053955,"z":0.0},{"x":27.145294189453126,"y":-10.055225372314454,"z":0.0},{"x":32.756404876708987,"y":-11.28966999053955,"z":0.0},{"x":32.756404876708987,"y":-10.055225372314454,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"12\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"~!@#$%^&*()_-+=?.,{}[]|\\\\/\\\"':;`\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"<>\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":2,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":16.741878509521486,"y":-3.820610284805298,"z":0.0},"pos":[{"x":16.741878509521486,"y":-3.820610284805298,"z":0.0},{"x":16.741878509521486,"y":-6.135055065155029,"z":0.0},{"x":16.741878509521486,"y":-3.820610284805298,"z":0.0},{"x":22.352989196777345,"y":-6.135055065155029,"z":0.0},{"x":22.352989196777345,"y":-3.820610284805298,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"AbcdefghijklmnopqrstuvWxyzabcd\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":16.741878509521486,"y":-14.84984016418457,"z":0.0},"pos":[{"x":16.741878509521486,"y":-14.84984016418457,"z":0.0},{"x":16.741878509521486,"y":-16.444284439086915,"z":0.0},{"x":16.741878509521486,"y":-14.84984016418457,"z":0.0},{"x":22.352989196777345,"y":-16.444284439086915,"z":0.0},{"x":22.352989196777345,"y":-14.84984016418457,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":0,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"~!@#$%^&*()_-+=?.,{}[]|\\\\/\\\"':;`\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"ITALIC\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":2.6944448947906496,"y":-16.984554290771486,"z":0.0},"pos":[{"x":2.6944448947906496,"y":-16.984554290771486,"z":0.0},{"x":2.6944448947906496,"y":-18.578998565673829,"z":0.0},{"x":2.6944448947906496,"y":-16.984554290771486,"z":0.0},{"x":8.30555534362793,"y":-18.578998565673829,"z":0.0},{"x":8.30555534362793,"y":-16.984554290771486,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCD\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":24.939748764038087,"y":-25.64972496032715,"z":0.0},"pos":[{"x":24.939748764038087,"y":-25.64972496032715,"z":0.0},{"x":24.939748764038087,"y":-28.68416976928711,"z":0.0},{"x":24.939748764038087,"y":-25.64972496032715,"z":0.0},{"x":30.550859451293947,"y":-28.68416976928711,"z":0.0},{"x":30.550859451293947,"y":-25.64972496032715,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567890\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}},{\"text\":\"123456789012345678901234567...\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":30,\"style\":\"BOLD\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":13.279644012451172,"y":-24.929725646972658,"z":0.0},"pos":[{"x":13.279644012451172,"y":-24.929725646972658,"z":0.0},{"x":13.279644012451172,"y":-28.68416976928711,"z":0.0},{"x":13.279644012451172,"y":-24.929725646972658,"z":0.0},{"x":18.89075469970703,"y":-28.68416976928711,"z":0.0},{"x":18.89075469970703,"y":-24.929725646972658,"z":0.0}]}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":2.694444417953491,"y":-18.578998565673829,"z":0.0},{"x":9.69444465637207,"y":-18.578998565673829,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":22.54743194580078,"y":-16.444284439086915,"z":0.0}},"spine":{"pos":[{"x":16.047433853149415,"y":-14.309571266174317,"z":0.0},{"x":16.047433853149415,"y":-18.578998565673829,"z":0.0}]},"tails":{"pos":[{"x":15.547433853149414,"y":-14.309571266174317,"z":0.0},{"x":15.547433853149414,"y":-18.578998565673829,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":22.54743194580078,"y":-6.135055065155029,"z":0.0}},"spine":{"pos":[{"x":16.047433853149415,"y":-2.0,"z":0.0},{"x":16.047433853149415,"y":-10.270110130310059,"z":0.0}]},"tails":{"pos":[{"x":15.547433853149414,"y":-2.0,"z":0.0},{"x":15.547433853149414,"y":-6.000044822692871,"z":0.0},{"x":15.547433853149414,"y":-10.270110130310059,"z":0.0}]},"zOrder":0}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":32.95085144042969,"y":-11.28966999053955,"z":0.0}},"spine":{"pos":[{"x":26.450849533081056,"y":-6.135055065155029,"z":0.0},{"x":26.450849533081056,"y":-16.444284439086915,"z":0.0}]},"tails":{"pos":[{"x":25.950849533081056,"y":-6.135055065155029,"z":0.0},{"x":25.950849533081056,"y":-16.444284439086915,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":37.53075408935547,"y":-11.28966999053955,"z":0.0},{"x":44.530757904052737,"y":-11.28966999053955,"z":0.0}]}},{"type":"multi-tailed-arrow","data":{"head":{"position":{"x":19.0851993560791,"y":-28.68416976928711,"z":0.0}},"spine":{"pos":[{"x":12.585199356079102,"y":-24.749725341796876,"z":0.0},{"x":12.585199356079102,"y":-32.618614196777347,"z":0.0}]},"tails":{"pos":[{"x":12.085199356079102,"y":-24.749725341796876,"z":0.0},{"x":12.085199356079102,"y":-32.618614196777347,"z":0.0}]},"zOrder":0}},{"type":"arrow","data":{"mode":"filled-triangle","pos":[{"x":24.939748764038087,"y":-28.68416976928711,"z":0.0},{"x":31.939748764038087,"y":-28.68416976928711,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[0.566990852355957,-18.829002380371095,0.0]},{"label":"C","location":[1.4330101013183594,-18.328994750976564,0.0]}],"bonds":[{"type":2,"atoms":[0,1]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[12.620939254760743,-13.540131568908692,0.0]},{"label":"C","location":[13.429929733276368,-14.127924919128418,0.0]},{"label":"C","location":[13.120933532714844,-15.079012870788575,0.0]},{"label":"C","location":[12.12094497680664,-15.079012870788575,0.0]},{"label":"C","location":[11.811948776245118,-14.127924919128418,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]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[11.754902839660645,-18.07900619506836,0.0]},{"label":"C","location":[11.754902839660645,-19.078990936279298,0.0]},{"label":"C","location":[12.620990753173829,-19.578983306884767,0.0]},{"label":"C","location":[13.486976623535157,-19.078990936279298,0.0]},{"label":"C","location":[13.486976623535157,-18.07900619506836,0.0]},{"label":"C","location":[12.620990753173829,-17.579011917114259,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]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[14.352989196777344,-1.75,0.0]},{"label":"C","location":[13.486888885498047,-2.25,0.0]},{"label":"C","location":[12.620888710021973,-1.75,0.0]},{"label":"C","location":[11.754888534545899,-2.25,0.0]},{"label":"C","location":[10.888888359069825,-1.75,0.0]}],"bonds":[{"type":2,"atoms":[1,0]},{"type":2,"atoms":[2,1]},{"type":1,"atoms":[3,2]},{"type":1,"atoms":[4,3]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[11.7557954788208,-5.500100135803223,0.0]},{"label":"C","location":[13.486083984375,-5.499699592590332,0.0]},{"label":"C","location":[12.622590065002442,-5.000000953674316,0.0]},{"label":"C","location":[13.486083984375,-6.500592231750488,0.0]},{"label":"C","location":[11.7557954788208,-6.505091667175293,0.0]},{"label":"C","location":[12.624690055847168,-7.000090599060059,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]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[12.621038436889649,-9.500088691711426,0.0]},{"label":"C","location":[13.121353149414063,-11.040129661560059,0.0]},{"label":"C","location":[13.430660247802735,-10.093903541564942,0.0]},{"label":"C","location":[12.120625495910645,-11.040129661560059,0.0]},{"label":"C","location":[11.811217308044434,-10.093903541564942,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.748519897460939,-6.567529678344727,0.0]},{"label":"C","location":[24.7497615814209,-6.567529678344727,0.0]},{"label":"C","location":[24.249191284179689,-5.702579498291016,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.756404876708986,-16.941797256469728,0.0]},{"label":"C","location":[24.752704620361329,-15.946769714355469,0.0]},{"label":"C","location":[23.74437713623047,-16.928796768188478,0.0]},{"label":"C","location":[23.74187660217285,-15.946769714355469,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":[34.145294189453128,-10.7832670211792,0.0]},{"label":"C","location":[34.92919921875,-10.16565990447998,0.0]},{"label":"C","location":[35.90220642089844,-10.388262748718262,0.0]},{"label":"C","location":[36.33631134033203,-11.284070014953614,0.0]},{"label":"C","location":[34.150794982910159,-11.790474891662598,0.0]},{"label":"C","location":[35.90290832519531,-12.19107723236084,0.0]},{"label":"C","location":[34.92919921875,-12.413680076599121,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]}]},"mol9":{"type":"molecule","atoms":[{"label":"N","location":[2.6617696285247804,-21.502716064453126,0.0]},{"label":"C","location":[3.528186082839966,-22.001922607421876,0.0]},{"label":"O","location":[4.393802642822266,-21.501319885253908,0.0]},{"label":"C","location":[3.5289859771728517,-23.001937866210939,0.0]},{"label":"C","location":[4.39520263671875,-23.501358032226564,0.0]},{"label":"C","location":[4.396002769470215,-24.501373291015626,0.0]},{"label":"C","location":[5.262418746948242,-25.000579833984376,0.0]},{"label":"C","location":[6.128235816955566,-24.499969482421876,0.0]},{"label":"O","location":[6.994552135467529,-24.999374389648439,0.0]},{"label":"C","location":[6.995352268218994,-25.99950408935547,0.0]},{"label":"C","location":[7.86176872253418,-26.49871063232422,0.0]},{"label":"O","location":[8.727384567260743,-25.99810028076172,0.0]},{"label":"C","location":[7.8625688552856449,-27.498733520507814,0.0]},{"label":"Cl","location":[8.728984832763672,-27.998138427734376,0.0]},{"label":"C","location":[6.127435684204102,-23.499954223632814,0.0]},{"label":"C","location":[5.261018753051758,-23.00074005126953,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[4,5]},{"type":4,"atoms":[5,6]},{"type":4,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":1,"atoms":[9,10]},{"type":1,"atoms":[10,11]},{"type":1,"atoms":[10,12]},{"type":1,"atoms":[12,13]},{"type":4,"atoms":[7,14]},{"type":4,"atoms":[14,15]},{"type":4,"atoms":[15,4]}]},"mol10":{"type":"molecule","atoms":[{"label":"C","location":[0.5,-32.113059997558597,0.0]},{"label":"C","location":[1.3656139373779297,-32.61376953125,0.0]},{"label":"C","location":[1.3648128509521485,-33.61377716064453,0.0]},{"label":"N","location":[2.232027053833008,-32.114463806152347,0.0]},{"label":"C","location":[3.097738265991211,-32.615074157714847,0.0]},{"label":"C","location":[3.964151382446289,-32.11585998535156,0.0]},{"label":"O","location":[3.9649505615234377,-31.1158447265625,0.0]},{"label":"C","location":[4.829765319824219,-32.61656951904297,0.0]},{"label":"O","location":[5.696178436279297,-32.11726379394531,0.0]},{"label":"C","location":[6.561788558959961,-32.61787414550781,0.0]},{"label":"C","location":[6.5609893798828129,-33.61798095703125,0.0]},{"label":"C","location":[7.426702499389648,-34.11858367919922,0.0]},{"label":"C","location":[8.293115615844727,-33.61937713623047,0.0]},{"label":"C","location":[9.158727645874024,-34.11998748779297,0.0]},{"label":"C","location":[10.025140762329102,-33.62078094482422,0.0]},{"label":"N","location":[10.890754699707032,-34.12138366699219,0.0]},{"label":"O","location":[10.02593994140625,-32.62067413330078,0.0]},{"label":"C","location":[8.293916702270508,-32.61936950683594,0.0]},{"label":"C","location":[7.428302764892578,-32.11865997314453,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[9,10]},{"type":4,"atoms":[10,11]},{"type":4,"atoms":[11,12]},{"type":1,"atoms":[12,13]},{"type":1,"atoms":[13,14]},{"type":1,"atoms":[14,15]},{"type":2,"atoms":[14,16]},{"type":4,"atoms":[12,17]},{"type":4,"atoms":[17,18]},{"type":4,"atoms":[18,9]}]},"mol11":{"type":"molecule","atoms":[{"label":"F","location":[20.279644012451173,-29.682788848876954,0.0]},{"label":"C","location":[21.146060943603517,-29.183582305908204,0.0]},{"label":"C","location":[22.011676788330079,-29.684192657470704,0.0]},{"label":"C","location":[22.878089904785158,-29.18478012084961,0.0]},{"label":"F","location":[23.74370574951172,-29.685588836669923,0.0]},{"label":"C","location":[22.878890991210939,-28.184764862060548,0.0]},{"label":"Br","location":[23.745304107666017,-27.685558319091798,0.0]},{"label":"C","location":[22.013275146484376,-27.684162139892579,0.0]},{"label":"C","location":[21.146862030029298,-28.18356704711914,0.0]},{"label":"F","location":[20.281246185302736,-27.682758331298829,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":4,"atoms":[1,2]},{"type":4,"atoms":[2,3]},{"type":1,"atoms":[3,4]},{"type":4,"atoms":[3,5]},{"type":1,"atoms":[5,6]},{"type":4,"atoms":[5,7]},{"type":4,"atoms":[7,8]},{"type":1,"atoms":[8,9]},{"type":4,"atoms":[8,1]}]},"mol12":{"type":"molecule","atoms":[{"label":"C","location":[45.72520065307617,-11.790976524353028,0.0]},{"label":"C","location":[45.72540283203125,-10.788464546203614,0.0]},{"label":"C","location":[46.430511474609378,-10.083159446716309,0.0]},{"label":"C","location":[46.43070983886719,-12.496281623840332,0.0]},{"label":"C","location":[47.4331169128418,-12.496281623840332,0.0]},{"label":"C","location":[48.138526916503909,-11.790976524353028,0.0]},{"label":"C","location":[48.138423919677737,-10.788464546203614,0.0]},{"label":"C","location":[47.4331169128418,-10.08305835723877,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]}]},"mol13":{"type":"molecule","atoms":[{"label":"C","location":[35.73244094848633,-28.435138702392579,0.0]},{"label":"C","location":[34.8660888671875,-28.93460464477539,0.0]},{"label":"C","location":[34.00054168701172,-28.43374252319336,0.0]},{"label":"Cl","location":[33.134193420410159,-28.933109283447267,0.0]}],"bonds":[{"type":2,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,3]}]}} \ No newline at end of file