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 }