Files
pymol-open-source/layer3/AtomIterators.cpp
2021-08-20 11:24:10 -04:00

215 lines
4.5 KiB
C++

/*
* Atom iterators
*
* (c) 2014 Schrodinger, Inc.
*/
#include <algorithm>
#include "AtomIterators.h"
#include "Selector.h"
#include "SelectorDef.h"
#include "ObjectMolecule.h"
#include "CoordSet.h"
#include "AtomInfo.h"
/*========================================================================*/
bool CoordSetAtomIterator::next() {
for (++atm; atm < obj->NAtom; ++atm) {
idx = cs->atmToIdx(atm);
if(idx < 0)
continue;
return true;
}
return false;
}
/*========================================================================*/
/**
* Make a new (owned) atom selection and update the global selector table for it.
*/
SeleAtomIterator::SeleAtomIterator(PyMOLGlobals * G_, const char * sele_) {
G = G_;
stmp = new char[1024];
SelectorGetTmp(G, (char*) sele_, stmp);
sele = SelectorIndexByName(G, stmp);
SelectorUpdateTable(G, cSelectorUpdateTableAllStates, -1);
reset();
}
SeleAtomIterator::~SeleAtomIterator() {
if (stmp) {
SelectorFreeTmp(G, stmp);
delete[] stmp;
}
}
void SeleAtomIterator::reset() {
a = cNDummyAtoms - 1;
}
/**
* advance the internal state to the next atom, return false if there is no
* next atom
*/
bool SeleAtomIterator::next() {
CSelector *I = G->Selector;
while ((++a) < I->Table.size()) {
atm = I->Table[a].atom;
obj = I->Obj[I->Table[a].model];
if(!SelectorIsMember(G, obj->AtomInfo[atm].selEntry, sele))
continue;
return true;
}
return false;
}
/*========================================================================*/
/**
* @param sele_ Atom selection to iterate over
* @param state_ Object state to iterate over (can be current (-2) or all (-1))
* @param update_table If true, then update the table (once) and do not call
* `SelectorIsMember` during iteration, assuming that the table stays valid and
* contains exactly the selected atoms. If false, then assume the table is
* up-to-date with a selection different to `sele_` (e.g. with all atoms) and
* ::SelectorIsMember needs to be called during iteration.
*/
SeleCoordIterator::SeleCoordIterator(
PyMOLGlobals* G_, int sele_, int state_, bool update_table)
{
G = G_;
statearg = state_;
// current state (use -3 for "effective" state)
if (statearg == cStateCurrent) {
statearg = SettingGetGlobal_i(G, cSetting_state) - 1;
}
// safety check
if (statearg < cStateAll) {
statearg = cSelectorUpdateTableEffectiveStates;
}
if (update_table) {
SelectorUpdateTable(G, statearg, sele_);
} else {
sele = sele_;
}
setPerObject(false);
reset();
}
void SeleCoordIterator::reset() {
a = cNDummyAtoms - 1;
state = statearg;
prev_obj = nullptr;
cs = nullptr;
if (isMultistate()) {
state = 0;
statemax = 0;
}
}
/**
* advance the internal state to the next atom, return false if there is no
* next atom
*/
bool SeleCoordIterator::next() {
CSelector *I = G->Selector;
for (a++; a < I->Table.size(); a++) {
obj = I->Obj[I->Table[a].model];
if (isMultistate()) {
if (isPerObject()) {
if (obj != prev_obj) {
if (nextStateInPrevObject())
continue;
// first cs of next object
prev_obj = obj;
state = 0;
}
} else if(statemax < obj->NCSet) {
statemax = obj->NCSet;
}
} else if (statearg == cSelectorUpdateTableEffectiveStates &&
obj != prev_obj) {
// "effective" state (no support here for settings all_states=1 or state=0)
state = std::max(0, obj->getCurrentState());
prev_obj = obj;
}
if(state >= obj->NCSet || !(cs = obj->CSet[state]))
continue;
atm = I->Table[a].atom;
idx = cs->atmToIdx(atm);
if(idx < 0)
continue;
if (sele > 0 && !SelectorIsMember(G, getAtomInfo()->selEntry, sele))
continue;
return true;
}
if (isMultistate()) {
if (isPerObject()) {
if (nextStateInPrevObject())
return next();
} else if ((++state) < statemax) {
a = cNDummyAtoms - 1;
return next();
}
}
return false;
}
AtomInfoType* AbstractAtomIterator::getAtomInfo()
{
return obj->AtomInfo + atm;
};
const AtomInfoType* AbstractAtomIterator::getAtomInfo() const
{
return obj->AtomInfo + atm;
};
float* AbstractAtomIterator::getCoord()
{
return cs->coordPtr(idx);
};
CoordSetAtomIterator::CoordSetAtomIterator(CoordSet* cs_)
{
cs = cs_;
obj = cs->Obj;
reset();
}
bool SeleCoordIterator::nextStateInPrevObject() {
if (prev_obj && (++state) < prev_obj->NCSet) {
a = prev_obj->SeleBase - 1;
return true;
}
return false;
}
// vi:sw=2:expandtab