Main Page   Namespace List   Class Hierarchy   Compound List   File List   Header Files   Sources   Namespace Members   Compound Members   File Members  

curve.cpp

00001 //$Header: /home/ben/Mapper/c++/RCS/curve.cpp,v 6.6 2002/07/14 17:08:52 ben Exp $
00002 // Copyright Benedict Adamson 2002.
00003 // This file is part of Mapper.
00004 
00005 // Mapper is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or
00008 // (at your option) any later version.
00009 
00010 // Mapper is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with Mapper; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00027 #include <cmath>
00028 
00029 #include "curve.h"
00030 #include "func.h"
00031 #include "minimise.h"
00032 
00033 
00034 
00035 static const double pi = M_PI;
00036 
00037 
00038 
00039 curve::curve(void)
00040 {
00041    //Do nothing
00042 }
00043 
00044 
00045 
00046 curve::~curve(void)
00047 {
00048    //Do nothing
00049 }
00050 
00051 
00052 
00053 vector<double> curve::shape(
00054    const double t
00055    ) const
00056 {
00057    {//preconditionss:
00058       assert( 2 <= this->param.size() );
00059    };
00060    const unsigned n = this->param.size();
00061    vector< double > s( n );
00062    s[0] = 1 - t;
00063    s[1] = t;
00064    if( 2 < n ){
00065       const double pt = pi * t;
00066       for( unsigned i = 2; i < n; i++ ){
00067          const double w = sin( pt * double(i-1) );
00068          s[0] -= w;
00069          s[i] = w;
00070       };
00071    };
00072    return s;
00073 }
00074 
00075 
00076 
00077 void curve::shape(
00078    const double t,
00079    vector< double > &s, //output
00080    vector< double > &dsdt //output
00081    ) const
00082 {
00083    {//preconditionss:
00084       assert( 2 <= this->param.size() );
00085    };
00086    const unsigned n = this->param.size();
00087    s = vector<double >( n );
00088    dsdt = vector<double >( n );
00089    s[0] = 1 - t;
00090    dsdt[0] = -1;
00091    s[1] = t;
00092    dsdt[1] = 1;
00093    if( 2 < n ){
00094       const double pt = pi * t;
00095       for( unsigned i = 2; i < n; i++ ){
00096          const double f = double(i-1);
00097          const double a = pt * f;
00098          const double w = sin( a );
00099          const double dwdt = pi * f * cos( a );
00100          s[0] -= w;
00101          dsdt[0] -= dwdt;
00102          s[i] = w;
00103          dsdt[i] = dwdt;
00104       };
00105    };
00106 }
00107 
00108 
00109 
00110 vector2 curve::position(
00111    const double t
00112    ) const
00113 {
00114    {//preconditions:
00115       assert( 2 <= this->param.size() );
00116       //normally( 0 <= t && t <= 1 );
00117    };
00118    vector2 p( 0, 0 );
00119    const unsigned n = this->param.size();
00120    vector< double > s( this->shape( t ) );
00121    assert( s.size() == n );
00122    for( unsigned i = 0; i < n; i++ ){
00123      const vector2 *ph = this->param[i];
00124      assert( ph );
00125      p += s[i] * (*ph);
00126    };
00127    return p;
00128 }
00129 
00130 
00131 
00132 namespace {
00133    
00134    
00135    
00143    class curve_distance2
00144       :
00145    public func::single_dimension
00146    {
00147          //Calculates the square of the distance between a given point
00148          //and points on a given curve.
00149       public: //constructors and destructor
00150          
00151          inline curve_distance2(void);
00152          //postoncditions:
00153          //assert( !this->c );
00154          //assert( !this->p );
00155          
00156          inline virtual ~curve_distance2(void);
00157          
00158       public: //attributes
00159          
00160          virtual double operator() (
00161             const double t
00162             ) const;
00163          //preconditions:
00164          //assert( this->c );
00165          //assert( this->p );
00166          
00167       public: //relationships
00168 
00172          const curve *c;
00173 
00177          const vector2 *p;
00178          
00179    };
00180    
00181    
00182    
00183    inline curve_distance2::curve_distance2(void)
00184       :
00185       c( 0 ),
00186       p( 0 )
00187       {
00188          //Do nothing
00189          {//postoncditions:
00190             assert( !this->c );
00191             assert( !this->p );
00192          };
00193       }
00194    
00195    
00196    
00197    inline curve_distance2::~curve_distance2(void)
00198       {
00199          //Do nothing
00200       }
00201    
00202    
00203    double curve_distance2::operator() (
00204       const double t
00205       ) const
00206       {
00207          {//preconditions
00208             assert( c );
00209             assert( p );
00210          };
00211          const vector2 dp( this->c->position( t ) - *(this->p) );
00212          return dp*dp;
00213       }
00214    
00215 };
00216 
00217 
00218 
00219 void nearest_point(
00220    const curve &cu,
00221    const vector2 &p,
00222    const double tol,
00223    const unsigned max_iter,
00224    double &t2, //output
00225    double &d22, //output
00226    unsigned &iter //output
00227    )
00228 {
00229    //Calculates the position on the curve (t on cu
00230    //which is closest to the given point (p).
00231    {//preconditions:
00232       assert( 2 <= cu.param.size() );
00233       assert( 0.0 < tol );
00234       assert( 0 < max_iter );
00235    };
00236    curve_distance2 cd2; //function object used for minimisation calculation
00237    cd2.c = &cu;
00238    cd2.p = &p;
00239    double t1, t3;
00240    double d21, d23;
00241    if( *cu.param[0] != *cu.param[1] ){//curve has length
00242       {//determine good starting point for bracket
00243          const unsigned np = cu.param.size();
00244          if( np <= 2 ){//straight line
00245             t1 = 0.25;
00246             t2 = 0.75;
00247          }else{//curved
00248             //Must be carefull because there could be multiple minima.
00249             //Try to find a point (t2) close to the global minimum.
00250             const unsigned n = (np-2)*2;
00251             unsigned i2; //the best so far
00252             for( unsigned i = 0; i <= n; i++ ){
00253                const double ti = double(i) / double(n);
00254                const double d2i = cd2( ti );
00255                if( 0 == i || d2i <= d22 ){//better than the best so far
00256                   i2 = i;
00257                   t2 = ti;
00258                   d22 = d2i;
00259                };
00260             };
00261             assert( i2 <= n );
00262             assert( 0 <= d22 );
00263             t1 = double( i2 - 1 ) / double(n);
00264          };
00265       };
00266       unsigned iter_1, iter_2;
00267       minimise::bracket(
00268          cd2, max_iter, iter_1,
00269          t1, t2, t3,
00270          d21, d22, d23
00271          );
00272       if( iter_1 < max_iter ){ //allowed to do better
00273          minimise::Brent(
00274             cd2,
00275             tol, max_iter - iter_1,
00276             t1, t2, t3,
00277             d21, d22, d23,
00278             iter_2
00279             );
00280       }else{ //failed to find bracket
00281          iter_2 = 0;
00282       };
00283       iter = iter_1 + iter_2;
00284       const double t2o = t2;
00285       t2 = min<double>( t2, 1 );
00286       t2 = max<double>( t2, 0 );
00287       if( t2o != t2 )
00288          d22 = cd2( t2 );
00289       ;
00290    }else{ //zero-length curve
00291       t2 = 0.5;
00292       iter = 0;
00293       d22 = cd2( t2 );
00294    };
00295    {//postconditions:
00296       assert( 0 <= t2 && t2 <= 1 );
00297       assert( iter <= max_iter );
00298       assert( 0 <= d22 );
00299    };
00300 }
00301 
00302 
00303 
00304 void curve::position(
00305    const double t,
00306    vector2 &p,
00307    vector2 &dpdt
00308    ) const
00309 {
00310    {//preconditions:
00311       assert( 2 <= this->param.size() );
00312       //normally( 0 <= t && t <= 1 );
00313    };
00314    {//initialise
00315       p = vector2( 0, 0 );
00316       dpdt = vector2( 0, 0 );
00317    };
00318    vector< double > s, dsdt;
00319    this->shape( t, s, dsdt );
00320    for( unsigned i = 0; i < this->param.size(); i++ ){
00321       const vector2 *ph = this->param[i];
00322       assert( ph );
00323       const vector2 v( *ph );
00324       p += s[i] * v;
00325       dpdt += dsdt[i] * v;
00326    };
00327 }

Generated at Sun Jul 14 20:38:07 2002 for Mapper by doxygen 1.0.0 written by Dimitri van Heesch, © 1997-1999