00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "marMatrix.h"
00020 #include <math.h>
00021 #include "marMathConst.h"
00022
00023 #include "curve.hxx"
00024
00025
00026 int kCurve::MAX_DIMENSION = 0;
00027 int kCurve::MAX_STATE_DIMENSION = 0;
00028
00029 #define KCURVE_CHANGE_DIMENSIONS( ) \
00030 kCurve::MAX_DIMENSION = ( kCurve::MAX_DIMENSION > _dimension )?\
00031 kCurve::MAX_DIMENSION: _dimension;\
00032 kCurve::MAX_STATE_DIMENSION = ( kCurve::MAX_STATE_DIMENSION > _stateDim )?\
00033 kCurve::MAX_STATE_DIMENSION: _stateDim;
00034
00035
00036
00037
00038 void f_catmull( double* N, double t )
00039 {
00040 double t2 = t * t;
00041 double t3 = t2 * t;
00042
00043 N[ 0 ] = -t3 + ( 2 * t2 ) - t;
00044 N[ 1 ] = ( 3 * t3 ) - ( 5 * t2 ) + 2;
00045 N[ 2 ] = -( 3 * t3 ) + ( 4 * t2 ) + t;
00046 N[ 3 ] = t3 - t2;
00047 }
00048
00049
00050 void f_d1_catmull( double* N, double t )
00051 {
00052 double t2 = t * t;
00053
00054 N[ 0 ] = -( 3 * t2 ) + ( 4 * t ) - 1;
00055 N[ 1 ] = ( 9 * t2 ) - ( 10 * t );
00056 N[ 2 ] = -( 9 * t2 ) + ( 8 * t ) + 1;
00057 N[ 3 ] = ( 3 * t2 ) - ( 2 * t );
00058 }
00059
00060
00061 void f_d2_catmull( double* N, double t )
00062 {
00063 N[ 0 ] = -( 6 * t ) + 4;
00064 N[ 1 ] = ( 18 * t ) - 10;
00065 N[ 2 ] = -( 18 * t ) + 8;
00066 N[ 3 ] = ( 6 * t ) - 2;
00067 }
00068
00069
00070 kCurve::kCurve( size_t dim, size_t sdim )
00071 : _dimension( dim ), _stateDim( sdim )
00072 {
00073 _mC = new double[ _dimension * 4 ];
00074 _mS = new double[ _stateDim * 4 ];
00075 KCURVE_CHANGE_DIMENSIONS( );
00076 }
00077
00078
00079 kCurve::~kCurve( )
00080 {
00081 reset( );
00082 delete[] _mC;
00083 delete[] _mS;
00084 }
00085
00086
00087 kCurve& kCurve::operator=( const kCurve& r )
00088 {
00089 reset( );
00090 delete[] _mC;
00091 delete[] _mS;
00092
00093 _dimension = r._dimension;
00094 _stateDim = r._stateDim;
00095
00096 _mC = new double[ _dimension * 4 ];
00097 _mS = new double[ _stateDim * 4 ];
00098
00099 for( int i = 0; i < r._controlPoints.size( ); i++ )
00100 addControlPoint( r._controlPoints[ i ],
00101 r._controlState[ i ] );
00102 return( *this );
00103 }
00104
00105
00106 uint kCurve::getClosestControlPoint( double* p )
00107 {
00108 int res;
00109
00110 marVector vp (p,_dimension),cp(_dimension);
00111 double dist, min;
00112
00113 cp = _controlPoints[ 0 ];
00114 min = ( cp - vp ).norm2( );
00115 res = 0;
00116
00117 for( int i = 1; i < _controlPoints.size( ); i++ )
00118 {
00119 cp = _controlPoints[ i ];
00120 dist = ( cp - vp ).norm2( );
00121 if( min > dist )
00122 {
00123 min = dist;
00124 res = i;
00125 }
00126 }
00127
00128 return( res );
00129 }
00130
00131
00132 void kCurve::getPoint( double* p, double s )
00133 {
00134 double t;
00135 int i;
00136
00137 calculeSplineArguments( s, i, t );
00138 evaluate( p, i, t );
00139 }
00140
00141
00142 void kCurve::getState( double* st, double s )
00143 {
00144 double t;
00145 int i;
00146
00147 calculeSplineArguments( s, i, t );
00148 evalState( st, i, t );
00149 }
00150
00151
00152 void kCurve::getTangent( double* tg, double s )
00153 {
00154 double t;
00155 int i;
00156
00157 calculeSplineArguments( s, i, t );
00158 derivative1( tg, i, t );
00159
00160
00161 marVector tmp( tg, _dimension );
00162 memcpy( tg,
00163 ( double* )( tmp.normalize( ) ),
00164 _dimension * sizeof( double ) );
00165 }
00166
00167
00168 void kCurve::getNormal( double* n, double s )
00169 {
00170 double t;
00171 int i;
00172
00173 calculeSplineArguments( s, i, t );
00174 derivative2( n, i, t );
00175
00176
00177 marVector tmp( n, _dimension );
00178 memcpy( n,
00179 ( double* )( tmp.normalize( ) ),
00180 _dimension * sizeof( double ) );
00181 }
00182
00183
00184 void kCurve::getBinormal( double* b, double s )
00185 {
00186
00187 marVector tg( _dimension ), n( _dimension );
00188 double t;
00189 int i;
00190
00191 calculeSplineArguments( s, i, t );
00192 derivative1( ( double* )tg, i, t );
00193 derivative2( ( double* )n, i, t );
00194
00195 memcpy( b,
00196 ( double* )( tg.cross( n ).normalize( ) ),
00197 _dimension * sizeof( double ) );
00198 }
00199
00200
00201 void kCurve::addControlPoint( double* cp, double* sp )
00202 {
00203 double* tmp = new double[ _dimension ];
00204 memcpy( tmp, cp, _dimension * sizeof( double ) );
00205 _controlPoints.push_back( tmp );
00206 if( sp != NULL && _stateDim > 0 ) {
00207
00208 double *tmp1 = new double[ _stateDim ];
00209 memcpy( tmp1, sp, _stateDim * sizeof( double ) );
00210 _controlState.push_back( tmp1 );
00211
00212 } else
00213 _controlState.push_back( NULL );
00214
00215 if( _controlPoints.size( ) == 1 ) {
00216
00217 _controlT.push_back( 0.0 );
00218 _controlL.push_back( 0.0 );
00219
00220 } else {
00221
00222
00223
00224
00225
00226 marVector v1( _dimension ), v0( _dimension );
00227 double len;
00228 int p;
00229
00230 p = _controlPoints.size( ) - 1;
00231 v1 = _controlPoints[ p ];
00232 v0 = _controlPoints[ p - 1 ];
00233 len = ( v1 - v0 ).norm2( ) + _controlL[ p - 1 ];
00234 _controlL.push_back( len );
00235 _controlT.push_back( 0.0 );
00236 for( int i = 0; i < _controlT.size( ); i++ )
00237 _controlT[ i ] = _controlL[ i ] / len;
00238
00239 }
00240 }
00241
00242
00243 void kCurve::getControlPoint( int i, double* cp, double* sp )
00244 {
00245 memcpy( cp, _controlPoints[ i ], _dimension * sizeof( double ) );
00246 if( sp != NULL && _controlState[ i ] != NULL && _stateDim > 0 )
00247 memcpy( sp, _controlState[ i ], _stateDim * sizeof( double ) );
00248 }
00249
00250
00251 void kCurve::setControlPoint( int i, double* cp, double* sp )
00252 {
00253 memcpy( _controlPoints[ i ], cp, _dimension * sizeof( double ) );
00254 if( sp != NULL && _stateDim > 0 )
00255 memcpy( _controlState[ i ], sp, _stateDim * sizeof( double ) );
00256
00257 if( _controlPoints.size( ) > 1 ) {
00258
00259 marVector v1( _dimension ), v0( _dimension );
00260 double len;
00261 int it;
00262
00263 for( it = i; it < _controlT.size( ); it++ ) {
00264
00265 v1 = _controlPoints[ it ];
00266 v0 = _controlPoints[ it - 1 ];
00267 len = ( v1 - v0 ).norm2( ) + _controlL[ it - 1 ];
00268 _controlL[ i ] = len;
00269
00270 }
00271
00272 for( it = 0; it < _controlT.size( ); it++ )
00273 _controlT[ it ] = _controlL[ it ] / len;
00274
00275 }
00276 }
00277
00278
00279 double kCurve::length( double step )
00280 {
00281
00282 marVector nV( 4 ), q( _dimension ), p( _dimension );
00283
00284 marMatrix mC( _mC, _dimension, 4 );
00285 double l = 0;
00286
00287 loadCatmullControlMatrix( 0 );
00288 f_catmull( ( double* )nV, 0 );
00289 p = ( mC * nV ) * 0.5;
00290
00291 for( int i = 0; i < _controlPoints.size( ); i++ ) {
00292
00293 loadCatmullControlMatrix( i );
00294 for( double t = 0.0; t <= 1.0; t += step ) {
00295
00296 f_catmull( ( double* )nV, t );
00297 q = ( mC * nV ) * 0.5;
00298 l += ( q - p ).norm2( );
00299 p = q;
00300
00301 }
00302
00303 }
00304 return( l );
00305 }
00306
00307
00308 double kCurve::projectOverControlPoints( double* pr, double* pt )
00309 {
00310
00311 marVector xpc( 3 ), xpo( pt, 3 );
00312
00313 marVector xpa( 3 ), xpn( 3 );
00314
00315 marVector xpr( pr, 3 );
00316 double sina, sinn, cosa, cosn, tha, thn;
00317 double d, e, t, l, tca, tcn, lca, lcn;
00318 uint icp = getClosestControlPoint( pt );
00319
00320 getControlPoint( icp, ( double* )xpc, NULL );
00321
00322 if( icp == 0 ) {
00323
00324 getControlPoint( icp + 1, ( double* )xpn, NULL );
00325
00326 sinn = ( ( xpo - xpc ).cross( xpn - xpc ) ).norm2( ) /
00327 ( ( xpo - xpc ).norm2( ) * ( xpn - xpc ).norm2( ) );
00328 cosn = ( xpo - xpc ).dot( xpn - xpc ) /
00329 ( ( xpo - xpc ).norm2( ) * ( xpn - xpc ).norm2( ) );
00330
00331
00332 thn = acos( cosn ) + ( ( sinn >= 0 )? PI: 0 );
00333
00334 if( 0 <= thn && thn <= (PI/2) ) {
00335
00336 tca = _controlT[ icp ];
00337 lca = _controlL[ icp ];
00338 tcn = _controlT[ icp + 1 ];
00339 lcn = _controlL[ icp + 1 ];
00340 xpa = xpc;
00341
00342 d = ( ( xpn - xpa ).cross( xpa - xpo ) ).norm2( ) /
00343 ( xpn - xpa ).norm2( );
00344 e = ( xpo - xpa ).norm2( );
00345 e = ( e * e ) - ( d * d );
00346 e = sqrt( e );
00347 xpr = ( ( xpn - xpa ).normalize( ) * e ) + xpa;
00348 l = ( xpr - xpa ).norm2( ) + lca;
00349 t = ( ( ( tcn - tca ) / ( lcn - lca ) ) * ( l - lca ) ) + tca;
00350
00351 } else {
00352
00353 xpr = xpc;
00354 t = 0;
00355
00356 }
00357
00358 } else if( icp == _controlPoints.size( ) - 1 ) {
00359
00360 getControlPoint( icp - 1, ( double* )xpa, NULL );
00361
00362 sina = ( ( xpa - xpc ).cross( xpo - xpc ) ).norm2( ) /
00363 ( ( xpa - xpc ).norm2( ) * ( xpo - xpc ).norm2( ) );
00364 cosa = ( xpa - xpc ).dot( xpo - xpc ) /
00365 ( ( xpa - xpc ).norm2( ) * ( xpo - xpc ).norm2( ) );
00366
00367
00368 tha = acos( cosa ) + ( ( sina >= 0 )? PI: 0 );
00369
00370
00371 if( 0 <= tha && tha <= (PI/2) ) {
00372
00373 tca = _controlT[ icp - 1 ];
00374 lca = _controlL[ icp - 1 ];
00375 tcn = _controlT[ icp ];
00376 lcn = _controlL[ icp ];
00377 xpn = xpc;
00378
00379 d = ( ( xpn - xpa ).cross( xpa - xpo ) ).norm2( ) /
00380 ( xpn - xpa ).norm2( );
00381 e = ( xpo - xpa ).norm2( );
00382 e = ( e * e ) - ( d * d );
00383 e = sqrt( e );
00384 xpr = ( ( xpn - xpa ).normalize( ) * e ) + xpa;
00385 l = ( xpr - xpa ).norm2( ) + lca;
00386 t = ( ( ( tcn - tca ) / ( lcn - lca ) ) * ( l - lca ) ) + tca;
00387
00388 } else {
00389
00390 xpr = xpc;
00391 t = _controlT[ _controlPoints.size( ) - 1 ];
00392
00393 }
00394
00395 } else {
00396
00397 getControlPoint( icp - 1, ( double* )xpa, NULL );
00398 getControlPoint( icp + 1, ( double* )xpn, NULL );
00399
00400 sina = ( ( xpa - xpc ).cross( xpo - xpc ) ).norm2( ) /
00401 ( ( xpa - xpc ).norm2( ) * ( xpo - xpc ).norm2( ) );
00402 sinn = ( ( xpo - xpc ).cross( xpn - xpc ) ).norm2( ) /
00403 ( ( xpo - xpc ).norm2( ) * ( xpn - xpc ).norm2( ) );
00404 cosa = ( xpa - xpc ).dot( xpo - xpc ) /
00405 ( ( xpa - xpc ).norm2( ) * ( xpo - xpc ).norm2( ) );
00406 cosn = ( xpo - xpc ).dot( xpn - xpc ) /
00407 ( ( xpo - xpc ).norm2( ) * ( xpn - xpc ).norm2( ) );
00408
00409
00410 tha = acos( cosa ) + ( ( sina >= 0 )? PI: 0 );
00411
00412 thn = acos( cosn ) + ( ( sinn >= 0 )? PI: 0 );
00413
00414 if( tha < thn ) {
00415
00416 tca = _controlT[ icp - 1 ];
00417 lca = _controlL[ icp - 1 ];
00418 tcn = _controlT[ icp ];
00419 lcn = _controlL[ icp ];
00420 xpn = xpc;
00421
00422 } else {
00423
00424 tca = _controlT[ icp ];
00425 lca = _controlL[ icp ];
00426 tcn = _controlT[ icp + 1 ];
00427 lcn = _controlL[ icp + 1 ];
00428 xpa = xpc;
00429
00430 }
00431
00432 d = ( ( xpn - xpa ).cross( xpa - xpo ) ).norm2( ) /
00433 ( xpn - xpa ).norm2( );
00434 e = ( xpo - xpa ).norm2( );
00435 e = ( e * e ) - ( d * d );
00436 e = sqrt( e );
00437 xpr = ( ( xpn - xpa ).normalize( ) * e ) + xpa;
00438 l = ( xpr - xpa ).norm2( ) + lca;
00439 t = ( ( ( tcn - tca ) / ( lcn - lca ) ) * ( l - lca ) ) + tca;
00440
00441 }
00442
00443 return( t );
00444 }
00445
00446
00447 double kCurve::projectOverCurve( double* pr, double* pt )
00448 {
00449 return( 0 );
00450 }
00451
00452
00453 void kCurve::evaluate( double* p, int i, double t )
00454 {
00455
00456 marVector nV( 4 ), q( _dimension );
00457
00458 marMatrix mC( _mC, _dimension, 4 );
00459
00460 loadCatmullControlMatrix( i );
00461 f_catmull( ( double* )nV, t );
00462 q = ( mC * nV ) * 0.5;
00463 memcpy( p, ( double* )q, _dimension * sizeof( double ) );
00464 }
00465
00466
00467 void kCurve::evalState( double* s, int i, double t )
00468 {
00469
00470 marVector nV( 4 ), q( _stateDim );
00471
00472 marMatrix mS( _mS, _stateDim, 4 );
00473
00474 loadCatmullStateMatrix( i );
00475 f_catmull( ( double* )nV, t );
00476 q = ( mS * nV ) * 0.5;
00477 memcpy( s, ( double* )q, _stateDim * sizeof( double ) );
00478 }
00479
00480
00481 void kCurve::derivative1( double* d, int i, double t )
00482 {
00483
00484 marVector nV( 4 ), q( _dimension );
00485
00486 marMatrix mC( _mC, _dimension, 4 );
00487
00488 loadCatmullControlMatrix( i );
00489 f_d1_catmull( ( double* )nV, t );
00490 q = ( mC * nV ) * 0.5;
00491 memcpy( d, ( double* )q, _dimension * sizeof( double ) );
00492 }
00493
00494
00495 void kCurve::derivative2( double* d, int i, double t )
00496 {
00497
00498 marVector nV( 4 ), q( _dimension );
00499
00500 marMatrix mC( _mC, _dimension, 4 );
00501
00502 loadCatmullControlMatrix( i );
00503 f_d2_catmull( ( double* )nV, t );
00504 q = ( mC * nV ) * 0.5;
00505 memcpy( d, ( double* )q, _dimension * sizeof( double ) );
00506 }
00507
00508
00509 void kCurve::reset( )
00510 {
00511 int i;
00512
00513 for( i = 0; i < _controlPoints.size( ); i++ )
00514 delete[] _controlPoints[ i ];
00515 _controlPoints.clear( );
00516
00517 for( i = 0; i < _controlState.size( ); i++ )
00518 if( _controlState[ i ] != NULL ) delete[] _controlState[ i ];
00519 _controlState.clear( );
00520
00521 _controlT.clear( );
00522 _controlL.clear( );
00523 }
00524
00525
00526 void kCurve::loadCatmullControlMatrix( int i )
00527 {
00528
00529 marMatrix mC( _mC, _dimension, 4 );
00530 int l;
00531
00532 for( int j = i - 1; j <= i + 2; j++ ) {
00533
00534 for( int k = 0; k < _dimension; k++ ) {
00535
00536 l = ( j >= 0 )? j: 0;
00537 l = ( l >= _controlPoints.size( ) )?
00538 _controlPoints.size( ) - 1: l;
00539 mC( k, j - i + 1 ) = _controlPoints[ l ][ k ];
00540
00541 }
00542
00543 }
00544 }
00545
00546
00547 void kCurve::loadCatmullStateMatrix( int i )
00548 {
00549
00550 marMatrix mS( _mS, _stateDim, 4 );
00551 int l;
00552
00553 for( int j = i - 1; j <= i + 2; j++ ) {
00554
00555 for( int k = 0; k < _stateDim; k++ ) {
00556
00557 l = ( j >= 0 )? j: 0;
00558 l = ( l >= _controlState.size( ) )?
00559 _controlState.size( ) - 1: l;
00560 mS( k, j - i + 1 ) = _controlState[ l ][ k ];
00561
00562 }
00563
00564 }
00565 }
00566
00567
00568 void kCurve::calculeSplineArguments( double s, int& i, double& t )
00569 {
00570 for( i = 0; i < _controlT.size( ) && _controlT[ i ] <= s; i++ );
00571
00572 if( s < 1.0 ) i--;
00573
00574 t = ( ( _controlL[ _controlL.size( ) - 1 ] * s ) - _controlL[ i ] ) /
00575 ( _controlL[ i + 1 ] - _controlL[ i ] );
00576 t = ( s < 1.0 )? t: 1.0;
00577 i = ( s < 1.0 )? i: _controlT.size( ) - 1;
00578 }
00579
00580