Something went wrong on our end
-
marco authored
git-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@2212 5a81b35b-ba03-0410-adc8-b2c5c5119f08
marco authoredgit-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@2212 5a81b35b-ba03-0410-adc8-b2c5c5119f08
entity_view.cc 22.85 KiB
//------------------------------------------------------------------------------
// This file is part of the OpenStructure project <www.openstructure.org>
//
// Copyright (C) 2008-2010 by the OpenStructure authors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3.0 of the License, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
/*
Author: Marco Biasini
*/
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/logic/tribool.hpp>
#include <ost/log.hh>
#include "entity_view.hh"
#include "entity_handle.hh"
#include "chain_view.hh"
#include "entity_visitor.hh"
#include "residue_view.hh"
#include "atom_view.hh"
#include "bond_table.hh"
#include "iterator.hh"
#include "query_state.hh"
#include "entity_property_mapper.hh"
#include "impl/entity_impl.hh"
#include "impl/query_impl.hh"
#include "impl/residue_impl.hh"
#include "impl/chain_impl.hh"
using boost::logic::tribool;
using boost::logic::indeterminate;
using boost::bind;
namespace ost { namespace mol {
typedef std::map<unsigned long, AtomView> HandleToViewMap;
class DLLEXPORT_OST_MOL EntityViewData {
public:
ChainViewList chains;
BondHandleList bonds;
HandleToViewMap handle_to_view;
AtomView ViewForHandle(const AtomHandle& atom)
{
HandleToViewMap::iterator i=handle_to_view.find(atom.GetHashCode());
if (i!=handle_to_view.end()) {
return i->second;
}
return AtomView();
}
};
EntityView::EntityView() {
}
EntityView::EntityView(const EntityHandle& entity,
ViewAddFlags flags)
: EntityBase(entity.Impl()), data_(new EntityViewData()) {
if (flags & ViewAddFlag::INCLUDE_CHAINS) {
impl::ChainImplList::const_iterator i=entity.Impl()->GetChainList().begin();
for (; i!=entity.Impl()->GetChainList().end(); ++i) {
this->AddChain(ChainHandle(*i), flags);
}
}
}
EntityView::EntityView(const EntityViewDataPtr& data,
const impl::EntityImplPtr impl):
EntityBase(impl), data_(data)
{}
const EntityViewDataPtr& EntityView::ViewData() const
{
return data_;
}
EntityViewDataPtr& EntityView::ViewData()
{
return data_;
}
void EntityView::Apply(EntityVisitor& visitor)
{
this->CheckValidity();
ChainViewList::iterator i;
visitor.OnEntry();
for (i=data_->chains.begin(); i!=data_->chains.end(); ++i) {
(*i).Apply(visitor);
}
BondHandleList::iterator j;
for(j=data_->bonds.begin();j!=data_->bonds.end();++j) {
(*j).Apply(visitor);
}
visitor.OnExit();
}
void EntityView::Apply(EntityViewVisitor& visitor)
{
this->CheckValidity();
ChainViewList::iterator i;
visitor.OnEntry();
for (i=data_->chains.begin(); i!=data_->chains.end(); ++i) {
(*i).Apply(visitor);
}
BondHandleList::iterator j;
for(j=data_->bonds.begin();j!=data_->bonds.end();++j)
{
(*j).Apply(visitor);
}
visitor.OnExit();
}
EntityHandle EntityView::GetHandle() const
{
return EntityHandle(Impl());
}
int EntityView::GetAtomCount() const
{
this->CheckValidity();
ChainViewList::const_iterator it=data_->chains.begin();
int count=0;
while(it!=data_->chains.end()) {
count+=(*it).GetAtomCount();
++it;
}
return count;
}
int EntityView::GetResidueCount() const
{
this->CheckValidity();
ChainViewList::const_iterator it=data_->chains.begin();
int count=0;
while (it!=data_->chains.end()) {
count+=(*it).GetResidueCount();
++it;
}
return count;
}
geom::Vec3 EntityView::GetCenterOfAtoms() const
{
geom::Vec3 center;
if (this->GetAtomCount()>0) {
unsigned int counter=0;
AtomViewIter it=this->AtomsBegin();
for(; it!=this->AtomsEnd(); ++it, ++counter) {
center+=(*it).GetPos();
}
center/=static_cast<Real>(counter);
}
return center;
}
geom::Vec3 EntityView::GetGeometricCenter() const
{
geom::Vec3 center;
center = (this->GetGeometricEnd() + this->GetGeometricStart())/2;
return center;
}
geom::Vec3 EntityView::GetCenterOfMass() const
{
geom::Vec3 center;
Real mass = this->GetMass();
if (this->GetAtomCount()>0 && mass>0) {
AtomViewIter it=this->AtomsBegin();
for(; it!=this->AtomsEnd(); ++it) {
center+=(*it).GetPos()*(*it).GetMass();
}
center/=mass;
}
return center;
}
Real EntityView::GetMass() const
{
Real mass = 0;
AtomViewIter it=this->AtomsBegin();
for(; it!=this->AtomsEnd(); ++it) {
mass+=(*it).GetMass();
}
return mass;
}
int EntityView::GetChainCount() const
{
this->CheckValidity();
return static_cast<int>(data_->chains.size());
}
ChainView EntityView::AddChain(const ChainHandle& chain_handle,
ViewAddFlags flags)
{
this->CheckValidity();
ChainView cv;
if (flags & ViewAddFlag::CHECK_DUPLICATES &&
(cv=this->FindChain(chain_handle)))
return cv;
cv=ChainView(*this, chain_handle);
data_->chains.push_back(cv);
if (flags & ViewAddFlag::INCLUDE_RESIDUES) {
const impl::ResidueImplList& l=chain_handle.Impl()->GetResidueList();
for (impl::ResidueImplList::const_iterator i=l.begin(); i!=l.end(); ++i) {
cv.AddResidue(ResidueHandle(*i), true);
}
}
return cv;
}
ResidueView EntityView::AddResidue(const ResidueHandle& residue_handle,
ViewAddFlags flags) {
this->CheckValidity();
ChainView cv=this->AddChain(residue_handle.GetChain(),
ViewAddFlag::CHECK_DUPLICATES);
return cv.AddResidue(residue_handle, flags);
}
ResidueView EntityView::AddResidue(const ResidueView& residue_view,
ViewAddFlags flags)
{
this->CheckValidity();
ChainView cv=this->AddChain(residue_view.GetChain(),
ViewAddFlag::CHECK_DUPLICATES);
return cv.AddResidue(residue_view, flags);
}
AtomView EntityView::AddAtom(const AtomHandle& atom_handle,
ViewAddFlags flags) {
ChainView cv=this->AddChain(atom_handle.GetResidue().GetChain(),
ViewAddFlag::CHECK_DUPLICATES);
ResidueView rv=cv.AddResidue(atom_handle.GetResidue(),
ViewAddFlag::CHECK_DUPLICATES);
return rv.AddAtom(atom_handle, flags);
}
ChainView EntityView::FindChain(const String& chain_name) const{
this->CheckValidity();
ChainViewList::const_iterator i;
i=std::find_if(data_->chains.begin(), data_->chains.end(),
bind(&ChainView::GetName, _1)==chain_name);
return (i!=data_->chains.end()) ? *i : ChainView();
}
ResidueView EntityView::FindResidue(const ResidueHandle& residue) const {
ChainHandle chain=residue.GetChain();
ChainView v=this->FindChain(chain);
return v.IsValid() ? v.FindResidue(residue) : ResidueView();
}
AtomView EntityView::FindAtom(const AtomHandle& atom) const
{
return data_->ViewForHandle(atom);
}
EntityView EntityView::Select(const String& query_string,
QueryFlags flags) const
{
return this->Select(Query(query_string), flags);
}
namespace {
typedef BondTable<AtomView> BondTableType;
void update_bond_table(BondTableType& bond_table,
const AtomView& ai,
const AtomView& view)
{
const BondHandleList& bonds = ai.GetBondList();
BondHandleList::const_iterator it;
for (it=bonds.begin(); it!=bonds.end(); ++it) {
bond_table.Update(*it, view);
}
}
}
EntityView EntityView::Select(const Query& query, QueryFlags flags) const
{
this->CheckValidity();
// Do the actual selection.
bool c_added, r_added;
EntityView view(this->GetHandle());
BondTableType bond_table;
QueryState qs(query.CreateQueryState(*this));
//BondHashTable bond_hash_table;
ChainViewList::const_iterator chain_it=data_->chains.begin();
for (; chain_it!=data_->chains.end(); ++chain_it) {
ChainView src_chain=*chain_it;
c_added=false;
tribool c=qs.EvalChain(src_chain.Impl());
if (c==true) {
// add everything , i.e. all residues and atoms of this chain.
// We can't use AddChain(chain, AddViewFlags::INCLUDE_ALL) since we need
// to keep track of all atoms added to get the bonds right.
ChainView dst_chain=view.AddChain(src_chain.GetHandle());
const ResidueViewList& residues=src_chain.GetResidueList();
ResidueViewList::const_iterator res_it;
for (res_it=residues.begin() ;res_it!=residues.end(); ++res_it) {
ResidueView src_res=*res_it;
ResidueView dst_res=dst_chain.AddResidue(src_res.GetHandle());
AtomViewList::const_iterator at_it = src_res.GetAtomList().begin();
for (;at_it != src_res.GetAtomList().end(); ++at_it) {
if (flags & QueryFlag::NO_BONDS) {
dst_res.AddAtom(*at_it);
} else {
update_bond_table(bond_table,
*at_it, dst_res.AddAtom((*at_it).GetHandle()));
}
}
}
} else if (indeterminate(c)) {
// Test residues
ChainView dst_chain;
ResidueViewList::const_iterator res_it=src_chain.GetResidueList().begin();
for (; res_it!=src_chain.GetResidueList().end(); ++res_it) {
ResidueView src_res=*res_it;
tribool r=qs.EvalResidue(src_res.Impl());
if (r==true) {
// Include all atoms
if (!c_added) {
c_added=true;
dst_chain=view.AddChain(src_chain.GetHandle());
}
ResidueView dst_res=dst_chain.AddResidue(src_res.GetHandle());
AtomViewList::const_iterator at_it = src_res.GetAtomList().begin();
for (;at_it != src_res.GetAtomList().end(); ++at_it) {
if (flags & QueryFlag::NO_BONDS) {
dst_res.AddAtom(*at_it);
} else {
update_bond_table(bond_table, *at_it,
dst_res.AddAtom((*at_it).GetHandle()));
}
}
} else if (indeterminate(r)) {
// Test atoms
r_added = false;
ResidueView dst_res;
AtomViewList::const_iterator at_it = src_res.GetAtomList().begin();
for (;at_it != src_res.GetAtomList().end(); ++at_it) {
tribool a = qs.EvalAtom((*at_it).Impl());
if (indeterminate(a) || a==true) {
if (!c_added) {
c_added=true;
dst_chain=view.AddChain(src_chain.GetHandle());
}
if (!r_added) {
r_added = true;
dst_res=dst_chain.AddResidue(src_res.GetHandle());
}
if (flags & QueryFlag::MATCH_RESIDUES) {
AtomViewList::const_iterator at_it2;
for (at_it2=src_res.GetAtomList().begin();
at_it2!=src_res.GetAtomList().end(); ++at_it2) {
if (flags & QueryFlag::NO_BONDS) {
dst_res.AddAtom(*at_it2);
} else {
update_bond_table(bond_table, *at_it2,
dst_res.AddAtom((*at_it2).GetHandle()));
}
}
break;
} else {
if (flags & QueryFlag::NO_BONDS) {
dst_res.AddAtom(*at_it);
} else {
update_bond_table(bond_table, *at_it,
dst_res.AddAtom((*at_it).GetHandle()));
}
}
}
qs.Reset(Prop::ATOM);
}
}
qs.Reset(Prop::RESIDUE);
}
}
}
if (!(flags & QueryFlag::NO_BONDS)) {
typedef BondTableType::MapType::const_iterator ConstIt;
for (ConstIt it=bond_table.bonds.begin();it!=bond_table.bonds.end(); ++it) {
if (flags & QueryFlag::EXCLUSIVE_BONDS || it->second.IsComplete()) {
BondHandle bh=it->second.bond;
view.AddBond(bh);
}
}
}
return view;
}
ChainView EntityView::FindChain(const ChainHandle& chain) const {
this->CheckValidity();
ChainViewList::const_iterator i;
i=std::find_if(data_->chains.begin(), data_->chains.end(),
bind(&ChainView::GetHandle, _1)==chain);
return (i!=data_->chains.end()) ? *i : ChainView();
}
bool EntityView::IsChainIncluded(const ChainHandle& chain) const
{
this->CheckValidity();
return this->FindChain(chain).IsValid();
}
bool EntityView::AddBond(const BondHandle& bh)
{
this->CheckValidity();
AtomView av1=data_->ViewForHandle(bh.GetFirst());
AtomView av2=data_->ViewForHandle(bh.GetSecond());
bool add=true;
if (av1) {
add=av1.AddBond(bh);
}
if (av2) {
add&=av2.AddBond(bh);
}
if (add) {
data_->bonds.push_back(bh);
return true;
}
return false;
}
const BondHandleList& EntityView::GetBondList() const
{
this->CheckValidity();
return data_->bonds;
}
const ChainViewList& EntityView::GetChainList() const
{
this->CheckValidity();
return data_->chains;
}
AtomViewIter EntityView::AtomsBegin() const
{
this->CheckValidity();
if (data_->chains.empty()) {
return AtomViewIter();
}
const ResidueViewList& rvl=data_->chains.front().GetResidueList();
if (rvl.empty()) {
return AtomViewIter();
}
return AtomViewIter(data_->chains.begin(), rvl.begin(),
rvl.front().GetAtomList().begin(), *this, true);
}
AtomViewIter EntityView::AtomsEnd() const {
this->CheckValidity();
if (data_->chains.empty()) {
return AtomViewIter();
}
const ResidueViewList& rvl=data_->chains.back().GetResidueList();
if (rvl.empty()) {
return AtomViewIter();
}
return AtomViewIter(data_->chains.end(), rvl.end(),
rvl.back().GetAtomList().end(), *this, false);
}
ResidueViewIter EntityView::ResiduesBegin() const {
this->CheckValidity();
if (data_->chains.empty()) {
return ResidueViewIter();
}
const ResidueViewList& rvl=data_->chains.front().GetResidueList();
return ResidueViewIter(data_->chains.begin(), rvl.begin(), *this);
}
ResidueViewIter EntityView::ResiduesEnd() const {
this->CheckValidity();
if (data_->chains.empty()) {
return ResidueViewIter();
}
const ResidueViewList& rvl=data_->chains.back().GetResidueList();
return ResidueViewIter(data_->chains.end(), rvl.end(), *this);
}
void EntityView::RemoveAtom(AtomView view) {
this->CheckValidity();
if (!view.IsValid())
return;
view.GetResidue().RemoveAtom(view);
}
void EntityView::RemoveResidue(ResidueView view) {
this->CheckValidity();
if (!view.IsValid())
return;
view.GetChain().RemoveResidue(view);
}
void EntityView::RemoveChain(ChainView view) {
this->CheckValidity();
if (!view.IsValid())
return;
view.RemoveResidues();
for (ChainViewList::iterator i=data_->chains.begin(),
e=data_->chains.end(); i!=e; ++i) {
if (*i==view) {
data_->chains.erase(i);
break;
}
}
}
void EntityView::RemoveBond(const BondHandle& bond)
{
this->CheckValidity();
BondHandleList::iterator i=std::find(data_->bonds.begin(),
data_->bonds.end(), bond);
if (i!=data_->bonds.end()) {
data_->bonds.erase(i);
AtomView av1=data_->ViewForHandle(bond.GetFirst());
AtomView av2=data_->ViewForHandle(bond.GetSecond());
if (av1) {
av1.RemoveBondInternal(bond);
}
if (av2) {
av2.RemoveBondInternal(bond);
}
}
}
int EntityView::GetBondCount() const
{
this->CheckValidity();
return static_cast<int>(data_->bonds.size());
}
EntityView EntityView::Copy() const
{
this->CheckValidity();
EntityView ev(this->GetHandle());
ChainViewList::const_iterator it=data_->chains.begin();
for (; it!=data_->chains.end(); ++it) {
ev.AddChain(*it, ViewAddFlag::INCLUDE_ALL);
}
for (BondHandleList::const_iterator i=data_->bonds.begin(),
e=data_->bonds.end(); i!=e; ++i) {
ev.AddBond(*i);
}
return ev;
}
ChainView EntityView::AddChain(const ChainView& chain_view,
ViewAddFlags flags)
{
this->CheckValidity();
ChainView cv;
if (flags & ViewAddFlag::CHECK_DUPLICATES &&
(cv=this->FindChain(chain_view.GetHandle()))) {
if (!(flags & ViewAddFlag::INCLUDE_RESIDUES)) {
return cv;
}
} else {
cv=ChainView(*this, chain_view.GetHandle());
}
data_->chains.push_back(cv);
if (flags & ViewAddFlag::INCLUDE_RESIDUES) {
ResidueViewList::const_iterator i=chain_view.GetResidueList().begin();
for (; i!=chain_view.GetResidueList().end(); ++i) {
cv.AddResidue(*i, flags);
}
}
return cv;
}
ResidueViewList EntityView::GetResidueList() const
{
this->CheckValidity();
ResidueViewList residues;
std::copy(ResiduesBegin(), ResiduesEnd(), std::back_inserter(residues));
return residues;
}
AtomViewList EntityView::GetAtomList() const
{
this->CheckValidity();
AtomViewList atoms;
std::copy(AtomsBegin(), AtomsEnd(), std::back_inserter(atoms));
return atoms;
}
AtomViewList EntityView::FindWithin(const geom::Vec3& center, Real radius) const
{
// could use some heuristic here to decide whether it is useful
// to use the FindWithin method of the handle or do a full search of
// all atoms included in the view.
this->CheckValidity();
AtomHandleList ahl=this->GetHandle().FindWithin(center, radius);
AtomViewList avl;
for (AtomHandleList::iterator i=ahl.begin(), e=ahl.end(); i!=e; ++i) {
if (AtomView v=this->FindAtom(*i)) {
avl.push_back(v);
}
}
return avl;
}
namespace {
class InclusiveBondAdder: public EntityVisitor
{
public:
InclusiveBondAdder(EntityView& view, EntityViewData& data):
view_(view), data_(data)
{ }
virtual bool VisitBond(const BondHandle& bh) {
if (data_.ViewForHandle(bh.GetFirst()) &&
data_.ViewForHandle(bh.GetSecond())) {
view_.AddBond(bh);
}
return true;
}
private:
EntityView& view_;
EntityViewData& data_;
};
}
void EntityView::AddAllInclusiveBonds()
{
this->CheckValidity();
for (BondHandleList::iterator i=data_->bonds.begin(),
e=data_->bonds.end(); i!=e; ++i) {
BondHandle bond=*i;
AtomView av1=data_->ViewForHandle(bond.GetFirst());
AtomView av2=data_->ViewForHandle(bond.GetSecond());
if (av1) {
av1.RemoveBondInternal(bond);
}
if (av2) {
av2.RemoveBondInternal(bond);
}
}
data_->bonds.clear();
InclusiveBondAdder bond_adder(*this, *data_.get());
Impl()->Apply(bond_adder);
}
AtomView EntityView::AddAtom(const AtomView& atom_view,
ViewAddFlags flags)
{
return this->AddAtom(atom_view.GetHandle(), flags);
}
std::pair<Real,Real> EntityView::GetMinMax(const String& prop,
Prop::Level hint) const
{
EntityPropertyMapper epm(prop, hint);
Real min_v=std::numeric_limits<Real>::max();
Real max_v=-std::numeric_limits<Real>::max();
for(AtomViewIter it=AtomsBegin(); it!=this->AtomsEnd(); ++it) {
Real v=epm.Get(*it);
max_v=std::max(v, max_v);
min_v=std::min(v, min_v);
}
return std::make_pair(min_v,max_v);
}
Real EntityView::GetAngle(const AtomHandle& a1, const AtomHandle& a2,
const AtomHandle& a3) const
{
return this->GetHandle().GetAngle(a1,a2,a3);
}
Real EntityView::GetAngle(const AtomView& a1, const AtomView& a2,
const AtomView& a3) const
{
return this->GetHandle().GetAngle(a1.GetHandle(),a2.GetHandle(),a3.GetHandle());
}
#ifdef _MSC_VER
AtomView EntityView::AddXAtom(const AtomHandle& ah, ViewAddFlags flags)
{
return this->AddAtom(ah,flags);
}
AtomView EntityView::FindXAtom(const AtomHandle& ah)
{
return this->FindAtom(ah);
}
#endif
geom::Vec3 EntityView::GetGeometricStart() const
{
this->CheckValidity();
geom::Vec3 m(std::numeric_limits<Real>::max(),
std::numeric_limits<Real>::max(),
std::numeric_limits<Real>::max());
for(AtomViewIter it=AtomsBegin(); it!=this->AtomsEnd(); ++it) {
m=geom::Min(m, (*it).GetPos());
}
return m;
}
AtomView EntityView::FindAtom(const String& chain_name,
const ResNum& num,
const String& atom_name) const
{
this->CheckValidity();
ChainView ch=this->FindChain(chain_name);
if (ch.IsValid()) {
return ch.FindAtom(num, atom_name);
}
return AtomView();
}
geom::Vec3 EntityView::GetGeometricEnd() const
{
this->CheckValidity();
geom::Vec3 m(-std::numeric_limits<Real>::max(),
-std::numeric_limits<Real>::max(),
-std::numeric_limits<Real>::max());
for(AtomViewIter it=AtomsBegin(); it!=this->AtomsEnd(); ++it) {
m=geom::Max(m, (*it).GetPos());
}
return m;
}
EntityView EntityView::CreateFullView() const
{
return this->Copy();
}
EntityView EntityView::CreateEmptyView() const
{
return this->GetHandle().CreateEmptyView();
}
void EntityView::AddAtomInternal(const AtomView& av)
{
data_->handle_to_view.insert(std::make_pair(av.GetHandle().GetHashCode(), av));
}
void EntityView::RemoveAtomInternal(const AtomView& av)
{
data_->handle_to_view.erase(av.GetHandle().GetHashCode());
}
namespace {
class EntityViewDumper : public EntityVisitor {
public:
EntityViewDumper(std::stringstream& stream, EntityView view):
stream_(stream), first_atom_(false),
first_res_(true)
{
view.Apply(*this);
}
virtual bool VisitAtom(const AtomHandle& atom)
{
if (!first_atom_) {
stream_ << " ";
} else {
first_atom_=false;
}
stream_ << atom.GetName();
return true;
}
virtual bool VisitResidue(const ResidueHandle& res)
{
if (first_res_) {
first_res_=false;
} else {
stream_ << "]" << std::endl;
}
stream_ << res.GetName() << res.GetNumber() << " [";
first_atom_=true;
return true;
}
virtual bool VisitChain(const ChainHandle& chain)
{
if (first_res_==false) {
stream_ << "]" << std::endl;
}
stream_ << "chain " << chain.GetName() << std::endl;
first_res_=true;
return true;
}
virtual void OnExit()
{
if (!first_res_) {
stream_ << "]" << std::endl;
}
}
virtual bool VisitBond(const BondHandle& bond)
{
return true;
}
private:
std::stringstream& stream_;
bool first_atom_;
bool first_res_;
};
}
String EntityView::Dump() const
{
std::stringstream stream;
EntityViewDumper dumper(stream, *this);
return stream.str();
}
}} // ns