api/c/indigo/src/indigo_molecule.cpp (3,982 lines of code) (raw):
/****************************************************************************
* Copyright (C) from 2009 to Present EPAM Systems.
*
* This file is part of Indigo toolkit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include "indigo_molecule.h"
#include "base_c/bitarray.h"
#include "base_cpp/output.h"
#include "base_cpp/scanner.h"
#include "indigo_array.h"
#include "indigo_io.h"
#include "indigo_ket_document.h"
#include "indigo_mapping.h"
#include "indigo_monomer_library.h"
#include "molecule/canonical_smiles_saver.h"
#include "molecule/elements.h"
#include "molecule/hybridization.h"
#include "molecule/ket_document_json_loader.h"
#include "molecule/molecule_auto_loader.h"
#include "molecule/molecule_automorphism_search.h"
#include "molecule/molecule_fingerprint.h"
#include "molecule/molecule_gross_formula.h"
#include "molecule/molecule_inchi.h"
#include "molecule/molecule_json_loader.h"
#include "molecule/molecule_json_saver.h"
#include "molecule/molecule_mass.h"
#include "molecule/molecule_name_parser.h"
#include "molecule/molecule_savers.h"
#include "molecule/query_molecule.h"
#include "molecule/sequence_loader.h"
#include "molecule/smiles_loader.h"
#include "molecule/smiles_saver.h"
IndigoBaseMolecule::IndigoBaseMolecule(int type_) : IndigoObject(type_)
{
}
IndigoBaseMolecule::~IndigoBaseMolecule()
{
}
const char* IndigoBaseMolecule::debugInfo() const
{
return "<base molecule>";
}
IndigoMolecule::IndigoMolecule() : IndigoBaseMolecule(MOLECULE)
{
}
bool IndigoBaseMolecule::is(const IndigoObject& object)
{
switch (object.type)
{
case MOLECULE:
case QUERY_MOLECULE:
case REACTION_MOLECULE:
case SCAFFOLD:
case RGROUP_FRAGMENT:
case RDF_MOLECULE:
case SMILES_MOLECULE:
case CML_MOLECULE:
case JSON_MOLECULE:
case CDX_MOLECULE:
case SUBMOLECULE:
return true;
case ARRAY_ELEMENT:
return is(((IndigoArrayElement&)object).get());
}
return false;
}
IndigoMolecule::~IndigoMolecule()
{
}
Molecule& IndigoMolecule::getMolecule()
{
return mol;
}
const Molecule& IndigoMolecule::getMolecule() const
{
return mol;
}
BaseMolecule& IndigoMolecule::getBaseMolecule()
{
return mol;
}
KetDocument& IndigoMolecule::getKetDocument()
{
return getBaseMolecule().getKetDocument();
}
const char* IndigoMolecule::getName()
{
if (mol.name.ptr() == 0)
return "";
return mol.name.ptr();
}
IndigoMolecule* IndigoMolecule::cloneFrom(IndigoObject& obj)
{
std::unique_ptr<IndigoMolecule> molptr = std::make_unique<IndigoMolecule>();
QS_DEF(Array<int>, mapping);
molptr->mol.clone(obj.getMolecule(), 0, &mapping);
auto& props = obj.getProperties();
molptr->copyProperties(props);
return molptr.release();
}
IndigoQueryMolecule::IndigoQueryMolecule() : IndigoBaseMolecule(QUERY_MOLECULE)
{
_nei_counters_edit_revision = -1;
}
IndigoQueryMolecule::~IndigoQueryMolecule()
{
}
QueryMolecule& IndigoQueryMolecule::getQueryMolecule()
{
return qmol;
}
IndigoQueryMolecule* IndigoQueryMolecule::cloneFrom(IndigoObject& obj)
{
std::unique_ptr<IndigoQueryMolecule> molptr = std::make_unique<IndigoQueryMolecule>();
QS_DEF(Array<int>, mapping);
molptr->qmol.clone(obj.getQueryMolecule(), 0, &mapping);
auto& props = obj.getProperties();
molptr->copyProperties(props);
return molptr.release();
}
void IndigoQueryMolecule::parseAtomConstraint(const char* type, const char* value, std::unique_ptr<QueryMolecule::Atom>& atom)
{
enum KeyType
{
Int,
Bool
};
struct Mapping
{
const char* key;
QueryMolecule::OpType value;
KeyType key_type;
};
static Mapping mappingForKeys[] = {
{"atomic-number", QueryMolecule::ATOM_NUMBER, Int},
{"charge", QueryMolecule::ATOM_CHARGE, Int},
{"isotope", QueryMolecule::ATOM_ISOTOPE, Int},
{"radical", QueryMolecule::ATOM_RADICAL, Int},
{"valence", QueryMolecule::ATOM_VALENCE, Int},
{"connectivity", QueryMolecule::ATOM_CONNECTIVITY, Int},
{"total-bond-order", QueryMolecule::ATOM_TOTAL_BOND_ORDER, Int},
{"hydrogens", QueryMolecule::ATOM_TOTAL_H, Int},
{"substituents", QueryMolecule::ATOM_SUBSTITUENTS, Int},
{"ring", QueryMolecule::ATOM_SSSR_RINGS, Int},
{"smallest-ring-size", QueryMolecule::ATOM_SMALLEST_RING_SIZE, Int},
{"ring-bonds", QueryMolecule::ATOM_RING_BONDS, Int},
{"rsite-mask", QueryMolecule::ATOM_RSITE, Int},
{"highlighting", QueryMolecule::HIGHLIGHTING, Bool},
};
for (int i = 0; i < NELEM(mappingForKeys); i++)
{
if (strcasecmp(type, mappingForKeys[i].key) == 0)
{
int int_value = 0;
if (value != NULL)
{
if (mappingForKeys[i].key_type == Int)
{
BufferScanner buf_scanner(value);
int_value = buf_scanner.readInt();
}
else if (mappingForKeys[i].key_type == Bool)
{
if (strcasecmp(value, "true") == 0)
int_value = 1;
else if (strcasecmp(value, "false") == 0)
int_value = 0;
else
{
BufferScanner buf_scanner(value);
int_value = buf_scanner.readInt();
}
}
}
atom = std::make_unique<QueryMolecule::Atom>(mappingForKeys[i].value, int_value);
return;
}
}
if (strcasecmp(type, "rsite") == 0)
{
int int_value = 0;
if (value != NULL)
{
BufferScanner buf_scanner(value);
int_value = buf_scanner.readInt();
}
atom = std::make_unique<QueryMolecule::Atom>(QueryMolecule::ATOM_RSITE, 1 << int_value);
return;
}
else if (strcasecmp(type, "smarts") == 0)
{
if (value == NULL)
throw IndigoError("Internal error: value argument in parseAtomConstraint has null value");
atom.reset(parseAtomSMARTS(value));
return;
}
else if (strcasecmp(type, "aromaticity") == 0)
{
int int_value = 0;
if (value != NULL)
{
if (strcasecmp(value, "aromatic") == 0)
int_value = ATOM_AROMATIC;
else if (strcasecmp(value, "aliphatic") == 0)
int_value = ATOM_ALIPHATIC;
else
throw IndigoError("unsupported aromaticity type: %s", value);
}
atom = std::make_unique<QueryMolecule::Atom>(QueryMolecule::ATOM_AROMATICITY, int_value);
return;
}
throw IndigoError("unsupported constraint type: %s", type);
}
QueryMolecule::Atom* IndigoQueryMolecule::parseAtomSMARTS(const char* string)
{
if (strlen(string) == 0)
return new QueryMolecule::Atom();
QS_DEF(QueryMolecule, qmol);
qmol.clear();
BufferScanner scanner(string);
SmilesLoader loader(scanner);
loader.loadSMARTS(qmol);
if (qmol.vertexCount() != 1)
throw IndigoError("cannot parse '%s' as a single-atom", string);
return qmol.releaseAtom(qmol.vertexBegin());
}
BaseMolecule& IndigoQueryMolecule::getBaseMolecule()
{
return qmol;
}
const char* IndigoQueryMolecule::getName()
{
if (qmol.name.ptr() == 0)
return "";
return qmol.name.ptr();
}
IndigoAtom::IndigoAtom(BaseMolecule& mol_, int idx_) : IndigoObject(ATOM), mol(mol_)
{
idx = idx_;
}
IndigoAtom::~IndigoAtom()
{
}
int IndigoAtom::getIndex()
{
return idx;
}
const char* IndigoAtom::debugInfo() const
{
return "<atom>";
}
bool IndigoAtom::is(IndigoObject& obj)
{
if (obj.type == IndigoObject::ATOM || obj.type == IndigoObject::ATOM_NEIGHBOR)
return true;
if (obj.type == IndigoObject::ARRAY_ELEMENT)
return is(((IndigoArrayElement&)obj).get());
return false;
}
IndigoAtom& IndigoAtom::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::ATOM || obj.type == IndigoObject::ATOM_NEIGHBOR)
return (IndigoAtom&)obj;
if (obj.type == IndigoObject::ARRAY_ELEMENT)
return cast(((IndigoArrayElement&)obj).get());
throw IndigoError("%s does not represent an atom", obj.debugInfo());
}
void IndigoAtom::remove()
{
mol.removeAtom(idx);
}
IndigoObject* IndigoAtom::clone()
{
return new IndigoAtom(mol, idx);
}
IndigoAtomsIter::IndigoAtomsIter(BaseMolecule* mol, int type_) : IndigoObject(ATOMS_ITER)
{
_mol = mol;
_type = type_;
_idx = -1;
}
IndigoAtomsIter::~IndigoAtomsIter()
{
}
int IndigoAtomsIter::_shift(int idx)
{
if (_type == PSEUDO)
{
for (; idx != _mol->vertexEnd(); idx = _mol->vertexNext(idx))
if (_mol->isPseudoAtom(idx))
break;
}
else if (_type == RSITE)
{
for (; idx != _mol->vertexEnd(); idx = _mol->vertexNext(idx))
if (_mol->isRSite(idx))
break;
}
else if (_type == STEREOCENTER)
{
for (; idx != _mol->vertexEnd(); idx = _mol->vertexNext(idx))
if (_mol->stereocenters.getType(idx) != 0)
break;
}
else if (_type == ALLENE_CENTER)
{
for (; idx != _mol->vertexEnd(); idx = _mol->vertexNext(idx))
if (_mol->allene_stereo.isCenter(idx))
break;
}
return idx;
}
bool IndigoAtomsIter::hasNext()
{
if (_idx == _mol->vertexEnd())
return false;
int next_idx;
if (_idx == -1)
next_idx = _shift(_mol->vertexBegin());
else
next_idx = _shift(_mol->vertexNext(_idx));
return next_idx != _mol->vertexEnd();
}
IndigoObject* IndigoAtomsIter::next()
{
if (_idx == -1)
_idx = _mol->vertexBegin();
else
_idx = _mol->vertexNext(_idx);
_idx = _shift(_idx);
if (_idx == _mol->vertexEnd())
return 0;
std::unique_ptr<IndigoAtom> atom = std::make_unique<IndigoAtom>(*_mol, _idx);
return atom.release();
}
IndigoBond::IndigoBond(BaseMolecule& mol_, int idx_) : IndigoObject(BOND), mol(mol_)
{
idx = idx_;
}
IndigoBond::~IndigoBond()
{
}
int IndigoBond::getIndex()
{
return idx;
}
const char* IndigoBond::debugInfo() const
{
return "<bond>";
}
bool IndigoBond::is(IndigoObject& obj)
{
if (obj.type == IndigoObject::BOND)
return true;
if (obj.type == IndigoObject::ARRAY_ELEMENT)
return is(((IndigoArrayElement&)obj).get());
return false;
}
IndigoBond& IndigoBond::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::BOND)
return (IndigoBond&)obj;
if (obj.type == IndigoObject::ARRAY_ELEMENT)
return cast(((IndigoArrayElement&)obj).get());
throw IndigoError("%s does not represent a bond", obj.debugInfo());
}
void IndigoBond::remove()
{
mol.removeBond(idx);
}
IndigoBondsIter::IndigoBondsIter(BaseMolecule& mol) : IndigoObject(BONDS_ITER), _mol(mol)
{
_idx = -1;
}
IndigoBondsIter::~IndigoBondsIter()
{
}
bool IndigoBondsIter::hasNext()
{
if (_idx == _mol.edgeEnd())
return false;
int next_idx;
if (_idx == -1)
next_idx = _mol.edgeBegin();
else
next_idx = _mol.edgeNext(_idx);
return next_idx != _mol.edgeEnd();
}
IndigoObject* IndigoBondsIter::next()
{
if (_idx == -1)
_idx = _mol.edgeBegin();
else
_idx = _mol.edgeNext(_idx);
if (_idx == _mol.edgeEnd())
return nullptr;
return new IndigoBond(_mol, _idx);
}
CEXPORT int indigoLoadMolecule(int source)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
MoleculeAutoLoader loader(IndigoScanner::get(obj));
loader.stereochemistry_options = self.stereochemistry_options;
loader.treat_x_as_pseudoatom = self.treat_x_as_pseudoatom;
loader.ignore_noncritical_query_features = self.ignore_noncritical_query_features;
loader.skip_3d_chirality = self.skip_3d_chirality;
loader.ignore_closing_bond_direction_mismatch = self.ignore_closing_bond_direction_mismatch;
loader.ignore_no_chiral_flag = self.ignore_no_chiral_flag;
loader.treat_stereo_as = self.treat_stereo_as;
loader.ignore_bad_valence = self.ignore_bad_valence;
loader.dearomatize_on_load = self.dearomatize_on_load;
loader.arom_options = self.arom_options;
std::unique_ptr<IndigoMolecule> molptr = std::make_unique<IndigoMolecule>();
Molecule& mol = molptr->mol;
loader.loadMolecule(mol);
molptr->getProperties().copy(loader.properties);
return self.addObject(molptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadQueryMolecule(int source)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
MoleculeAutoLoader loader(IndigoScanner::get(obj));
loader.stereochemistry_options = self.stereochemistry_options;
loader.treat_x_as_pseudoatom = self.treat_x_as_pseudoatom;
loader.dearomatize_on_load = self.dearomatize_on_load;
loader.arom_options = self.arom_options;
std::unique_ptr<IndigoQueryMolecule> molptr = std::make_unique<IndigoQueryMolecule>();
QueryMolecule& qmol = molptr->qmol;
loader.loadMolecule(qmol);
molptr->copyProperties(loader.properties);
return self.addObject(molptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadMonomerLibrary(int source)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
std::unique_ptr<IndigoMonomerLibrary> libptr = std::make_unique<IndigoMonomerLibrary>();
MoleculeJsonLoader loader(IndigoScanner::get(obj));
loader.stereochemistry_options.ignore_errors = true;
loader.loadMonomerLibrary(libptr->get());
return self.addObject(libptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadKetDocument(int source)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
std::string json_str;
if (IndigoBaseMolecule::is(obj))
{
json_str = indigoJson(source);
}
else
{
auto& scanner = IndigoScanner::get(obj);
scanner.readAll(json_str);
}
std::unique_ptr<IndigoKetDocument> docptr = std::make_unique<IndigoKetDocument>();
KetDocumentJsonLoader loader{};
loader.parseJson(json_str, docptr->get());
return self.addObject(docptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadSequence(int source, const char* seq_type, int library)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
IndigoObject& lib_obj = self.getObject(library);
SequenceLoader loader(IndigoScanner::get(obj), IndigoMonomerLibrary::get(lib_obj));
std::unique_ptr<IndigoKetDocument> docptr = std::make_unique<IndigoKetDocument>();
loader.loadSequence(docptr->get(), seq_type);
return self.addObject(docptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadSequenceFromString(const char* string, const char* seq_type, int library)
{
INDIGO_BEGIN
{
int source = indigoReadString(string);
int result;
if (source <= 0)
return -1;
result = indigoLoadSequence(source, seq_type, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadSequenceFromFile(const char* filename, const char* seq_type, int library)
{
INDIGO_BEGIN
{
int source = indigoReadFile(filename);
int result;
if (source < 0)
return -1;
result = indigoLoadSequence(source, seq_type, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadFasta(int source, const char* seq_type, int library)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
IndigoObject& lib_obj = self.getObject(library);
SequenceLoader loader(IndigoScanner::get(obj), IndigoMonomerLibrary::get(lib_obj));
std::unique_ptr<IndigoKetDocument> docptr = std::make_unique<IndigoKetDocument>();
loader.loadFasta(docptr->get(), seq_type);
return self.addObject(docptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadFastaFromString(const char* string, const char* seq_type, int library)
{
INDIGO_BEGIN
{
int source = indigoReadString(string);
int result;
if (source <= 0)
return -1;
result = indigoLoadFasta(source, seq_type, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadFastaFromFile(const char* filename, const char* seq_type, int library)
{
INDIGO_BEGIN
{
int source = indigoReadFile(filename);
int result;
if (source < 0)
return -1;
result = indigoLoadFasta(source, seq_type, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadIdt(int source, int library)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
IndigoObject& lib_obj = self.getObject(library);
MonomerTemplateLibrary& lib = IndigoMonomerLibrary::get(lib_obj);
SequenceLoader loader(IndigoScanner::get(obj), lib);
std::unique_ptr<IndigoKetDocument> docptr = std::make_unique<IndigoKetDocument>();
loader.loadIdt(docptr->get());
return self.addObject(docptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadIdtFromString(const char* string, int library)
{
INDIGO_BEGIN
{
int source = indigoReadString(string);
int result;
if (source <= 0)
return -1;
result = indigoLoadIdt(source, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadIdtFromFile(const char* filename, int library)
{
INDIGO_BEGIN
{
int source = indigoReadFile(filename);
int result;
if (source < 0)
return -1;
result = indigoLoadIdt(source, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadHelm(int source, int library)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
IndigoObject& lib_obj = self.getObject(library);
SequenceLoader loader(IndigoScanner::get(obj), IndigoMonomerLibrary::get(lib_obj));
std::unique_ptr<IndigoKetDocument> docptr = std::make_unique<IndigoKetDocument>();
loader.loadHELM(docptr->get());
return self.addObject(docptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadHelmFromString(const char* string, int library)
{
INDIGO_BEGIN
{
int source = indigoReadString(string);
int result;
if (source <= 0)
return -1;
result = indigoLoadHelm(source, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadHelmFromFile(const char* filename, int library)
{
INDIGO_BEGIN
{
int source = indigoReadFile(filename);
int result;
if (source < 0)
return -1;
result = indigoLoadHelm(source, library);
indigoFree(source);
return result;
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadSmarts(int source)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(source);
SmilesLoader loader(IndigoScanner::get(obj));
std::unique_ptr<IndigoQueryMolecule> molptr = std::make_unique<IndigoQueryMolecule>();
QueryMolecule& qmol = molptr->qmol;
loader.loadSMARTS(qmol);
return self.addObject(molptr.release());
}
INDIGO_END(-1);
}
static bool isReacton(const char* string)
{
auto isIn = [](const char* source, const char* pattern) -> bool { return std::string(source).find(pattern) != std::string::npos; };
auto startWith = [](const char* source, const char* pattern) -> bool { return strncmp(source, pattern, strlen(pattern)) == 0; };
return isIn(string, ">>") || startWith(string, "$RXN") || isIn(string, "<reactantList>");
}
CEXPORT int indigoLoadStructureFromString(const char* string, const char* params)
{
INDIGO_BEGIN
{
if (strncmp(string, "InChI", strlen("InChI")) == 0)
{
return indigoLoadMoleculeFromString(string);
}
const std::string strParams(params ? params : "");
bool isQuery = (strParams.find("query") != std::string::npos) ? true : false;
bool isSmarts = (strParams.find("smarts") != std::string::npos) ? true : false;
bool isReaction = isReacton(string);
if (isSmarts)
{
if (isReaction)
return indigoLoadReactionSmartsFromString(string);
else
return indigoLoadSmartsFromString(string);
}
if (isQuery)
{
if (isReaction)
return indigoLoadQueryReactionFromString(string);
else
return indigoLoadQueryMoleculeFromString(string);
}
try
{
if (isReaction)
return indigoLoadReactionFromString(string);
else
return indigoLoadMoleculeFromString(string);
}
catch (Exception& e)
{
if (std::string(e.message()).find("query") == std::string::npos && std::string(e.message()).find("queries") == std::string::npos)
{
throw e;
}
if (isReaction)
return indigoLoadQueryReactionFromString(string);
else
return indigoLoadQueryMoleculeFromString(string);
}
}
INDIGO_END(-1);
}
CEXPORT int indigoLoadStructureFromBuffer(const byte* buff, int bufferSize, const char* params)
{
BufferScanner scanner(buff, bufferSize);
Array<char> arr;
MoleculeAutoLoader::readAllDataToString(scanner, arr);
return indigoLoadStructureFromString(arr.ptr(), params);
}
CEXPORT int indigoLoadStructureFromFile(const char* filename, const char* params)
{
INDIGO_BEGIN
{
FileScanner scanner(self.filename_encoding, filename);
Array<char> arr;
MoleculeAutoLoader::readAllDataToString(scanner, arr);
return indigoLoadStructureFromString(arr.ptr(), params);
}
INDIGO_END(-1);
}
IndigoMoleculeComponent::IndigoMoleculeComponent(BaseMolecule& mol_, int index_) : IndigoObject(COMPONENT), mol(mol_)
{
index = index_;
}
IndigoMoleculeComponent::~IndigoMoleculeComponent()
{
}
int IndigoMoleculeComponent::getIndex()
{
return index;
}
IndigoObject* IndigoMoleculeComponent::clone()
{
std::unique_ptr<IndigoBaseMolecule> res;
BaseMolecule* newmol;
if (mol.isQueryMolecule())
{
res = std::make_unique<IndigoQueryMolecule>();
newmol = &(((IndigoQueryMolecule*)res.get())->qmol);
}
else
{
res = std::make_unique<IndigoMolecule>();
newmol = &(((IndigoMolecule*)res.get())->mol);
}
Filter filter(mol.getDecomposition().ptr(), Filter::EQ, index);
newmol->makeSubmolecule(mol, filter, 0, 0);
for (auto it = newmol->properties().begin(); it != newmol->properties().end(); ++it)
{
auto& props = newmol->properties().value(it);
res->getProperties().merge(props);
}
return res.release();
}
IndigoComponentsIter::IndigoComponentsIter(BaseMolecule& mol_) : IndigoObject(COMPONENT), mol(mol_)
{
_idx = -1;
}
IndigoComponentsIter::~IndigoComponentsIter()
{
}
bool IndigoComponentsIter::hasNext()
{
return _idx + 1 < mol.countComponents();
}
IndigoObject* IndigoComponentsIter::next()
{
if (!hasNext())
return 0;
_idx++;
return new IndigoMoleculeComponent(mol, _idx);
}
IndigoSGroupAtomsIter::IndigoSGroupAtomsIter(BaseMolecule& mol, SGroup& sgroup) : IndigoObject(SGROUP_ATOMS_ITER), _mol(mol), _sgroup(sgroup)
{
_idx = -1;
}
IndigoSGroupAtomsIter::~IndigoSGroupAtomsIter()
{
}
bool IndigoSGroupAtomsIter::hasNext()
{
return _idx + 1 < _sgroup.atoms.size();
}
IndigoObject* IndigoSGroupAtomsIter::next()
{
if (!hasNext())
return 0;
_idx++;
return new IndigoAtom(_mol, _sgroup.atoms[_idx]);
}
IndigoSGroupBondsIter::IndigoSGroupBondsIter(BaseMolecule& mol, SGroup& sgroup) : IndigoObject(SGROUP_ATOMS_ITER), _mol(mol), _sgroup(sgroup)
{
_idx = -1;
}
IndigoSGroupBondsIter::~IndigoSGroupBondsIter()
{
}
bool IndigoSGroupBondsIter::hasNext()
{
return _idx + 1 < _sgroup.bonds.size();
}
IndigoObject* IndigoSGroupBondsIter::next()
{
if (!hasNext())
return 0;
_idx++;
return new IndigoBond(_mol, _sgroup.bonds[_idx]);
}
int _indigoIterateAtoms(Indigo& self, int molecule, int type)
{
return self.addObject(new IndigoAtomsIter(&self.getObject(molecule).getBaseMolecule(), type));
}
CEXPORT int indigoIterateAtoms(int molecule)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
if (obj.type == IndigoObject::COMPONENT)
{
IndigoMoleculeComponent& mc = (IndigoMoleculeComponent&)obj;
return self.addObject(new IndigoComponentAtomsIter(mc.mol, mc.index));
}
if (obj.type == IndigoObject::SUBMOLECULE)
{
IndigoSubmolecule& sm = (IndigoSubmolecule&)obj;
return self.addObject(new IndigoSubmoleculeAtomsIter(sm));
}
if (obj.type == IndigoObject::DATA_SGROUP)
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(obj);
return self.addObject(new IndigoSGroupAtomsIter(dsg.mol, dsg.mol.sgroups.getSGroup(dsg.idx)));
}
if (obj.type == IndigoObject::SUPERATOM)
{
IndigoSuperatom& sa = IndigoSuperatom::cast(obj);
return self.addObject(new IndigoSGroupAtomsIter(sa.mol, sa.mol.sgroups.getSGroup(sa.idx)));
}
if (obj.type == IndigoObject::REPEATING_UNIT)
{
IndigoRepeatingUnit& ru = IndigoRepeatingUnit::cast(obj);
return self.addObject(new IndigoSGroupAtomsIter(ru.mol, ru.mol.sgroups.getSGroup(ru.idx)));
}
if (obj.type == IndigoObject::MULTIPLE_GROUP)
{
IndigoMultipleGroup& mr = IndigoMultipleGroup::cast(obj);
return self.addObject(new IndigoSGroupAtomsIter(mr.mol, mr.mol.sgroups.getSGroup(mr.idx)));
}
if (obj.type == IndigoObject::GENERIC_SGROUP)
{
IndigoGenericSGroup& gg = IndigoGenericSGroup::cast(obj);
return self.addObject(new IndigoSGroupAtomsIter(gg.mol, gg.mol.sgroups.getSGroup(gg.idx)));
}
return _indigoIterateAtoms(self, molecule, IndigoAtomsIter::ALL);
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateBonds(int molecule)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
if (obj.type == IndigoObject::COMPONENT)
{
IndigoMoleculeComponent& mc = (IndigoMoleculeComponent&)obj;
return self.addObject(new IndigoComponentBondsIter(mc.mol, mc.index));
}
if (obj.type == IndigoObject::SUBMOLECULE)
{
IndigoSubmolecule& sm = (IndigoSubmolecule&)obj;
return self.addObject(new IndigoSubmoleculeBondsIter(sm));
}
if (obj.type == IndigoObject::DATA_SGROUP)
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(obj);
return self.addObject(new IndigoSGroupBondsIter(dsg.mol, dsg.mol.sgroups.getSGroup(dsg.idx)));
}
if (obj.type == IndigoObject::SUPERATOM)
{
IndigoSuperatom& sa = IndigoSuperatom::cast(obj);
return self.addObject(new IndigoSGroupBondsIter(sa.mol, sa.mol.sgroups.getSGroup(sa.idx)));
}
if (obj.type == IndigoObject::REPEATING_UNIT)
{
IndigoRepeatingUnit& ru = IndigoRepeatingUnit::cast(obj);
return self.addObject(new IndigoSGroupBondsIter(ru.mol, ru.mol.sgroups.getSGroup(ru.idx)));
}
if (obj.type == IndigoObject::MULTIPLE_GROUP)
{
IndigoMultipleGroup& mr = IndigoMultipleGroup::cast(obj);
return self.addObject(new IndigoSGroupBondsIter(mr.mol, mr.mol.sgroups.getSGroup(mr.idx)));
}
if (obj.type == IndigoObject::GENERIC_SGROUP)
{
IndigoGenericSGroup& gg = IndigoGenericSGroup::cast(obj);
return self.addObject(new IndigoSGroupBondsIter(gg.mol, gg.mol.sgroups.getSGroup(gg.idx)));
}
BaseMolecule& mol = obj.getBaseMolecule();
return self.addObject(new IndigoBondsIter(mol));
}
INDIGO_END(-1);
}
CEXPORT int indigoCountAtoms(int molecule)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
if (obj.type == IndigoObject::COMPONENT)
{
IndigoMoleculeComponent& mc = (IndigoMoleculeComponent&)obj;
return mc.mol.countComponentVertices(mc.index);
}
if (obj.type == IndigoObject::SUBMOLECULE)
{
IndigoSubmolecule& sm = (IndigoSubmolecule&)obj;
return sm.vertices.size();
}
if (obj.type == IndigoObject::DATA_SGROUP)
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(obj);
return dsg.get().atoms.size();
}
if (obj.type == IndigoObject::SUPERATOM)
{
IndigoSuperatom& sa = IndigoSuperatom::cast(obj);
return sa.get().atoms.size();
}
BaseMolecule& mol = obj.getBaseMolecule();
return mol.vertexCount();
}
INDIGO_END(-1);
}
CEXPORT int indigoCountBonds(int molecule)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
if (obj.type == IndigoObject::COMPONENT)
{
IndigoMoleculeComponent& mc = (IndigoMoleculeComponent&)obj;
return mc.mol.countComponentEdges(mc.index);
}
if (obj.type == IndigoObject::SUBMOLECULE)
{
IndigoSubmolecule& sm = (IndigoSubmolecule&)obj;
return sm.edges.size();
}
if (obj.type == IndigoObject::DATA_SGROUP)
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(obj);
return dsg.get().bonds.size();
}
if (obj.type == IndigoObject::SUPERATOM)
{
IndigoSuperatom& sa = IndigoSuperatom::cast(obj);
return sa.get().bonds.size();
}
BaseMolecule& mol = obj.getBaseMolecule();
return mol.edgeCount();
}
INDIGO_END(-1);
}
CEXPORT int indigoCountPseudoatoms(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int i, res = 0;
for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
if (mol.isPseudoAtom(i))
res++;
return res;
}
INDIGO_END(-1);
}
CEXPORT int indigoCountRSites(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int i, res = 0;
for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
if (mol.isRSite(i))
res++;
return res;
}
INDIGO_END(-1);
}
CEXPORT int indigoIteratePseudoatoms(int molecule)
{
INDIGO_BEGIN
{
return _indigoIterateAtoms(self, molecule, IndigoAtomsIter::PSEUDO);
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateRSites(int molecule)
{
INDIGO_BEGIN
{
return _indigoIterateAtoms(self, molecule, IndigoAtomsIter::RSITE);
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateStereocenters(int molecule)
{
INDIGO_BEGIN
{
return _indigoIterateAtoms(self, molecule, IndigoAtomsIter::STEREOCENTER);
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateAlleneCenters(int molecule)
{
INDIGO_BEGIN
{
return _indigoIterateAtoms(self, molecule, IndigoAtomsIter::ALLENE_CENTER);
}
INDIGO_END(-1);
}
CEXPORT const char* indigoSymbol(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
auto& tmp = self.getThreadTmpData();
ia.mol.getAtomSymbol(ia.idx, tmp.string);
return tmp.string.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoIsPseudoatom(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
if (ia.mol.isPseudoAtom(ia.idx))
return 1;
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoIsRSite(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
if (ia.mol.isRSite(ia.idx))
return 1;
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoIsTemplateAtom(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
if (ia.mol.isTemplateAtom(ia.idx))
return 1;
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoSingleAllowedRGroup(int rsite)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(rsite));
return ia.mol.getSingleAllowedRGroup(ia.idx);
}
INDIGO_END(-1);
}
IndigoRGroup::IndigoRGroup() : IndigoObject(RGROUP)
{
}
IndigoRGroup::~IndigoRGroup()
{
}
int IndigoRGroup::getIndex()
{
return idx;
}
IndigoRGroup& IndigoRGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::RGROUP)
return (IndigoRGroup&)obj;
throw IndigoError("%s is not an rgroup", obj.debugInfo());
}
IndigoRGroupsIter::IndigoRGroupsIter(BaseMolecule* mol) : IndigoObject(RGROUPS_ITER)
{
_mol = mol;
_idx = 0;
}
IndigoRGroupsIter::~IndigoRGroupsIter()
{
}
CEXPORT int indigoIterateRGroups(int molecule)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
if (IndigoBaseMolecule::is(obj))
{
BaseMolecule& mol = obj.getBaseMolecule();
return self.addObject(new IndigoRGroupsIter(&mol));
}
throw IndigoError("%s can not have r-groups", obj.debugInfo());
}
INDIGO_END(-1);
}
IndigoRGroupFragment::IndigoRGroupFragment(IndigoRGroup& rgp, int idx) : IndigoObject(RGROUP_FRAGMENT)
{
rgroup.idx = rgp.idx;
rgroup.mol = rgp.mol;
frag_idx = idx;
}
IndigoRGroupFragment::IndigoRGroupFragment(BaseMolecule* mol, int rgroup_idx, int fragment_idx) : IndigoObject(RGROUP_FRAGMENT)
{
rgroup.mol = mol;
rgroup.idx = rgroup_idx;
frag_idx = fragment_idx;
}
IndigoRGroupFragment::~IndigoRGroupFragment()
{
}
int IndigoRGroupFragment::getIndex()
{
return frag_idx;
}
void IndigoRGroupFragment::remove()
{
rgroup.mol->rgroups.getRGroup(rgroup.idx).fragments.remove(frag_idx);
}
QueryMolecule& IndigoRGroupFragment::getQueryMolecule()
{
return rgroup.mol->rgroups.getRGroup(rgroup.idx).fragments[frag_idx]->asQueryMolecule();
}
Molecule& IndigoRGroupFragment::getMolecule()
{
return rgroup.mol->rgroups.getRGroup(rgroup.idx).fragments[frag_idx]->asMolecule();
}
BaseMolecule& IndigoRGroupFragment::getBaseMolecule()
{
return *rgroup.mol->rgroups.getRGroup(rgroup.idx).fragments[frag_idx];
}
IndigoObject* IndigoRGroupFragment::clone()
{
BaseMolecule* mol = rgroup.mol->rgroups.getRGroup(rgroup.idx).fragments[frag_idx];
std::unique_ptr<IndigoBaseMolecule> molptr;
if (mol->isQueryMolecule())
{
molptr = std::make_unique<IndigoQueryMolecule>();
molptr->getQueryMolecule().clone(*mol, 0, 0);
}
else
{
molptr = std::make_unique<IndigoMolecule>();
molptr->getMolecule().clone(*mol, 0, 0);
}
return molptr.release();
}
IndigoRGroupFragmentsIter::IndigoRGroupFragmentsIter(IndigoRGroup& rgp) : IndigoObject(RGROUP_FRAGMENTS_ITER)
{
_mol = rgp.mol;
_rgroup_idx = rgp.idx;
_frag_idx = -1;
}
IndigoRGroupFragmentsIter::~IndigoRGroupFragmentsIter()
{
}
bool IndigoRGroupFragmentsIter::hasNext()
{
PtrPool<BaseMolecule>& frags = _mol->rgroups.getRGroup(_rgroup_idx).fragments;
if (_frag_idx == -1)
return frags.begin() != frags.end();
return frags.next(_frag_idx) != frags.end();
}
IndigoObject* IndigoRGroupFragmentsIter::next()
{
if (!hasNext())
return nullptr;
PtrPool<BaseMolecule>& frags = _mol->rgroups.getRGroup(_rgroup_idx).fragments;
if (_frag_idx == -1)
_frag_idx = frags.begin();
else
_frag_idx = frags.next(_frag_idx);
return new IndigoRGroupFragment(_mol, _rgroup_idx, _frag_idx);
}
CEXPORT int indigoIterateRGroupFragments(int rgroup)
{
INDIGO_BEGIN
{
IndigoRGroup& rgp = IndigoRGroup::cast(self.getObject(rgroup));
return self.addObject(new IndigoRGroupFragmentsIter(rgp));
}
INDIGO_END(-1);
}
CEXPORT int indigoCountRGroups(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.rgroups.getRGroupCount();
}
INDIGO_END(-1);
}
CEXPORT int indigoCopyRGroups(int molecule_from, int molecule_to)
{
INDIGO_BEGIN
{
BaseMolecule& mol_from = self.getObject(molecule_from).getBaseMolecule();
BaseMolecule& mol_to = self.getObject(molecule_to).getBaseMolecule();
mol_from.rgroups.copyRGroupsFromMolecule(mol_to.rgroups);
return 0;
}
INDIGO_END(-1);
}
bool IndigoRGroupsIter::hasNext()
{
bool result = false;
/*
* Skip empty fragments
*/
while ((_idx < _mol->rgroups.getRGroupCount()) && (_mol->rgroups.getRGroup(_idx + 1).fragments.size() == 0))
{
++_idx;
}
if (_idx < _mol->rgroups.getRGroupCount())
result = true;
return result;
}
IndigoObject* IndigoRGroupsIter::next()
{
if (!hasNext())
return 0;
_idx += 1;
std::unique_ptr<IndigoRGroup> rgroup = std::make_unique<IndigoRGroup>();
rgroup->mol = _mol;
rgroup->idx = _idx;
return rgroup.release();
}
CEXPORT int indigoCountAttachmentPoints(int rgroup)
{
INDIGO_BEGIN
{
IndigoObject& object = self.getObject(rgroup);
if (IndigoBaseMolecule::is(object))
return object.getBaseMolecule().attachmentPointCount();
IndigoRGroup& rgp = IndigoRGroup::cast(object);
return rgp.mol->rgroups.getRGroup(rgp.idx).fragments[0]->attachmentPointCount();
}
INDIGO_END(-1);
}
CEXPORT int indigoDegree(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
return ia.mol.getVertex(ia.idx).degree();
}
INDIGO_END(-1);
}
CEXPORT int indigoGetCharge(int atom, int* charge)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
int ch = ia.mol.getAtomCharge(ia.idx);
if (ch == CHARGE_UNKNOWN)
{
*charge = 0;
return 0;
}
*charge = ch;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoValence(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
return ia.mol.asMolecule().getAtomValence(ia.idx);
}
INDIGO_END(-1);
}
CEXPORT int indigoGetHybridization(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
auto& molecule = ia.mol.asMolecule();
return static_cast<int>(HybridizationCalculator::calculate(molecule, ia.idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoCheckValence(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
if (ia.mol.isPseudoAtom(ia.idx) || ia.mol.isRSite(ia.idx) || ia.mol.isTemplateAtom(ia.idx))
return 1;
int res = ia.mol.getAtomValence_NoThrow(ia.idx, -100);
return res == -100 ? 1 : 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetExplicitValence(int atom, int* valence)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
int val = ia.mol.getExplicitValence(ia.idx);
if (val == -1)
{
*valence = 0;
return 0;
}
*valence = val;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetExplicitValence(int atom, int valence)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.asMolecule().setExplicitValence(ia.idx, valence);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoIsotope(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
int iso = ia.mol.getAtomIsotope(ia.idx);
return iso == -1 ? 0 : iso;
}
INDIGO_END(-1);
}
CEXPORT int indigoAtomicNumber(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
if (ia.mol.isPseudoAtom(ia.idx))
throw IndigoError("indigoAtomicNumber() called on a pseudoatom");
if (ia.mol.isRSite(ia.idx))
throw IndigoError("indigoAtomicNumber() called on an R-site");
int num = ia.mol.getAtomNumber(ia.idx);
return num == -1 ? 0 : num;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetRadicalElectrons(int atom, int* electrons)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
int rad = ia.mol.getAtomRadical(ia.idx);
if (rad == -1)
{
*electrons = 0;
return 0;
}
*electrons = Element::radicalElectrons(rad);
return 1;
}
INDIGO_END(-1);
}
static int mapRadicalToIndigoRadical(int radical)
{
switch (radical)
{
case 0:
return 0;
case RADICAL_SINGLET:
return INDIGO_SINGLET;
case RADICAL_DOUBLET:
return INDIGO_DOUBLET;
case RADICAL_TRIPLET:
return INDIGO_TRIPLET;
default:
throw IndigoError("Unknown radical type");
}
}
static int mapIndigoRadicalToRadical(int indigo_radical)
{
switch (indigo_radical)
{
case 0:
return 0;
case INDIGO_SINGLET:
return RADICAL_SINGLET;
case INDIGO_DOUBLET:
return RADICAL_DOUBLET;
case INDIGO_TRIPLET:
return RADICAL_TRIPLET;
default:
throw IndigoError("Unknown radical type");
}
}
CEXPORT int indigoGetRadical(int atom, int* radical)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
int rad = ia.mol.getAtomRadical(ia.idx);
if (rad == -1)
{
*radical = 0;
return 0;
}
*radical = mapRadicalToIndigoRadical(rad);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetRadical(int atom, int radical)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.asMolecule().setAtomRadical(ia.idx, mapIndigoRadicalToRadical(radical));
return 1;
}
INDIGO_END(-1);
}
CEXPORT float* indigoXYZ(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
Vec3f& pos = mol.getAtomXyz(ia.idx);
auto& tmp = self.getThreadTmpData();
tmp.xyz[0] = pos.x;
tmp.xyz[1] = pos.y;
tmp.xyz[2] = pos.z;
return tmp.xyz;
}
INDIGO_END(0);
}
CEXPORT int indigoSetXYZ(int atom, float x, float y, float z)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
Vec3f& pos = mol.getAtomXyz(ia.idx);
pos.set(x, y, z);
return 1;
}
INDIGO_END(0);
}
CEXPORT int indigoResetCharge(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
if (mol.isQueryMolecule())
mol.asQueryMolecule().getAtom(ia.idx).removeConstraints(QueryMolecule::ATOM_CHARGE);
else
mol.asMolecule().setAtomCharge(ia.idx, 0);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoResetExplicitValence(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
if (mol.isQueryMolecule())
mol.asQueryMolecule().getAtom(ia.idx).removeConstraints(QueryMolecule::ATOM_VALENCE);
else
mol.asMolecule().resetExplicitValence(ia.idx);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoResetRadical(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
if (mol.isQueryMolecule())
mol.asQueryMolecule().getAtom(ia.idx).removeConstraints(QueryMolecule::ATOM_RADICAL);
else
mol.asMolecule().setAtomRadical(ia.idx, 0);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoResetIsotope(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
if (mol.isQueryMolecule())
mol.asQueryMolecule().getAtom(ia.idx).removeConstraints(QueryMolecule::ATOM_ISOTOPE);
else
mol.asMolecule().setAtomIsotope(ia.idx, 0);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoResetRsite(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& mol = ia.mol;
mol.asQueryMolecule().getAtom(ia.idx).removeConstraints(QueryMolecule::ATOM_RSITE);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetAttachmentPoint(int atom, int order)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.addAttachmentPoint(order, ia.idx);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoClearAttachmentPoints(int item)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(item).getBaseMolecule();
mol.removeAttachmentPoints();
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoRemoveConstraints(int item, const char* str_type)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(item));
QueryMolecule& qmol = ia.mol.asQueryMolecule();
if (strcasecmp(str_type, "smarts") == 0)
throw IndigoError("indigoRemoveConstraints(): type 'smarts' is not supported", str_type);
std::unique_ptr<QueryMolecule::Atom> atom;
IndigoQueryMolecule::parseAtomConstraint(str_type, NULL, atom);
if (atom->children.size() != 0)
throw IndigoError("indigoRemoveConstraints(): can not parse type: %s", str_type);
qmol.getAtom(ia.idx).removeConstraints(atom->type);
qmol.invalidateAtom(ia.idx, BaseMolecule::CHANGED_ALL);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoAddConstraint(int atom, const char* type, const char* value)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
QueryMolecule& qmol = ia.mol.asQueryMolecule();
std::unique_ptr<QueryMolecule::Atom> atom_constraint;
IndigoQueryMolecule::parseAtomConstraint(type, value, atom_constraint);
qmol.resetAtom(ia.idx, QueryMolecule::Atom::und(qmol.releaseAtom(ia.idx), atom_constraint.release()));
qmol.invalidateAtom(ia.idx, BaseMolecule::CHANGED_ALL);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoAddConstraintNot(int atom, const char* type, const char* value)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
QueryMolecule& qmol = ia.mol.asQueryMolecule();
std::unique_ptr<QueryMolecule::Atom> atom_constraint;
IndigoQueryMolecule::parseAtomConstraint(type, value, atom_constraint);
qmol.resetAtom(ia.idx, QueryMolecule::Atom::und(qmol.releaseAtom(ia.idx), QueryMolecule::Atom::nicht(atom_constraint.release())));
qmol.invalidateAtom(ia.idx, BaseMolecule::CHANGED_ALL);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoAddConstraintOr(int atom, const char* type, const char* value)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
QueryMolecule& qmol = ia.mol.asQueryMolecule();
std::unique_ptr<QueryMolecule::Atom> atom_constraint;
IndigoQueryMolecule::parseAtomConstraint(type, value, atom_constraint);
qmol.resetAtom(ia.idx, QueryMolecule::Atom::oder(qmol.releaseAtom(ia.idx), atom_constraint.release()));
qmol.invalidateAtom(ia.idx, BaseMolecule::CHANGED_ALL);
return 1;
}
INDIGO_END(-1);
}
/*
CEXPORT int indigoAddConstraintOrNot(int atom, const char* type, const char* value)
{
INDIGO_BEGIN
{
IndigoAtom &ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule *mol = ia.mol;
QueryMolecule& qmol = mol->asQueryMolecule();
std::unique_ptr<QueryMolecule::Atom> atom_constraint;
IndigoQueryMolecule::parseAtomConstraint(type, value, atom_constraint);
qmol.resetAtom(ia.idx, QueryMolecule::Atom::oder(qmol.releaseAtom(ia.idx), QueryMolecule::Atom::nicht(atom_constraint.release())));
return 1;
}
INDIGO_END(-1);
}
* */
CEXPORT const int* indigoSymmetryClasses(int molecule, int* count_out)
{
INDIGO_BEGIN
{
Molecule& mol = self.getObject(molecule).getMolecule();
QS_DEF(Molecule, m2);
m2.clone_KeepIndices(mol);
m2.aromatize(self.arom_options);
QS_DEF(Array<int>, ignored);
ignored.clear_resize(m2.vertexEnd());
ignored.zerofill();
for (int i = m2.vertexBegin(); i < m2.vertexEnd(); i = m2.vertexNext(i))
if (m2.convertableToImplicitHydrogen(i))
ignored[i] = 1;
MoleculeAutomorphismSearch of;
QS_DEF(Array<int>, orbits);
of.find_canonical_ordering = true;
of.ignored_vertices = ignored.ptr();
of.process(m2);
of.getCanonicallyOrderedOrbits(orbits);
auto& tmp = self.getThreadTmpData();
tmp.string.resize(orbits.sizeInBytes());
tmp.string.copy((char*)orbits.ptr(), orbits.sizeInBytes());
if (count_out != 0)
*count_out = orbits.size();
return (const int*)tmp.string.ptr();
}
INDIGO_END(0);
}
CEXPORT const char* indigoLayeredCode(int molecule)
{
INDIGO_BEGIN
{
Molecule& mol = self.getObject(molecule).getMolecule();
auto& tmp = self.getThreadTmpData();
ArrayOutput output(tmp.string);
MoleculeInChI inchi_saver(output);
inchi_saver.outputInChI(mol);
tmp.string.push(0);
return tmp.string.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoCreateSubmolecule(int molecule, int nvertices, int* vertices)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<int>, vertices_arr);
vertices_arr.copy(vertices, nvertices);
if (mol.isQueryMolecule())
{
std::unique_ptr<IndigoQueryMolecule> molptr = std::make_unique<IndigoQueryMolecule>();
molptr->qmol.makeSubmolecule(mol, vertices_arr, 0, 0);
return self.addObject(molptr.release());
}
else
{
std::unique_ptr<IndigoMolecule> molptr = std::make_unique<IndigoMolecule>();
molptr->mol.makeSubmolecule(mol, vertices_arr, 0, 0);
return self.addObject(molptr.release());
}
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSubmolecule(int molecule, int nvertices, int* vertices)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<int>, vertices_arr);
vertices_arr.copy(vertices, nvertices);
// Collect edges by vertices
QS_DEF(Array<int>, vertices_mask);
vertices_mask.clear_resize(mol.vertexEnd());
vertices_mask.zerofill();
for (int i = 0; i < nvertices; i++)
vertices_mask[vertices[i]] = 1;
QS_DEF(Array<int>, edges);
edges.clear();
for (int i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
{
const Edge& edge = mol.getEdge(i);
if (vertices_mask[edge.beg] && vertices_mask[edge.end])
edges.push(i);
}
return self.addObject(new IndigoSubmolecule(mol, vertices_arr, edges));
}
INDIGO_END(-1);
}
CEXPORT int indigoCreateEdgeSubmolecule(int molecule, int nvertices, int* vertices, int nedges, int* edges)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<int>, vertices_arr);
QS_DEF(Array<int>, edges_arr);
vertices_arr.copy(vertices, nvertices);
edges_arr.copy(edges, nedges);
if (mol.isQueryMolecule())
{
std::unique_ptr<IndigoQueryMolecule> molptr = std::make_unique<IndigoQueryMolecule>();
molptr->qmol.makeEdgeSubmolecule(mol, vertices_arr, edges_arr, 0, 0);
return self.addObject(molptr.release());
}
else
{
std::unique_ptr<IndigoMolecule> molptr = std::make_unique<IndigoMolecule>();
molptr->mol.makeEdgeSubmolecule(mol, vertices_arr, edges_arr, 0, 0);
return self.addObject(molptr.release());
}
}
INDIGO_END(-1);
}
CEXPORT int indigoRemoveAtoms(int molecule, int nvertices, int* vertices)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<int>, indices);
indices.copy(vertices, nvertices);
mol.removeAtoms(indices);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoRemoveBonds(int molecule, int nbonds, int* bonds)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<int>, indices);
indices.copy(bonds, nbonds);
mol.removeBonds(indices);
return 1;
}
INDIGO_END(-1);
}
IndigoObject* IndigoMolecule::clone()
{
return cloneFrom(*this);
}
const char* IndigoMolecule::debugInfo() const
{
return "<molecule>";
}
IndigoObject* IndigoQueryMolecule::clone()
{
return cloneFrom(*this);
}
const char* IndigoQueryMolecule::debugInfo() const
{
return "<query molecule>";
}
const MoleculeAtomNeighbourhoodCounters& IndigoQueryMolecule::getNeiCounters()
{
// TODO: implement query.getAtomEdit(...) instead of getAtom(...) to update nei counters
// automatically. Current approach is too complictated because
// we need to call updateEditRevision manually after changing an atom.
// if (_nei_counters_edit_revision != qmol.getEditRevision())
{
_nei_counters.calculate(qmol);
_nei_counters_edit_revision = qmol.getEditRevision();
}
return _nei_counters;
}
CEXPORT int indigoIsChiral(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.isChiral();
}
INDIGO_END(-1);
}
CEXPORT int indigoBondOrder(int bond)
{
INDIGO_BEGIN
{
IndigoBond& ib = IndigoBond::cast(self.getObject(bond));
int num = ib.mol.getBondOrder(ib.idx);
return num == -1 ? 0 : num;
}
INDIGO_END(-1);
}
CEXPORT int indigoTopology(int bond)
{
INDIGO_BEGIN
{
IndigoBond& ib = IndigoBond::cast(self.getObject(bond));
int topology = ib.mol.getBondTopology(ib.idx);
if (topology == TOPOLOGY_RING)
return INDIGO_RING;
if (topology == TOPOLOGY_CHAIN)
return INDIGO_CHAIN;
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetAtom(int molecule, int idx)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoAtom(mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoGetBond(int molecule, int idx)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoBond(mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoSource(int bond)
{
INDIGO_BEGIN
{
IndigoBond& ib = IndigoBond::cast(self.getObject(bond));
return self.addObject(new IndigoAtom(ib.mol, ib.mol.getEdge(ib.idx).beg));
}
INDIGO_END(-1);
}
CEXPORT int indigoDestination(int bond)
{
INDIGO_BEGIN
{
IndigoBond& ib = IndigoBond::cast(self.getObject(bond));
return self.addObject(new IndigoAtom(ib.mol, ib.mol.getEdge(ib.idx).end));
}
INDIGO_END(-1);
}
IndigoAtomNeighbor::IndigoAtomNeighbor(BaseMolecule& mol_, int atom_idx, int bond_idx_) : IndigoAtom(mol_, atom_idx)
{
type = ATOM_NEIGHBOR;
bond_idx = bond_idx_;
}
IndigoAtomNeighbor::~IndigoAtomNeighbor()
{
}
IndigoAtomNeighborsIter::IndigoAtomNeighborsIter(BaseMolecule& molecule, int atom_idx) : IndigoObject(ATOM_NEIGHBORS_ITER), _mol(molecule)
{
_atom_idx = atom_idx;
_nei_idx = -1;
}
IndigoAtomNeighborsIter::~IndigoAtomNeighborsIter()
{
}
IndigoObject* IndigoAtomNeighborsIter::next()
{
const Vertex& vertex = _mol.getVertex(_atom_idx);
if (_nei_idx == -1)
_nei_idx = vertex.neiBegin();
else if (_nei_idx != vertex.neiEnd())
_nei_idx = vertex.neiNext(_nei_idx);
if (_nei_idx == vertex.neiEnd())
return 0;
return new IndigoAtomNeighbor(_mol, vertex.neiVertex(_nei_idx), vertex.neiEdge(_nei_idx));
}
bool IndigoAtomNeighborsIter::hasNext()
{
const Vertex& vertex = _mol.getVertex(_atom_idx);
if (_nei_idx == -1)
return vertex.neiBegin() != vertex.neiEnd();
if (_nei_idx == vertex.neiEnd())
return false;
return vertex.neiNext(_nei_idx) != vertex.neiEnd();
}
CEXPORT int indigoIterateNeighbors(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
return self.addObject(new IndigoAtomNeighborsIter(ia.mol, ia.idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoBond(int nei)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(nei);
if (obj.type != IndigoObject::ATOM_NEIGHBOR)
throw IndigoError("indigoBond(): not applicable to %s", obj.debugInfo());
IndigoAtomNeighbor& atomnei = (IndigoAtomNeighbor&)obj;
return self.addObject(new IndigoBond(atomnei.mol, atomnei.bond_idx));
}
INDIGO_END(-1);
}
CEXPORT float indigoAlignAtoms(int molecule, int natoms, int* atom_ids, float* desired_xyz)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
QS_DEF(Array<Vec3f>, points);
QS_DEF(Array<Vec3f>, goals);
int i;
if (natoms < 1)
throw IndigoError("indigoAlignAtoms(): can not align %d atoms", natoms);
if (atom_ids == 0 || desired_xyz == 0)
throw IndigoError("indigoAlignAtoms(): zero pointer given as input");
points.clear();
goals.clear();
for (i = 0; i < natoms; i++)
{
points.push(mol.getAtomXyz(atom_ids[i]));
goals.push(Vec3f(desired_xyz[i * 3], desired_xyz[i * 3 + 1], desired_xyz[i * 3 + 2]));
}
if (points.size() < 1)
return true;
float sqsum;
Transform3f matr;
if (!matr.bestFit(points.size(), points.ptr(), goals.ptr(), &sqsum))
return false;
for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
mol.getAtomXyz(i).transformPoint(matr);
return (float)(sqrt(sqsum / natoms));
}
INDIGO_END(-1);
}
CEXPORT int indigoClearXYZ(int molecule)
{
INDIGO_BEGIN
{
self.getObject(molecule).getBaseMolecule().clearXyz();
return molecule;
}
INDIGO_END(-1);
}
CEXPORT int indigoCountSuperatoms(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sgroups.getSGroupCount(SGroup::SG_TYPE_SUP);
}
INDIGO_END(-1);
}
CEXPORT int indigoCountDataSGroups(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sgroups.getSGroupCount(SGroup::SG_TYPE_DAT);
}
INDIGO_END(-1);
}
CEXPORT int indigoCountRepeatingUnits(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sgroups.getSGroupCount(SGroup::SG_TYPE_SRU);
}
INDIGO_END(-1);
}
CEXPORT int indigoCountMultipleGroups(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sgroups.getSGroupCount(SGroup::SG_TYPE_MUL);
}
INDIGO_END(-1);
}
CEXPORT int indigoCountGenericSGroups(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sgroups.getSGroupCount(SGroup::SG_TYPE_GEN);
}
INDIGO_END(-1);
}
IndigoDataSGroupsIter::IndigoDataSGroupsIter(BaseMolecule& molecule, Array<int>&& refs)
: IndigoObject(DATA_SGROUPS_ITER), _mol(molecule), _refs(std::move(refs))
{
_idx = -1;
}
IndigoDataSGroupsIter::~IndigoDataSGroupsIter()
{
}
bool IndigoDataSGroupsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoDataSGroupsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoDataSGroup> sgroup = std::make_unique<IndigoDataSGroup>(_mol, _refs[_idx]);
return sgroup.release();
}
CEXPORT int indigoIterateDataSGroups(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.sgroups.findSGroups(SGroup::SG_TYPE, SGroup::SG_TYPE_DAT, sgs);
return self.addObject(new IndigoDataSGroupsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
IndigoDataSGroup::IndigoDataSGroup(BaseMolecule& mol_, int idx_) : IndigoObject(DATA_SGROUP), mol(mol_)
{
idx = idx_;
}
IndigoDataSGroup& IndigoDataSGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::DATA_SGROUP)
return (IndigoDataSGroup&)obj;
throw IndigoError("%s is not a data sgroup", obj.debugInfo());
}
DataSGroup& IndigoDataSGroup::get()
{
return (DataSGroup&)mol.sgroups.getSGroup(idx);
}
void IndigoDataSGroup::remove()
{
mol.removeSGroup(idx);
}
IndigoDataSGroup::~IndigoDataSGroup()
{
}
int IndigoDataSGroup::getIndex()
{
return idx;
}
IndigoSuperatom::IndigoSuperatom(BaseMolecule& mol_, int idx_) : IndigoObject(SUPERATOM), mol(mol_)
{
idx = idx_;
}
IndigoSuperatom::~IndigoSuperatom()
{
}
int IndigoSuperatom::getIndex()
{
return idx;
}
void IndigoSuperatom::remove()
{
mol.removeSGroup(idx);
}
const char* IndigoSuperatom::getName()
{
return ((Superatom&)mol.sgroups.getSGroup(idx)).subscript.ptr();
}
IndigoSuperatom& IndigoSuperatom::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::SUPERATOM)
return (IndigoSuperatom&)obj;
throw IndigoError("%s is not a superatom", obj.debugInfo());
}
Superatom& IndigoSuperatom::get()
{
return (Superatom&)mol.sgroups.getSGroup(idx);
}
IndigoSuperatomsIter::IndigoSuperatomsIter(BaseMolecule& molecule, Array<int>&& refs) : IndigoObject(SUPERATOMS_ITER), _mol(molecule), _refs(std::move(refs))
{
_idx = -1;
}
IndigoSuperatomsIter::~IndigoSuperatomsIter()
{
}
bool IndigoSuperatomsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoSuperatomsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoSuperatom> sgroup = std::make_unique<IndigoSuperatom>(_mol, _refs[_idx]);
return sgroup.release();
}
IndigoRepeatingUnit::IndigoRepeatingUnit(BaseMolecule& mol_, int idx_) : IndigoObject(REPEATING_UNIT), mol(mol_)
{
idx = idx_;
}
IndigoRepeatingUnit::~IndigoRepeatingUnit()
{
}
int IndigoRepeatingUnit::getIndex()
{
return idx;
}
void IndigoRepeatingUnit::remove()
{
mol.removeSGroup(idx);
}
IndigoRepeatingUnit& IndigoRepeatingUnit::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::REPEATING_UNIT)
return (IndigoRepeatingUnit&)obj;
throw IndigoError("%s is not a repeating unit", obj.debugInfo());
}
RepeatingUnit& IndigoRepeatingUnit::get()
{
return (RepeatingUnit&)mol.sgroups.getSGroup(idx);
}
IndigoRepeatingUnitsIter::IndigoRepeatingUnitsIter(BaseMolecule& molecule, Array<int>&& refs)
: IndigoObject(REPEATING_UNITS_ITER), _mol(molecule), _refs(std::move(refs))
{
_idx = -1;
}
IndigoRepeatingUnitsIter::~IndigoRepeatingUnitsIter()
{
}
bool IndigoRepeatingUnitsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoRepeatingUnitsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoRepeatingUnit> sgroup = std::make_unique<IndigoRepeatingUnit>(_mol, _refs[_idx]);
return sgroup.release();
}
IndigoMultipleGroup::IndigoMultipleGroup(BaseMolecule& mol_, int idx_) : IndigoObject(MULTIPLE_GROUP), mol(mol_)
{
idx = idx_;
}
IndigoMultipleGroup::~IndigoMultipleGroup()
{
}
int IndigoMultipleGroup::getIndex()
{
return idx;
}
void IndigoMultipleGroup::remove()
{
mol.removeSGroup(idx);
}
IndigoMultipleGroup& IndigoMultipleGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::MULTIPLE_GROUP)
return (IndigoMultipleGroup&)obj;
throw IndigoError("%s is not a multiple group", obj.debugInfo());
}
MultipleGroup& IndigoMultipleGroup::get()
{
return (MultipleGroup&)mol.sgroups.getSGroup(idx);
}
IndigoMultipleGroupsIter::IndigoMultipleGroupsIter(BaseMolecule& molecule, Array<int>&& refs)
: IndigoObject(MULTIPLE_GROUPS_ITER), _mol(molecule), _refs(std::move(refs))
{
_idx = -1;
}
IndigoMultipleGroupsIter::~IndigoMultipleGroupsIter()
{
}
bool IndigoMultipleGroupsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoMultipleGroupsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoMultipleGroup> sgroup = std::make_unique<IndigoMultipleGroup>(_mol, _refs[_idx]);
return sgroup.release();
}
IndigoGenericSGroup::IndigoGenericSGroup(BaseMolecule& mol_, int idx_) : IndigoObject(GENERIC_SGROUP), mol(mol_)
{
idx = idx_;
}
IndigoGenericSGroup::~IndigoGenericSGroup()
{
}
int IndigoGenericSGroup::getIndex()
{
return idx;
}
void IndigoGenericSGroup::remove()
{
mol.removeSGroup(idx);
}
IndigoGenericSGroup& IndigoGenericSGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::GENERIC_SGROUP)
return (IndigoGenericSGroup&)obj;
throw IndigoError("%s is not a generic sgroup", obj.debugInfo());
}
SGroup& IndigoGenericSGroup::get()
{
return (SGroup&)mol.sgroups.getSGroup(idx);
}
IndigoGenericSGroupsIter::IndigoGenericSGroupsIter(BaseMolecule& molecule, Array<int>&& refs)
: IndigoObject(GENERIC_SGROUPS_ITER), _mol(molecule), _refs(std::move(refs))
{
_idx = -1;
}
IndigoGenericSGroupsIter::~IndigoGenericSGroupsIter()
{
}
bool IndigoGenericSGroupsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoGenericSGroupsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoGenericSGroup> sgroup = std::make_unique<IndigoGenericSGroup>(_mol, _refs[_idx]);
return sgroup.release();
}
CEXPORT int indigoIterateGenericSGroups(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.sgroups.findSGroups(SGroup::SG_TYPE, SGroup::SG_TYPE_GEN, sgs);
return self.addObject(new IndigoGenericSGroupsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
IndigoSGroup::IndigoSGroup(BaseMolecule& mol_, int sg_idx_) : IndigoObject(SGROUP), mol(mol_)
{
idx = sg_idx_;
}
IndigoSGroup::~IndigoSGroup()
{
}
const char* IndigoSGroup::debugInfo() const
{
return "<sgroup>";
}
int IndigoSGroup::getIndex()
{
return idx;
}
void IndigoSGroup::remove()
{
mol.removeSGroup(idx);
}
IndigoSGroup& IndigoSGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::SGROUP || obj.type == IndigoObject::DATA_SGROUP || obj.type == IndigoObject::SUPERATOM ||
obj.type == IndigoObject::REPEATING_UNIT || obj.type == IndigoObject::MULTIPLE_GROUP || obj.type == IndigoObject::GENERIC_SGROUP)
return (IndigoSGroup&)obj;
throw IndigoError("%s is not a sgroup", obj.debugInfo());
}
SGroup& IndigoSGroup::get()
{
return (SGroup&)mol.sgroups.getSGroup(idx);
}
IndigoSGroupsIter::IndigoSGroupsIter(BaseMolecule& molecule, Array<int>&& sg_refs) : IndigoObject(SGROUPS_ITER), _mol(molecule), _refs(std::move(sg_refs))
{
_idx = -1;
}
IndigoSGroupsIter::~IndigoSGroupsIter()
{
}
const char* IndigoSGroupsIter::debugInfo() const
{
return "<sgroups iterator>";
}
bool IndigoSGroupsIter::hasNext()
{
if (_idx == -1)
return _refs.size() > 0;
return _idx + 1 < _refs.size();
}
IndigoObject* IndigoSGroupsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoSGroup> sgroup = std::make_unique<IndigoSGroup>(_mol, _refs[_idx]);
return sgroup.release();
}
CEXPORT int indigoIterateSGroups(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
for (auto i = mol.sgroups.begin(); i != mol.sgroups.end(); i = mol.sgroups.next(i))
{
sgs.push(i);
}
return self.addObject(new IndigoSGroupsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
IndigoTGroup::IndigoTGroup(BaseMolecule& mol_, int tg_idx_) : IndigoObject(TGROUP), mol(mol_)
{
idx = tg_idx_;
}
IndigoTGroup::~IndigoTGroup()
{
}
const char* IndigoTGroup::debugInfo() const
{
return "<tgroup>";
}
int IndigoTGroup::getIndex()
{
return idx;
}
void IndigoTGroup::remove()
{
mol.tgroups.remove(idx);
}
IndigoTGroup& IndigoTGroup::cast(IndigoObject& obj)
{
if (obj.type == IndigoObject::TGROUP)
return (IndigoTGroup&)obj;
throw IndigoError("%s is not a tgroup", obj.debugInfo());
}
TGroup& IndigoTGroup::get()
{
return (TGroup&)mol.tgroups.getTGroup(idx);
}
IndigoTGroupsIter::IndigoTGroupsIter(BaseMolecule& molecule) : IndigoObject(TGROUPS_ITER), _mol(molecule)
{
_idx = -1;
}
IndigoTGroupsIter::~IndigoTGroupsIter()
{
}
const char* IndigoTGroupsIter::debugInfo() const
{
return "<tgroups iterator>";
}
bool IndigoTGroupsIter::hasNext()
{
if (_idx == -1)
return _mol.tgroups.getTGroupCount() > 0;
return _idx + 1 < _mol.tgroups.getTGroupCount();
}
IndigoObject* IndigoTGroupsIter::next()
{
if (!hasNext())
return 0;
if (_idx == -1)
_idx = 0;
else
_idx++;
std::unique_ptr<IndigoTGroup> tgroup = std::make_unique<IndigoTGroup>(_mol, _idx);
return tgroup.release();
}
CEXPORT int indigoIterateTGroups(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoTGroupsIter(mol));
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateRepeatingUnits(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.sgroups.findSGroups(SGroup::SG_TYPE, SGroup::SG_TYPE_SRU, sgs);
return self.addObject(new IndigoRepeatingUnitsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateMultipleGroups(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.sgroups.findSGroups(SGroup::SG_TYPE, SGroup::SG_TYPE_MUL, sgs);
return self.addObject(new IndigoMultipleGroupsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateSuperatoms(int molecule)
{
INDIGO_BEGIN
{
QS_DEF(Array<int>, sgs);
sgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.sgroups.findSGroups(SGroup::SG_TYPE, SGroup::SG_TYPE_SUP, sgs);
return self.addObject(new IndigoSuperatomsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSuperatom(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= mol.sgroups.end())
throw IndigoError("Invalid Sgroup index %d", index);
SGroup& sg = mol.sgroups.getSGroup(index);
if (sg.sgroup_type == SGroup::SG_TYPE_SUP)
return self.addObject(new IndigoSuperatom(mol, index));
throw IndigoError("Sgroup with index %d is not a Superatom", index);
}
INDIGO_END(-1);
}
CEXPORT int indigoGetDataSGroup(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= mol.sgroups.end())
throw IndigoError("Invalid Sgroup index %d", index);
SGroup& sg = mol.sgroups.getSGroup(index);
if (sg.sgroup_type == SGroup::SG_TYPE_DAT)
return self.addObject(new IndigoDataSGroup(mol, index));
throw IndigoError("Sgroup with index %d is not a DataSGroup", index);
}
INDIGO_END(-1);
}
CEXPORT int indigoGetGenericSGroup(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= mol.sgroups.end())
throw IndigoError("Invalid Sgroup index %d", index);
SGroup& sg = mol.sgroups.getSGroup(index);
if (sg.sgroup_type == SGroup::SG_TYPE_GEN)
return self.addObject(new IndigoGenericSGroup(mol, index));
throw IndigoError("Sgroup with index %d is not a GenericSGroup", index);
}
INDIGO_END(-1);
}
CEXPORT int indigoGetMultipleGroup(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= mol.sgroups.end())
throw IndigoError("Invalid Sgroup index %d", index);
SGroup& sg = mol.sgroups.getSGroup(index);
if (sg.sgroup_type == SGroup::SG_TYPE_MUL)
return self.addObject(new IndigoMultipleGroup(mol, index));
throw IndigoError("Sgroup with index %d is not a MultipleGroup", index);
}
INDIGO_END(-1);
}
CEXPORT int indigoGetRepeatingUnit(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= mol.sgroups.end())
throw IndigoError("Invalid Sgroup index %d", index);
SGroup& sg = mol.sgroups.getSGroup(index);
if (sg.sgroup_type == SGroup::SG_TYPE_SRU)
return self.addObject(new IndigoRepeatingUnit(mol, index));
throw IndigoError("Sgroup with index %d is not a RepeatingUnit", index);
}
INDIGO_END(-1);
}
CEXPORT const char* indigoDescription(int data_sgroup)
{
INDIGO_BEGIN
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(data_sgroup));
if (dsg.get().name.size() < 1)
return "";
return dsg.get().name.ptr();
}
INDIGO_END(0);
}
CEXPORT const char* indigoData(int data_sgroup)
{
INDIGO_BEGIN
{
IndigoDataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(data_sgroup));
if (dsg.get().data.size() < 1)
return "";
return dsg.get().data.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoAddDataSGroup(int molecule, int natoms, int* atoms, int nbonds, int* bonds, const char* name, const char* data)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int idx = mol.sgroups.addSGroup(SGroup::SG_TYPE_DAT);
DataSGroup& dsg = (DataSGroup&)mol.sgroups.getSGroup(idx);
if (atoms != nullptr)
dsg.atoms.concat(atoms, natoms);
if (bonds != nullptr)
dsg.bonds.concat(bonds, nbonds);
if (data != nullptr)
dsg.data.readString(data, true);
if (name != nullptr)
dsg.name.readString(name, true);
return self.addObject(new IndigoDataSGroup(mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoAddSuperatom(int molecule, int natoms, int* atoms, const char* name)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int idx = mol.sgroups.addSGroup(SGroup::SG_TYPE_SUP);
Superatom& satom = (Superatom&)mol.sgroups.getSGroup(idx);
satom.subscript.appendString(name, true);
if (atoms == nullptr)
throw IndigoError("indigoAddSuperatom(): atoms were not specified");
else
satom.atoms.concat(atoms, natoms);
return self.addObject(new IndigoSuperatom(mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoSetDataSGroupXY(int sgroup, float x, float y, const char* options)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
dsg.display_pos.x = x;
dsg.display_pos.y = y;
dsg.detached = true;
if (options != 0 && options[0] != 0)
{
if (strcasecmp(options, "absolute") == 0)
dsg.relative = false;
else if (strcasecmp(options, "relative") == 0)
dsg.relative = true;
else
throw IndigoError("indigoSetDataSGroupXY(): invalid options string");
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupData(int sgroup, const char* data)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (data != 0)
dsg.data.readString(data, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupCoords(int sgroup, float x, float y)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
dsg.display_pos.x = x;
dsg.display_pos.y = y;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupDescription(int sgroup, const char* description)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (description != 0)
dsg.description.readString(description, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupFieldName(int sgroup, const char* name)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (name != 0)
dsg.name.readString(name, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupQueryCode(int sgroup, const char* querycode)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (querycode != 0)
dsg.querycode.readString(querycode, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupQueryOper(int sgroup, const char* queryoper)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (queryoper != 0)
dsg.queryoper.readString(queryoper, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupDisplay(int sgroup, const char* option)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (option != 0 && option[0] != 0)
{
if (strcasecmp(option, "attached") == 0)
dsg.detached = false;
else if (strcasecmp(option, "detached") == 0)
dsg.detached = true;
else
throw IndigoError("indigoSetSgroupDisplay(): invalid option string");
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupLocation(int sgroup, const char* option)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (option != 0 && option[0] != 0)
{
if (strcasecmp(option, "absolute") == 0)
dsg.relative = false;
else if (strcasecmp(option, "relative") == 0)
dsg.relative = true;
else
throw IndigoError("indigoSetSgroupLocation(): invalid option string");
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupTag(int sgroup, const char* tag)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (tag != 0 && tag[0] != 0)
{
dsg.tag = tag[0];
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupTagAlign(int sgroup, int tag_align)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (tag_align > 0 && tag_align < 10)
{
dsg.dasp_pos = tag_align;
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupDataType(int sgroup, const char* data_type)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
if (data_type != 0 && data_type[0] != 0)
{
dsg.type.readString(data_type, true);
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupXCoord(int sgroup, float x)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
dsg.display_pos.x = x;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupYCoord(int sgroup, float y)
{
INDIGO_BEGIN
{
DataSGroup& dsg = IndigoDataSGroup::cast(self.getObject(sgroup)).get();
dsg.display_pos.y = y;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoCreateSGroup(const char* type, int mapping, const char* name)
{
INDIGO_BEGIN
{
IndigoMapping& map = IndigoMapping::cast(self.getObject(mapping));
BaseMolecule& mol = map.to;
BaseMolecule& temp = map.from;
Array<int>& m = map.mapping;
int idx = mol.sgroups.addSGroup(type);
if (idx != -1)
{
SGroup& sgroup = mol.sgroups.getSGroup(idx);
for (auto i : temp.vertices())
{
sgroup.atoms.push(m[i]);
}
for (auto i : mol.edges())
{
const Edge& edge = mol.getEdge(i);
if (((sgroup.atoms.find(edge.beg) != -1) && (sgroup.atoms.find(edge.end) == -1)) ||
((sgroup.atoms.find(edge.end) != -1) && (sgroup.atoms.find(edge.beg) == -1)))
{
sgroup.bonds.push(i);
}
}
if (sgroup.sgroup_type == SGroup::SG_TYPE_SUP)
{
Superatom& sa = (Superatom&)sgroup;
sa.subscript.appendString(name, true);
return self.addObject(new IndigoSuperatom(mol, idx));
}
else if (sgroup.sgroup_type == SGroup::SG_TYPE_SRU)
{
RepeatingUnit& ru = (RepeatingUnit&)sgroup;
ru.subscript.appendString(name, true);
return self.addObject(new IndigoRepeatingUnit(mol, idx));
}
else if (sgroup.sgroup_type == SGroup::SG_TYPE_MUL)
{
return self.addObject(new IndigoMultipleGroup(mol, idx));
}
else if (sgroup.sgroup_type == SGroup::SG_TYPE_DAT)
{
return self.addObject(new IndigoDataSGroup(mol, idx));
}
else
{
return self.addObject(new IndigoGenericSGroup(mol, idx));
}
}
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupClass(int sgroup, const char* sgclass)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
sup.sa_class.readString(sgclass, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT const char* indigoGetSGroupClass(int sgroup)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
if (sup.sa_class.size() < 1)
return "";
return sup.sa_class.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoSetSGroupName(int sgroup, const char* sgname)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
sup.subscript.readString(sgname, true);
return 1;
}
INDIGO_END(-1);
}
CEXPORT const char* indigoGetSGroupName(int sgroup)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
if (sup.subscript.size() < 1)
return "";
return sup.subscript.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoGetSGroupNumCrossBonds(int sgroup)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
return sup.bonds.size();
}
INDIGO_END(-1);
}
CEXPORT int indigoAddSGroupAttachmentPoint(int sgroup, int aidx, int lvidx, const char* apid)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
int ap_idx = sup.attachment_points.add();
Superatom::_AttachmentPoint& ap = sup.attachment_points.at(ap_idx);
ap.aidx = aidx;
ap.lvidx = lvidx;
ap.apid.readString(apid, true);
return ap_idx;
}
INDIGO_END(-1);
}
CEXPORT int indigoDeleteSGroupAttachmentPoint(int sgroup, int ap_idx)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
sup.attachment_points.remove(ap_idx);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupDisplayOption(int sgroup)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
if (sup.contracted > DisplayOption::Undefined)
return (int)sup.contracted;
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupDisplayOption(int sgroup, int option)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
sup.contracted = (DisplayOption)option;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupSeqId(int sgroup)
{
INDIGO_BEGIN
{
Superatom& sup = IndigoSuperatom::cast(self.getObject(sgroup)).get();
if (sup.seqid != -1)
return sup.seqid;
return 0;
}
INDIGO_END(0);
}
CEXPORT float* indigoGetSGroupCoords(int sgroup)
{
INDIGO_BEGIN
{
IndigoDataSGroup& ds = IndigoDataSGroup::cast(self.getObject(sgroup));
auto& tmp = self.getThreadTmpData();
auto& xy = ds.get().display_pos;
tmp.xyz[0] = xy.x;
tmp.xyz[1] = xy.y;
tmp.xyz[2] = 0.f;
return tmp.xyz;
}
INDIGO_END(0);
}
CEXPORT int indigoGetSGroupMultiplier(int sgroup)
{
INDIGO_BEGIN
{
MultipleGroup& mg = IndigoMultipleGroup::cast(self.getObject(sgroup)).get();
return mg.multiplier;
}
INDIGO_END(-1);
}
CEXPORT const char* indigoGetRepeatingUnitSubscript(int sgroup)
{
INDIGO_BEGIN
{
RepeatingUnit& ru = IndigoRepeatingUnit::cast(self.getObject(sgroup)).get();
return ru.subscript.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoGetRepeatingUnitConnectivity(int sgroup)
{
INDIGO_BEGIN
{
RepeatingUnit& ru = IndigoRepeatingUnit::cast(self.getObject(sgroup)).get();
return ru.connectivity;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupMultiplier(int sgroup, int multiplier)
{
INDIGO_BEGIN
{
MultipleGroup& mg = IndigoMultipleGroup::cast(self.getObject(sgroup)).get();
mg.multiplier = multiplier;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupBrackets(int sgroup, int brk_style, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4)
{
INDIGO_BEGIN
{
SGroup* psg = 0;
if (self.getObject(sgroup).type == IndigoObject::GENERIC_SGROUP)
psg = &(IndigoGenericSGroup::cast(self.getObject(sgroup)).get());
else if (self.getObject(sgroup).type == IndigoObject::REPEATING_UNIT)
psg = &(IndigoRepeatingUnit::cast(self.getObject(sgroup)).get());
else if (self.getObject(sgroup).type == IndigoObject::MULTIPLE_GROUP)
psg = &(IndigoMultipleGroup::cast(self.getObject(sgroup)).get());
else
throw IndigoError("indigoSetSgroupBrackets(): brackets properties are not supported for this Sgroup type");
psg->brk_style = brk_style;
psg->brackets.clear();
Vec2f* brackets = psg->brackets.push();
brackets[0].set(x1, y1);
brackets[1].set(x2, y2);
brackets = psg->brackets.push();
brackets[0].set(x3, y3);
brackets[1].set(x4, y4);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoFindSGroups(int item, const char* property, const char* value)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(item).getBaseMolecule();
QS_DEF(Array<int>, sgs);
sgs.clear();
mol.sgroups.findSGroups(property, value, sgs);
return self.addObject(new IndigoSGroupsIter(mol, std::move(sgs)));
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupType(int sgroup)
{
INDIGO_BEGIN
{
IndigoSGroup& sg = IndigoSGroup::cast(self.getObject(sgroup));
return sg.get().sgroup_type;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupIndex(int sgroup)
{
INDIGO_BEGIN
{
IndigoSGroup& sg = IndigoSGroup::cast(self.getObject(sgroup));
return sg.idx;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupOriginalId(int sgroup)
{
INDIGO_BEGIN
{
IndigoSGroup& sg = IndigoSGroup::cast(self.getObject(sgroup));
return sg.get().original_group;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupOriginalId(int sgroup, int new_original)
{
INDIGO_BEGIN
{
IndigoSGroup& sgr = IndigoSGroup::cast(self.getObject(sgroup));
for (auto i = sgr.mol.sgroups.begin(); i != sgr.mol.sgroups.end(); i = sgr.mol.sgroups.next(i))
{
SGroup& sg = sgr.mol.sgroups.getSGroup(i);
if (sg.original_group == new_original && i != sgr.idx)
throw IndigoError("indigoSetSGroupOriginalId: duplicated sgroup id %d )", new_original);
}
int old_original = sgr.get().original_group;
if (old_original > 0)
{
for (auto i = sgr.mol.sgroups.begin(); i != sgr.mol.sgroups.end(); i = sgr.mol.sgroups.next(i))
{
SGroup& sg = sgr.mol.sgroups.getSGroup(i);
if (sg.parent_group == old_original)
sg.parent_group = new_original;
}
}
sgr.get().original_group = new_original;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoGetSGroupParentId(int sgroup)
{
INDIGO_BEGIN
{
IndigoSGroup& sg = IndigoSGroup::cast(self.getObject(sgroup));
return sg.get().parent_group;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetSGroupParentId(int sgroup, int parent)
{
INDIGO_BEGIN
{
IndigoSGroup& sgr = IndigoSGroup::cast(self.getObject(sgroup));
bool original_found = false;
for (auto i = sgr.mol.sgroups.begin(); i != sgr.mol.sgroups.end(); i = sgr.mol.sgroups.next(i))
{
SGroup& sg = sgr.mol.sgroups.getSGroup(i);
if (sg.original_group == parent)
original_found = true;
}
if (!original_found)
throw IndigoError("indigoSetSGroupParentId: sgroup with original id %d is not found)", parent);
sgr.get().parent_group = parent;
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoAddTemplate(int molecule, int templates, const char* tname)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
BaseMolecule& temp = self.getObject(templates).getBaseMolecule();
int tgidx = temp.tgroups.findTGroup(tname);
if (tgidx != -1)
{
TGroup& tg = temp.tgroups.getTGroup(tgidx);
int idx = mol.addTemplate(tg);
return idx + 1;
}
return 0;
}
INDIGO_END(-1);
}
CEXPORT int indigoRemoveTemplate(int molecule, const char* tname)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int tgidx = mol.tgroups.findTGroup(tname);
if (tgidx != -1)
{
mol.tgroups.remove(tgidx);
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoFindTemplate(int molecule, const char* tname)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int tgidx = mol.tgroups.findTGroup(tname);
if (tgidx != -1)
{
return tgidx + 1;
}
return 0;
}
INDIGO_END(-1);
}
CEXPORT const char* indigoGetTGroupClass(int tgroup)
{
INDIGO_BEGIN
{
TGroup& tg = IndigoTGroup::cast(self.getObject(tgroup)).get();
if (tg.tgroup_class.size() < 1)
return "";
return tg.tgroup_class.ptr();
}
INDIGO_END(0);
}
CEXPORT const char* indigoGetTGroupName(int tgroup)
{
INDIGO_BEGIN
{
TGroup& tg = IndigoTGroup::cast(self.getObject(tgroup)).get();
if (tg.tgroup_name.size() < 1)
return "";
return tg.tgroup_name.ptr();
}
INDIGO_END(0);
}
CEXPORT const char* indigoGetTGroupAlias(int tgroup)
{
INDIGO_BEGIN
{
TGroup& tg = IndigoTGroup::cast(self.getObject(tgroup)).get();
if (tg.tgroup_alias.size() < 1)
return "";
return tg.tgroup_alias.ptr();
}
INDIGO_END(0);
}
CEXPORT int indigoTransformSCSRtoCTAB(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
mol.transformSCSRtoFullCTAB();
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoTransformCTABtoSCSR(int molecule, int templates)
{
INDIGO_BEGIN
{
QS_DEF(ObjArray<TGroup>, tgs);
tgs.clear();
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
BaseMolecule& temp = self.getObject(templates).getBaseMolecule();
for (auto i = temp.tgroups.begin(); i != temp.tgroups.end(); i = temp.tgroups.next(i))
{
TGroup& tg = tgs.push();
tg.copy(temp.tgroups.getTGroup(i));
}
mol.ignore_chem_templates = self.scsr_ignore_chem_templates;
mol.transformFullCTABtoSCSR(tgs);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoCountHeavyAtoms(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
int i, cnt = 0;
for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
if (!mol.possibleAtomNumber(i, ELEM_H))
cnt++;
return cnt;
}
INDIGO_END(-1);
}
CEXPORT int indigoCountComponents(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return bm.countComponents();
}
INDIGO_END(-1);
}
CEXPORT int indigoCloneComponent(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= bm.countComponents())
throw IndigoError("indigoCloneComponent(): bad index %d (0-%d allowed)", index, bm.countComponents() - 1);
Filter filter(bm.getDecomposition().ptr(), Filter::EQ, index);
std::unique_ptr<IndigoMolecule> im = std::make_unique<IndigoMolecule>();
im->mol.makeSubmolecule(bm, filter, 0, 0);
return self.addObject(im.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoComponentIndex(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
return ia.mol.vertexComponent(ia.idx);
}
INDIGO_END(-1);
}
CEXPORT int indigoComponent(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
if (index < 0 || index >= bm.countComponents())
throw IndigoError("indigoComponent(): bad index %d (0-%d allowed)", index, bm.countComponents() - 1);
return self.addObject(new IndigoMoleculeComponent(bm, index));
}
INDIGO_END(-1);
}
IndigoComponentAtomsIter::IndigoComponentAtomsIter(BaseMolecule& mol, int cidx) : IndigoObject(COMPONENT_ATOMS_ITER), _mol(mol)
{
if (cidx < 0 || cidx >= mol.countComponents())
throw IndigoError("%d is not a valid component number (0-%d allowed)", cidx, _mol.countComponents() - 1);
_idx = -1;
_cidx = cidx;
}
IndigoComponentAtomsIter::~IndigoComponentAtomsIter()
{
}
bool IndigoComponentAtomsIter::hasNext()
{
return _next() != _mol.vertexEnd();
}
IndigoObject* IndigoComponentAtomsIter::next()
{
int idx = _next();
if (idx == _mol.vertexEnd())
return 0;
_idx = idx;
return new IndigoAtom(_mol, idx);
}
int IndigoComponentAtomsIter::_next()
{
int idx;
if (_idx == -1)
idx = _mol.vertexBegin();
else
idx = _mol.vertexNext(_idx);
for (; idx != _mol.vertexEnd(); idx = _mol.vertexNext(idx))
if (_mol.vertexComponent(idx) == _cidx)
break;
return idx;
}
IndigoComponentBondsIter::IndigoComponentBondsIter(BaseMolecule& mol, int cidx) : IndigoObject(COMPONENT_BONDS_ITER), _mol(mol)
{
if (cidx < 0 || cidx >= _mol.countComponents())
throw IndigoError("%d is not a valid component number (0-%d allowed)", cidx, _mol.countComponents() - 1);
_idx = -1;
_cidx = cidx;
}
IndigoComponentBondsIter::~IndigoComponentBondsIter()
{
}
bool IndigoComponentBondsIter::hasNext()
{
return _next() != _mol.edgeEnd();
}
IndigoObject* IndigoComponentBondsIter::next()
{
int idx = _next();
if (idx == _mol.edgeEnd())
return 0;
_idx = idx;
return new IndigoBond(_mol, idx);
}
int IndigoComponentBondsIter::_next()
{
int idx;
if (_idx == -1)
idx = _mol.edgeBegin();
else
idx = _mol.edgeNext(_idx);
for (; idx != _mol.edgeEnd(); idx = _mol.edgeNext(idx))
{
const Edge& edge = _mol.getEdge(idx);
int comp = _mol.vertexComponent(edge.beg);
if (comp != _mol.vertexComponent(edge.end))
throw IndigoError("internal: edge ends belong to different components");
if (comp == _cidx)
break;
}
return idx;
}
CEXPORT int indigoIterateComponents(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoComponentsIter(bm));
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateComponentAtoms(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoComponentAtomsIter(bm, index));
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateComponentBonds(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoComponentBondsIter(bm, index));
}
INDIGO_END(-1);
}
CEXPORT int indigoCountComponentAtoms(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return bm.countComponentVertices(index);
}
INDIGO_END(-1);
}
CEXPORT int indigoCountComponentBonds(int molecule, int index)
{
INDIGO_BEGIN
{
BaseMolecule& bm = self.getObject(molecule).getBaseMolecule();
return bm.countComponentEdges(index);
}
INDIGO_END(-1);
}
CEXPORT int indigoCreateMolecule()
{
INDIGO_BEGIN
{
std::unique_ptr<IndigoMolecule> obj = std::make_unique<IndigoMolecule>();
return self.addObject(obj.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoCreateQueryMolecule()
{
INDIGO_BEGIN
{
return self.addObject(new IndigoQueryMolecule());
}
INDIGO_END(-1);
}
CEXPORT int indigoMerge(int where, int what)
{
INDIGO_BEGIN
{
BaseMolecule& mol_where = self.getObject(where).getBaseMolecule();
BaseMolecule& mol_what = self.getObject(what).getBaseMolecule();
std::unique_ptr<IndigoMapping> res = std::make_unique<IndigoMapping>(mol_what, mol_where);
mol_where.mergeWithMolecule(mol_what, &res->mapping, 0);
return self.addObject(res.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoAddAtom(int molecule, const char* symbol)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(molecule);
BaseMolecule& bmol = obj.getBaseMolecule();
int idx;
if (bmol.isQueryMolecule())
{
QueryMolecule& qmol = bmol.asQueryMolecule();
idx = qmol.addAtom(IndigoQueryMolecule::parseAtomSMARTS(symbol));
}
else
{
Molecule& mol = bmol.asMolecule();
int elem = Element::fromString2(symbol);
if (elem > 0)
idx = mol.addAtom(elem);
else
{
idx = mol.addAtom(ELEM_PSEUDO);
mol.setPseudoAtom(idx, symbol);
}
}
return self.addObject(new IndigoAtom(bmol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoResetAtom(int atom, const char* symbol)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& bmol = ia.mol;
if (bmol.isQueryMolecule())
{
QueryMolecule& qmol = bmol.asQueryMolecule();
qmol.resetAtom(ia.idx, IndigoQueryMolecule::parseAtomSMARTS(symbol));
}
else
{
Molecule& mol = ia.mol.asMolecule();
int elem = Element::fromString2(symbol);
if (elem > 0)
mol.resetAtom(ia.idx, elem);
else if (!mol.isTemplateAtom(ia.idx))
{
mol.resetAtom(ia.idx, ELEM_PSEUDO);
mol.setPseudoAtom(ia.idx, symbol);
}
else
{
mol.setTemplateAtomName(ia.idx, symbol);
}
}
bmol.invalidateAtom(ia.idx, BaseMolecule::CHANGED_ATOM_NUMBER);
return 1;
}
INDIGO_END(-1);
}
CEXPORT const char* indigoGetTemplateAtomClass(int atom)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& bmol = ia.mol;
Molecule& mol = ia.mol.asMolecule();
if (mol.isTemplateAtom(ia.idx))
{
return ia.mol.getTemplateAtomClass(ia.idx);
}
else
throw IndigoError("indigoGetTemplateAtomClass(): atom %d is not template atom", ia.idx);
return "";
}
INDIGO_END(0);
}
CEXPORT int indigoSetTemplateAtomClass(int atom, const char* name)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
BaseMolecule& bmol = ia.mol;
Molecule& mol = ia.mol.asMolecule();
if (mol.isTemplateAtom(ia.idx))
{
mol.setTemplateAtomClass(ia.idx, name);
}
else
throw IndigoError("indigoSetTemplateAtomClass(): atom %d is not template atom", ia.idx);
return 1;
}
INDIGO_END(-1);
}
static void _parseRSites(const char* name, Array<int>& rsites)
{
BufferScanner scanner(name);
rsites.clear();
while (!scanner.isEOF())
{
scanner.skipSpace();
if (scanner.lookNext() != 'R')
throw IndigoError("indigoAddRSite(): cannot parse '%s' as r-site name(s)", name);
scanner.readChar();
if (scanner.isEOF())
break;
if (isdigit(scanner.lookNext()))
{
int idx = scanner.readInt();
rsites.push(idx);
}
scanner.skipSpace();
if (scanner.lookNext() == ',' || scanner.lookNext() == ';')
scanner.readChar();
}
}
static void _indigoSetRSite(Molecule& mol, int atom_index, const char* name)
{
// Parse r-sites
QS_DEF(Array<int>, rsites);
_parseRSites(name, rsites);
mol.resetAtom(atom_index, ELEM_RSITE);
mol.setRSiteBits(atom_index, 0);
for (int i = 0; i < rsites.size(); i++)
mol.allowRGroupOnRSite(atom_index, rsites[i]);
}
CEXPORT int indigoAddRSite(int molecule, const char* name)
{
INDIGO_BEGIN
{
Molecule& mol = self.getObject(molecule).getMolecule();
int idx = mol.addAtom(ELEM_RSITE);
try
{
_indigoSetRSite(mol, idx, name);
}
catch (...)
{
// Remove atom if there is an exception (r-site index is very big for example)
mol.removeAtom(idx);
throw;
}
return self.addObject(new IndigoAtom(mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoSetRSite(int atom, const char* name)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
Molecule& mol = ia.mol.asMolecule();
_indigoSetRSite(mol, ia.idx, name);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetCharge(int atom, int charge)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.asMolecule().setAtomCharge(ia.idx, charge);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetIsotope(int atom, int isotope)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.asMolecule().setAtomIsotope(ia.idx, isotope);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoSetImplicitHCount(int atom, int impl_h)
{
INDIGO_BEGIN
{
IndigoAtom& ia = IndigoAtom::cast(self.getObject(atom));
ia.mol.asMolecule().setImplicitH(ia.idx, impl_h);
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoAddBond(int source, int destination, int order)
{
INDIGO_BEGIN
{
IndigoAtom& s_atom = IndigoAtom::cast(self.getObject(source));
IndigoAtom& d_atom = IndigoAtom::cast(self.getObject(destination));
if (&s_atom.mol != &d_atom.mol)
throw IndigoError("indigoAddBond(): molecules do not match");
int idx;
if (s_atom.mol.isQueryMolecule())
idx = s_atom.mol.asQueryMolecule().addBond(s_atom.idx, d_atom.idx, new QueryMolecule::Bond(QueryMolecule::BOND_ORDER, order));
else
idx = s_atom.mol.asMolecule().addBond(s_atom.idx, d_atom.idx, order);
return self.addObject(new IndigoBond(s_atom.mol, idx));
}
INDIGO_END(-1);
}
CEXPORT int indigoSetBondOrder(int bond, int order)
{
INDIGO_BEGIN
{
IndigoBond& ib = IndigoBond::cast(self.getObject(bond));
ib.mol.asMolecule().setBondOrder(ib.idx, order, false);
return 1;
}
INDIGO_END(-1);
}
IndigoSubmolecule::IndigoSubmolecule(BaseMolecule& mol_, Array<int>& vertices_, Array<int>& edges_) : IndigoObject(SUBMOLECULE), _mol(mol_)
{
vertices.copy(vertices_);
edges.copy(edges_);
idx = -1;
}
IndigoSubmolecule::IndigoSubmolecule(BaseMolecule& mol_, List<int>& vertices_, List<int>& edges_) : IndigoObject(SUBMOLECULE), _mol(mol_)
{
int i;
vertices.clear();
edges.clear();
for (i = vertices_.begin(); i != vertices_.end(); i = vertices_.next(i))
vertices.push(vertices_[i]);
for (i = edges_.begin(); i != edges_.end(); i = edges_.next(i))
edges.push(edges_[i]);
idx = -1;
}
IndigoSubmolecule::~IndigoSubmolecule()
{
}
void IndigoSubmolecule::_createSubMolecule()
{
if (_submol.get() != 0 && _submol_revision == _mol.getEditRevision())
{
return;
}
if (_mol.isQueryMolecule())
{
_submol = std::make_unique<QueryMolecule>();
}
else
{
_submol = std::make_unique<Molecule>();
}
_submol->makeEdgeSubmolecule(_mol, vertices, edges, 0, 0);
_submol_revision = _mol.getEditRevision();
}
BaseMolecule& IndigoSubmolecule::getBaseMolecule()
{
_createSubMolecule();
return *_submol;
}
int IndigoSubmolecule::getIndex()
{
if (idx == -1)
throw IndigoError("index not set");
return idx;
}
IndigoObject* IndigoSubmolecule::clone()
{
std::unique_ptr<IndigoObject> res;
BaseMolecule* newmol;
if (_mol.isQueryMolecule())
{
res = std::make_unique<IndigoQueryMolecule>();
newmol = &(((IndigoQueryMolecule*)res.get())->qmol);
}
else
{
res = std::make_unique<IndigoMolecule>();
newmol = &(((IndigoMolecule*)res.get())->mol);
}
newmol->makeEdgeSubmolecule(_mol, vertices, edges, 0, 0);
return res.release();
}
IndigoSubmoleculeAtomsIter::IndigoSubmoleculeAtomsIter(IndigoSubmolecule& submol) : IndigoObject(SUBMOLECULE_ATOMS_ITER), _submol(submol)
{
_idx = -1;
}
IndigoSubmoleculeAtomsIter::~IndigoSubmoleculeAtomsIter()
{
}
bool IndigoSubmoleculeAtomsIter::hasNext()
{
return _idx + 1 < _submol.vertices.size();
}
IndigoObject* IndigoSubmoleculeAtomsIter::next()
{
if (!hasNext())
return 0;
_idx++;
return new IndigoAtom(_submol.getOriginalMolecule(), _submol.vertices[_idx]);
}
IndigoSubmoleculeBondsIter::IndigoSubmoleculeBondsIter(IndigoSubmolecule& submol) : IndigoObject(SUBMOLECULE_BONDS_ITER), _submol(submol)
{
_idx = -1;
}
IndigoSubmoleculeBondsIter::~IndigoSubmoleculeBondsIter()
{
}
bool IndigoSubmoleculeBondsIter::hasNext()
{
return _idx + 1 < _submol.edges.size();
}
IndigoObject* IndigoSubmoleculeBondsIter::next()
{
if (!hasNext())
return 0;
_idx++;
return new IndigoBond(_submol.getOriginalMolecule(), _submol.edges[_idx]);
}
CEXPORT int indigoCountSSSR(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return mol.sssrCount();
}
INDIGO_END(-1);
}
CEXPORT int indigoIterateSSSR(int molecule)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoSSSRIter(mol));
}
INDIGO_END(-1);
}
IndigoSSSRIter::IndigoSSSRIter(BaseMolecule& mol) : IndigoObject(SSSR_ITER), _mol(mol)
{
_idx = -1;
}
IndigoSSSRIter::~IndigoSSSRIter()
{
}
bool IndigoSSSRIter::hasNext()
{
return _idx + 1 < _mol.sssrCount();
}
IndigoObject* IndigoSSSRIter::next()
{
if (!hasNext())
return 0;
_idx++;
List<int>& vertices = _mol.sssrVertices(_idx);
List<int>& edges = _mol.sssrEdges(_idx);
std::unique_ptr<IndigoSubmolecule> res = std::make_unique<IndigoSubmolecule>(_mol, vertices, edges);
res->idx = _idx;
return res.release();
}
IndigoSubtreesIter::IndigoSubtreesIter(BaseMolecule& mol, int min_vertices, int max_vertices) : IndigoObject(SUBTREES_ITER), _mol(mol), _enumerator(mol)
{
_enumerator.min_vertices = min_vertices;
_enumerator.max_vertices = max_vertices;
_enumerator.context = this;
_enumerator.callback = _handleTree;
_enumerator.process();
_idx = -1;
}
IndigoSubtreesIter::~IndigoSubtreesIter()
{
}
void IndigoSubtreesIter::_handleTree(Graph& graph, const Array<int>& vertices, const Array<int>& edges, void* context)
{
IndigoSubtreesIter* self = (IndigoSubtreesIter*)context;
Array<int>& self_vertices = self->_vertices.push();
Array<int>& self_edges = self->_edges.push();
self_vertices.copy(vertices);
self_edges.copy(edges);
}
bool IndigoSubtreesIter::hasNext()
{
return _idx + 1 < _vertices.size();
}
IndigoObject* IndigoSubtreesIter::next()
{
if (!hasNext())
return 0;
_idx++;
std::unique_ptr<IndigoSubmolecule> res = std::make_unique<IndigoSubmolecule>(_mol, _vertices[_idx], _edges[_idx]);
res->idx = _idx;
return res.release();
}
CEXPORT int indigoIterateSubtrees(int molecule, int min_atoms, int max_atoms)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoSubtreesIter(mol, min_atoms, max_atoms));
}
INDIGO_END(-1);
}
IndigoRingsIter::IndigoRingsIter(BaseMolecule& mol, int min_vertices, int max_vertices) : IndigoObject(RINGS_ITER), _mol(mol), _enumerator(mol)
{
_enumerator.min_length = min_vertices;
_enumerator.max_length = max_vertices;
_enumerator.context = this;
_enumerator.cb_handle_cycle = _handleCycle;
_enumerator.process();
_idx = -1;
}
IndigoRingsIter::~IndigoRingsIter()
{
}
bool IndigoRingsIter::_handleCycle(Graph& graph, const Array<int>& vertices, const Array<int>& edges, void* context)
{
IndigoRingsIter* self = (IndigoRingsIter*)context;
self->_vertices.push().copy(vertices);
self->_edges.push().copy(edges);
return true;
}
bool IndigoRingsIter::hasNext()
{
return _idx + 1 < _vertices.size();
}
IndigoObject* IndigoRingsIter::next()
{
if (!hasNext())
return 0;
_idx++;
std::unique_ptr<IndigoSubmolecule> res = std::make_unique<IndigoSubmolecule>(_mol, _vertices[_idx], _edges[_idx]);
res->idx = _idx;
return res.release();
}
CEXPORT int indigoIterateRings(int molecule, int min_atoms, int max_atoms)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoRingsIter(mol, min_atoms, max_atoms));
}
INDIGO_END(-1);
}
IndigoEdgeSubmoleculeIter::IndigoEdgeSubmoleculeIter(BaseMolecule& mol, int min_edges, int max_edges)
: IndigoObject(EDGE_SUBMOLECULE_ITER), _mol(mol), _enumerator(mol)
{
_enumerator.min_edges = min_edges;
_enumerator.max_edges = max_edges;
_enumerator.userdata = this;
_enumerator.cb_subgraph = _handleSubgraph;
_enumerator.process();
_idx = -1;
}
IndigoEdgeSubmoleculeIter::~IndigoEdgeSubmoleculeIter()
{
}
void IndigoEdgeSubmoleculeIter::_handleSubgraph(Graph& graph, const int* v_mapping, const int* e_mapping, void* context)
{
IndigoEdgeSubmoleculeIter* self = (IndigoEdgeSubmoleculeIter*)context;
Array<int>& vertices = self->_vertices.push();
Array<int>& edges = self->_edges.push();
Graph::filterVertices(graph, v_mapping, FILTER_NEQ, -1, vertices);
Graph::filterEdges(graph, e_mapping, FILTER_NEQ, -1, edges);
}
bool IndigoEdgeSubmoleculeIter::hasNext()
{
return _idx + 1 < _vertices.size();
}
IndigoObject* IndigoEdgeSubmoleculeIter::next()
{
if (!hasNext())
return 0;
_idx++;
std::unique_ptr<IndigoSubmolecule> res = std::make_unique<IndigoSubmolecule>(_mol, _vertices[_idx], _edges[_idx]);
res->idx = _idx;
return res.release();
}
CEXPORT int indigoIterateEdgeSubmolecules(int molecule, int min_bonds, int max_bonds)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoEdgeSubmoleculeIter(mol, min_bonds, max_bonds));
}
INDIGO_END(-1);
}
CEXPORT int indigoCountHydrogens(int item, int* hydro)
{
INDIGO_BEGIN
{
if (hydro == 0)
throw IndigoError("indigoCountHydrogens(): null pointer");
IndigoObject& obj = self.getObject(item);
if (IndigoAtom::is(obj))
{
IndigoAtom& ia = IndigoAtom::cast(obj);
int res = ia.mol.getAtomTotalH(ia.idx);
if (res == -1)
return 0;
*hydro = res;
}
else if (IndigoBaseMolecule::is(obj))
{
Molecule& mol = obj.getMolecule();
*hydro = 0;
for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
{
if (mol.getAtomNumber(i) == ELEM_H)
(*hydro)++;
else if (!mol.isPseudoAtom(i) && !mol.isRSite(i))
(*hydro) += mol.getImplicitH(i);
}
}
return 1;
}
INDIGO_END(-1);
}
CEXPORT int indigoCountImplicitHydrogens(int item)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(item);
if (IndigoAtom::is(obj))
{
IndigoAtom& ia = IndigoAtom::cast(obj);
return ia.mol.asMolecule().getImplicitH(ia.idx);
}
else if (IndigoBaseMolecule::is(obj))
{
Molecule& mol = obj.getMolecule();
int i, sum = 0;
for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
sum += mol.getImplicitH(i);
return sum;
}
else
throw IndigoError("indigoCountImplicitHydrogens: %s is not a molecule nor an atom", obj.debugInfo());
}
INDIGO_END(-1);
}
//
// IndigoAttachmentPointsIter
//
IndigoAttachmentPointsIter::IndigoAttachmentPointsIter(BaseMolecule& mol, int order) : IndigoObject(ATTACHMENT_POINTS_ITER), _mol(mol)
{
_order = order;
_index = -1;
}
IndigoObject* IndigoAttachmentPointsIter::next()
{
if (!hasNext())
return 0;
_index++;
int atom_index = _mol.getAttachmentPoint(_order, _index);
if (atom_index == -1)
throw IndigoError("Internal error in IndigoAttachmentPointsIter::next");
return new IndigoAtom(_mol, atom_index);
}
bool IndigoAttachmentPointsIter::hasNext()
{
return _mol.getAttachmentPoint(_order, _index + 1) != -1;
}
CEXPORT int indigoIterateAttachmentPoints(int molecule, int order)
{
INDIGO_BEGIN
{
BaseMolecule& mol = self.getObject(molecule).getBaseMolecule();
return self.addObject(new IndigoAttachmentPointsIter(mol, order));
}
INDIGO_END(-1);
}
/*
Converts a chemical name into a corresponding structure
Returns -1 if parsing fails or no structure is found
Parameters:
name - a name to parse
params - a string containing parsing options or nullptr if no options are changed
*/
CEXPORT int indigoNameToStructure(const char* name, const char* params)
{
INDIGO_BEGIN
{
if (name == nullptr)
{
throw IndigoError("indigoNameToStructure: invalid parameter");
}
MoleculeNameParser parser;
if (params)
{
/*
Duplicate params string as we call destructive function strtok() on callee side
We can get rid of it if we have sustainable options in the future
*/
char* options = ::strdup(params);
if (options)
{
parser.setOptions(options);
::free(options);
}
}
std::unique_ptr<IndigoMolecule> molptr = std::make_unique<IndigoMolecule>();
Molecule& mol = molptr->mol;
parser.parseMolecule(name, mol);
return self.addObject(molptr.release());
}
INDIGO_END(-1);
}
CEXPORT int indigoCheckRGroups(int item)
{
INDIGO_BEGIN
{
IndigoObject& obj = self.getObject(item);
if (IndigoBaseMolecule::is(obj))
{
if (indigoCountRSites(item) || indigoCountAttachmentPoints(item) || indigoCountRGroups(item))
{
return 1;
}
}
else
{
throw IndigoError("%s is not a base molecule", obj.debugInfo());
}
return 0;
}
INDIGO_END(-1);
}