From bb3d3fdbc3f6d2341efb2461934d7241ccb774f7 Mon Sep 17 00:00:00 2001 From: even1024 Date: Tue, 22 Nov 2022 15:46:28 +0300 Subject: [PATCH 1/6] cdxml export layout fix (#897) * cdxml export layout fix * cdxml export layout fix * cdxml export layout fix * cdxml export layout fix * cdxml export layout fix * cdxml export layout fix * layout comment Co-authored-by: Roman Porozhnetov --- api/c/indigo/src/indigo_layout.cpp | 5 +- .../ref/formats/ket_cdxml_ket.py.out | 92 + .../ref/formats/rxn_to_cdxml.py.out | 2148 ++++++++--------- .../tests/formats/ket_cdxml_ket.py | 35 + .../tests/formats/reactions/agents.ket | 398 +++ core/indigo-core/molecule/metadata_storage.h | 3 + .../molecule/molecule_cdxml_saver.h | 14 +- .../molecule/src/metadata_storage.cpp | 20 +- .../molecule/src/molecule_cdxml_loader.cpp | 16 +- .../molecule/src/molecule_cdxml_saver.cpp | 447 ++-- .../reaction/reaction_cdxml_saver.h | 6 +- .../reaction/src/reaction_cdxml_saver.cpp | 78 +- .../reaction/src/reaction_json_saver.cpp | 4 +- core/render2d/src/render_cdxml.cpp | 2 +- 14 files changed, 1913 insertions(+), 1355 deletions(-) create mode 100644 api/tests/integration/ref/formats/ket_cdxml_ket.py.out create mode 100644 api/tests/integration/tests/formats/ket_cdxml_ket.py create mode 100644 api/tests/integration/tests/formats/reactions/agents.ket diff --git a/api/c/indigo/src/indigo_layout.cpp b/api/c/indigo/src/indigo_layout.cpp index 106da0fdb9..794ed4df41 100644 --- a/api/c/indigo/src/indigo_layout.cpp +++ b/api/c/indigo/src/indigo_layout.cpp @@ -98,9 +98,8 @@ CEXPORT int indigoLayout(int object) else if (IndigoBaseReaction::is(obj)) { BaseReaction& rxn = obj.getBaseReaction(); - if (rxn.isMultistep()) - throw IndigoError("Multistep layout is not implemented yet."); - else + bool no_layout = rxn.catalystCount() || rxn.intermediateCount() || rxn.specialConditionsCount() || rxn.meta().getNonChemicalMetaCount(); + if (!no_layout) { ReactionLayout rl(rxn, self.smart_layout); rl.max_iterations = self.layout_max_iterations; diff --git a/api/tests/integration/ref/formats/ket_cdxml_ket.py.out b/api/tests/integration/ref/formats/ket_cdxml_ket.py.out new file mode 100644 index 0000000000..b0d7232554 --- /dev/null +++ b/api/tests/integration/ref/formats/ket_cdxml_ket.py.out @@ -0,0 +1,92 @@ +*** KET to CDXML to KET *** +agents.ket +*** Try as Reaction *** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + O + + + + + + + + + + + + + + + + + + + + + + + + + + OH + + + + + + + + + + + + + + + + + + + ClH + + + + + + test + + + + + + + +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.5,"y":-5.074999809265137,"z":0.0},{"x":12.800000190734864,"y":-5.025000095367432,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"test\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":4,\"style\":\"CUSTOM_FONT_SIZE_20px\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":10.149999618530274,"y":-5.574999809265137,"z":0.0}}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.5,"y":-5.074999809265137,"z":0.0},{"x":12.800000190734864,"y":-5.025000095367432,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[6.520544052124023,-5.325058937072754,0.0]},{"label":"C","location":[6.520544052124023,-6.325052738189697,0.0]},{"label":"C","location":[5.654489040374756,-6.82504940032959,0.0]},{"label":"C","location":[4.788554668426514,-6.324931621551514,0.0]},{"label":"C","location":[4.788554668426514,-5.32493782043457,0.0]},{"label":"C","location":[5.654489040374756,-4.824941158294678,0.0]},{"label":"C","location":[5.654489040374756,-3.8249473571777345,0.0]},{"label":"O","location":[4.788554668426514,-3.324950695037842,0.0]},{"label":"C","location":[6.520544052124023,-3.324950695037842,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":2,"atoms":[6,7]},{"type":1,"atoms":[6,8]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[17.261444091796876,-5.758026123046875,0.0]},{"label":"C","location":[17.261444091796876,-6.75801944732666,0.0]},{"label":"C","location":[16.395389556884767,-7.258016109466553,0.0]},{"label":"C","location":[15.529335975646973,-6.75801944732666,0.0]},{"label":"C","location":[15.529335975646973,-5.758026123046875,0.0]},{"label":"C","location":[16.395389556884767,-5.258028984069824,0.0]},{"label":"C","location":[16.395389556884767,-4.258035659790039,0.0]},{"label":"C","location":[15.529335975646973,-3.7580387592315676,0.0]},{"label":"C","location":[14.663400650024414,-3.2580418586730959,0.0]},{"label":"O","location":[16.02933120727539,-2.8919837474823,0.0]},{"label":"C","location":[15.029337882995606,-4.624094009399414,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[7,9]},{"type":1,"atoms":[7,10]}]},"mol2":{"type":"molecule","atoms":[{"label":"Cl","location":[10.475000381469727,-4.5,0.0]}],"bonds":[]}} diff --git a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out index 0c4ce15c54..e2b4e3be8e 100644 --- a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out +++ b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out @@ -22,146 +22,146 @@ molfile loader: atom lists are allowed only for queries - - - - - - - - + + + + + + + + N - - + + O - + O - + H - + H - + H - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + N - - + + H - + H - + H - - - - + + + + - - - + + + Cl,Br,I - + H - - + + - - - - - - - - - + + + + + + + + + N - - + + N - + O - + O - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -169,9 +169,9 @@ molfile loader: atom lists are allowed only for queries + - + - + 1,3-Quinazoline 2,4-dione formation @@ -202,63 +202,63 @@ molfile loader: 'any' atoms are allowed only for queries - - + + A - + N - + A - + H - - - + + + - - + + A - + N - + A - - + + O - - - - - - + + + + + + - + - + @@ -284,81 +284,79 @@ AmideFormation.ket - - - - + + + + O - + O - + H - - - - + + + + - - + + N - - + + H - + H - + H - - - - + + + + - - - - + + + + O - + NH - - - - - + + + + + - - + - - + + - + @@ -383,81 +381,79 @@ AmideFormation.ket - - - - + + + + O - + O - + H - - - - + + + + - - + + N - - + + H - + H - + H - - - - + + + + - - - - + + + + O - + NH - - - - - + + + + + - - + - - + + - + @@ -483,81 +479,81 @@ AmideFormation.rxn - - - - + + + + O - + O - + H - - - - + + + + - - + + N - - + + H - + H - + H - - - - + + + + - - - - + + + + O - + NH - - - - - + + + + + + - + - + Amide Formation @@ -585,81 +581,81 @@ AmideFormation.rxn - - - - + + + + O - + O - + H - - - - + + + + - - + + N - - + + H - + H - + H - - - - + + + + - - - - + + + + O - + NH - - - - - + + + + + + - + - + Amide Formation @@ -688,83 +684,83 @@ CN_Bond-S-GRP.rxn - - - - - - + + + + + + R1 - + Br - + - - - - - - + + + + + + R2 - + NH - + H - - + + - - - - - - + + + + + + R2 - - - - - + + + + + R1 - + NH - - + + + - + - + @@ -789,83 +785,83 @@ CN_Bond-S-GRP.rxn - - - - - - + + + + + + R1 - + Br - + - - - - - - + + + + + + R2 - + NH - + H - - + + - - - - - - + + + + + + R2 - - - - - + + + + + R1 - + NH - - + + + - + - + @@ -891,51 +887,51 @@ CN_Bond.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + + - + - + @@ -960,51 +956,51 @@ CN_Bond.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + + - + - + @@ -1030,51 +1026,51 @@ CN_Bond_map.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + + - + - + @@ -1099,51 +1095,51 @@ CN_Bond_map.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + + - + - + @@ -1169,61 +1165,61 @@ Claisen.ket - - - - - - - - + + + + + + + + O - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + OH - - - - - - - - - - + + + + + + + + + + - + - + @@ -1248,61 +1244,61 @@ Claisen.ket - - - - - - - - + + + + + + + + O - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + OH - - - - - - - - - - + + + + + + + + + + - + - + @@ -1328,61 +1324,61 @@ Claisen.rxn - - - - - - - - + + + + + + + + O - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + OH - - - - - - - - - - + + + + + + + + + + - + - + @@ -1407,61 +1403,61 @@ Claisen.rxn - - - - - - - - + + + + + + + + O - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + OH - - - - - - - - - - + + + + + + + + + + - + - + @@ -1487,175 +1483,175 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + OH - + O - + H - + H - - + + R1 - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + N - + H - + H - - - - - + + + + + NH - - + + R2 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + N - + O - + H - + H - + H - - - - - + + + + + NH - - + + R2 - - + + R1 - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + @@ -1680,175 +1676,175 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + OH - + O - + H - + H - - + + R1 - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + N - + H - + H - - - - - + + + + + NH - - + + R2 - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + N - + O - + H - + H - + H - - - - - + + + + + NH - - + + R2 - - + + R1 - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + @@ -1876,79 +1872,79 @@ molfile loader: atom lists are allowed only for queries - - + + A - - + + H - + A - + Cl,Br,I - - - - + + + + - - + + OH - + H - + - - + + A - - + + H - + A - + OH - - - - + + + + + - + - + @@ -1974,101 +1970,101 @@ amiderxn3.rxn - - + + R1 - - + + O - + OH - - - + + + - - + + NH 2 - + R2 - + - - + + R3 - + SH - - - - - + + + + + - - + + R1 - - + + O - + NH - + R2 - - - - + + + + - - + + R3 - + SH - - - - - + + + + + + @@ -2079,9 +2075,9 @@ amiderxn3.rxn + - + - + @@ -2106,101 +2102,101 @@ amiderxn3.rxn - - + + R1 - - + + O - + OH - - - + + + - - + + NH 2 - + R2 - + - - + + R3 - + SH - - - - - + + + + + - - + + R1 - - + + O - + NH - + R2 - - - - + + + + - - + + R3 - + SH - - - - - + + + + + + @@ -2211,9 +2207,9 @@ amiderxn3.rxn + - + - + @@ -2239,40 +2235,40 @@ only_products.rxn - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + @@ -2297,40 +2293,40 @@ only_products.rxn - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + @@ -2356,40 +2352,40 @@ only_reactants.rxn - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + @@ -2414,40 +2410,40 @@ only_reactants.rxn - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + @@ -2473,117 +2469,117 @@ v3000.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + - - - - + + + + NH - - - - + + + + + @@ -2603,9 +2599,9 @@ v3000.rxn + - + - + @@ -2630,117 +2626,117 @@ v3000.rxn - - - - + + + + Br - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - + + NH - - + + H - - + + - - - - + + + + NH - - - - + + + + - - - - + + + + NH - - - - + + + + + @@ -2760,9 +2756,9 @@ v3000.rxn + - + - + diff --git a/api/tests/integration/tests/formats/ket_cdxml_ket.py b/api/tests/integration/tests/formats/ket_cdxml_ket.py new file mode 100644 index 0000000000..fee1010362 --- /dev/null +++ b/api/tests/integration/tests/formats/ket_cdxml_ket.py @@ -0,0 +1,35 @@ +import os +import sys + +sys.path.append( + os.path.normpath( + os.path.join(os.path.abspath(__file__), "..", "..", "..", "common") + ) +) +from env_indigo import * # noqa + +indigo = Indigo() + +print("*** KET to CDXML to KET ***") + +root = joinPathPy("reactions/", __file__) +files = [ + "agents.ket", +] + +files.sort() + +for filename in files: + print(filename) + try: + print("*** Try as Reaction ***") + ket = indigo.loadReactionFromFile(os.path.join(root, filename)) + ket.layout() + cdxml_text = ket.cdxml() + print(cdxml_text) + ket = indigo.loadReaction(cdxml_text) + ket.layout() + print(ket.json()) + except IndigoException as e: + print(getIndigoExceptionText(e)) + print("*** Try as QueryReaction ***") diff --git a/api/tests/integration/tests/formats/reactions/agents.ket b/api/tests/integration/tests/formats/reactions/agents.ket new file mode 100644 index 0000000000..229dd2dc26 --- /dev/null +++ b/api/tests/integration/tests/formats/reactions/agents.ket @@ -0,0 +1,398 @@ +{ + "root": { + "nodes": [ + { + "$ref": "mol0" + }, + { + "$ref": "mol1" + }, + { + "$ref": "mol2" + }, + { + "type": "arrow", + "data": { + "mode": "open-angle", + "pos": [ + { + "x": 8.5, + "y": -5.075, + "z": 0 + }, + { + "x": 12.8, + "y": -5.025, + "z": 0 + } + ] + } + }, + { + "type": "text", + "data": { + "content": "{\"blocks\":[{\"key\":\"2kdue\",\"text\":\"test\",\"type\":\"unstyled\",\"depth\":0,\"inlineStyleRanges\":[],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}", + "position": { + "x": 10.15, + "y": -5.575, + "z": 0 + }, + "pos": [ + { + "x": 10.15, + "y": -5.575, + "z": 0 + }, + { + "x": 10, + "y": -5.885000014305115, + "z": 0 + }, + { + "x": 10.553544950485229, + "y": -5.885000014305115, + "z": 0 + }, + { + "x": 10.553544950485229, + "y": -5.525, + "z": 0 + } + ] + } + } + ] + }, + "mol0": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 6.520544012660644, + -5.3250590038717265, + 0 + ] + }, + { + "label": "C", + "location": [ + 6.520544012660644, + -6.325052596669469, + 0 + ] + }, + { + "label": "C", + "location": [ + 5.654488955625508, + -6.82504939306834, + 0 + ] + }, + { + "label": "C", + "location": [ + 4.788555109934954, + -6.324931385324887, + 0 + ] + }, + { + "label": "C", + "location": [ + 4.788555109934954, + -5.324937792527145, + 0 + ] + }, + { + "label": "C", + "location": [ + 5.654488955625508, + -4.824940996128274, + 0 + ] + }, + { + "label": "C", + "location": [ + 5.654488955625508, + -3.8249474033305315, + 0 + ] + }, + { + "label": "O", + "location": [ + 4.788555109934954, + -3.324950606931661, + 0 + ] + }, + { + "label": "C", + "location": [ + 6.520544012660644, + -3.324950606931661, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 2, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 3 + ] + }, + { + "type": 2, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 2, + "atoms": [ + 0, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 2, + "atoms": [ + 6, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 6, + 8 + ] + } + ] + }, + "mol1": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 17.261444890065047, + -5.7580259267170035, + 0 + ] + }, + { + "label": "C", + "location": [ + 17.261444890065047, + -6.758019519514746, + 0 + ] + }, + { + "label": "C", + "location": [ + 16.39538983302991, + -7.258016315913617, + 0 + ] + }, + { + "label": "C", + "location": [ + 15.529334775994775, + -6.758019519514746, + 0 + ] + }, + { + "label": "C", + "location": [ + 15.529334775994775, + -5.7580259267170035, + 0 + ] + }, + { + "label": "C", + "location": [ + 16.39538983302991, + -5.258029130318132, + 0 + ] + }, + { + "label": "C", + "location": [ + 16.39538983302991, + -4.25803553752039, + 0 + ] + }, + { + "label": "C", + "location": [ + 15.529334775994775, + -3.7580387411215193, + 0 + ] + }, + { + "label": "C", + "location": [ + 14.66340093030422, + -3.258041944722648, + 0 + ] + }, + { + "label": "O", + "location": [ + 16.029331572393644, + -2.8919836840863837, + 0 + ] + }, + { + "label": "C", + "location": [ + 15.029337979595905, + -4.624093798156655, + 0 + ] + } + ], + "bonds": [ + { + "type": 1, + "atoms": [ + 0, + 1 + ] + }, + { + "type": 2, + "atoms": [ + 1, + 2 + ] + }, + { + "type": 1, + "atoms": [ + 2, + 3 + ] + }, + { + "type": 2, + "atoms": [ + 3, + 4 + ] + }, + { + "type": 1, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 2, + "atoms": [ + 0, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 6 + ] + }, + { + "type": 1, + "atoms": [ + 6, + 7 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 8 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 9 + ] + }, + { + "type": 1, + "atoms": [ + 7, + 10 + ] + } + ] + }, + "mol2": { + "type": "molecule", + "atoms": [ + { + "label": "Cl", + "location": [ + 10.475, + -4.500000000000001, + 0 + ] + } + ], + "stereoFlagPosition": { + "x": 10.475, + "y": 3.500000000000001, + "z": 0 + } + } +} \ No newline at end of file diff --git a/core/indigo-core/molecule/metadata_storage.h b/core/indigo-core/molecule/metadata_storage.h index 1e8392daca..b58513d929 100644 --- a/core/indigo-core/molecule/metadata_storage.h +++ b/core/indigo-core/molecule/metadata_storage.h @@ -62,7 +62,10 @@ namespace indigo } int getMetaCount(uint32_t meta_type) const; + int getNonChemicalMetaCount() const; + const MetaObject& getMetaObject(uint32_t meta_type, int index) const; + int getMetaObjectIndex(uint32_t meta_type, int index) const; protected: PtrArray _meta_data; // TODO: should be replaced with list of unique_ptr diff --git a/core/indigo-core/molecule/molecule_cdxml_saver.h b/core/indigo-core/molecule/molecule_cdxml_saver.h index 0e4743ba43..7f09232256 100644 --- a/core/indigo-core/molecule/molecule_cdxml_saver.h +++ b/core/indigo-core/molecule/molecule_cdxml_saver.h @@ -66,6 +66,8 @@ namespace indigo static const int SCALE = 30; static const int MAX_PAGE_HEIGHT = 64; + const float PLUS_HALF_HEIGHT = 7.5 / 2; + struct Bounds { Vec2f min, max; @@ -77,8 +79,11 @@ namespace indigo void addFontToTable(int id, const char* charset, const char* name); void addColorTable(const char* color); void addColorToTable(int id, int r, int g, int b); - void saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale, int id, Array& ids); - void addMetaData(const MetaDataStorage& meta, int id); + void saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale, int frag_id, int& id, std::vector& ids); + void saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale); + + void addMetaObject(const MetaObject& obj, int id); + void addText(const Vec2f& pos, const char* text); void addText(const Vec2f& pos, const char* text, const char* alignment); void addCustomText(const Vec2f& pos, const char* alignment, float line_height, const char* text); @@ -96,6 +101,7 @@ namespace indigo void addDefaultFontTable(); void addDefaultColorTable(); + int getId(); DECL_ERROR; @@ -122,8 +128,8 @@ namespace indigo std::unordered_set _bonds_included; std::vector _out_connections; - Array _atoms_ids; - Array _bonds_ids; + std::vector _atoms_ids; + std::vector _bonds_ids; std::map> _super_atoms; int _id; diff --git a/core/indigo-core/molecule/src/metadata_storage.cpp b/core/indigo-core/molecule/src/metadata_storage.cpp index 5ee8c7912d..0ffb799281 100644 --- a/core/indigo-core/molecule/src/metadata_storage.cpp +++ b/core/indigo-core/molecule/src/metadata_storage.cpp @@ -45,21 +45,21 @@ void MetaDataStorage::clone(const MetaDataStorage& other) append(other); } -const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) const +int MetaDataStorage::getMetaObjectIndex(uint32_t meta_type, int index) const { switch (meta_type) { case KETTextObject::CID: - return *_meta_data[_text_object_indexes[index]]; + return _text_object_indexes[index]; break; case KETSimpleObject::CID: - return *_meta_data[_simple_object_indexes[index]]; + return _simple_object_indexes[index]; break; case KETReactionPlus::CID: - return *_meta_data[_plus_indexes[index]]; + return _plus_indexes[index]; break; case KETReactionArrow::CID: - return *_meta_data[_arrow_indexes[index]]; + return _arrow_indexes[index]; break; default: throw Error("Unknown meta type"); @@ -67,6 +67,16 @@ const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) } } +const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) const +{ + return *_meta_data[getMetaObjectIndex(meta_type, index)]; +} + +int MetaDataStorage::getNonChemicalMetaCount() const +{ + return getMetaCount(KETTextObject::CID) + getMetaCount(KETSimpleObject::CID); +} + int MetaDataStorage::getMetaCount(uint32_t meta_type) const { switch (meta_type) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index db71ca6997..92ec0c100f 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -1016,6 +1016,13 @@ void MoleculeCdxmlLoader::_parseText(const XMLElement* pElem, std::vectorValue(); if (text_element == "s") { + std::string label_plain = pTextStyle->GetText(); + if (label_plain == "+") + { + _pluses.push_back(text_bbox.center()); + return; + } + font_face = 0; font_size = 0.0; auto pStyleAttribute = pTextStyle->FirstAttribute(); @@ -1040,7 +1047,6 @@ void MoleculeCdxmlLoader::_parseText(const XMLElement* pElem, std::vector 0) text_vec_styles.push_back(std::string(KETFontCustomSizeStr) + "_" + std::to_string((int)ceil(font_size)) + "px"); - std::string label_plain = pTextStyle->GetText(); std::remove_if(label_plain.begin(), label_plain.end(), [](char c) { return (c == '\r'); }); auto labels = split(label_plain, '\n'); @@ -1086,8 +1092,12 @@ void MoleculeCdxmlLoader::_parseText(const XMLElement* pElem, std::vector 0 && text_bbox.height() > 0) + tpos.set(text_bbox.center().x, text_bbox.center().y, 0); + + text_parsed.emplace_back(tpos, s.GetString()); } void MoleculeCdxmlLoader::_parseBracket(CdxmlBracket& bracket, const XMLAttribute* pAttr) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp index 9766bc45a9..0ab6b91ba0 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp @@ -32,6 +32,11 @@ using namespace tinyxml2; IMPL_ERROR(MoleculeCdxmlSaver, "molecule CDXML saver"); +int MoleculeCdxmlSaver::getId() +{ + return _id; +} + MoleculeCdxmlSaver::MoleculeCdxmlSaver(Output& output) : _output(output) { _bond_length = SCALE; @@ -799,7 +804,14 @@ void MoleculeCdxmlSaver::addFragmentNodes(BaseMolecule& mol, tinyxml2::XMLElemen } } -void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float structure_scale, int id, Array& ids) +void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale) +{ + std::vector ids; + int id = 0; + saveMoleculeFragment(mol, offset, scale, -1, id, ids); +} + +void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float structure_scale, int frag_id, int& id, std::vector& ids) { _atoms_ids.clear(); _bonds_ids.clear(); @@ -818,9 +830,9 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of _current->LinkEndChild(fragment); _current = fragment; - if (id > 0) + if (frag_id > 0) { - fragment->SetAttribute("id", id); + fragment->SetAttribute("id", frag_id); _id = id; } else @@ -828,16 +840,16 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of if (ids.size()) { - _atoms_ids.copy(ids); - if (_atoms_ids.top() > _id) - _id = _atoms_ids.top(); + _atoms_ids = ids; + if (_atoms_ids.back() > _id) + _id = _atoms_ids.back(); } else for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) - _atoms_ids.push(++_id); + _atoms_ids.push_back(++_id); for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) - _bonds_ids.push(++_id); + _bonds_ids.push_back(++_id); Vec2f min_coord, max_coord; @@ -876,235 +888,240 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of addText(chiral_pos, "Chiral"); _current = fragment; } + + for (int i = 0; i < mol.meta().metaData().size(); ++i) + addMetaObject(*mol.meta().metaData()[i], ++_id); + _current = parent; + id = _id; } -void MoleculeCdxmlSaver::addMetaData(const MetaDataStorage& meta, int id) +void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) { - const auto& meta_objects = meta.metaData(); - for (int meta_index = 0; meta_index < meta_objects.size(); ++meta_index) + PropertiesMap attrs; + attrs.clear(); + switch (obj._class_id) { - id++; - PropertiesMap attrs; - attrs.clear(); - auto pobj = meta_objects[meta_index]; - switch (pobj->_class_id) + case KETReactionArrow::CID: { + KETReactionArrow& ar = (KETReactionArrow&)(obj); + attrs.insert("FillType", "None"); + attrs.insert("ArrowheadType", "Solid"); + attrs.insert("HeadSize", "2250"); + attrs.insert("ArrowheadWidth", "563"); + switch (ar._arrow_type) { - case KETReactionArrow::CID: { - KETReactionArrow& ar = (KETReactionArrow&)(*pobj); - attrs.insert("FillType", "None"); - attrs.insert("ArrowheadType", "Solid"); - attrs.insert("HeadSize", "2250"); - attrs.insert("ArrowheadWidth", "563"); - switch (ar._arrow_type) - { - case KETReactionArrow::EOpenAngle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "25"); - break; - case KETReactionArrow::EFilledTriangle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "2250"); - break; - - case KETReactionArrow::EFilledBow: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "1125"); - break; - - case KETReactionArrow::EDashedOpenAngle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "25"); - attrs.insert("LineType", "Dashed"); - break; - - case KETReactionArrow::EFailed: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "1125"); - attrs.insert("NoGo", "Cross"); - break; - - case KETReactionArrow::EBothEndsFilledTriangle: - attrs.insert("ArrowheadCenterSize", "2250"); - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadTail", "Full"); - break; - - case KETReactionArrow::EEquilibriumFilledHalfBow: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "1125"); - attrs.insert("ArrowShaftSpacing", "300"); - break; - - case KETReactionArrow::EEquilibriumFilledTriangle: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "2250"); - attrs.insert("ArrowShaftSpacing", "300"); - break; - - case KETReactionArrow::EEquilibriumOpenAngle: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "25"); - attrs.insert("ArrowShaftSpacing", "300"); - break; - - case KETReactionArrow::EUnbalancedEquilibriumFilledHalfBow: - break; - - case KETReactionArrow::EUnbalancedEquilibriumLargeFilledHalfBow: - break; - - case KETReactionArrow::EUnbalancedEquilibriumOpenHalfAngle: - break; - - case KETReactionArrow::EUnbalancedEquilibriumFilledHalfTriangle: - break; - - case KETReactionArrow::EEllipticalArcFilledBow: - break; - - case KETReactionArrow::EEllipticalArcFilledTriangle: - break; - - case KETReactionArrow::EEllipticalArcOpenAngle: - break; - - case KETReactionArrow::EEllipticalArcOpenHalfAngle: - break; - - default: - break; - } + case KETReactionArrow::EOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + break; + case KETReactionArrow::EFilledTriangle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "2250"); + break; - Vec3f ar_beg(ar._begin.x, -ar._begin.y, 0); - Vec3f ar_end(ar._end.x, -ar._end.y, 0); - ar_beg.scale(_bond_length); - ar_end.scale(_bond_length); + case KETReactionArrow::EFilledBow: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + break; - attrs.insert("Head3D", std::to_string(ar_end.x) + " " + std::to_string(ar_end.y) + " " + std::to_string(ar_end.z)); - attrs.insert("Tail3D", std::to_string(ar_beg.x) + " " + std::to_string(ar_beg.y) + " " + std::to_string(ar_beg.z)); - addElement("arrow", id, ar._end, ar._begin, attrs); - } - break; - case KETReactionPlus::CID: { - KETReactionPlus& rp = (KETReactionPlus&)(*pobj); + case KETReactionArrow::EDashedOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("LineType", "Dashed"); + break; + + case KETReactionArrow::EFailed: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("NoGo", "Cross"); + break; + + case KETReactionArrow::EBothEndsFilledTriangle: + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadTail", "Full"); + break; + + case KETReactionArrow::EEquilibriumFilledHalfBow: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EEquilibriumFilledTriangle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EEquilibriumOpenAngle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfBow: + break; + + case KETReactionArrow::EUnbalancedEquilibriumLargeFilledHalfBow: + break; + + case KETReactionArrow::EUnbalancedEquilibriumOpenHalfAngle: + break; + + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfTriangle: + break; + + case KETReactionArrow::EEllipticalArcFilledBow: + break; + + case KETReactionArrow::EEllipticalArcFilledTriangle: + break; + + case KETReactionArrow::EEllipticalArcOpenAngle: + break; + + case KETReactionArrow::EEllipticalArcOpenHalfAngle: + break; + + default: + break; } - break; - case KETSimpleObject::CID: { - auto simple_obj = (KETSimpleObject*)pobj; - Rect2f bbox(simple_obj->_coordinates.first, simple_obj->_coordinates.second); - switch (simple_obj->_mode) + + Vec3f ar_beg(ar._begin.x, -ar._begin.y, 0); + Vec3f ar_end(ar._end.x, -ar._end.y, 0); + ar_beg.scale(_bond_length); + ar_end.scale(_bond_length); + + attrs.insert("Head3D", std::to_string(ar_end.x) + " " + std::to_string(ar_end.y) + " " + std::to_string(ar_end.z)); + attrs.insert("Tail3D", std::to_string(ar_beg.x) + " " + std::to_string(ar_beg.y) + " " + std::to_string(ar_beg.z)); + addElement("arrow", id, ar._end, ar._begin, attrs); + } + break; + case KETReactionPlus::CID: { + KETReactionPlus& rp = (KETReactionPlus&)(obj); + attrs.insert("GraphicType", "Symbol"); + attrs.insert("SymbolType", "Plus"); + Vec2f v1(rp._pos.x, rp._pos.y - PLUS_HALF_HEIGHT / _bond_length); + Vec2f v2(rp._pos.x, rp._pos.y + PLUS_HALF_HEIGHT / _bond_length); + addElement("graphic", id, v1, v2, attrs); + } + break; + case KETSimpleObject::CID: { + KETSimpleObject& simple_obj = (KETSimpleObject&)obj; + Rect2f bbox(simple_obj._coordinates.first, simple_obj._coordinates.second); + switch (simple_obj._mode) + { + case KETSimpleObject::EKETEllipse: { + auto ecenter = bbox.center(); + Vec2f maj_axis, min_axis; + if (bbox.width() > bbox.height()) { - case KETSimpleObject::EKETEllipse: { - auto ecenter = bbox.center(); - Vec2f maj_axis, min_axis; - if (bbox.width() > bbox.height()) - { - maj_axis.copy(bbox.rightMiddle()); - min_axis.copy(bbox.topMiddle()); - } - else - { - maj_axis.copy(bbox.topMiddle()); - min_axis.copy(bbox.rightMiddle()); - } - ecenter.scale(_bond_length); - min_axis.scale(_bond_length); - maj_axis.scale(_bond_length); - ecenter.y = -ecenter.y; - min_axis.y = -min_axis.y; - maj_axis.y = -maj_axis.y; - Rect2f bbox_new(ecenter, bbox.rightTop()); - bbox.copy(bbox_new); - attrs.insert("Center3D", std::to_string(ecenter.x) + " " + std::to_string(ecenter.y)); - attrs.insert("MajorAxisEnd3D", std::to_string(maj_axis.x) + " " + std::to_string(maj_axis.y)); - attrs.insert("MinorAxisEnd3D", std::to_string(min_axis.x) + " " + std::to_string(min_axis.y)); - attrs.insert("GraphicType", "Oval"); + maj_axis.copy(bbox.rightMiddle()); + min_axis.copy(bbox.topMiddle()); } - break; - case KETSimpleObject::EKETRectangle: - attrs.insert("GraphicType", "Rectangle"); - break; - case KETSimpleObject::EKETLine: - attrs.insert("GraphicType", "Line"); - break; + else + { + maj_axis.copy(bbox.topMiddle()); + min_axis.copy(bbox.rightMiddle()); } - addElement("graphic", id, bbox.leftBottom(), bbox.rightTop(), attrs); + ecenter.scale(_bond_length); + min_axis.scale(_bond_length); + maj_axis.scale(_bond_length); + ecenter.y = -ecenter.y; + min_axis.y = -min_axis.y; + maj_axis.y = -maj_axis.y; + Rect2f bbox_new(ecenter, bbox.rightTop()); + bbox.copy(bbox_new); + attrs.insert("Center3D", std::to_string(ecenter.x) + " " + std::to_string(ecenter.y)); + attrs.insert("MajorAxisEnd3D", std::to_string(maj_axis.x) + " " + std::to_string(maj_axis.y)); + attrs.insert("MinorAxisEnd3D", std::to_string(min_axis.x) + " " + std::to_string(min_axis.y)); + attrs.insert("GraphicType", "Oval"); } break; - case KETTextObject::CID: { - const KETTextObject& ko = static_cast(*pobj); - double text_offset_y = 0; - int font_size = 13; - CDXMLFontStyle font_face(0); - for (auto& text_item : ko._block) + case KETSimpleObject::EKETRectangle: + attrs.insert("GraphicType", "Rectangle"); + break; + case KETSimpleObject::EKETLine: + attrs.insert("GraphicType", "Line"); + break; + } + addElement("graphic", id, bbox.leftBottom(), bbox.rightTop(), attrs); + } + break; + case KETTextObject::CID: { + const KETTextObject& ko = static_cast(obj); + double text_offset_y = 0; + int font_size = 13; + CDXMLFontStyle font_face(0); + for (auto& text_item : ko._block) + { + int first_index = -1; + int second_index = -1; + double text_offset_x = 0; + FONT_STYLE_SET current_styles; + Vec2f text_origin(ko._pos.x, ko._pos.y); + 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); + t->SetAttribute("id", id); + t->SetAttribute("p", pos_str.c_str()); + t->SetAttribute("Justification", "Left"); + t->SetAttribute("InterpretChemically", "no"); + for (auto& kvp : text_item.styles) { - int first_index = -1; - int second_index = -1; - double text_offset_x = 0; - FONT_STYLE_SET current_styles; - Vec2f text_origin(ko._pos.x, ko._pos.y); - 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); - t->SetAttribute("p", pos_str.c_str()); - t->SetAttribute("Justification", "Left"); - t->SetAttribute("InterpretChemically", "no"); - for (auto& kvp : text_item.styles) + if (first_index == -1) { - if (first_index == -1) - { - first_index = kvp.first; - current_styles = kvp.second; - continue; - } - second_index = kvp.first; + first_index = kvp.first; + current_styles = kvp.second; + continue; + } + second_index = kvp.first; - std::wstring_convert> utf82w; - std::wstring_convert> w2utf8; + 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)); - for (const auto& text_style : current_styles) + auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(text_item.text).substr(first_index, second_index - first_index)); + for (const auto& text_style : current_styles) + { + switch (text_style.first) { - switch (text_style.first) - { - case KETTextObject::EPlain: - break; - case KETTextObject::EBold: - font_face.is_bold = text_style.second; - break; - case KETTextObject::EItalic: - font_face.is_italic = text_style.second; - break; - case KETTextObject::ESuperScript: - font_face.is_superscript = text_style.second; - break; - case KETTextObject::ESubScript: - font_face.is_subscript = text_style.second; - break; - default: - font_size = text_style.second ? text_style.first : 13; - break; - } + case KETTextObject::EPlain: + break; + case KETTextObject::EBold: + font_face.is_bold = text_style.second; + break; + case KETTextObject::EItalic: + font_face.is_italic = text_style.second; + break; + case KETTextObject::ESuperScript: + font_face.is_superscript = text_style.second; + break; + case KETTextObject::ESubScript: + font_face.is_subscript = text_style.second; + break; + default: + font_size = text_style.second ? text_style.first : 13; + break; } - - XMLElement* s = _doc->NewElement("s"); - t->LinkEndChild(s); - s->SetAttribute("font", 4); - s->SetAttribute("size", font_size); - s->SetAttribute("face", font_face.face); - XMLText* txt = _doc->NewText(sub_text.c_str()); - s->LinkEndChild(txt); - current_styles = kvp.second; - first_index = second_index; } + + XMLElement* s = _doc->NewElement("s"); + t->LinkEndChild(s); + s->SetAttribute("font", 4); + s->SetAttribute("size", font_size); + s->SetAttribute("face", font_face.face); + XMLText* txt = _doc->NewText(sub_text.c_str()); + s->LinkEndChild(txt); + current_styles = kvp.second; + first_index = second_index; } } - break; - } + } + break; } } @@ -1341,7 +1358,7 @@ void MoleculeCdxmlSaver::saveMolecule(BaseMolecule& mol) Vec2f offset(-min_coord.x, -max_coord.y); - saveMoleculeFragment(mol, offset, 1, -1, _atoms_ids); + saveMoleculeFragment(mol, offset, 1); endPage(); endDocument(); } diff --git a/core/indigo-core/reaction/reaction_cdxml_saver.h b/core/indigo-core/reaction/reaction_cdxml_saver.h index bfdcd1a294..6b9324c950 100644 --- a/core/indigo-core/reaction/reaction_cdxml_saver.h +++ b/core/indigo-core/reaction/reaction_cdxml_saver.h @@ -53,10 +53,10 @@ namespace indigo void _addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, int arrow_id); void _addScheme(MoleculeCdxmlSaver& molsaver); void _closeScheme(MoleculeCdxmlSaver& molsaver); - void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::unordered_map& mol_ids, ObjArray>& nodes_ids, int arrow_id); - void _generateCdxmlObjIds(BaseReaction& rxn, std::unordered_map& mol_ids, std::unordered_map& meta_ids, - ObjArray>& nodes_ids, int& arrow_id); + void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::vector& mol_ids, std::vector>& nodes_ids, int arrow_id); + void _generateCdxmlObjIds(BaseReaction& rxn, std::vector& mol_ids, std::vector& meta_ids, std::vector>& nodes_ids); void _addTitle(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver); + int _id; }; } // namespace indigo diff --git a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp index c994333f39..5fc36467a4 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp @@ -66,7 +66,7 @@ void _getBounds(BaseMolecule& mol, Vec2f& min, Vec2f& max, float scale) IMPL_ERROR(ReactionCdxmlSaver, "reaction CDXML saver"); -ReactionCdxmlSaver::ReactionCdxmlSaver(Output& output) : _output(output) +ReactionCdxmlSaver::ReactionCdxmlSaver(Output& output) : _output(output), _id(0) { } @@ -77,35 +77,39 @@ ReactionCdxmlSaver::~ReactionCdxmlSaver() void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) { int i; - std::unordered_map mol_ids; - std::unordered_map meta_ids; + std::vector mol_ids; + std::vector meta_ids; - ObjArray> nodes_ids; - - int arrow_id; + std::vector> nodes_ids; MoleculeCdxmlSaver molsaver(_output); MoleculeCdxmlSaver::Bounds b; - _generateCdxmlObjIds(rxn, mol_ids, meta_ids, nodes_ids, arrow_id); - molsaver.beginDocument(NULL); molsaver.addDefaultFontTable(); molsaver.addDefaultColorTable(); molsaver.beginPage(NULL); + _id = molsaver.getId(); + _generateCdxmlObjIds(rxn, mol_ids, meta_ids, nodes_ids); + + int arrow_id = rxn.meta().getMetaCount(KETReactionArrow::CID) ? meta_ids[rxn.meta().getMetaObjectIndex(KETReactionArrow::CID, 0)] : ++_id; + Vec2f offset(0, 0); for (i = rxn.begin(); i != rxn.end(); i = rxn.next(i)) - molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1, mol_ids[i], nodes_ids[i]); + molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1, mol_ids[i], _id, nodes_ids[i]); - _addPlusses(rxn, molsaver); if (rxn.meta().metaData().size()) // we have metadata { - molsaver.addMetaData(rxn.meta(), arrow_id); + for (int i = 0; i < rxn.meta().metaData().size(); ++i) + { + molsaver.addMetaObject(*rxn.meta().metaData()[i], meta_ids[i]); + } } else { + _addPlusses(rxn, molsaver); _addArrow(rxn, molsaver, arrow_id); } @@ -169,7 +173,6 @@ void ReactionCdxmlSaver::_addPlusses(BaseReaction& rxn, MoleculeCdxmlSaver& mols void ReactionCdxmlSaver::_addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, int arrow_id) { - int id = -1; Vec2f p1(0, 0); Vec2f p2(0, 0); PropertiesMap attrs; @@ -270,7 +273,7 @@ void ReactionCdxmlSaver::_addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsav attrs.insert("ArrowType", "FullHead"); attrs.insert("HeadSize", "1000"); - molsaver.addElement("graphic", id, p1, p2, attrs); + molsaver.addElement("graphic", ++_id, p1, p2, attrs); } void ReactionCdxmlSaver::_addScheme(MoleculeCdxmlSaver& molsaver) @@ -291,7 +294,7 @@ void ReactionCdxmlSaver::_closeScheme(MoleculeCdxmlSaver& molsaver) molsaver.endCurrentElement(); } -void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::unordered_map& mol_ids, ObjArray>& nodes_ids, +void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::vector& mol_ids, std::vector>& nodes_ids, int arrow_id) { int id = -1; @@ -305,11 +308,13 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave Array buf; ArrayOutput buf_out(buf); + for (auto i = rxn.reactantBegin(); i < rxn.reactantEnd(); i = rxn.reactantNext(i)) { if (mol_ids[i] > 0) buf_out.printf("%d ", mol_ids[i]); } + if (buf.size() > 1) { buf.pop(); @@ -323,6 +328,7 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave if (mol_ids[i] > 0) buf_out.printf("%d ", mol_ids[i]); } + if (buf.size() > 1) { buf.pop(); @@ -340,6 +346,7 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave above_arrow += std::to_string(mol_ids[i]); } } + if (above_arrow.size()) attrs.insert("ReactionStepObjectsAboveArrow", above_arrow.c_str()); @@ -384,44 +391,29 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave molsaver.addCustomElement(id, name, attrs); } -void ReactionCdxmlSaver::_generateCdxmlObjIds(BaseReaction& rxn, std::unordered_map& mol_ids, std::unordered_map& meta_ids, - ObjArray>& nodes_ids, int& arrow_id) +void ReactionCdxmlSaver::_generateCdxmlObjIds(BaseReaction& rxn, std::vector& mol_ids, std::vector& meta_ids, + std::vector>& nodes_ids) { - int id = 1; - arrow_id = id++; - - // generate ids for meta objects. 1 node and 1 extra object. text or graphics - for (auto i = 0; i < rxn.meta().metaData().size(); ++i) - { - int r_id = i + rxn.end(); - id++; - meta_ids.insert(std::make_pair(r_id, id)); - nodes_ids.expand(r_id + 1); - nodes_ids[r_id].clear_resize(1); - nodes_ids[r_id].zerofill(); - id += 2; - nodes_ids[r_id][0] = id; - } - for (auto i = rxn.begin(); i != rxn.end(); i = rxn.next(i)) { - id++; - mol_ids.insert(std::make_pair(i, id)); + mol_ids.push_back(++_id); BaseMolecule& mol = rxn.getBaseMolecule(i); - - nodes_ids.expand(i + 1); - nodes_ids[i].clear_resize(mol.vertexEnd()); - nodes_ids[i].zerofill(); + nodes_ids.push_back({}); for (auto j = mol.vertexBegin(); j != mol.vertexEnd(); j = mol.vertexNext(j)) - { - id++; - nodes_ids[i][j] = id; - } + nodes_ids[i].push_back(++_id); } - return; + // generate ids for meta objects. 1 node and 1 extra object. text or graphics + for (auto i = 0; i < rxn.meta().metaData().size(); ++i) + { + int r_id = i + rxn.end(); + meta_ids.push_back(++_id); + nodes_ids.push_back({}); + _id += 2; + nodes_ids[r_id].push_back(_id); + } } void ReactionCdxmlSaver::_addTitle(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver) diff --git a/core/indigo-core/reaction/src/reaction_json_saver.cpp b/core/indigo-core/reaction/src/reaction_json_saver.cpp index 72b6746823..1e0edeaddb 100644 --- a/core/indigo-core/reaction/src/reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_json_saver.cpp @@ -282,9 +282,9 @@ void ReactionJsonSaver::saveReaction(BaseReaction& rxn) int arrows_count = rxn.meta().getMetaCount(KETReactionArrow::CID); int simple_count = rxn.meta().getMetaCount(KETSimpleObject::CID) + rxn.meta().getMetaCount(KETTextObject::CID); - if (arrows_count > 1 || simple_count) + if (arrows_count || simple_count) { - // if more than one arrow or metadata + // if metadata presents saveReactionWithMetaData(rxn, *merged, json_saver); } else diff --git a/core/render2d/src/render_cdxml.cpp b/core/render2d/src/render_cdxml.cpp index 8306805cea..0c36555647 100644 --- a/core/render2d/src/render_cdxml.cpp +++ b/core/render2d/src/render_cdxml.cpp @@ -411,7 +411,7 @@ void RenderParamCdxmlInterface::_renderMols(RenderParams& params) Pos& p = positions[mol_idx]; Vec2f offset = p.offset; offset.scale(1 / p.scale); - saver.saveMoleculeFragment(mols[mol_idx]->asMolecule(), offset, p.scale, -1, ids); + saver.saveMoleculeFragment(mols[mol_idx]->asMolecule(), offset, p.scale); if (mol_idx < params.titles.size()) { From 536f77b7a6c7d8e550f18406f02cd7f19875056d Mon Sep 17 00:00:00 2001 From: Mikhail Kviatkovskii Date: Thu, 24 Nov 2022 23:02:28 +0400 Subject: [PATCH 2/6] ci: add bingo-postgres push for master --- .github/workflows/indigo-ci.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/indigo-ci.yaml b/.github/workflows/indigo-ci.yaml index 26df0a325b..988c6712ad 100644 --- a/.github/workflows/indigo-ci.yaml +++ b/.github/workflows/indigo-ci.yaml @@ -957,7 +957,10 @@ jobs: uses: actions/upload-artifact@v2 with: name: bingo-postgres-${{ matrix.postgres_major_version }}-linux-x86_64 - path: dist/bingo-postgres*.tgz + path: dist/bingo-postgres*. + - name: Publish master + if: github.ref == 'refs/heads/master' + run: docker push epmlsop/bingo-postgres:${{ matrix.postgres_major_version }}-latest - name: Publish Test Report if: always() uses: mikepenz/action-junit-report@v1 From 649afb2ce038e37b06268a009f6dc38944c86e59 Mon Sep 17 00:00:00 2001 From: even1024 Date: Fri, 25 Nov 2022 01:17:00 +0300 Subject: [PATCH 3/6] Bugfix/896 cdxml export multistep (#904) * arrow refactoring * multistep fix * tests added * layout comment fix * clang fix Co-authored-by: Roman Porozhnetov --- .../ref/formats/ket_cdxml_ket.py.out | 105 ++++++++++- .../ref/formats/rxn_to_cdxml.py.out | 49 ++--- .../tests/formats/ket_cdxml_ket.py | 1 + .../tests/formats/reactions/multi.ket | 1 + .../integration/tests/formats/rxn_to_cdxml.py | 1 + core/indigo-core/molecule/ket_commons.h | 31 +++- .../molecule/molecule_cdxml_loader.h | 3 - .../molecule/molecule_cdxml_saver.h | 1 + .../molecule/src/molecule_cdxml_loader.cpp | 6 +- .../molecule/src/molecule_cdxml_saver.cpp | 170 +++++++++--------- core/indigo-core/reaction/base_reaction.h | 11 +- .../reaction/reaction_cdxml_saver.h | 3 +- .../reaction/src/reaction_cdxml_loader.cpp | 15 +- .../reaction/src/reaction_cdxml_saver.cpp | 60 ++++--- .../reaction/src/reaction_json_loader.cpp | 70 +++----- 15 files changed, 344 insertions(+), 183 deletions(-) create mode 100644 api/tests/integration/tests/formats/reactions/multi.ket diff --git a/api/tests/integration/ref/formats/ket_cdxml_ket.py.out b/api/tests/integration/ref/formats/ket_cdxml_ket.py.out index b0d7232554..e816b392ef 100644 --- a/api/tests/integration/ref/formats/ket_cdxml_ket.py.out +++ b/api/tests/integration/ref/formats/ket_cdxml_ket.py.out @@ -89,4 +89,107 @@ agents.ket -{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.5,"y":-5.074999809265137,"z":0.0},{"x":12.800000190734864,"y":-5.025000095367432,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"test\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":4,\"style\":\"CUSTOM_FONT_SIZE_20px\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":10.149999618530274,"y":-5.574999809265137,"z":0.0}}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.5,"y":-5.074999809265137,"z":0.0},{"x":12.800000190734864,"y":-5.025000095367432,"z":0.0}]}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[6.520544052124023,-5.325058937072754,0.0]},{"label":"C","location":[6.520544052124023,-6.325052738189697,0.0]},{"label":"C","location":[5.654489040374756,-6.82504940032959,0.0]},{"label":"C","location":[4.788554668426514,-6.324931621551514,0.0]},{"label":"C","location":[4.788554668426514,-5.32493782043457,0.0]},{"label":"C","location":[5.654489040374756,-4.824941158294678,0.0]},{"label":"C","location":[5.654489040374756,-3.8249473571777345,0.0]},{"label":"O","location":[4.788554668426514,-3.324950695037842,0.0]},{"label":"C","location":[6.520544052124023,-3.324950695037842,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":2,"atoms":[6,7]},{"type":1,"atoms":[6,8]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[17.261444091796876,-5.758026123046875,0.0]},{"label":"C","location":[17.261444091796876,-6.75801944732666,0.0]},{"label":"C","location":[16.395389556884767,-7.258016109466553,0.0]},{"label":"C","location":[15.529335975646973,-6.75801944732666,0.0]},{"label":"C","location":[15.529335975646973,-5.758026123046875,0.0]},{"label":"C","location":[16.395389556884767,-5.258028984069824,0.0]},{"label":"C","location":[16.395389556884767,-4.258035659790039,0.0]},{"label":"C","location":[15.529335975646973,-3.7580387592315676,0.0]},{"label":"C","location":[14.663400650024414,-3.2580418586730959,0.0]},{"label":"O","location":[16.02933120727539,-2.8919837474823,0.0]},{"label":"C","location":[15.029337882995606,-4.624094009399414,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[7,9]},{"type":1,"atoms":[7,10]}]},"mol2":{"type":"molecule","atoms":[{"label":"Cl","location":[10.475000381469727,-4.5,0.0]}],"bonds":[]}} +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":8.5,"y":-5.074999809265137,"z":0.0},{"x":12.800000190734864,"y":-5.025000095367432,"z":0.0}]}},{"type":"text","data":{"content":"{\"blocks\":[{\"text\":\"test\",\"inlineStyleRanges\":[{\"offset\":0,\"length\":4,\"style\":\"CUSTOM_FONT_SIZE_20px\"}],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}","position":{"x":10.149999618530274,"y":-5.574999809265137,"z":0.0}}}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[6.520544052124023,-5.325058937072754,0.0]},{"label":"C","location":[6.520544052124023,-6.325052738189697,0.0]},{"label":"C","location":[5.654489040374756,-6.82504940032959,0.0]},{"label":"C","location":[4.788554668426514,-6.324931621551514,0.0]},{"label":"C","location":[4.788554668426514,-5.32493782043457,0.0]},{"label":"C","location":[5.654489040374756,-4.824941158294678,0.0]},{"label":"C","location":[5.654489040374756,-3.8249473571777345,0.0]},{"label":"O","location":[4.788554668426514,-3.324950695037842,0.0]},{"label":"C","location":[6.520544052124023,-3.324950695037842,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":2,"atoms":[6,7]},{"type":1,"atoms":[6,8]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[17.261444091796876,-5.758026123046875,0.0]},{"label":"C","location":[17.261444091796876,-6.75801944732666,0.0]},{"label":"C","location":[16.395389556884767,-7.258016109466553,0.0]},{"label":"C","location":[15.529335975646973,-6.75801944732666,0.0]},{"label":"C","location":[15.529335975646973,-5.758026123046875,0.0]},{"label":"C","location":[16.395389556884767,-5.258028984069824,0.0]},{"label":"C","location":[16.395389556884767,-4.258035659790039,0.0]},{"label":"C","location":[15.529335975646973,-3.7580387592315676,0.0]},{"label":"C","location":[14.663400650024414,-3.2580418586730959,0.0]},{"label":"O","location":[16.02933120727539,-2.8919837474823,0.0]},{"label":"C","location":[15.029337882995606,-4.624094009399414,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":2,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":2,"atoms":[3,4]},{"type":1,"atoms":[4,5]},{"type":2,"atoms":[0,5]},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[6,7]},{"type":1,"atoms":[7,8]},{"type":1,"atoms":[7,9]},{"type":1,"atoms":[7,10]}]},"mol2":{"type":"molecule","atoms":[{"label":"Cl","location":[10.475000381469727,-4.5,0.0]}],"bonds":[]}} +multi.ket +*** Try as Reaction *** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":7.324999809265137,"y":-3.700000047683716,"z":0.0},{"x":10.425000190734864,"y":-3.7249999046325685,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":18.875,"y":-3.575000047683716,"z":0.0},{"x":22.100000381469728,"y":-3.674999952316284,"z":0.0}]}},{"type":"plus","location":[4.400000095367432,-3.6500000953674318,0.0]},{"type":"plus","location":[14.199999809265137,-3.549999952316284,0.0]},{"type":"plus","location":[1.625,-3.674999952316284,0.0]}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[3.532207489013672,-4.122548580169678,0.0]},{"label":"C","location":[3.5285041332244875,-3.127451181411743,0.0]},{"label":"C","location":[2.5202949047088625,-4.109637260437012,0.0]},{"label":"C","location":[2.5177924633026125,-3.127451181411743,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[0,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[2,3]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[5.274374008178711,-4.082470417022705,0.0]},{"label":"C","location":[6.275625705718994,-4.082470417022705,0.0]},{"label":"C","location":[5.775050163269043,-3.217529535293579,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[0,2]},{"type":1,"atoms":[1,2]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[0.4000000059604645,-2.700000047683716,0.0]},{"label":"C","location":[-0.10000000149011612,-3.566025495529175,0.0]},{"label":"C","location":[0.4000000059604645,-4.432050704956055,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[22.55984878540039,-3.050074338912964,0.0]},{"label":"C","location":[24.290151596069337,-3.049588918685913,0.0]},{"label":"C","location":[23.426637649536134,-2.549967050552368,0.0]},{"label":"C","location":[24.290151596069337,-4.05053186416626,0.0]},{"label":"C","location":[22.55984878540039,-4.055019855499268,0.0]},{"label":"C","location":[23.428821563720704,-4.550033092498779,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[0,4]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[10.854475975036621,-3.118603229522705,0.0]},{"label":"C","location":[11.638409614562989,-2.5010316371917726,0.0]},{"label":"C","location":[12.611440658569336,-2.7235817909240724,0.0]},{"label":"C","location":[13.045523643493653,-3.6193912029266359,0.0]},{"label":"C","location":[10.8599853515625,-4.125787734985352,0.0]},{"label":"C","location":[12.612141609191895,-4.526418209075928,0.0]},{"label":"C","location":[11.638409614562989,-4.748968601226807,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":1,"atoms":[3,5]},{"type":1,"atoms":[0,4]},{"type":1,"atoms":[4,6]},{"type":1,"atoms":[5,6]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[15.508987426757813,-2.8249926567077638,0.0]},{"label":"C","location":[15.508987426757813,-3.825007438659668,0.0]},{"label":"C","location":[16.375,-4.325014591217041,0.0]},{"label":"C","location":[17.241010665893556,-3.825007438659668,0.0]},{"label":"C","location":[17.241010665893556,-2.8249926567077638,0.0]},{"label":"C","location":[16.375,-2.3249852657318117,0.0]}],"bonds":[{"type":1,"atoms":[0,5]},{"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]}]}} diff --git a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out index e2b4e3be8e..168882e03b 100644 --- a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out +++ b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out @@ -3,6 +3,7 @@ *** Try as Reaction *** molfile loader: atom lists are allowed only for queries *** Try as QueryReaction *** +1-3-Quinazoline-2-4-dione.rxn @@ -169,7 +170,7 @@ molfile loader: atom lists are allowed only for queries + - + @@ -183,6 +184,7 @@ AcetylateSecondaryAmine.rxn *** Try as Reaction *** molfile loader: 'any' atoms are allowed only for queries *** Try as QueryReaction *** +AcetylateSecondaryAmine.rxn @@ -256,7 +258,7 @@ molfile loader: 'any' atoms are allowed only for queries - + @@ -551,7 +553,7 @@ AmideFormation.rxn + - + @@ -653,7 +655,7 @@ AmideFormation.rxn + - + @@ -758,7 +760,7 @@ CN_Bond-S-GRP.rxn + - + @@ -859,7 +861,7 @@ CN_Bond-S-GRP.rxn + - + @@ -929,7 +931,7 @@ CN_Bond.rxn + - + @@ -998,7 +1000,7 @@ CN_Bond.rxn + - + @@ -1068,7 +1070,7 @@ CN_Bond_map.rxn + - + @@ -1137,7 +1139,7 @@ CN_Bond_map.rxn + - + @@ -1376,7 +1378,7 @@ Claisen.rxn - + @@ -1455,7 +1457,7 @@ Claisen.rxn - + @@ -1649,7 +1651,7 @@ Markush6.rxn + - + @@ -1842,7 +1844,7 @@ Markush6.rxn + - + @@ -1853,6 +1855,7 @@ SN2_XtoOR_Stereo.rxn *** Try as Reaction *** molfile loader: atom lists are allowed only for queries *** Try as QueryReaction *** +SN2_XtoOR_Stereo.rxn @@ -1942,7 +1945,7 @@ molfile loader: atom lists are allowed only for queries + - + @@ -2075,7 +2078,7 @@ amiderxn3.rxn + - + @@ -2207,7 +2210,7 @@ amiderxn3.rxn + - + @@ -2266,7 +2269,7 @@ only_products.rxn + - + @@ -2324,7 +2327,7 @@ only_products.rxn + - + @@ -2383,7 +2386,7 @@ only_reactants.rxn + - + @@ -2441,7 +2444,7 @@ only_reactants.rxn + - + @@ -2599,7 +2602,7 @@ v3000.rxn + - + @@ -2756,7 +2759,7 @@ v3000.rxn + - + diff --git a/api/tests/integration/tests/formats/ket_cdxml_ket.py b/api/tests/integration/tests/formats/ket_cdxml_ket.py index fee1010362..e02e284af1 100644 --- a/api/tests/integration/tests/formats/ket_cdxml_ket.py +++ b/api/tests/integration/tests/formats/ket_cdxml_ket.py @@ -15,6 +15,7 @@ root = joinPathPy("reactions/", __file__) files = [ "agents.ket", + "multi.ket", ] files.sort() diff --git a/api/tests/integration/tests/formats/reactions/multi.ket b/api/tests/integration/tests/formats/reactions/multi.ket new file mode 100644 index 0000000000..368b8be42e --- /dev/null +++ b/api/tests/integration/tests/formats/reactions/multi.ket @@ -0,0 +1 @@ +{"root":{"nodes":[{"$ref":"mol0"},{"$ref":"mol1"},{"$ref":"mol2"},{"$ref":"mol3"},{"$ref":"mol4"},{"$ref":"mol5"},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":7.324999809265137,"y":-3.700000047683716,"z":0.0},{"x":10.425000190734864,"y":-3.7249999046325685,"z":0.0}]}},{"type":"arrow","data":{"mode":"open-angle","pos":[{"x":18.875,"y":-3.575000047683716,"z":0.0},{"x":22.100000381469728,"y":-3.674999952316284,"z":0.0}]}},{"type":"plus","location":[4.400000095367432,-3.6500000953674318,0.0]},{"type":"plus","location":[14.199999809265137,-3.549999952316284,0.0]},{"type":"plus","location":[1.625,-3.674999952316284,0.0]}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[3.532207489013672,-4.122548580169678,0.0]},{"label":"C","location":[3.5285041332244875,-3.127451181411743,0.0]},{"label":"C","location":[2.5202949047088625,-4.109637260437012,0.0]},{"label":"C","location":[2.5177924633026125,-3.127451181411743,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[0,2]},{"type":1,"atoms":[1,3]},{"type":1,"atoms":[2,3]}]},"mol1":{"type":"molecule","atoms":[{"label":"C","location":[5.274374008178711,-4.082470417022705,0.0]},{"label":"C","location":[6.275625705718994,-4.082470417022705,0.0]},{"label":"C","location":[5.775050163269043,-3.217529535293579,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[0,2]},{"type":1,"atoms":[1,2]}]},"mol2":{"type":"molecule","atoms":[{"label":"C","location":[0.4000000059604645,-2.700000047683716,0.0]},{"label":"C","location":[-0.10000000149011612,-3.566025495529175,0.0]},{"label":"C","location":[0.4000000059604645,-4.432050704956055,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]}]},"mol3":{"type":"molecule","atoms":[{"label":"C","location":[22.55984878540039,-3.050074338912964,0.0]},{"label":"C","location":[24.290151596069337,-3.049588918685913,0.0]},{"label":"C","location":[23.426637649536134,-2.549967050552368,0.0]},{"label":"C","location":[24.290151596069337,-4.05053186416626,0.0]},{"label":"C","location":[22.55984878540039,-4.055019855499268,0.0]},{"label":"C","location":[23.428821563720704,-4.550033092498779,0.0]}],"bonds":[{"type":2,"atoms":[2,0]},{"type":2,"atoms":[3,1]},{"type":1,"atoms":[0,4]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[4,5]},{"type":1,"atoms":[5,3]}]},"mol4":{"type":"molecule","atoms":[{"label":"C","location":[10.854475975036621,-3.118603229522705,0.0]},{"label":"C","location":[11.638409614562989,-2.5010316371917726,0.0]},{"label":"C","location":[12.611440658569336,-2.7235817909240724,0.0]},{"label":"C","location":[13.045523643493653,-3.6193912029266359,0.0]},{"label":"C","location":[10.8599853515625,-4.125787734985352,0.0]},{"label":"C","location":[12.612141609191895,-4.526418209075928,0.0]},{"label":"C","location":[11.638409614562989,-4.748968601226807,0.0]}],"bonds":[{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":1,"atoms":[2,3]},{"type":1,"atoms":[3,5]},{"type":1,"atoms":[0,4]},{"type":1,"atoms":[4,6]},{"type":1,"atoms":[5,6]}]},"mol5":{"type":"molecule","atoms":[{"label":"C","location":[15.508987426757813,-2.8249926567077638,0.0]},{"label":"C","location":[15.508987426757813,-3.825007438659668,0.0]},{"label":"C","location":[16.375,-4.325014591217041,0.0]},{"label":"C","location":[17.241010665893556,-3.825007438659668,0.0]},{"label":"C","location":[17.241010665893556,-2.8249926567077638,0.0]},{"label":"C","location":[16.375,-2.3249852657318117,0.0]}],"bonds":[{"type":1,"atoms":[0,5]},{"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]}]}} \ No newline at end of file diff --git a/api/tests/integration/tests/formats/rxn_to_cdxml.py b/api/tests/integration/tests/formats/rxn_to_cdxml.py index 4f58a19871..ea420a2583 100644 --- a/api/tests/integration/tests/formats/rxn_to_cdxml.py +++ b/api/tests/integration/tests/formats/rxn_to_cdxml.py @@ -30,4 +30,5 @@ print("*** Try as QueryReaction ***") rxn = indigo.loadQueryReactionFromFile(os.path.join(root, filename)) indigo.setOption("layout-horintervalfactor", "1.4") + print(filename) print(rxn.cdxml()) diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index 89afef6428..c00716f771 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -37,6 +37,10 @@ namespace indigo const auto KETFontSuperscriptStr = "SUPERSCRIPT"; const auto KETFontSubscriptStr = "SUBSCRIPT"; const auto KETFontCustomSizeStr = "CUSTOM_FONT_SIZE"; + const uint8_t KETReactantArea = 0; + const uint8_t KETReagentUpArea = 1; + const uint8_t KETReagentDownArea = 2; + const uint8_t KETProductArea = 3; struct compareFunction { @@ -58,6 +62,28 @@ namespace indigo return string_hash(s, count); } + inline 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 |= KETReagentUpArea; + + if (std::signbit(dt2)) + bit_mask |= KETReagentDownArea; + + return bit_mask; + } + class KETSimpleObject : public MetaObject { public: @@ -285,8 +311,8 @@ namespace indigo CONNECTED = -1 }; - ReactionComponent(int ctype, const Rect2f& box, std::unique_ptr mol) - : component_type(ctype), bbox(box), molecule(std::move(mol)), summ_block_idx(NOT_CONNECTED){}; + 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; @@ -294,6 +320,7 @@ namespace indigo std::list::iterator summ_block_it; int summ_block_idx; std::vector coordinates; + int index; }; } diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index 61bfeb2af3..eb675ca10b 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -259,9 +259,6 @@ namespace indigo std::vector _fragment_nodes; std::vector _pluses; std::vector, int>> _arrows; - - std::unordered_set _superced_ids; - float _bond_length; std::vector _stereo_centers; diff --git a/core/indigo-core/molecule/molecule_cdxml_saver.h b/core/indigo-core/molecule/molecule_cdxml_saver.h index 7f09232256..adc1b41f62 100644 --- a/core/indigo-core/molecule/molecule_cdxml_saver.h +++ b/core/indigo-core/molecule/molecule_cdxml_saver.h @@ -83,6 +83,7 @@ namespace indigo void saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale); void addMetaObject(const MetaObject& obj, int id); + void addArrow(int id, int arrow_type, const Vec2f& beg, const Vec2f& end); void addText(const Vec2f& pos, const char* text); void addText(const Vec2f& pos, const char* text, const char* alignment); diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 92ec0c100f..72db1ea69c 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -60,6 +60,7 @@ void MoleculeCdxmlLoader::_initMolecule(BaseMolecule& mol) mol.clear(); nodes.clear(); bonds.clear(); + _arrows.clear(); _id_to_atom_idx.clear(); _id_to_node_index.clear(); _id_to_bond_index.clear(); @@ -930,10 +931,7 @@ void MoleculeCdxmlLoader::_parseGraphic(const XMLElement* pElem) auto pAttr = pElem->FirstAttribute(); applyDispatcher(pAttr, graphic_dispatcher); - if (graphic_type == "Line" && arrow_type == "FullHead") - { - } - else if (graphic_type == "Symbol" && symbol_type == "Plus") + if (graphic_type == "Symbol" && symbol_type == "Plus") { _pluses.emplace_back(graph_bbox.center()); } diff --git a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp index 0ab6b91ba0..c4b66635f4 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp @@ -896,109 +896,115 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of id = _id; } -void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) +void MoleculeCdxmlSaver::addArrow(int id, int arrow_type, const Vec2f& beg, const Vec2f& end) { PropertiesMap attrs; - attrs.clear(); - switch (obj._class_id) + attrs.insert("FillType", "None"); + attrs.insert("ArrowheadType", "Solid"); + attrs.insert("HeadSize", "2250"); + attrs.insert("ArrowheadWidth", "563"); + switch (arrow_type) { - case KETReactionArrow::CID: { - KETReactionArrow& ar = (KETReactionArrow&)(obj); - attrs.insert("FillType", "None"); - attrs.insert("ArrowheadType", "Solid"); - attrs.insert("HeadSize", "2250"); - attrs.insert("ArrowheadWidth", "563"); - switch (ar._arrow_type) - { - case KETReactionArrow::EOpenAngle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "25"); - break; - case KETReactionArrow::EFilledTriangle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "2250"); - break; + case KETReactionArrow::EOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + break; + case KETReactionArrow::EFilledTriangle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "2250"); + break; - case KETReactionArrow::EFilledBow: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "1125"); - break; + case KETReactionArrow::EFilledBow: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + break; - case KETReactionArrow::EDashedOpenAngle: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "25"); - attrs.insert("LineType", "Dashed"); - break; + case KETReactionArrow::EDashedOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("LineType", "Dashed"); + break; - case KETReactionArrow::EFailed: - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadCenterSize", "1125"); - attrs.insert("NoGo", "Cross"); - break; + case KETReactionArrow::EFailed: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("NoGo", "Cross"); + break; - case KETReactionArrow::EBothEndsFilledTriangle: - attrs.insert("ArrowheadCenterSize", "2250"); - attrs.insert("ArrowheadHead", "Full"); - attrs.insert("ArrowheadTail", "Full"); - break; + case KETReactionArrow::EBothEndsFilledTriangle: + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadTail", "Full"); + break; - case KETReactionArrow::EEquilibriumFilledHalfBow: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "1125"); - attrs.insert("ArrowShaftSpacing", "300"); - break; + case KETReactionArrow::EEquilibriumFilledHalfBow: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("ArrowShaftSpacing", "300"); + break; - case KETReactionArrow::EEquilibriumFilledTriangle: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "2250"); - attrs.insert("ArrowShaftSpacing", "300"); - break; + case KETReactionArrow::EEquilibriumFilledTriangle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowShaftSpacing", "300"); + break; - case KETReactionArrow::EEquilibriumOpenAngle: - attrs.insert("ArrowheadHead", "HalfLeft"); - attrs.insert("ArrowheadTail", "HalfLeft"); - attrs.insert("ArrowheadCenterSize", "25"); - attrs.insert("ArrowShaftSpacing", "300"); - break; + case KETReactionArrow::EEquilibriumOpenAngle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("ArrowShaftSpacing", "300"); + break; - case KETReactionArrow::EUnbalancedEquilibriumFilledHalfBow: - break; + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfBow: + break; - case KETReactionArrow::EUnbalancedEquilibriumLargeFilledHalfBow: - break; + case KETReactionArrow::EUnbalancedEquilibriumLargeFilledHalfBow: + break; - case KETReactionArrow::EUnbalancedEquilibriumOpenHalfAngle: - break; + case KETReactionArrow::EUnbalancedEquilibriumOpenHalfAngle: + break; - case KETReactionArrow::EUnbalancedEquilibriumFilledHalfTriangle: - break; + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfTriangle: + break; - case KETReactionArrow::EEllipticalArcFilledBow: - break; + case KETReactionArrow::EEllipticalArcFilledBow: + break; - case KETReactionArrow::EEllipticalArcFilledTriangle: - break; + case KETReactionArrow::EEllipticalArcFilledTriangle: + break; - case KETReactionArrow::EEllipticalArcOpenAngle: - break; + case KETReactionArrow::EEllipticalArcOpenAngle: + break; - case KETReactionArrow::EEllipticalArcOpenHalfAngle: - break; + case KETReactionArrow::EEllipticalArcOpenHalfAngle: + break; - default: - break; - } + default: + break; + } - Vec3f ar_beg(ar._begin.x, -ar._begin.y, 0); - Vec3f ar_end(ar._end.x, -ar._end.y, 0); - ar_beg.scale(_bond_length); - ar_end.scale(_bond_length); + Vec3f ar_beg(beg.x, -beg.y, 0); + Vec3f ar_end(end.x, -end.y, 0); + ar_beg.scale(_bond_length); + ar_end.scale(_bond_length); - attrs.insert("Head3D", std::to_string(ar_end.x) + " " + std::to_string(ar_end.y) + " " + std::to_string(ar_end.z)); - attrs.insert("Tail3D", std::to_string(ar_beg.x) + " " + std::to_string(ar_beg.y) + " " + std::to_string(ar_beg.z)); - addElement("arrow", id, ar._end, ar._begin, attrs); + attrs.insert("Head3D", std::to_string(ar_end.x) + " " + std::to_string(ar_end.y) + " " + std::to_string(ar_end.z)); + attrs.insert("Tail3D", std::to_string(ar_beg.x) + " " + std::to_string(ar_beg.y) + " " + std::to_string(ar_beg.z)); + addElement("arrow", id, end, beg, attrs); +} + +void MoleculeCdxmlSaver::addMetaObject(const MetaObject& obj, int id) +{ + PropertiesMap attrs; + attrs.clear(); + switch (obj._class_id) + { + case KETReactionArrow::CID: { + KETReactionArrow& ar = (KETReactionArrow&)(obj); + addArrow(id, ar._arrow_type, ar._begin, ar._end); } break; case KETReactionPlus::CID: { diff --git a/core/indigo-core/reaction/base_reaction.h b/core/indigo-core/reaction/base_reaction.h index cdc001c955..2a7d5135da 100644 --- a/core/indigo-core/reaction/base_reaction.h +++ b/core/indigo-core/reaction/base_reaction.h @@ -79,12 +79,13 @@ namespace indigo public: void copy(const ReactionBlock& other) { - indexes.copy(other.indexes); - arrows_to.copy(other.arrows_to); + reactants.copy(other.reactants); + products.copy(other.products); + arrow_index = other.arrow_index; } - Array indexes; - Array arrows_to; - int role; + Array reactants; + Array products; + int arrow_index; }; class DLLEXPORT BaseReaction : public NonCopyable diff --git a/core/indigo-core/reaction/reaction_cdxml_saver.h b/core/indigo-core/reaction/reaction_cdxml_saver.h index 6b9324c950..5015d52e26 100644 --- a/core/indigo-core/reaction/reaction_cdxml_saver.h +++ b/core/indigo-core/reaction/reaction_cdxml_saver.h @@ -53,7 +53,8 @@ namespace indigo void _addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, int arrow_id); void _addScheme(MoleculeCdxmlSaver& molsaver); void _closeScheme(MoleculeCdxmlSaver& molsaver); - void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::vector& mol_ids, std::vector>& nodes_ids, int arrow_id); + void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::vector& mol_ids, std::vector>& nodes_ids, + const std::pair& arrow_id); void _generateCdxmlObjIds(BaseReaction& rxn, std::vector& mol_ids, std::vector& meta_ids, std::vector>& nodes_ids); void _addTitle(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver); int _id; diff --git a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp index b6a2091742..ae7da6b3b0 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp @@ -183,6 +183,20 @@ void ReactionCdxmlLoader::loadReaction(BaseReaction& rxn) } } + for (auto id : intermediates_ids) + { + auto elem_it = _cdxml_elements.find(id); + if (elem_it != _cdxml_elements.end()) + { + loader.loadMoleculeFromFragment(*_pmol, elem_it->second); + if (_pmol->vertexCount()) + rxn.addIntermediateCopy(*_pmol, 0, 0); + else + throw Error("Empty product: %d", id); + _cdxml_elements.erase(elem_it); + } + } + for (auto id : agents_ids) { auto elem_it = _cdxml_elements.find(id); @@ -199,7 +213,6 @@ void ReactionCdxmlLoader::loadReaction(BaseReaction& rxn) 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))); } - _pmol->meta().resetMetaData(); } _cdxml_elements.erase(elem_it); } diff --git a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp index 5fc36467a4..96bda277dd 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp @@ -93,7 +93,18 @@ void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) _id = molsaver.getId(); _generateCdxmlObjIds(rxn, mol_ids, meta_ids, nodes_ids); - int arrow_id = rxn.meta().getMetaCount(KETReactionArrow::CID) ? meta_ids[rxn.meta().getMetaObjectIndex(KETReactionArrow::CID, 0)] : ++_id; + std::vector> arrow_ids; + int arrow_count = rxn.meta().getMetaCount(KETReactionArrow::CID); + if (arrow_count) + { + for (int i = 0; i < arrow_count; ++i) + { + int array_index = rxn.meta().getMetaObjectIndex(KETReactionArrow::CID, i); + arrow_ids.emplace_back(meta_ids[array_index], arrow_count > 1 ? array_index : -1); + } + } + else + arrow_ids.emplace_back(++_id, -1); Vec2f offset(0, 0); @@ -110,11 +121,12 @@ void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) else { _addPlusses(rxn, molsaver); - _addArrow(rxn, molsaver, arrow_id); + _addArrow(rxn, molsaver, arrow_ids.front().first); } _addScheme(molsaver); - _addStep(rxn, molsaver, mol_ids, nodes_ids, arrow_id); + for (const auto& ar_id : arrow_ids) + _addStep(rxn, molsaver, mol_ids, nodes_ids, ar_id); _closeScheme(molsaver); if (rxn.name.size() > 0) @@ -263,17 +275,7 @@ void ReactionCdxmlSaver::_addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsav } } - Array buf; - ArrayOutput buf_out(buf); - buf_out.printf("%d", arrow_id); - buf.push(0); - - attrs.insert("id", buf.ptr()); - attrs.insert("GraphicType", "Line"); - attrs.insert("ArrowType", "FullHead"); - attrs.insert("HeadSize", "1000"); - - molsaver.addElement("graphic", ++_id, p1, p2, attrs); + molsaver.addArrow(arrow_id, KETReactionArrow::EOpenAngle, p2, p1); } void ReactionCdxmlSaver::_addScheme(MoleculeCdxmlSaver& molsaver) @@ -295,7 +297,7 @@ void ReactionCdxmlSaver::_closeScheme(MoleculeCdxmlSaver& molsaver) } void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::vector& mol_ids, std::vector>& nodes_ids, - int arrow_id) + const std::pair& arrow_id) { int id = -1; Array name; @@ -309,9 +311,18 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave Array buf; ArrayOutput buf_out(buf); - for (auto i = rxn.reactantBegin(); i < rxn.reactantEnd(); i = rxn.reactantNext(i)) + if (arrow_id.second < 0) { - if (mol_ids[i] > 0) + for (auto i = rxn.reactantBegin(); i < rxn.reactantEnd(); i = rxn.reactantNext(i)) + { + if (mol_ids[i] > 0) + buf_out.printf("%d ", mol_ids[i]); + } + } + else + { + auto& rb = rxn.reactionBlock(arrow_id.second); + for (auto i : rb.reactants) buf_out.printf("%d ", mol_ids[i]); } @@ -323,9 +334,18 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave } buf.clear(); - for (auto i = rxn.productBegin(); i < rxn.productEnd(); i = rxn.productNext(i)) + if (arrow_id.second < 0) { - if (mol_ids[i] > 0) + for (auto i = rxn.productBegin(); i < rxn.productEnd(); i = rxn.productNext(i)) + { + if (mol_ids[i] > 0) + buf_out.printf("%d ", mol_ids[i]); + } + } + else + { + auto& rb = rxn.reactionBlock(arrow_id.second); + for (auto i : rb.products) buf_out.printf("%d ", mol_ids[i]); } @@ -354,7 +374,7 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave attrs.insert("ReactionStepObjectsAboveArrow", above_arrow.c_str()); buf.clear(); - buf_out.printf("%d", arrow_id); + buf_out.printf("%d", arrow_id.first); buf.push(0); attrs.insert("ReactionStepArrows", buf.ptr()); diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index c0bdde8032..fd0c93d07b 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -206,16 +206,6 @@ void ReactionJsonLoader::constructMultipleArrowReaction(BaseReaction& rxn) } } } - - for (auto& cb : _component_summ_blocks) - { - auto& rb = rxn.addReactionBlock(); - rb.role = cb.role; - for (auto v : cb.indexes) - rb.indexes.push() = v; - for (auto v : cb.arrows_to) - rb.arrows_to.push() = v; - } } void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) @@ -256,7 +246,7 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) mol_bottoms.emplace_back(bbox.bottom(), i); mol_lefts.emplace_back(bbox.left(), i); mol_rights.emplace_back(bbox.right(), i); - _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, std::move(component)); + _reaction_components.emplace_back(ReactionComponent::MOLECULE, bbox, i, std::move(component)); } for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) @@ -264,7 +254,7 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) auto& plus = (const KETReactionPlus&)rxn.meta().getMetaObject(KETReactionPlus::CID, i); const Vec2f& plus_pos = plus._pos; Rect2f bbox(plus_pos - PLUS_BBOX_SHIFT, plus_pos + PLUS_BBOX_SHIFT); - _reaction_components.emplace_back(ReactionComponent::PLUS, bbox, std::unique_ptr(nullptr)); + _reaction_components.emplace_back(ReactionComponent::PLUS, bbox, i, std::unique_ptr(nullptr)); _reaction_components.back().coordinates.push_back(plus_pos); int index = _reaction_components.size() - 1; mol_tops.emplace_back(bbox.top(), index); @@ -280,7 +270,7 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) const Vec2f& arr_begin = arrow._begin; const Vec2f& arr_end = arrow._end; Rect2f bbox(arr_begin - ARROW_BBOX_SHIFT, arr_end + ARROW_BBOX_SHIFT); - _reaction_components.emplace_back(arrow_type, bbox, std::unique_ptr(nullptr)); + _reaction_components.emplace_back(arrow_type, bbox, i, std::unique_ptr(nullptr)); _reaction_components.back().coordinates.push_back(arr_begin); _reaction_components.back().coordinates.push_back(arr_end); int index = _reaction_components.size() - 1; @@ -406,7 +396,8 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) int arrow_type = arrow._arrow_type; const Vec2f& arr_begin = arrow._begin; const Vec2f& arr_end = arrow._end; - float min_dist_prod = -1, min_dist_reac = -1, idx_cs_min_prod = -1, idx_cs_min_reac = -1; + float min_dist_prod = -1, min_dist_reac = -1; + int idx_cs_min_prod = -1, idx_cs_min_reac = -1; for (int index_cs = 0; index_cs < _component_summ_blocks.size(); ++index_cs) { auto& csb = _component_summ_blocks[index_cs]; @@ -430,10 +421,13 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) } } + auto& rb = rxn.addReactionBlock(); + rb.arrow_index = i; + if (min_dist_prod > 0 && min_dist_reac > 0) // if both ends present { - _reaction_components[count + rxn.meta().getMetaCount(KETReactionPlus::CID) + i].summ_block_idx = - ReactionComponent::CONNECTED; // mark arrow as connected + auto& rc_arrow = _reaction_components[count + rxn.meta().getMetaCount(KETReactionPlus::CID) + i]; + rc_arrow.summ_block_idx = ReactionComponent::CONNECTED; // mark arrow as connected auto& csb_min_prod = _component_summ_blocks[idx_cs_min_prod]; if (csb_min_prod.role == BaseReaction::UNDEFINED) csb_min_prod.role = BaseReaction::PRODUCT; @@ -448,6 +442,10 @@ void ReactionJsonLoader::parseMultipleArrowReaction(BaseReaction& rxn) // idx_cs_min_reac -> idx_cs_min_prod csb_min_reac.arrows_to.push_back(idx_cs_min_prod); + for (auto ri : csb_min_reac.indexes) + rb.reactants.push(_reaction_components[ri].index); + for (auto pi : csb_min_prod.indexes) + rb.products.push(_reaction_components[pi].index); } } @@ -493,13 +491,11 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) } auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, 0); - Vec2f arrow_vec(arrow._begin); - arrow_vec.sub(arrow._end); for (int i = 0; i < rxn.meta().getMetaCount(KETTextObject::CID); ++i) { - auto& text = (const KETReactionPlus&)rxn.meta().getMetaObject(KETTextObject::CID, i); - Rect2f bbox(text._pos, text._pos); // change to real text box later + 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 components.emplace_back(bbox, ReactionFragmentType::TEXT, nullptr); } @@ -512,39 +508,31 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) auto& cmol = *std::get(comp); for (int idx = cmol.vertexBegin(); idx < cmol.vertexEnd(); idx = cmol.vertexNext(idx)) { - Vec3f& v3 = cmol.getAtomXyz(idx); - Vec2f slope1(v3.x, v3.y); - Vec2f slope2(slope1); - slope1.sub(arrow._begin); - slope2.sub(arrow._end); - auto dt1 = Vec2f::dot(slope1, arrow_vec); - auto dt2 = Vec2f::dot(slope2, arrow_vec); - if (std::signbit(dt1) != std::signbit(dt2)) + Vec3f& pt3d = cmol.getAtomXyz(idx); + Vec2f pt(pt3d.x, pt3d.y); + int side = getPointSide(pt, arrow._begin, arrow._end); + switch (side) { + case KETReagentUpArea: + case KETReagentDownArea: rxn.addCatalystCopy(cmol, 0, 0); break; - } - else if (std::signbit(dt1) && std::signbit(dt2)) - { + case KETProductArea: rxn.addProductCopy(cmol, 0, 0); break; - } - else - { + default: rxn.addReactantCopy(cmol, 0, 0); break; } + break; } } + break; case ReactionFragmentType::TEXT: { const auto& bbox = std::get(comp); - Vec2f slope1(bbox.leftTop().x, bbox.leftTop().y); - Vec2f slope2(slope1); - slope1.sub(arrow._begin); - slope2.sub(arrow._end); - auto dt1 = Vec2f::dot(slope1, arrow_vec); - auto dt2 = Vec2f::dot(slope2, arrow_vec); - if (std::signbit(dt1) != std::signbit(dt2)) + Vec2f pt(bbox.center()); + int side = getPointSide(pt, arrow._begin, arrow._end); + if (side == KETReagentUpArea || side == KETReagentDownArea) { rxn.addSpecialCondition(text_meta_idx, bbox); break; From 9508247149d1b1dbf455e4cb9340566e8d2d9758 Mon Sep 17 00:00:00 2001 From: Konstantin Perikov Date: Fri, 25 Nov 2022 12:56:43 +0000 Subject: [PATCH 4/6] Improve ssl bingo elastic (#863) * improve ssl ignoring for opensearch instances * update versions * update imports * properly ignore opensearch test * ignore in surefire --- bingo/bingo-elastic/java/pom.xml | 9 ++- .../indigo/elastic/ElasticRepository.java | 67 +++++++++++++++---- .../java/com/epam/indigo/BaseElasticTest.java | 6 +- .../epam/indigo/BaseLocalOpensearchTest.java | 43 ++++++++++++ .../com/epam/indigo/elastic/BatchTest.java | 3 +- .../elastic/CompareLargeFileTestIT.java | 2 +- .../indigo/elastic/FullUsageMoleculeTest.java | 3 +- .../elastic/LoadMoleculeFromFileTest.java | 3 +- .../elastic/NoSQLElasticCompareAbstract.java | 4 +- .../elastic/RepositoryValidationTest.java | 4 +- .../SaveMoleculeFromIndigoRecordTest.java | 3 +- .../epam/indigo/predicate/ReactionsTest.java | 1 - 12 files changed, 121 insertions(+), 27 deletions(-) create mode 100644 bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseLocalOpensearchTest.java diff --git a/bingo/bingo-elastic/java/pom.xml b/bingo/bingo-elastic/java/pom.xml index 6ae5320e95..0df0ee1caa 100644 --- a/bingo/bingo-elastic/java/pom.xml +++ b/bingo/bingo-elastic/java/pom.xml @@ -53,18 +53,18 @@ org.elasticsearch.client elasticsearch-rest-high-level-client - 7.16.2 + 7.13.0 org.junit.jupiter junit-jupiter - 5.8.2 + 5.9.0 test org.testcontainers elasticsearch - 1.16.2 + 1.17.6 test @@ -87,6 +87,9 @@ 2.22.2 0 + + com.epam.indigo.BaseLocalOpensearchTest + diff --git a/bingo/bingo-elastic/java/src/main/java/com/epam/indigo/elastic/ElasticRepository.java b/bingo/bingo-elastic/java/src/main/java/com/epam/indigo/elastic/ElasticRepository.java index 7fad79c54f..1237a649f8 100644 --- a/bingo/bingo-elastic/java/src/main/java/com/epam/indigo/elastic/ElasticRepository.java +++ b/bingo/bingo-elastic/java/src/main/java/com/epam/indigo/elastic/ElasticRepository.java @@ -24,10 +24,16 @@ import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import java.io.IOException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; import java.util.*; import java.util.function.Consumer; import java.util.stream.Stream; @@ -41,7 +47,7 @@ public class ElasticRepository implements GenericRepository { private String indexName; - private String hostName; + private List hostsNames; private int port; private String scheme; private String userName; @@ -225,8 +231,8 @@ public ElasticRepositoryBuilder withIndexName(String indexName) { return this; } - public ElasticRepositoryBuilder withHostName(String hostName) { - operations.add(repo -> repo.hostName = hostName); + public ElasticRepositoryBuilder withHostsNames(List hostsNames) { + operations.add(repo -> repo.hostsNames = hostsNames); return this; } @@ -279,16 +285,22 @@ public ElasticRepository build() { ElasticRepository repository = new ElasticRepository<>(); operations.forEach(operation -> operation.accept(repository)); if (repository.elasticClient == null) { - RestClientBuilder builder = RestClient.builder(new HttpHost(repository.hostName, repository.port, repository.scheme)); + RestClientBuilder builder = RestClient.builder(repository.hostsNames.stream().map(hostName -> new HttpHost(hostName, repository.port, repository.scheme)).toArray(HttpHost[]::new)); if (repository.userName != null && repository.password != null) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(repository.userName, repository.password)); - builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder - .disableAuthCaching() - .setSSLHostnameVerifier((s, sslSession) -> repository.ignoreSSL) - .setDefaultCredentialsProvider(credentialsProvider)); + if (repository.ignoreSSL) { + builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder + .disableAuthCaching() + .setSSLContext(initSSLContext()) + .setSSLHostnameVerifier((s, sslSession) -> repository.ignoreSSL) + .setDefaultCredentialsProvider(credentialsProvider)); + } else { + builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder + .setDefaultCredentialsProvider(credentialsProvider)); + } } repository.elasticClient = new RestHighLevelClient(builder); } @@ -296,6 +308,33 @@ public ElasticRepository build() { return repository; } + private SSLContext initSSLContext() { + SSLContext sc = null; + try { + TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } + }; + // Install the all-trusting trust manager + sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + } catch (NoSuchAlgorithmException e) { + throw new BingoElasticException( + "Elasticsearch isn't started at"); + } catch (KeyManagementException e) { + throw new RuntimeException(e); + } + return sc; + } + private void validate(ElasticRepository repository) { boolean ping; if (null == repository.indexName || repository.indexName.isEmpty()) { @@ -304,13 +343,13 @@ private void validate(ElasticRepository repository) { try { ping = repository.elasticClient.ping(RequestOptions.DEFAULT); if (!ping) { - throw new BingoElasticException("Elasticsearch isn't started at " + repository.hostName + ":" + repository.port); + throw new BingoElasticException("Elasticsearch isn't started at " + repository.scheme + "://" + repository.hostsNames + ":" + repository.port); } } catch (IOException e) { - throw new BingoElasticException("Elasticsearch isn't started at " + repository.hostName + ":" + repository.port); + throw new BingoElasticException("Elasticsearch isn't started at " + repository.scheme + "://" + repository.hostsNames + ":" + repository.port); } catch (ElasticsearchException e) { - throw new BingoElasticException("Elasticsearch isn't started at " + repository.hostName + ":" + repository.port - + " " + e.getDetailedMessage()); + throw new BingoElasticException("Elasticsearch isn't started at " + repository.scheme + "://" + repository.hostsNames + ":" + repository.port + + " " + e.getDetailedMessage()); } } diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseElasticTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseElasticTest.java index 00a0dc2be8..77e4d74825 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseElasticTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseElasticTest.java @@ -9,6 +9,8 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer; import org.testcontainers.utility.DockerImageName; +import java.util.Collections; + /** * This class provides elastic connection for any tests based on Elasticsearch */ @@ -35,7 +37,7 @@ protected static void setUpRepository(Class recordClassR ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); repositoryReaction = builder.withIndexName(NamingConstants.BINGO_REACTIONS) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withRefreshInterval("1s") @@ -44,7 +46,7 @@ protected static void setUpRepository(Class recordClassR ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); repositoryMolecule = builder.withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withRefreshInterval("1s") diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseLocalOpensearchTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseLocalOpensearchTest.java new file mode 100644 index 0000000000..76484b44f2 --- /dev/null +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/BaseLocalOpensearchTest.java @@ -0,0 +1,43 @@ +package com.epam.indigo; + +import com.epam.indigo.elastic.ElasticRepository; +import com.epam.indigo.model.Helpers; +import com.epam.indigo.model.IndigoRecord; +import com.epam.indigo.model.NamingConstants; +import com.epam.indigo.predicate.SimilarityMatch; +import org.junit.Ignore; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/*** + * Test for local usage for OpenSearch connectivity. Ignored for now + */ +public class BaseLocalOpensearchTest { + + @Test + @Ignore + public void connectivityTest() { + ElasticRepository.ElasticRepositoryBuilder builder + = new ElasticRepository.ElasticRepositoryBuilder<>(); + ElasticRepository repository = builder.withIndexName(NamingConstants.BINGO_MOLECULES) + .withHostsNames(Collections.singletonList("localhost")) + .withPort(9201) + .withScheme("https") + .withUserName("admin") + .withPassword("admin") + .withRefreshInterval("1s") + .withIgnoreSSL(true) + .build(); + assertNotNull(repository); + List indigoResult = repository.stream().limit(10).filter( + new SimilarityMatch<>(Helpers.loadFromSmiles("O.O"))) + .collect(Collectors.toList()); + assertEquals(10, indigoResult.size()); + } +} diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/BatchTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/BatchTest.java index d44ef24a9d..a0a062755b 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/BatchTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/BatchTest.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,7 +33,7 @@ public static void setUpDataStore() { ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); repository = builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withReplicas(0) diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/CompareLargeFileTestIT.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/CompareLargeFileTestIT.java index fb15554682..5f4921dbe7 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/CompareLargeFileTestIT.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/CompareLargeFileTestIT.java @@ -6,7 +6,7 @@ import com.epam.indigo.model.IndigoRecord; import com.epam.indigo.model.IndigoRecordMolecule; import com.epam.indigo.predicate.*; -import org.elasticsearch.core.Tuple; +import org.elasticsearch.common.collect.Tuple; import org.junit.jupiter.api.*; import java.util.*; diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/FullUsageMoleculeTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/FullUsageMoleculeTest.java index 78f6f139ed..3549b67cbf 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/FullUsageMoleculeTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/FullUsageMoleculeTest.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -40,7 +41,7 @@ public static void setUpElastic() { ElasticRepositoryBuilder builder = new ElasticRepositoryBuilder<>(); repository = builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withRefreshInterval("1s") diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/LoadMoleculeFromFileTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/LoadMoleculeFromFileTest.java index 4be865e818..134e85b311 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/LoadMoleculeFromFileTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/LoadMoleculeFromFileTest.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; @@ -41,7 +42,7 @@ public static void setUpElastic() { ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); repository = builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withRefreshInterval("1s") diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/NoSQLElasticCompareAbstract.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/NoSQLElasticCompareAbstract.java index 3b66f38fbf..e431c74fda 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/NoSQLElasticCompareAbstract.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/NoSQLElasticCompareAbstract.java @@ -7,6 +7,8 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer; import org.testcontainers.utility.DockerImageName; +import java.util.Collections; + /** * TODO: Add generic support or add IndigoRecordReaction support */ @@ -27,7 +29,7 @@ public static void setUpDataStore() { ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); repository = builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withReplicas(0) diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/RepositoryValidationTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/RepositoryValidationTest.java index ba85afc0ff..915595ca0b 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/RepositoryValidationTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/RepositoryValidationTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.Collections; + public class RepositoryValidationTest { @Test() @@ -15,7 +17,7 @@ void testFailedRepo() { ElasticRepository.ElasticRepositoryBuilder builder = new ElasticRepository.ElasticRepositoryBuilder<>(); builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName("localost") + .withHostsNames(Collections.singletonList("localhost")) .withPort(9999) .withScheme("http"); Assertions.assertThrows(BingoElasticException.class, builder::build); diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/SaveMoleculeFromIndigoRecordTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/SaveMoleculeFromIndigoRecordTest.java index d6345ae53b..c338bc426a 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/SaveMoleculeFromIndigoRecordTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/elastic/SaveMoleculeFromIndigoRecordTest.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -37,7 +38,7 @@ public static void setUpElastic() { ElasticRepositoryBuilder builder = new ElasticRepositoryBuilder<>(); repository = builder .withIndexName(NamingConstants.BINGO_MOLECULES) - .withHostName(elasticsearchContainer.getHost()) + .withHostsNames(Collections.singletonList(elasticsearchContainer.getHost())) .withPort(elasticsearchContainer.getFirstMappedPort()) .withScheme("http") .withRefreshInterval("1s") diff --git a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/predicate/ReactionsTest.java b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/predicate/ReactionsTest.java index 3894df2313..4d0edc1b7e 100644 --- a/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/predicate/ReactionsTest.java +++ b/bingo/bingo-elastic/java/src/test/java/com/epam/indigo/predicate/ReactionsTest.java @@ -10,7 +10,6 @@ import java.io.File; import java.nio.file.Files; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; From df6ffb484ccce9548071f5a8bf2ec066f57a5faf Mon Sep 17 00:00:00 2001 From: Mikhail Kviatkovskii Date: Fri, 25 Nov 2022 21:15:45 +0400 Subject: [PATCH 5/6] bingo: postgres: add support for Postgres 15, drop support for Postgres 10 (#903) --- .github/workflows/indigo-ci.yaml | 17 +++-- bingo/postgres/CMakeLists.txt | 9 ++- bingo/postgres/sql/15/bingo_am.sql.in | 66 +++++++++++++++++++ bingo/postgres/src/pg_am/pg_bingo_import.cpp | 10 +++ bingo/postgres/src/pg_am/pg_bingo_utils.cpp | 2 +- .../src/pg_common/bingo_pg_common.cpp | 3 +- .../postgres/src/pg_common/bingo_pg_fix_pre.h | 2 +- bingo/postgres/src/pg_core/bingo_pg_build.cpp | 4 +- .../src/pg_core/bingo_pg_build_engine.cpp | 4 +- bingo/postgres/src/pg_core/bingo_pg_index.cpp | 5 +- .../src/pg_core/bingo_pg_search_engine.cpp | 2 +- 11 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 bingo/postgres/sql/15/bingo_am.sql.in diff --git a/.github/workflows/indigo-ci.yaml b/.github/workflows/indigo-ci.yaml index 988c6712ad..2b1385163c 100644 --- a/.github/workflows/indigo-ci.yaml +++ b/.github/workflows/indigo-ci.yaml @@ -908,7 +908,7 @@ jobs: strategy: fail-fast: false matrix: - postgres_major_version: [ 10, 11, 12, 13, 14 ] + postgres_major_version: [ 11, 12, 13, 14, 15 ] runs-on: ubuntu-latest steps: - name: Checkout @@ -958,7 +958,12 @@ jobs: with: name: bingo-postgres-${{ matrix.postgres_major_version }}-linux-x86_64 path: dist/bingo-postgres*. - - name: Publish master + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Publish Docker images if: github.ref == 'refs/heads/master' run: docker push epmlsop/bingo-postgres:${{ matrix.postgres_major_version }}-latest - name: Publish Test Report @@ -973,7 +978,7 @@ jobs: strategy: fail-fast: false matrix: - postgres_major_version: [ "10", "11", "12", "13" ] + postgres_major_version: [ "11", "12", "13", "14", "15" ] runs-on: windows-latest steps: - name: Checkout @@ -985,7 +990,7 @@ jobs: run: git fetch --tags -f - name: Setup Postgres run: | - $pg_version = switch(${{ matrix.postgres_major_version }}) { "13" { "13.6" } "12" { "12.10" } "11" { "11.15" } "10" { "10.20" } } + $pg_version = switch(${{ matrix.postgres_major_version }}) { "15" { "15.1" } "14" { "14.6" } "13" { "13.9" } "12" { "12.13" } "11" { "11.18" } } curl -O https://get.enterprisedb.com/postgresql/postgresql-${pg_version}-1-windows-x64-binaries.zip Expand-Archive postgresql-${pg_version}-1-windows-x64-binaries.zip mv postgresql-${pg_version}-1-windows-x64-binaries/pgsql pgsql @@ -1006,7 +1011,7 @@ jobs: strategy: fail-fast: false matrix: - postgres_major_version: [ 10, 11, 12, 13, 14 ] + postgres_major_version: [ 11, 12, 13, 14, 15 ] runs-on: macos-latest steps: - name: Checkout @@ -1018,7 +1023,7 @@ jobs: run: git fetch --tags -f - name: Setup Postgres run: | - case ${{ matrix.postgres_major_version }} in 14) pg_version=14.2;; 13) pg_version=13.6;; 12) pg_version=12.10;; 11) pg_version=11.15;; 10) pg_version=10.20;; esac; + case ${{ matrix.postgres_major_version }} in 15) pg_version=15.1;; 14) pg_version=14.6;; 13) pg_version=13.9;; 12) pg_version=12.13;; 11) pg_version=11.18;; esac; curl -O https://get.enterprisedb.com/postgresql/postgresql-${pg_version}-1-osx-binaries.zip unzip postgresql-${pg_version}-1-osx-binaries.zip mv pgsql/include/zlib.h pgsql/include/zlib.h.bck diff --git a/bingo/postgres/CMakeLists.txt b/bingo/postgres/CMakeLists.txt index b4406ac94b..d6867ce817 100644 --- a/bingo/postgres/CMakeLists.txt +++ b/bingo/postgres/CMakeLists.txt @@ -12,6 +12,11 @@ if (NOT PostgreSQL_FOUND) else() project(bingo-postgres C CXX) + string(REPLACE "." ";" PostgreSQL_VERSION_LIST ${PostgreSQL_VERSION_STRING}) + list(GET PostgreSQL_VERSION_LIST 0 PostgreSQL_VERSION_MAJOR) + list(GET PostgreSQL_VERSION_LIST 1 PostgreSQL_VERSION_MINOR) + + file(GLOB ${PROJECT_NAME}_SOURCES CONFIGURE_DEPENDS src/pg_am/*.cpp src/pg_am/*.c src/pg_common/*.cpp src/pg_common/*.c @@ -21,6 +26,7 @@ else() PUBLIC bingo-core-c-static) target_include_directories(${PROJECT_NAME} PUBLIC ${PostgreSQL_INCLUDE_DIRS} + PUBLIC /usr/include/postgresql/${PostgreSQL_VERSION_MAJOR}/server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/pg_common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/pg_core) @@ -49,9 +55,6 @@ else() string(REPLACE "-fvisibility=hidden" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) endif () - string(REPLACE "." ";" PostgreSQL_VERSION_LIST ${PostgreSQL_VERSION_STRING}) - list(GET PostgreSQL_VERSION_LIST 0 PostgreSQL_VERSION_MAJOR) - list(GET PostgreSQL_VERSION_LIST 1 PostgreSQL_VERSION_MINOR) if (PostgreSQL_VERSION_MAJOR GREATER 9) set(PostgreSQL_VERSION ${PostgreSQL_VERSION_MAJOR}) else () diff --git a/bingo/postgres/sql/15/bingo_am.sql.in b/bingo/postgres/sql/15/bingo_am.sql.in new file mode 100644 index 0000000000..09eb0030df --- /dev/null +++ b/bingo/postgres/sql/15/bingo_am.sql.in @@ -0,0 +1,66 @@ +CREATE OR REPLACE FUNCTION bingo_handler(internal) +RETURNS index_am_handler +AS 'BINGO_PATHNAME' +LANGUAGE C STRICT VOLATILE; + +CREATE ACCESS METHOD bingo_idx TYPE INDEX HANDLER bingo_handler; + + +--**************************** MANGO OPERATOR CLASS ********************* +CREATE OPERATOR CLASS molecule +FOR TYPE text USING bingo_idx +AS + OPERATOR 1 public.@ (text, sub), + OPERATOR 2 public.@ (text, exact), + OPERATOR 3 public.@ (text, smarts), + OPERATOR 4 public.@ (text, gross), + OPERATOR 5 public.< (text, mass), + OPERATOR 6 public.> (text, mass), + OPERATOR 7 public.@ (text, sim), + FUNCTION 1 matchSub(text, sub), + FUNCTION 2 matchExact(text, exact), + FUNCTION 3 matchSmarts(text, smarts), + FUNCTION 4 matchGross(text, gross), + FUNCTION 5 _match_mass_less(text, mass), + FUNCTION 6 _match_mass_great(text, mass), + FUNCTION 7 matchSim(text, sim); + +CREATE OPERATOR CLASS bmolecule +FOR TYPE bytea USING bingo_idx +AS + OPERATOR 1 public.@ (bytea, sub), + OPERATOR 2 public.@ (bytea, exact), + OPERATOR 3 public.@ (bytea, smarts), + OPERATOR 4 public.@ (bytea, gross), + OPERATOR 5 public.< (bytea, mass), + OPERATOR 6 public.> (bytea, mass), + OPERATOR 7 public.@ (bytea, sim), + FUNCTION 1 matchSub(bytea, sub), + FUNCTION 2 matchExact(bytea, exact), + FUNCTION 3 matchSmarts(bytea, smarts), + FUNCTION 4 matchGross(bytea, gross), + FUNCTION 5 _match_mass_less(bytea, mass), + FUNCTION 6 _match_mass_great(bytea, mass), + FUNCTION 7 matchSim(bytea, sim); + +--**************************** RINGO OPERATOR CLASS ********************* +CREATE OPERATOR CLASS reaction +FOR TYPE text USING bingo_idx +AS + OPERATOR 1 public.@ (text, rsub), + OPERATOR 2 public.@ (text, rexact), + OPERATOR 3 public.@ (text, rsmarts), + FUNCTION 1 matchRSub(text, rsub), + FUNCTION 2 matchRExact(text, rexact), + FUNCTION 3 matchRSmarts(text, rsmarts); + +CREATE OPERATOR CLASS breaction +FOR TYPE bytea USING bingo_idx +AS + OPERATOR 1 public.@ (bytea, rsub), + OPERATOR 2 public.@ (bytea, rexact), + OPERATOR 3 public.@ (bytea, rsmarts), + FUNCTION 1 matchRSub(bytea, rsub), + FUNCTION 2 matchRExact(bytea, rexact), + FUNCTION 3 matchRSmarts(bytea, rsmarts); + diff --git a/bingo/postgres/src/pg_am/pg_bingo_import.cpp b/bingo/postgres/src/pg_am/pg_bingo_import.cpp index a97d30bc22..75ee544e0b 100644 --- a/bingo/postgres/src/pg_am/pg_bingo_import.cpp +++ b/bingo/postgres/src/pg_am/pg_bingo_import.cpp @@ -9,7 +9,9 @@ extern "C" #include "catalog/pg_type.h" #include "executor/spi.h" #include "utils/builtins.h" +#if PG_VERSION_NUM / 100 < 1500 #include "utils/int8.h" +#endif } #include "bingo_pg_fix_post.h" @@ -140,7 +142,11 @@ class BingoImportHandler : public BingoPgCommon::BingoSessionHandler BINGO_PG_TRY { data.reset(new int64); +#if PG_VERSION_NUM / 100 < 1500 scanint8(str, false, data.get()); +#else + *data = pg_strtoint64(str); +#endif } BINGO_PG_HANDLE(data.reset(0); throw BingoPgError("error while converting to int64: %s", message)); } @@ -182,7 +188,11 @@ class BingoImportHandler : public BingoPgCommon::BingoSessionHandler BINGO_PG_TRY { data.reset(new int32); +#if PG_VERSION_NUM / 100 < 1500 *data = pg_atoi(str2.ptr(), sizeof(int32), 0); +#else + *data = pg_strtoint32(str2.ptr()); +#endif } BINGO_PG_HANDLE(data.reset(0); throw BingoPgError("error while converting to int32: %s", message)); } diff --git a/bingo/postgres/src/pg_am/pg_bingo_utils.cpp b/bingo/postgres/src/pg_am/pg_bingo_utils.cpp index 59d5cb94a7..4f8803e4ff 100644 --- a/bingo/postgres/src/pg_am/pg_bingo_utils.cpp +++ b/bingo/postgres/src/pg_am/pg_bingo_utils.cpp @@ -1,5 +1,4 @@ #include "bingo_pg_fix_pre.h" -#include "gzip/gzip_scanner.h" extern "C" { @@ -21,6 +20,7 @@ extern "C" #include "base_cpp/scanner.h" #include "bingo_core_c.h" #include "bingo_postgres.h" +#include "gzip/gzip_scanner.h" #include "bingo_pg_buffer.h" #include "bingo_pg_common.h" diff --git a/bingo/postgres/src/pg_common/bingo_pg_common.cpp b/bingo/postgres/src/pg_common/bingo_pg_common.cpp index a0854fea9d..9ebadda143 100644 --- a/bingo/postgres/src/pg_common/bingo_pg_common.cpp +++ b/bingo/postgres/src/pg_common/bingo_pg_common.cpp @@ -1,6 +1,4 @@ #include "bingo_pg_fix_pre.h" -#include "gzip/gzip_scanner.h" -#include extern "C" { @@ -23,6 +21,7 @@ extern "C" #include "base_c/bitarray.h" #include "base_cpp/output.h" #include "base_cpp/tlscont.h" +#include "gzip/gzip_scanner.h" #include "bingo_core_c.h" diff --git a/bingo/postgres/src/pg_common/bingo_pg_fix_pre.h b/bingo/postgres/src/pg_common/bingo_pg_fix_pre.h index 09b08e39e3..8246508fe2 100644 --- a/bingo/postgres/src/pg_common/bingo_pg_fix_pre.h +++ b/bingo/postgres/src/pg_common/bingo_pg_fix_pre.h @@ -2,7 +2,7 @@ #define __bingo_pg_fix_pre_h__ // Visual Studio 2013 has isnan and isinf functions defined in math.h. -// PostgeSQL defines isnan and isind macroses, so we need to include math.h +// PostgreSQL defines isnan and isind macroses, so we need to include math.h // before PostgreSQL includes // // See also: diff --git a/bingo/postgres/src/pg_core/bingo_pg_build.cpp b/bingo/postgres/src/pg_core/bingo_pg_build.cpp index aa84404bd3..6e44361195 100644 --- a/bingo/postgres/src/pg_core/bingo_pg_build.cpp +++ b/bingo/postgres/src/pg_core/bingo_pg_build.cpp @@ -1,7 +1,5 @@ #include "bingo_pg_fix_pre.h" -#include - extern "C" { #include "postgres.h" @@ -16,6 +14,8 @@ extern "C" #include "bingo_pg_build.h" +#include + #include "base_cpp/profiling.h" #include "bingo_pg_buffer.h" diff --git a/bingo/postgres/src/pg_core/bingo_pg_build_engine.cpp b/bingo/postgres/src/pg_core/bingo_pg_build_engine.cpp index 39f5d313c5..66ef433595 100644 --- a/bingo/postgres/src/pg_core/bingo_pg_build_engine.cpp +++ b/bingo/postgres/src/pg_core/bingo_pg_build_engine.cpp @@ -1,5 +1,5 @@ #include "bingo_pg_fix_pre.h" -#include "gzip/gzip_scanner.h" + extern "C" { #include "postgres.h" @@ -11,8 +11,8 @@ extern "C" #include "base_cpp/array.h" #include "base_cpp/tlscont.h" +#include "gzip/gzip_scanner.h" -#include "bingo_core_c.h" #include "bingo_pg_build_engine.h" #include "bingo_pg_config.h" diff --git a/bingo/postgres/src/pg_core/bingo_pg_index.cpp b/bingo/postgres/src/pg_core/bingo_pg_index.cpp index 5628f24e9d..ffec71d18d 100644 --- a/bingo/postgres/src/pg_core/bingo_pg_index.cpp +++ b/bingo/postgres/src/pg_core/bingo_pg_index.cpp @@ -1,7 +1,5 @@ #include "bingo_pg_fix_pre.h" -#include - extern "C" { #include "postgres.h" @@ -12,11 +10,12 @@ extern "C" #include "bingo_pg_fix_post.h" +#include + #include "base_cpp/profiling.h" #include "bingo_core_c.h" #include "bingo_pg_build_engine.h" -#include "bingo_pg_common.h" #include "bingo_pg_config.h" #include "bingo_pg_ext_bitset.h" #include "bingo_pg_index.h" diff --git a/bingo/postgres/src/pg_core/bingo_pg_search_engine.cpp b/bingo/postgres/src/pg_core/bingo_pg_search_engine.cpp index e6774c01d3..71ab504809 100644 --- a/bingo/postgres/src/pg_core/bingo_pg_search_engine.cpp +++ b/bingo/postgres/src/pg_core/bingo_pg_search_engine.cpp @@ -1,5 +1,4 @@ #include "bingo_pg_fix_pre.h" -#include "gzip/gzip_scanner.h" extern "C" { @@ -18,6 +17,7 @@ extern "C" #include "base_cpp/array.h" #include "base_cpp/profiling.h" #include "base_cpp/tlscont.h" +#include "gzip/gzip_scanner.h" #include "bingo_core_c.h" From 0689e76721233a6aa1a4968fc40e3089a6b9f117 Mon Sep 17 00:00:00 2001 From: Mikhail Kviatkovskii Date: Tue, 29 Nov 2022 15:17:07 +0400 Subject: [PATCH 6/6] api: java: fix Maven publish plugin --- api/java/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/java/pom.xml b/api/java/pom.xml index e5728942a8..4d1752d5ea 100644 --- a/api/java/pom.xml +++ b/api/java/pom.xml @@ -47,7 +47,7 @@ net.java.dev.jna jna - 5.11.0 + 5.12.1 org.junit.jupiter @@ -145,7 +145,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.6.13 true