Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDXML agents and reactions support. #832, #836, #837, #835, #834, #832, #830, #853 #872

Merged
merged 13 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
472 changes: 236 additions & 236 deletions api/tests/integration/ref/formats/cdxml_to_mol.py.out

Large diffs are not rendered by default.

2,697 changes: 0 additions & 2,697 deletions api/tests/integration/ref/formats/linux/rxn_to_cdxml.py.out

This file was deleted.

2,697 changes: 0 additions & 2,697 deletions api/tests/integration/ref/formats/mac/rxn_to_cdxml.py.out

This file was deleted.

2,697 changes: 0 additions & 2,697 deletions api/tests/integration/ref/formats/mingw/rxn_to_cdxml.py.out

This file was deleted.

4 changes: 2 additions & 2 deletions api/tests/integration/ref/formats/mol_to_cdxml.py.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ stereo_either-0020.mol
<!DOCTYPE CDXML SYSTEM "http://www.cambridgesoft.com/xml/cdxml.dtd">
<CDXML BondLength="30.000000" LabelFont="3" CaptionFont="4">
<fonttable>
<font id="3" charset="iso-8859-1" name="Arial"/>
<font id="4" charset="iso-8859-1" name="Times New Roman"/>
<font id="1" charset="utf-8" name="Arial"/>
<font id="2" charset="utf-8" name="Times New Roman"/>
</fonttable>
<colortable>
<color r="1" g="1" b="1"/>
Expand Down
1,428 changes: 714 additions & 714 deletions api/tests/integration/ref/formats/rxn_to_cdxml.py.out

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions api/tests/integration/tests/formats/rxn_to_cdxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@
print("*** Try as Reaction ***")
rxn = indigo.loadReactionFromFile(os.path.join(root, filename))
indigo.setOption("layout-horintervalfactor", "1.4")
rxn.layout()
print(rxn.cdxml())
print("*** Compare with QueryReaction ***")
rxn2 = indigo.loadQueryReactionFromFile(os.path.join(root, filename))
rxn2.layout()
print(rxn2.cdxml())
except IndigoException as e:
print(getIndigoExceptionText(e))
print("*** Try as QueryReaction ***")
rxn = indigo.loadQueryReactionFromFile(os.path.join(root, filename))
indigo.setOption("layout-horintervalfactor", "1.4")
rxn.layout()
print(rxn.cdxml())
4 changes: 4 additions & 0 deletions api/wasm/indigo-ketcher/indigo-ketcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ namespace indigo
{
return _checkResultString(indigoCml(id()));
}
else if (outputFormat == "cdxml" || outputFormat == "chemical/x-cdxml")
{
return _checkResultString(indigoCdxml(id()));
}
else if (outputFormat == "inchi" || outputFormat == "chemical/x-inchi")
{
return _checkResultString(indigoInchiGetInchi(id()));
Expand Down
7 changes: 7 additions & 0 deletions core/indigo-core/common/base_cpp/properties_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <string>

#include "base_cpp/properties_map.h"

Expand All @@ -38,6 +39,12 @@ void PropertiesMap::copy(PropertiesMap& other)
insert(other.key(p), other.value(p));
}
}

void PropertiesMap::insert(const char* key, const std::string& value)
{
insert(key, value.c_str());
}

void PropertiesMap::insert(const char* key, const char* value)
{
if (_properties.find(key))
Expand Down
2 changes: 2 additions & 0 deletions core/indigo-core/common/base_cpp/properties_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ namespace indigo
void copy(RedBlackStringObjMap<Array<char>>& properties);
void copy(PropertiesMap&);
void insert(const char* key, const char* value);
void insert(const char* key, const std::string& value);

Array<char>& insert(const char* key);

const char* key(int);
Expand Down
10 changes: 10 additions & 0 deletions core/indigo-core/common/math/algebra.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,16 @@ namespace indigo
return Vec2f(middleX(), middleY());
}

inline float width() const
{
return _rightTop.x - _leftBottom.x;
}

inline float height() const
{
return _rightTop.y - _leftBottom.y;
}

protected:
Vec2f _leftBottom;
Vec2f _rightTop;
Expand Down
1 change: 0 additions & 1 deletion core/indigo-core/molecule/base_molecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ namespace indigo
SKIP_ATTACHMENT_POINTS = 0x10,
SKIP_TGROUPS = 0x20,
SKIP_TEMPLATE_ATTACHMENT_POINTS = 0x40,
COPY_BOND_DIRECTIONS = 0x80
};

class Molecule;
Expand Down
21 changes: 14 additions & 7 deletions core/indigo-core/molecule/ket_commons.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ namespace indigo
{
const double KETDefaultFontSize = 13;
const double KETFontScaleFactor = 47;
const auto KETFontBoldStr = "BOLD";
const auto KETFontItalicStr = "ITALIC";
const auto KETFontSuperscriptStr = "SUPERSCRIPT";
const auto KETFontSubscriptStr = "SUBSCRIPT";
const auto KETFontCustomSizeStr = "CUSTOM_FONT_SIZE";

struct compareFunction
{
Expand All @@ -53,8 +58,6 @@ namespace indigo
return string_hash(s, count);
}

const std::unordered_map<std::string, int> KTextStylesMap{{"BOLD", 0}, {"ITALIC", 1}, {"SUPERSCRIPT", 2}, {"SUBSCRIPT", 3}};

class KETSimpleObject : public MetaObject
{
public:
Expand Down Expand Up @@ -85,13 +88,17 @@ namespace indigo
public:
enum
{
EBold = 0,
EItalic = 1,
ESuperScript = 2,
ESubScript = 3,
EFontSize = 4
EPlain = 0,
EBold = 1,
EItalic = 2,
ESuperScript = 3,
ESubScript = 4,
EFontSize = 5
};

const std::unordered_map<std::string, int> KTextStylesMap{
{KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}};

struct KETTextLine
{
std::string text;
Expand Down
3 changes: 2 additions & 1 deletion core/indigo-core/molecule/metadata_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ namespace indigo
public:
DECL_ERROR;
void clone(const MetaDataStorage& other);
void append(const MetaDataStorage& other);

virtual ~MetaDataStorage()
{
}

void addMetaObject(MetaObject* pobj);
int addMetaObject(MetaObject* pobj);

void resetMetaData()
{
Expand Down
54 changes: 46 additions & 8 deletions core/indigo-core/molecule/molecule_cdxml_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ typedef int INT32;
typedef unsigned int UINT32;
#include "molecule/CDXConstants.h"

const int KCDXMLChemicalFontStyle = 96;

namespace tinyxml2
{
class XMLHandle;
Expand Down Expand Up @@ -77,6 +79,23 @@ namespace indigo
int val;
};

union CDXMLFontStyle {
CDXMLFontStyle(unsigned int val) : face(val)
{
}
struct
{
unsigned int is_bold : 1;
unsigned int is_italic : 1;
unsigned int is_underline : 1;
unsigned int is_outline : 1;
unsigned int is_shadow : 1;
unsigned int is_subscript : 1;
unsigned int is_superscript : 1;
};
unsigned int face;
};

struct _ExtConnection
{
int bond_id;
Expand Down Expand Up @@ -156,35 +175,47 @@ namespace indigo
MoleculeCdxmlLoader(Scanner& scanner);

void loadMolecule(BaseMolecule& mol);
void loadMoleculeFromFragment(BaseMolecule& mol, tinyxml2::XMLElement* pElem);

static void applyDispatcher(const tinyxml2::XMLAttribute* pAttr,
const std::unordered_map<std::string, std::function<void(const std::string&)>>& dispatcher);
void parseCDXMLAttributes(const tinyxml2::XMLAttribute* pAttr);
void parseBBox(const std::string& data, Rect2f& bbox);
void parsePos(const std::string& data, Vec3f& bbox);

StereocentersOptions stereochemistry_options;
bool ignore_bad_valence;
bool _has_bounding_box;
Rect2f _cdxml_bbox;
AutoInt _cdxml_bond_length;
std::vector<CdxmlNode> _nodes;
std::vector<CdxmlBond> _bonds;
std::vector<CdxmlBracket> _brackets;
Rect2f cdxml_bbox;
AutoInt cdxml_bond_length;
std::vector<CdxmlNode> nodes;
std::vector<CdxmlBond> bonds;
std::vector<CdxmlBracket> brackets;
static const int SCALE = 30;

protected:
Scanner* _scanner;
const tinyxml2::XMLNode* _fragment;
void _parseCDXMLAttributes(const tinyxml2::XMLAttribute* pAttr);
void _initMolecule(BaseMolecule& mol);
void _parseCollections(BaseMolecule& mol);

void _parseNode(CdxmlNode& node, tinyxml2::XMLElement* pElem);
void _addNode(CdxmlNode& node);

void _parseBond(CdxmlBond& bond, const tinyxml2::XMLAttribute* pAttr);
void _addBond(CdxmlBond& node);

void _parseBracket(CdxmlBracket& bracket, const tinyxml2::XMLAttribute* pAttr);
void _parseText(const tinyxml2::XMLElement* pElem);
void _parseGraphic(const tinyxml2::XMLElement* pElem);
void _parseArrow(const tinyxml2::XMLElement* pElem);

void _applyDispatcher(const tinyxml2::XMLAttribute* pAttr, const std::unordered_map<std::string, std::function<void(std::string&)>>& dispatcher);
void _addAtomsAndBonds(BaseMolecule& mol, const std::vector<int>& atoms, const std::vector<CdxmlBond>& bonds);
void _addBracket(BaseMolecule& mol, const CdxmlBracket& bracket);
void _handleSGroup(SGroup& sgroup, const std::unordered_set<int>& atoms, BaseMolecule& bmol);

void _parseCDXMLPage(tinyxml2::XMLElement* pElem);
void _parseCDXMLFragment(tinyxml2::XMLElement* pElem);
void _parseCDXMLElements(tinyxml2::XMLElement* pElem, bool no_siblings = false);
void _parseFragmentAttributes(const tinyxml2::XMLAttribute* pAttr);

void _appendQueryAtom(const char* atom_label, std::unique_ptr<QueryMolecule::Atom>& atom);
Expand All @@ -196,6 +227,13 @@ namespace indigo
std::unordered_map<int, int> _id_to_node_index;
std::unordered_map<int, int> _id_to_bond_index;
std::vector<int> _fragment_nodes;
std::vector<std::pair<Vec3f, std::string>> _text_objects;
std::vector<Vec2f> _pluses;
std::vector<std::pair<std::pair<Vec3f, Vec3f>, int>> _arrows;

std::unordered_set<int> _superced_ids;

float _bond_length;

private:
MoleculeCdxmlLoader(const MoleculeCdxmlLoader&); // no implicit copy
Expand Down
11 changes: 5 additions & 6 deletions core/indigo-core/molecule/molecule_cdxml_saver.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <memory>

#include "base_cpp/properties_map.h"
#include "ket_commons.h"
#include "math/algebra.h"

namespace tinyxml2
Expand All @@ -44,11 +45,8 @@ namespace indigo
~MoleculeCdxmlSaver();

void saveMolecule(BaseMolecule& mol);
enum
{
BOND_LENGTH = 30
};

static const int SCALE = 30;
static const int MAX_PAGE_HEIGHT = 64;
struct Bounds
{
Vec2f min, max;
Expand All @@ -61,11 +59,12 @@ namespace indigo
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<int>& nodes_ids);
void addMetaData(const MetaDataStorage& meta, 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);
void addTitle(const Vec2f& pos, const char* text);
void addGraphic(int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs);
void addElement(const char* element, int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs);
void addCustomElement(int id, Array<char>& name, PropertiesMap& attrs);
void startCurrentElement(int id, Array<char>& name, PropertiesMap& attrs);
void endCurrentElement();
Expand Down
37 changes: 7 additions & 30 deletions core/indigo-core/molecule/src/base_molecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ void BaseMolecule::clear()
use_scsr_name = false;
expand_mod_templates = false;
ignore_chem_templates = false;

updateEditRevision();
_meta.resetMetaData();
}

bool BaseMolecule::hasCoord(BaseMolecule& mol)
Expand Down Expand Up @@ -267,6 +267,7 @@ void BaseMolecule::_mergeWithSubmolecule_Sub(BaseMolecule& mol, const Array<int>
reaction_atom_inversion.expandFill(vertexEnd(), 0);
reaction_atom_exact_change.expandFill(vertexEnd(), 0);
reaction_bond_reacting_center.expandFill(edgeEnd(), 0);
_bond_directions.expandFill(edgeEnd(), -1);

for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
{
Expand All @@ -278,37 +279,13 @@ void BaseMolecule::_mergeWithSubmolecule_Sub(BaseMolecule& mol, const Array<int>
reaction_atom_exact_change[mapping[i]] = mol.reaction_atom_exact_change[i];
}

if (skip_flags & COPY_BOND_DIRECTIONS)
{
_bond_directions.expandFill(edgeEnd() + mol.edgeEnd(), 0);
}
else
_bond_directions.expandFill(mol.edgeEnd(), 0);

for (int j = mol.edgeBegin(); j != mol.edgeEnd(); j = mol.edgeNext(j))
{
const Edge& edge = mol.getEdge(j);

if ((mapping[edge.beg] > -1) && (mapping[edge.end] > -1))
{
int bond_idx = findEdgeIndex(mapping[edge.beg], mapping[edge.end]);
if (bond_idx > -1)
{
reaction_bond_reacting_center[bond_idx] = mol.reaction_bond_reacting_center[j];
}
}
}

// trick for molecules with incorrect stereochemistry, of which we do permutations
if ((skip_flags & COPY_BOND_DIRECTIONS) || (vertexCount() == mol.vertexCount() && edgeCount() == mol.edgeCount()))
{
for (int j = mol.edgeBegin(); j != mol.edgeEnd(); j = mol.edgeNext(j))
{
const Edge& edge = mol.getEdge(j);

if (mol.getBondDirection(j) != 0)
_bond_directions[findEdgeIndex(mapping[edge.beg], mapping[edge.end])] = mol.getBondDirection(j);
}
int edge_idx = edge_mapping[j];
if (edge_idx < 0)
continue;
reaction_bond_reacting_center[edge_idx] = mol.reaction_bond_reacting_center[j];
_bond_directions[edge_idx] = mol.getBondDirection(j);
}

// RGroups
Expand Down
12 changes: 9 additions & 3 deletions core/indigo-core/molecule/src/metadata_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using namespace indigo;

IMPL_ERROR(MetaDataStorage, "metadata storage");

void MetaDataStorage::addMetaObject(MetaObject* pobj)
int MetaDataStorage::addMetaObject(MetaObject* pobj)
{
int index = _meta_data.size();
_meta_data.expand(index + 1);
Expand All @@ -29,16 +29,22 @@ void MetaDataStorage::addMetaObject(MetaObject* pobj)
default:
break;
}
return index;
}

void MetaDataStorage::clone(const MetaDataStorage& other)
void MetaDataStorage::append(const MetaDataStorage& other)
{
resetMetaData();
const auto& meta = other.metaData();
for (int i = 0; i < meta.size(); i++)
addMetaObject(meta[i]->clone());
}

void MetaDataStorage::clone(const MetaDataStorage& other)
{
resetMetaData();
append(other);
}

const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) const
{
switch (meta_type)
Expand Down
2 changes: 2 additions & 0 deletions core/indigo-core/molecule/src/molecule_auto_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ void MoleculeAutoLoader::_loadMolecule(BaseMolecule& mol, bool query)
_scanner->skipSpace();
if (_scanner->lookNext() == '<' && _scanner->findWord("CDXML"))
{
if (_scanner->findWord("<arrow"))
throw Error("CDXML: not a molecule. Arrows found.");
_scanner->seek(pos, SEEK_SET);
MoleculeCdxmlLoader loader(*_scanner);
loader.stereochemistry_options = stereochemistry_options;
Expand Down
Loading