/* Copyright (c) 1997-2007 Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version: http://www.gnu.org/licenses/gpl.txt. This program 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 General Public License for more details. */ #ident "$Project: polymake $$Id: SpringEmbedderBase.tcc 7579 2007-01-22 11:34:46Z gawrilow $" #include #include namespace polymake { namespace graph { template void SpringEmbedderBase::init_params(const argv_option *options) { if (options[opt_eps]) epsilon=std::atof(options[opt_eps]); else epsilon=1e-4; epsilon_2=epsilon*epsilon; if (options[opt_viscosity]) viscosity=std::atof(options[opt_viscosity]); else viscosity=1; if (options[opt_inertion]) inertion=std::atof(options[opt_inertion]); else inertion=1; } static inline void calc_internal_constants(double& a, double& b, double& c, double& d, double viscosity, double inertion) { a=std::exp(-viscosity/inertion); b=(1-a)/viscosity; c=inertion*b; d=(1-c)/viscosity; } template bool SpringEmbedderBase::calculate(int max_iterations) { const int n_nodes=G.nodes(); std::vector forces(n_nodes); const double viscosity_increasing_factor=1.2; int incr_viscosity=0, decr_viscosity=0; double a,b,c,d; calc_internal_constants(a,b,c,d,viscosity,inertion); for (int iter=0; itertop().calculate_forces(forces); #ifdef POLY_DEBUG cout << "iteration " << iter << endl; #endif int oscillated=0, moved=0; typename std::vector::iterator f=forces.begin(); for (typename Entire< Nodes >::iterator this_node=entire(nodes(G)); !this_node.at_end(); ++this_node, ++f) { #ifdef POLY_DEBUG cout << '[' << this_node.index() << "]: x=(" << this_node->x << "); f=(" << *f << "); v=(" << this_node->v << ")\n"; #endif vector3 v1=a*this_node->v + b*(*f), dx=c*this_node->v + d*(*f); if (sqr(dx) >= epsilon_2) { if (this_node->v * v1 < 0) ++oscillated; else ++moved; } this_node->v=v1; this_node->x+=dx; if (gravity) this_node->x-=barycenter; } if (oscillated*2 >= n_nodes) { if (++incr_viscosity>=2) { viscosity *= viscosity_increasing_factor; calc_internal_constants(a,b,c,d,viscosity,inertion); incr_viscosity=0; #ifdef POLY_DEBUG cout << "++ viscosity ++\n"; #endif } decr_viscosity=0; } else { if (!moved) return true; if (!oscillated) { if (++decr_viscosity>=10 && viscosity>1 || decr_viscosity>=200 && viscosity>0.75) { viscosity /= viscosity_increasing_factor; calc_internal_constants(a,b,c,d,viscosity,inertion); decr_viscosity=0; #ifdef POLY_DEBUG cout << "-- viscosity --\n"; #endif } } else { decr_viscosity=0; } incr_viscosity=0; } #ifdef POLY_DEBUG cout << "-------------------------------------------\n" "moved=" << moved << " oscillated=" << oscillated << " viscosity=" << viscosity << '\n'; #endif } return false; } } } // Local Variables: // mode:C++ // c-basic-offset:3 // End: