00001 #include <assert.h>
00002 #include <math.h>
00003 #include "Segment.h"
00004
00005
00006
00007
00008
00009
00010 Segment::Segment( const Vector4& p0, const Vector4& p1 )
00011 :
00012 p0( p0 ),
00013 p1( p1 )
00014 {
00015
00016 }
00017
00018
00019
00020
00021
00022
00023 double Segment::Distance( const Vector4& p ) const
00024 {
00025 return sqrt( DistanceSquared( p ) );
00026 }
00027
00028
00029
00030
00031
00032
00033 double Segment::Distance( const Segment& s ) const
00034 {
00035 return sqrt( DistanceSquared( s ) );
00036 }
00037
00038
00039
00040
00041
00042
00043 double Segment::DistanceSquared( const Segment& s ) const
00044 {
00045 Vector4 kDiff = this->p0 - s.p0;
00046 Vector4 d0 = p1 - p0;
00047 Vector4 d1 = s.p1 - s.p0;
00048 double fA00 = d0.MagSquared();
00049 double fA01 = -d0.Dot( d1 );
00050 double fA11 = d1.MagSquared();
00051 double fB0 = kDiff.Dot( d0 );
00052 double fC = kDiff.MagSquared();
00053 double fDet = fabs( fA00 * fA11 - fA01 * fA01 );
00054 double fB1, fS, fT, fSqrDist, fTmp;
00055
00056
00057 double gs_fTolerance = 0.00000001;
00058 if ( fDet >= gs_fTolerance )
00059 {
00060
00061 fB1 = -kDiff.Dot( d1 );
00062 fS = fA01*fB1-fA11*fB0;
00063 fT = fA01*fB0-fA00*fB1;
00064
00065 if ( fS >= 0.0f )
00066 {
00067 if ( fS <= fDet )
00068 {
00069 if ( fT >= 0.0f )
00070 {
00071 if ( fT <= fDet )
00072 {
00073
00074 double fInvDet = 1.0f/fDet;
00075 fS *= fInvDet;
00076 fT *= fInvDet;
00077 fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) +
00078 fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC;
00079 }
00080 else
00081 {
00082 fT = 1.0f;
00083 fTmp = fA01+fB0;
00084 if ( fTmp >= 0.0f )
00085 {
00086 fS = 0.0f;
00087 fSqrDist = fA11+2.0f*fB1+fC;
00088 }
00089 else if ( -fTmp >= fA00 )
00090 {
00091 fS = 1.0f;
00092 fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp);
00093 }
00094 else
00095 {
00096 fS = -fTmp/fA00;
00097 fSqrDist = fTmp*fS+fA11+2.0f*fB1+fC;
00098 }
00099 }
00100 }
00101 else
00102 {
00103 fT = 0.0f;
00104 if ( fB0 >= 0.0f )
00105 {
00106 fS = 0.0f;
00107 fSqrDist = fC;
00108 }
00109 else if ( -fB0 >= fA00 )
00110 {
00111 fS = 1.0f;
00112 fSqrDist = fA00+2.0f*fB0+fC;
00113 }
00114 else
00115 {
00116 fS = -fB0/fA00;
00117 fSqrDist = fB0*fS+fC;
00118 }
00119 }
00120 }
00121 else
00122 {
00123 if ( fT >= 0.0 )
00124 {
00125 if ( fT <= fDet )
00126 {
00127 fS = 1.0f;
00128 fTmp = fA01+fB1;
00129 if ( fTmp >= 0.0f )
00130 {
00131 fT = 0.0f;
00132 fSqrDist = fA00+2.0f*fB0+fC;
00133 }
00134 else if ( -fTmp >= fA11 )
00135 {
00136 fT = 1.0f;
00137 fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
00138 }
00139 else
00140 {
00141 fT = -fTmp/fA11;
00142 fSqrDist = fTmp*fT+fA00+2.0f*fB0+fC;
00143 }
00144 }
00145 else
00146 {
00147 fTmp = fA01+fB0;
00148 if ( -fTmp <= fA00 )
00149 {
00150 fT = 1.0f;
00151 if ( fTmp >= 0.0f )
00152 {
00153 fS = 0.0f;
00154 fSqrDist = fA11+2.0f*fB1+fC;
00155 }
00156 else
00157 {
00158 fS = -fTmp/fA00;
00159 fSqrDist = fTmp*fS+fA11+2.0f*fB1+fC;
00160 }
00161 }
00162 else
00163 {
00164 fS = 1.0f;
00165 fTmp = fA01+fB1;
00166 if ( fTmp >= 0.0f )
00167 {
00168 fT = 0.0f;
00169 fSqrDist = fA00+2.0f*fB0+fC;
00170 }
00171 else if ( -fTmp >= fA11 )
00172 {
00173 fT = 1.0f;
00174 fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
00175 }
00176 else
00177 {
00178 fT = -fTmp/fA11;
00179 fSqrDist = fTmp*fT+fA00+2.0f*fB0+fC;
00180 }
00181 }
00182 }
00183 }
00184 else
00185 {
00186 if ( -fB0 < fA00 )
00187 {
00188 fT = 0.0f;
00189 if ( fB0 >= 0.0f )
00190 {
00191 fS = 0.0f;
00192 fSqrDist = fC;
00193 }
00194 else
00195 {
00196 fS = -fB0/fA00;
00197 fSqrDist = fB0*fS+fC;
00198 }
00199 }
00200 else
00201 {
00202 fS = 1.0f;
00203 fTmp = fA01+fB1;
00204 if ( fTmp >= 0.0f )
00205 {
00206 fT = 0.0f;
00207 fSqrDist = fA00+2.0f*fB0+fC;
00208 }
00209 else if ( -fTmp >= fA11 )
00210 {
00211 fT = 1.0f;
00212 fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp);
00213 }
00214 else
00215 {
00216 fT = -fTmp/fA11;
00217 fSqrDist = fTmp*fT+fA00+2.0f*fB0+fC;
00218 }
00219 }
00220 }
00221 }
00222 }
00223 else
00224 {
00225 if ( fT >= 0.0f )
00226 {
00227 if ( fT <= fDet )
00228 {
00229 fS = 0.0f;
00230 if ( fB1 >= 0.0f )
00231 {
00232 fT = 0.0f;
00233 fSqrDist = fC;
00234 }
00235 else if ( -fB1 >= fA11 )
00236 {
00237 fT = 1.0f;
00238 fSqrDist = fA11+2.0f*fB1+fC;
00239 }
00240 else
00241 {
00242 fT = -fB1/fA11;
00243 fSqrDist = fB1*fT+fC;
00244 }
00245 }
00246 else
00247 {
00248 fTmp = fA01+fB0;
00249 if ( fTmp < 0.0f )
00250 {
00251 fT = 1.0f;
00252 if ( -fTmp >= fA00 )
00253 {
00254 fS = 1.0f;
00255 fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp);
00256 }
00257 else
00258 {
00259 fS = -fTmp/fA00;
00260 fSqrDist = fTmp*fS+fA11+2.0f*fB1+fC;
00261 }
00262 }
00263 else
00264 {
00265 fS = 0.0f;
00266 if ( fB1 >= 0.0f )
00267 {
00268 fT = 0.0f;
00269 fSqrDist = fC;
00270 }
00271 else if ( -fB1 >= fA11 )
00272 {
00273 fT = 1.0f;
00274 fSqrDist = fA11+2.0f*fB1+fC;
00275 }
00276 else
00277 {
00278 fT = -fB1/fA11;
00279 fSqrDist = fB1*fT+fC;
00280 }
00281 }
00282 }
00283 }
00284 else
00285 {
00286 if ( fB0 < 0.0f )
00287 {
00288 fT = 0.0f;
00289 if ( -fB0 >= fA00 )
00290 {
00291 fS = 1.0f;
00292 fSqrDist = fA00+2.0f*fB0+fC;
00293 }
00294 else
00295 {
00296 fS = -fB0/fA00;
00297 fSqrDist = fB0*fS+fC;
00298 }
00299 }
00300 else
00301 {
00302 fS = 0.0f;
00303 if ( fB1 >= 0.0f )
00304 {
00305 fT = 0.0f;
00306 fSqrDist = fC;
00307 }
00308 else if ( -fB1 >= fA11 )
00309 {
00310 fT = 1.0f;
00311 fSqrDist = fA11+2.0f*fB1+fC;
00312 }
00313 else
00314 {
00315 fT = -fB1/fA11;
00316 fSqrDist = fB1*fT+fC;
00317 }
00318 }
00319 }
00320 }
00321 }
00322 else
00323 {
00324
00325 if ( fA01 > 0.0f )
00326 {
00327
00328 if ( fB0 >= 0.0f )
00329 {
00330 fS = 0.0f;
00331 fT = 0.0f;
00332 fSqrDist = fC;
00333 }
00334 else if ( -fB0 <= fA00 )
00335 {
00336 fS = -fB0/fA00;
00337 fT = 0.0f;
00338 fSqrDist = fB0*fS+fC;
00339 }
00340 else
00341 {
00342 fB1 = -kDiff.Dot( d1 );
00343 fS = 1.0f;
00344 fTmp = fA00+fB0;
00345 if ( -fTmp >= fA01 )
00346 {
00347 fT = 1.0f;
00348 fSqrDist = fA00+fA11+fC+2.0f*(fA01+fB0+fB1);
00349 }
00350 else
00351 {
00352 fT = -fTmp/fA01;
00353 fSqrDist = fA00+2.0f*fB0+fC+fT*(fA11*fT+2.0f*(fA01+fB1));
00354 }
00355 }
00356 }
00357 else
00358 {
00359
00360 if ( -fB0 >= fA00 )
00361 {
00362 fS = 1.0f;
00363 fT = 0.0f;
00364 fSqrDist = fA00+2.0f*fB0+fC;
00365 }
00366 else if ( fB0 <= 0.0f )
00367 {
00368 fS = -fB0/fA00;
00369 fT = 0.0f;
00370 fSqrDist = fB0*fS+fC;
00371 }
00372 else
00373 {
00374 fB1 = -kDiff.Dot( d1 );
00375 fS = 0.0f;
00376 if ( fB0 >= -fA01 )
00377 {
00378 fT = 1.0f;
00379 fSqrDist = fA11+2.0f*fB1+fC;
00380 }
00381 else
00382 {
00383 fT = -fB0/fA01;
00384 fSqrDist = fC+fT*(2.0f*fB1+fA11*fT);
00385 }
00386 }
00387 }
00388 }
00389
00390 return fabs( fSqrDist );
00391 }
00392
00393
00394
00395
00396
00397
00398 double Segment::DistanceSquared( const Vector4& p ) const
00399 {
00400
00401 #ifndef NDEBUG
00402 Segment s( p, p );
00403 double checkSegmentDistance = DistanceSquared( s );
00404 #endif
00405
00406 Vector4 segmentDirection = p1 - p0;
00407 Vector4 pointDirection = p - p0;
00408 double dot = segmentDirection.Dot( pointDirection );
00409 if( dot <= 0.0 )
00410 {
00411
00412
00413
00414 double returnMe = pointDirection.MagSquared();
00415 assert( returnMe == checkSegmentDistance );
00416 return returnMe;
00417 }
00418
00419 double segmentLengthSqr = segmentDirection.MagSquared();
00420 if( dot >= segmentLengthSqr )
00421 {
00422
00423
00424
00425 pointDirection -= segmentDirection;
00426 double returnMe = pointDirection.MagSquared();
00427 assert( ( checkSegmentDistance - returnMe ) < 0.00000001 );
00428 return returnMe;
00429 }
00430 else
00431 {
00432
00433
00434
00435 dot /= segmentLengthSqr;
00436 pointDirection -= segmentDirection * dot;
00437 double returnMe = pointDirection.MagSquared();
00438 assert( ( checkSegmentDistance - returnMe ) < 0.00000001 );
00439 return returnMe;
00440 }
00441 }
00442