00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00025
00026 #ifndef BUILDABLE_ATOM_ALGORITHMS_H
00027 #define BUILDABLE_ATOM_ALGORITHMS_H
00028
00029
00030 #include "atom_algorithms.h"
00031 #include "buildable_atom.h"
00032 #include "linear_algebra.h"
00033
00034 #include <boost/concept_check.hpp>
00035
00036 #include <iterator>
00037 #include <queue>
00038 #include <set>
00039
00040
00041 namespace BTK {
00042
00045
00046
00049 template <typename AtomType>
00050 void
00051 add_bond(AtomType& first,
00052 AtomType& last);
00053
00058 template <typename AtomType>
00059 unsigned
00060 bond_distance_4(AtomType& a1,
00061 AtomType& a2);
00062
00068 template <typename AtomIterator>
00069 void
00070 build(AtomIterator first,
00071 AtomIterator last);
00072
00080
00081
00082
00083
00084 template <typename AtomType>
00085 void
00086 build_atom(AtomType& a);
00087
00088 #if 0
00093 template <typename AtomIterator>
00094 void
00095 conservative_build(AtomIterator first,
00096 AtomIterator last);
00097 #endif
00098
00104 template <typename AtomType>
00105 void
00106 restricted_rotate(AtomType& start,
00107 AtomType& boundary,
00108 double delta_angle);
00109
00117 template <typename AtomType, typename UnaryFunction>
00118 UnaryFunction
00119 for_each_buildable_atom(AtomType& start,
00120 AtomType& boundary,
00121 UnaryFunction func);
00122
00124
00125 }
00126
00127
00128
00129
00130
00131
00133
00134
00135
00136 namespace BTK{
00137 namespace Internal{
00138 template <typename AtomType, typename UnaryFunction>
00139 void
00140 for_each_buildable_atom_iter(AtomType& a,
00141 std::set<AtomType*>& visited,
00142 UnaryFunction func);
00143
00144 template <typename AtomType>
00145 void
00146 cache_bond_distance_4(AtomType& a);
00147
00148 template <typename AtomType>
00149 void
00150 cache_bond_distance_4_iter(AtomType& start,
00151 AtomType& boundary,
00152 AtomType& a1,
00153 unsigned dist);
00154
00155 template <typename AtomType>
00156 bool
00157 build_atom_iter(std::set<AtomType*>& visited,
00158 std::queue<AtomType*>& bfs_queue,
00159 std::map<AtomType*,AtomType*>& traceback);
00160
00161 template <typename AtomType>
00162 void
00163 build_atom_traceback(AtomType& a,
00164 std::map<AtomType*,AtomType*>& traceback);
00165 }
00166 }
00167
00168
00169
00170 template <typename AtomType>
00171 void
00172 BTK::
00173 add_bond(AtomType& first,
00174 AtomType& last)
00175 {
00176 first.add_adjacent(last);
00177 last.add_adjacent(first);
00178
00181 }
00182
00183
00184 template <typename AtomType>
00185 unsigned
00186 BTK::
00187 bond_distance_4(AtomType& a1,
00188 AtomType& a2)
00189 {
00190
00191 boost::function_requires<boost::ConvertibleConcept<AtomType,BuildableAtom> >();
00192
00193 AtomType* ap1 = &a1;
00194 AtomType* ap2 = &a2;
00195 if(ap1 == ap2) return 0;
00196 else if(ap1 > ap2) std::swap(ap1,ap2);
00197
00198 if(! ap1->is_bond_distance_cached()) {
00199 Internal::cache_bond_distance_4(*ap1);
00200 ap1->set_is_bond_distance_cached(true);
00201 }
00202
00203 return ap1->bond_distance_4(*ap2);
00204 }
00205
00206 template <typename AtomIterator>
00207 void
00208 BTK::
00209 build(AtomIterator first,
00210 AtomIterator last)
00211 {
00212 for(;first!=last;++first){
00213 build_atom(*first);
00214 }
00215 }
00216
00217
00218 template <typename AtomType>
00219 void
00220 BTK::
00221 build_atom(AtomType& a)
00222 {
00223
00224 if(a.build()) return;
00225
00226 std::set<AtomType*> visited;
00227 std::queue<AtomType*> bfs_queue;
00228 std::map<AtomType*,AtomType*> traceback;
00229
00230 visited.insert(&a);
00231 bfs_queue.push(&a);
00232 traceback[&a] = 0;
00233
00234 bool result = Internal::build_atom_iter(visited,bfs_queue,traceback);
00235
00236
00237 if(!result) a.boot_build();
00238 }
00239
00240
00241 template <typename AtomType>
00242 void
00243 BTK::
00244 restricted_rotate(AtomType& start,
00245 AtomType& boundary,
00246 double delta_angle)
00247 {
00248 boost::function_requires<boost::ConvertibleConcept<AtomType,BuildableAtom> >();
00249
00250 BTKMatrix rot_matrix( create_rotation_matrix(start.position()-boundary.position(),delta_angle) );
00251 BTKVector rot_offset( prec_prod(rot_matrix,-boundary.position())+boundary.position() );
00252
00253 for_each_buildable_atom(start,boundary,atom_rotator<AtomType>(rot_matrix,rot_offset));
00254 }
00255
00256
00257 template <typename AtomType, typename UnaryFunction>
00258 UnaryFunction
00259 BTK::
00260 for_each_buildable_atom(AtomType& start,
00261 AtomType& boundary,
00262 UnaryFunction func)
00263 {
00264 boost::function_requires<boost::ConvertibleConcept<AtomType,BuildableAtom> >();
00265
00266 std::set<AtomType*> visited;
00267
00268 visited.insert(&start);
00269 visited.insert(&boundary);
00270 Internal::for_each_buildable_atom_iter(start,visited,func);
00271 return func;
00272 }
00273
00274
00275
00276
00277
00279
00280
00281 template <typename AtomType, typename UnaryFunction>
00282 void
00283 BTK::Internal::
00284 for_each_buildable_atom_iter(AtomType& a,
00285 std::set<AtomType*>& visited,
00286 UnaryFunction func)
00287 {
00288 typename BuildableAtom::adjacent_iterator ai=a.adjacent_begin(), ai_end=a.adjacent_end();
00289
00290 for (;ai!=ai_end;ai++){
00291 if( visited.find(static_cast<AtomType*>(*ai)) == visited.end() ){
00292 visited.insert(static_cast<AtomType*>(*ai));
00293 func(*static_cast<AtomType*>(*ai));
00294 for_each_buildable_atom_iter(*static_cast<AtomType*>(*ai),visited,func);
00295 }
00296 }
00297 }
00298
00299 template <typename AtomType>
00300 void
00301 BTK::Internal::
00302 cache_bond_distance_4(AtomType& a)
00303 {
00306
00307
00308 cache_bond_distance_4_iter(a,a,a,0);
00309 }
00310
00311
00312 template <typename AtomType>
00313 void
00314 BTK::Internal::
00315 cache_bond_distance_4_iter(AtomType& start,
00316 AtomType& boundary,
00317 AtomType& a1,
00318 unsigned dist)
00319 {
00320 dist += 1;
00321
00322 BuildableAtom::const_adjacent_iterator ai=start.adjacent_begin(),ai_end=start.adjacent_end();
00323 for (;ai!=ai_end;++ai){
00324 AtomType& a2 = *static_cast<AtomType*>(*ai);
00325 if(&a2 == &boundary) continue;
00326
00327 AtomType* ap1 = &a1;
00328 AtomType* ap2 = &a2;
00329 if( ap1 > ap2 ) std::swap(ap1,ap2);
00330 if( dist < ap1->bond_distance_4(*ap2) ){
00331 ap1->set_bond_distance_4(*ap2,dist);
00332 }
00333 if( dist < 4 ) cache_bond_distance_4_iter(a2,start,a1,dist);
00334 }
00335 }
00336
00337
00338 template <typename AtomType>
00339 bool
00340 BTK::Internal::
00341 build_atom_iter(std::set<AtomType*>& visited,
00342 std::queue<AtomType*>& bfs_queue,
00343 std::map<AtomType*,AtomType*>& traceback)
00344 {
00345 AtomType& a = *(bfs_queue.front());
00346 bfs_queue.pop();
00347 bool are_any_built = false;
00348
00349 BuildableAtom::adjacent_iterator ai=a.adjacent_begin(),ai_end=a.adjacent_end();
00350 for(;ai!=ai_end;++ai){
00351 AtomType& a2 = *static_cast<AtomType*>(*ai);
00352
00353 if(visited.find(&a2) != visited.end()) continue;
00354
00355 if(!a2.is_built()) {
00356 if(a2.build()) {
00357
00358
00359
00360
00361 build_atom_traceback(a,traceback);
00362 return true;
00363 }
00364 } else {
00365 are_any_built = true;
00366 }
00367
00368 traceback[&a2] = &a;
00369 visited.insert(&a2);
00370 bfs_queue.push(&a2);
00371 }
00372
00373 while(! bfs_queue.empty() ){
00374 bool result = build_atom_iter(visited,bfs_queue,traceback);
00375 if(result) are_any_built = true;
00376 }
00377 return are_any_built;
00378 }
00379
00380
00381 template <typename AtomType>
00382 void
00383 BTK::Internal::
00384 build_atom_traceback(AtomType& a,
00385 std::map<AtomType*,AtomType*>& traceback)
00386 {
00387 if(!a.build()){
00388
00389 build_atom(a);
00390 if(!a.is_built()) return;
00391 }
00392 AtomType* a2 = traceback[&a];
00393 if(!a2) return;
00394 build_atom_traceback(*a2,traceback);
00395 }
00396
00397
00398
00399 #endif
00400
00401