Files
rdkit/Code/GraphMol/QueryBond.cpp
2011-01-13 04:22:56 +00:00

207 lines
6.0 KiB
C++

// $Id$
//
// Copyright (C) 2001-2006 Greg Landrum and Rational Discovery LLC
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include <GraphMol/QueryBond.h>
namespace RDKit{
QueryBond::QueryBond(BondType bT) : Bond(bT) {
if( bT != Bond::UNSPECIFIED ) dp_query = makeBondOrderEqualsQuery(bT);
else dp_query = makeBondNullQuery();
};
QueryBond::~QueryBond(){
if( dp_query ) {
delete dp_query;
dp_query=0;
}
};
QueryBond &QueryBond::operator=(const QueryBond &other){
// FIX: should we copy molecule ownership? I don't think so.
// FIX: how to deal with atom indices?
dp_mol = 0;
d_bondType = other.d_bondType;
dp_query = other.dp_query->copy();
if(dp_props) delete dp_props;
if(other.dp_props)
dp_props = new Dict(*other.dp_props);
return *this;
}
Bond *QueryBond::copy() const {
QueryBond *res = new QueryBond(*this);
return res;
}
void QueryBond::setBondType(BondType bT) {
// NOTE: calling this blows out any existing query
d_bondType = bT;
if(dp_query){
delete dp_query;
dp_query = 0;
}
dp_query = makeBondOrderEqualsQuery(bT);
}
void QueryBond::setBondDir(BondDir bD) {
// NOTE: calling this blows out any existing query
//
// Ignoring bond orders (which this implicitly does by blowing out
// any bond order query) is ok for organic molecules, where the
// only bonds assigned directions are single. It'll fail in other
// situations, whatever those may be.
//
d_dirTag = bD;
#if 0
if(dp_query){
delete dp_query;
dp_query = 0;
}
dp_query = makeBondDirEqualsQuery(bD);
#endif
}
void QueryBond::expandQuery(QUERYBOND_QUERY *what,
Queries::CompositeQueryType how,
bool maintainOrder){
QUERYBOND_QUERY *origQ = dp_query;
std::string descrip;
switch(how) {
case Queries::COMPOSITE_AND:
dp_query = new BOND_AND_QUERY;
descrip = "BondAnd";
break;
case Queries::COMPOSITE_OR:
dp_query = new BOND_OR_QUERY;
descrip = "BondOr";
break;
case Queries::COMPOSITE_XOR:
dp_query = new BOND_XOR_QUERY;
descrip = "BondXor";
break;
default:
UNDER_CONSTRUCTION("unrecognized combination query");
}
dp_query->setDescription(descrip);
if(maintainOrder){
dp_query->addChild(QUERYBOND_QUERY::CHILD_TYPE(origQ));
dp_query->addChild(QUERYBOND_QUERY::CHILD_TYPE(what));
} else {
dp_query->addChild(QUERYBOND_QUERY::CHILD_TYPE(what));
dp_query->addChild(QUERYBOND_QUERY::CHILD_TYPE(origQ));
}
}
bool QueryBond::Match(const Bond::BOND_SPTR what) const {
return Match(what.get());
}
namespace {
bool localMatch(BOND_EQUALS_QUERY const *q1,BOND_EQUALS_QUERY const *q2){
if(q1->getNegation()==q2->getNegation()){
return q1->getVal()==q2->getVal();
} else {
return q1->getVal()!=q2->getVal();
}
}
bool queriesMatch(QueryBond::QUERYBOND_QUERY const *q1,
QueryBond::QUERYBOND_QUERY const *q2){
PRECONDITION(q1,"no q1");
PRECONDITION(q2,"no q2");
static const unsigned int nQueries=6;
static std::string equalityQueries[nQueries]={"BondRingSize","BondMinRingSize","BondOrder","BondDir",\
"BondInRing","BondInNRings"};
bool res=false;
std::string d1=q1->getDescription();
std::string d2=q2->getDescription();
if(d1=="BondNull"||d2=="BondNull"){
res = true;
} else if(d1=="BondOr"){
// FIX: handle negation on BondOr and BondAnd
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter1=q1->beginChildren();iter1!=q1->endChildren();++iter1){
if(d2=="BondOr"){
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter2=q2->beginChildren();iter2!=q2->endChildren();++iter2){
if(queriesMatch(iter1->get(),iter2->get())){
res=true;
break;
}
}
} else {
if(queriesMatch(iter1->get(),q2)) {
res=true;
}
}
if(res) break;
}
} else if(d1=="BondAnd"){
res=true;
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter1=q1->beginChildren();iter1!=q1->endChildren();++iter1){
bool matched=false;
if(d2=="BondAnd"){
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter2=q2->beginChildren();iter2!=q2->endChildren();++iter2){
if(queriesMatch(iter1->get(),iter2->get())){
matched=true;
break;
}
}
} else {
matched = queriesMatch(iter1->get(),q2);
}
if(!matched){
res=false;
break;
}
}
// FIX : handle BondXOr
} else if(d2=="BondOr"){
// FIX: handle negation on BondOr and BondAnd
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter2=q2->beginChildren();iter2!=q2->endChildren();++iter2){
if(queriesMatch(q1,iter2->get())) {
res=true;
break;
}
}
} else if(d2=="BondAnd"){
res=true;
for(QueryBond::QUERYBOND_QUERY::CHILD_VECT_CI iter2=q2->beginChildren();iter2!=q2->endChildren();++iter2){
if(queriesMatch(q1,iter2->get())){
res=false;
break;
}
}
} else if(std::find(&equalityQueries[0],&equalityQueries[nQueries],d1)!= &equalityQueries[nQueries]){
res=localMatch(static_cast<BOND_EQUALS_QUERY const *>(q1),
static_cast<BOND_EQUALS_QUERY const *>(q2));
}
return res;
}
} //end of local namespace
bool QueryBond::Match(Bond const *what) const {
PRECONDITION(dp_query,"no query set");
if(!what->hasQuery()){
return dp_query->Match(what);
} else {
return queriesMatch(dp_query,what->getQuery());
}
}
} // end o' namespace