Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef RingExtractor_INCLUDE_ONCE
00033 #define RingExtractor_INCLUDE_ONCE
00034
00035 #include <vlCore/glsl_math.hpp>
00036 #include <vector>
00037 #include <algorithm>
00038 #include <map>
00039 #include <set>
00040
00041 namespace vl
00042 {
00044 class RingExtractor
00045 {
00046 public:
00047 RingExtractor(Molecule* mol): mMolecule(mol) {}
00048
00049 void setMolecule(Molecule* mol) { mMolecule = mol; }
00050
00051 Molecule* molecule() const { return mMolecule; }
00052
00053 void run()
00054 {
00055 if (!molecule()->atoms().empty())
00056 {
00057 bootstrap();
00058 removeDoubles();
00059 sortCycles();
00060 keepMinimalCycles();
00061 keepAromaticCycles();
00062
00063 }
00064 }
00065
00066 void bootstrap()
00067 {
00068 if (!molecule()->atoms().empty())
00069 {
00070 molecule()->computeAtomAdjacency();
00071 for(int i=0; i<molecule()->atomCount(); ++i)
00072 molecule()->atom(i)->setVisited(false);
00073 std::vector< ref<Atom> > current_path;
00074 depthFirstVisit( molecule()->atoms()[0].get(), current_path );
00075 }
00076 }
00077
00078 void depthFirstVisit(Atom* atom, std::vector< ref<Atom> >& current_path)
00079 {
00080 if ( !atom->visited() || current_path.empty())
00081 {
00082 atom->setVisited(true);
00083 current_path.push_back(atom);
00084 for(unsigned i=0; i<atom->adjacentAtoms().size(); ++i)
00085 depthFirstVisit( atom->adjacentAtoms()[i], current_path );
00086 current_path.pop_back();
00087 atom->setVisited(false);
00088 }
00089 else
00090 {
00091
00092
00093 for(size_t i = current_path.size()-1; i--; )
00094 {
00095 if ( current_path[i] == atom )
00096 {
00097 std::vector< ref<Atom> > cycle;
00098 for(; i<current_path.size(); ++i)
00099 cycle.push_back( current_path[i] );
00100 if (cycle.size() > 2)
00101 molecule()->cycles().push_back(cycle);
00102 break;
00103 }
00104 }
00105 }
00106 }
00107
00108 void keepAromaticCycles()
00109 {
00110 std::vector< std::vector< ref<Atom> > > kept_cycles;
00111 for(unsigned icycle=0; icycle<molecule()->cycles().size(); ++icycle)
00112 {
00113 int ok = true;
00114 for(unsigned iatom=0; iatom<molecule()->cycle(icycle).size(); ++iatom)
00115 {
00116 int iatom2 = (iatom+1) % molecule()->cycle(icycle).size();
00117 Atom* atom1 = molecule()->cycle(icycle)[iatom].get();
00118 Atom* atom2 = molecule()->cycle(icycle)[iatom2].get();
00119
00120 Bond* bond = molecule()->bond(atom1, atom2);
00121 if (bond && bond->bondType() != BT_Aromatic)
00122 {
00123 ok = false;
00124 break;
00125 }
00126 }
00127 if (ok && molecule()->cycle(icycle).size())
00128 kept_cycles.push_back(molecule()->cycle(icycle));
00129 }
00130 molecule()->cycles() = kept_cycles;
00131 }
00132
00133 void sortCycles()
00134 {
00135 for(unsigned icycle=0; icycle<molecule()->cycles().size(); ++icycle)
00136 {
00137 std::vector< ref<Atom> >& cycle = molecule()->cycle(icycle);
00138 for(unsigned iatom=0; iatom<cycle.size()-1; ++iatom)
00139 {
00140 Atom* atom = cycle[iatom].get();
00141 for(unsigned j=iatom+1; j<cycle.size(); ++j)
00142 {
00143 if (atom->isAtomAdjacent(cycle[j].get()))
00144 {
00145 Atom* tmp = cycle[iatom+1].get();
00146 cycle[iatom+1] = cycle[j];
00147 cycle[j] = tmp;
00148 break;
00149 }
00150 }
00151 }
00152 }
00153 }
00154
00155 void keepPlanarCycles(float epsilon)
00156 {
00157 std::vector< std::vector< ref<Atom> > > kept_cycles;
00158 for(unsigned icycle=0; icycle<molecule()->cycles().size(); ++icycle)
00159 {
00160 AABB aabb;
00161 for(unsigned iatom=0; iatom<molecule()->cycle(icycle).size(); ++iatom)
00162 aabb += (vec3)molecule()->cycle(icycle)[iatom]->coordinates();
00163 fvec3 center = (fvec3)aabb.center();
00164
00165 fvec3 normal;
00166 for(unsigned iatom=0; iatom<molecule()->cycle(icycle).size(); ++iatom)
00167 {
00168 int iatom2 = (iatom+1) % molecule()->cycle(icycle).size();
00169 Atom* atom1 = molecule()->cycle(icycle)[iatom].get();
00170 Atom* atom2 = molecule()->cycle(icycle)[iatom2].get();
00171 fvec3 v1 = (atom1->coordinates()-center).normalize();
00172 fvec3 v2 = (atom2->coordinates()-center).normalize();
00173 normal += cross(v1, v2);
00174 }
00175 normal.normalize();
00176
00177 int ok = true;
00178 for(unsigned iatom=0; iatom<molecule()->cycle(icycle).size(); ++iatom)
00179 {
00180 fvec3 v1 = molecule()->cycle(icycle)[iatom]->coordinates() - center;
00181 float dist = dot(normal, v1);
00182 if (fabs(dist)>epsilon)
00183 {
00184 ok = false;
00185 break;
00186 }
00187 }
00188 if (ok && molecule()->cycle(icycle).size())
00189 kept_cycles.push_back(molecule()->cycle(icycle));
00190 }
00191 molecule()->cycles() = kept_cycles;
00192 }
00193
00194 void removeDoubles()
00195 {
00196 for(unsigned icycle=0; icycle<molecule()->cycles().size(); ++icycle)
00197 std::stable_sort(molecule()->cycle(icycle).begin(), molecule()->cycle(icycle).end());
00198 std::stable_sort(molecule()->cycles().begin(), molecule()->cycles().end());
00199 std::vector< std::vector< ref<Atom> > >::iterator new_end = std::unique(molecule()->cycles().begin(), molecule()->cycles().end());
00200 std::vector< std::vector< ref<Atom> > > unique_cycles;
00201 for(std::vector< std::vector< ref<Atom> > >::iterator it = molecule()->cycles().begin(); it != new_end; ++it)
00202 unique_cycles.push_back(*it);
00203 molecule()->cycles() = unique_cycles;
00204 }
00205
00206 void keepMinimalCycles()
00207 {
00208 std::vector< std::vector< ref<Atom> > > sub_cycles;
00209
00210 std::map<Atom*, bool> my_atom;
00211 for(unsigned j=0; j<molecule()->atoms().size(); ++j)
00212 my_atom[molecule()->atoms()[j].get()] = false;
00213
00214 for(unsigned icycle=0; icycle<molecule()->cycles().size(); ++icycle)
00215 {
00216
00217 for(unsigned j=0; j<molecule()->cycles()[icycle].size(); ++j)
00218 my_atom[ molecule()->cycles()[icycle][j].get() ] = true;
00219
00220 bool is_sup_cycle = false;
00221 for(unsigned j=0; j<molecule()->cycles().size(); ++j)
00222 {
00223 if (j == icycle)
00224 continue;
00225 unsigned shared_atoms = 0;
00226 for(unsigned k=0; k<molecule()->cycles()[j].size(); k++)
00227 shared_atoms += my_atom[ molecule()->cycles()[j][k].get() ] ? 1 : 0;
00228 if ( shared_atoms == molecule()->cycles()[j].size() )
00229 {
00230 is_sup_cycle = true;
00231 break;
00232 }
00233 }
00234 if (!is_sup_cycle)
00235 sub_cycles.push_back( molecule()->cycles()[icycle] );
00236
00237
00238 for(unsigned j=0; j<molecule()->cycles()[icycle].size(); ++j)
00239 my_atom[ molecule()->cycles()[icycle][j].get() ] = false;
00240 }
00241 molecule()->cycles() = sub_cycles;
00242 }
00243
00244 protected:
00245 Molecule* mMolecule;
00246 };
00247 }
00248
00249 #endif