in core/indigo-core/molecule/src/molecule_substructure_matcher.cpp [378:516]
bool MoleculeSubstructureMatcher::matchQueryAtom(QueryMolecule::Atom* query, BaseMolecule& target, int super_idx, FragmentMatchCache* fmcache, dword flags)
{
int i;
switch (query->type)
{
case QueryMolecule::OP_NONE:
return true;
case QueryMolecule::OP_AND:
for (i = 0; i < query->children.size(); i++)
if (!matchQueryAtom(query->child(i), target, super_idx, fmcache, flags))
return false;
return true;
case QueryMolecule::OP_OR:
for (i = 0; i < query->children.size(); i++)
if (matchQueryAtom(query->child(i), target, super_idx, fmcache, flags))
return true;
return false;
case QueryMolecule::OP_NOT:
return !matchQueryAtom(query->child(0), target, super_idx, fmcache, flags ^ MATCH_DISABLED_AS_TRUE);
case QueryMolecule::ATOM_NUMBER:
return query->valueWithinRange(target.getAtomNumber(super_idx));
case QueryMolecule::ATOM_PSEUDO:
return target.isPseudoAtom(super_idx) && strcmp(query->alias.ptr(), target.getPseudoAtom(super_idx)) == 0;
case QueryMolecule::ATOM_TEMPLATE:
return target.isTemplateAtom(super_idx) && strcmp(query->alias.ptr(), target.getTemplateAtom(super_idx)) == 0;
case QueryMolecule::ATOM_RSITE:
return true;
case QueryMolecule::ATOM_ISOTOPE:
return query->valueWithinRange(target.getAtomIsotope(super_idx));
case QueryMolecule::ATOM_CHARGE: {
if (flags & MATCH_ATOM_CHARGE)
return query->valueWithinRange(target.getAtomCharge(super_idx));
return (flags & MATCH_DISABLED_AS_TRUE) != 0;
}
case QueryMolecule::ATOM_RADICAL: {
if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
return false;
int radical = target.getAtomRadical_NoThrow(super_idx, -1);
if (radical == -1)
return false;
return query->valueWithinRange(radical);
}
case QueryMolecule::ATOM_VALENCE: {
if (flags & MATCH_ATOM_VALENCE)
{
if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
return false;
int valence = target.getAtomValence_NoThrow(super_idx, -1);
if (valence == -1)
return false;
return query->valueWithinRange(valence);
}
return (flags & MATCH_DISABLED_AS_TRUE) != 0;
}
case QueryMolecule::ATOM_CONNECTIVITY: {
int conn = target.getVertex(super_idx).degree();
if (!target.isPseudoAtom(super_idx) && !target.isRSite(super_idx))
conn += target.asMolecule().getImplicitH_NoThrow(super_idx, 0);
return query->valueWithinRange(conn);
}
case QueryMolecule::ATOM_TOTAL_BOND_ORDER: {
// TODO: target.isPseudoAtom(super_idx) || target.isRSite(super_idx)
int conn = target.asMolecule().getAtomConnectivity_NoThrow(super_idx, -1);
if (conn == -1)
return false;
return query->valueWithinRange(conn);
}
case QueryMolecule::ATOM_TOTAL_H: {
if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx) || target.isTemplateAtom(super_idx))
return false;
return query->valueWithinRange(target.getAtomTotalH(super_idx));
}
case QueryMolecule::ATOM_SUBSTITUENTS:
case QueryMolecule::ATOM_SUBSTITUENTS_AS_DRAWN:
return query->valueWithinRange(target.getAtomSubstCount(super_idx));
case QueryMolecule::ATOM_SSSR_RINGS:
return query->valueWithinRange(target.vertexCountSSSR(super_idx));
case QueryMolecule::ATOM_SMALLEST_RING_SIZE:
return query->valueWithinRange(target.vertexSmallestRingSize(super_idx));
case QueryMolecule::ATOM_RING_BONDS:
case QueryMolecule::ATOM_RING_BONDS_AS_DRAWN:
return query->valueWithinRange(target.getAtomRingBondsCount(super_idx));
case QueryMolecule::ATOM_PI_BONDED: {
return query->valueWithinRange(static_cast<int>(target.asMolecule().isPiBonded(super_idx)));
}
case QueryMolecule::ATOM_UNSATURATION:
return !target.isSaturatedAtom(super_idx);
case QueryMolecule::ATOM_FRAGMENT: {
if (fmcache == 0)
throw Error("unexpected 'fragment' constraint");
QueryMolecule* fragment = query->fragment.get();
const char* smarts = fragment->fragment_smarts.ptr();
if (fragment->vertexCount() == 0)
throw Error("empty fragment");
if (smarts != 0 && strlen(smarts) > 0)
{
fmcache->expand(super_idx + 1);
int* value = fmcache->at(super_idx).at2(smarts);
if (value != 0)
return *value != 0;
}
MoleculeSubstructureMatcher matcher(target.asMolecule());
matcher.not_ignore_first_atom = true;
matcher.setQuery(*fragment);
matcher.fmcache = fmcache;
bool result = matcher.fix(fragment->vertexBegin(), super_idx);
if (result)
result = matcher.find();
if (smarts != 0 && strlen(smarts) > 0)
{
fmcache->expand(super_idx + 1);
fmcache->at(super_idx).insert(smarts, result ? 1 : 0);
}
return result;
}
case QueryMolecule::ATOM_AROMATICITY:
return query->valueWithinRange(target.getAtomAromaticity(super_idx));
case QueryMolecule::HIGHLIGHTING:
return query->valueWithinRange((int)target.isAtomHighlighted(super_idx));
case QueryMolecule::ATOM_IMPLICIT_H:
return query->valueWithinRange(target.asMolecule().getImplicitH(super_idx));
case QueryMolecule::ATOM_CHIRALITY:
return target.stereocenters.getType(super_idx) == MoleculeStereocenters::ATOM_ABS; // TODO: Investigate right way to match
default:
throw Error("bad query atom type: %d", query->type);
}
}