00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <math.h>
00045
00046 #include "OSGConfig.h"
00047
00048 #include <assert.h>
00049
00050 #include "OSGLine.h"
00051 #include "OSGPlane.h"
00052 #include "OSGBoxVolume.h"
00053 #include "OSGSphereVolume.h"
00054 #include "OSGCylinderVolume.h"
00055 #include "OSGFrustumVolume.h"
00056
00057 OSG_USING_NAMESPACE
00058
00066
00067
00068 Line::Line(void) :
00069 _pos(0.f, 0.f ,0.f),
00070 _dir(0.f, 0.f, 0.f)
00071 {
00072 }
00073
00074
00075 Line::Line(const Line &obj) :
00076 _pos(obj._pos),
00077 _dir(obj._dir)
00078 {
00079 }
00080
00081
00082 Line::Line(const Pnt3f &p0, const Pnt3f &p1)
00083 {
00084 setValue(p0, p1);
00085 }
00086
00087
00088 Line::Line(const Pnt3f &pos, const Vec3f &dir)
00089 {
00090 setValue(pos, dir);
00091 }
00092
00093
00094
00095
00096 Line::~Line(void)
00097 {
00098 }
00099
00100
00101
00102 void Line::setValue(const Pnt3f &p0, const Pnt3f &p1)
00103 {
00104 _pos = p0;
00105 _dir = p1 - p0;
00106
00107 _dir.normalize();
00108 }
00109
00110
00111 void Line::setValue(const Pnt3f &pos, const Vec3f &dir)
00112 {
00113 _pos = pos;
00114 _dir = dir;
00115 _dir.normalize();
00116 }
00117
00122 bool Line::getClosestPoints(const Line &line2,
00123 Pnt3f &ptOnThis,
00124 Pnt3f &ptOnLine2)
00125 const
00126 {
00127
00128
00129 Vec3f normal=_dir.cross(line2._dir);
00130 if(normal.isZero()) return false;
00131
00132 Vec3f p0p1=line2._pos-_pos;
00133 Real32 lengthSqr=normal.squareLength();
00134 Real32 s=p0p1.cross(line2._dir).dot(normal) / lengthSqr;
00135 Real32 t=p0p1.cross( _dir).dot(normal) / lengthSqr;
00136
00137 ptOnThis = _pos + s * _dir;
00138 ptOnLine2=line2._pos + t * line2._dir;
00139
00140 return true;
00141 }
00142
00146 Pnt3f Line::getClosestPoint(const Pnt3f &point) const
00147 {
00148 Vec3f vec(point - _pos);
00149
00150 return _pos + _dir * vec.dot(_dir);
00151 }
00152
00153
00157 Real32 Line::distance(const Pnt3f &point) const
00158 {
00159 return (point - getClosestPoint(point)).length();
00160 }
00161
00162
00163
00164
00168 bool Line::intersect(const SphereVolume &sphere) const
00169 {
00170 Real32 ent;
00171 Real32 ex;
00172
00173 return this->intersect(sphere, ent, ex);
00174 }
00175
00179 bool Line::intersect(const SphereVolume &sphere,
00180 Real32 &enter,
00181 Real32 &exit ) const
00182 {
00183
00184 Vec3f v;
00185 Pnt3f center;
00186
00187 sphere.getCenter(center);
00188
00189 Real32 radius;
00190 Real32 h;
00191 Real32 b;
00192 Real32 d;
00193 Real32 t1;
00194 Real32 t2;
00195
00196 radius = sphere.getRadius();
00197
00198 v = center - _pos;
00199
00200 h = (v.dot(v))-(radius*radius);
00201 b = (v.dot(_dir));
00202
00203 if(h >= 0 && b <= 0)
00204 return false;
00205
00206 d = b * b - h;
00207
00208 if(d < 0)
00209 return false;
00210
00211 d = osgsqrt(d);
00212 t1 = b - d;
00213
00214
00215
00216
00217 t2 = b + d;
00218
00219 if( t1 < Eps )
00220 {
00221 if( t2 < Eps /*|| t2 > 1*/)
00222 {
00223 return false;
00224 }
00225 }
00226
00227 enter = t1;
00228 exit = t2;
00229
00230 return true;
00231 }
00232
00236 bool Line::intersect(const CylinderVolume &cyl) const
00237 {
00238 Real32 ent;
00239 Real32 ex;
00240
00241 return this->intersect(cyl, ent, ex);
00242 }
00243
00248 bool Line::intersect(const CylinderVolume &cyl,
00249 Real32 &enter,
00250 Real32 &exit ) const
00251 {
00252 Real32 radius = cyl.getRadius();
00253
00254 Vec3f adir;
00255 Vec3f o_adir;
00256 Pnt3f apos;
00257
00258 cyl.getAxis(apos, adir);
00259
00260 o_adir = adir;
00261 adir.normalize();
00262
00263 bool isect;
00264
00265 Real32 ln;
00266 Real32 dl;
00267 Vec3f RC;
00268 Vec3f n;
00269 Vec3f D;
00270
00271 RC = _pos - apos;
00272
00273 n = _dir.cross (adir);
00274 ln = n .length( );
00275
00276 if(ln == 0)
00277 {
00278 D = RC - (RC.dot(adir)) * adir;
00279 dl = D.length();
00280
00281 if(dl <= radius)
00282 {
00283 enter = 0;
00284 exit = Inf;
00285 }
00286 else
00287 {
00288 return false;
00289 }
00290 }
00291 else
00292 {
00293 n.normalize();
00294
00295 dl = osgabs(RC.dot(n));
00296 isect = (dl <= radius);
00297
00298 if(isect)
00299 {
00300 Real32 t;
00301 Real32 s;
00302 Vec3f O;
00303
00304 O = RC.cross(adir);
00305 t = - (O.dot(n)) / ln;
00306 O = n.cross(adir);
00307
00308 O.normalize();
00309
00310 s = osgabs (
00311 (osgsqrt ((radius * radius) - (dl * dl))) / (_dir.dot(O)));
00312
00313 exit = t + s;
00314
00315 if(exit < 0)
00316 return false;
00317
00318 enter = t - s;
00319
00320 if(enter < 0)
00321 enter = 0;
00322 }
00323 else
00324 {
00325 return false;
00326 }
00327 }
00328
00329 Real32 t;
00330
00331 Plane bottom(-adir, apos);
00332
00333 if(bottom.intersect(*this, t))
00334 {
00335 if(bottom.isInHalfSpace(_pos))
00336 {
00337 if(t > enter)
00338 enter = t;
00339 }
00340 else
00341 {
00342 if(t < exit)
00343 exit = t;
00344 }
00345 }
00346 else
00347 {
00348 if(bottom.isInHalfSpace(_pos))
00349 return false;
00350 }
00351
00352 Plane top(adir, apos + o_adir);
00353
00354 if(top.intersect(*this, t))
00355 {
00356 if(top.isInHalfSpace(_pos))
00357 {
00358 if(t > enter)
00359 enter = t;
00360 }
00361 else
00362 {
00363 if(t < exit)
00364 exit = t;
00365 }
00366 }
00367 else
00368 {
00369 if(top.isInHalfSpace(_pos))
00370 return false;
00371 }
00372
00373 return (enter < exit);
00374 }
00375
00379 bool Line::intersect(const FrustumVolume &frustum) const
00380 {
00381 Real32 ent;
00382 Real32 ex;
00383
00384 return this->intersect(frustum, ent, ex);
00385 }
00386
00392 #if !defined(OSG_DO_DOC) || defined(OSG_DOC_DEV)
00393
00394 OSG_BEGIN_NAMESPACE
00395
00398 struct face
00399 {
00400 Pnt3f point;
00401 Vec3f inner_vector;
00402 Vec3f inner_normal;
00403 };
00404
00405 OSG_END_NAMESPACE
00406
00407 #endif
00408
00409 bool Line::intersect(const FrustumVolume &frustum ,
00410 Real32 &enter ,
00411 Real32 &exit ) const
00412 {
00413 const Real32 inf = 2 << 16;
00414
00415 Pnt3f enter_point = _pos + _dir * 0;
00416 Pnt3f exit_point = _pos + _dir * inf;
00417
00418 face faces[6];
00419
00420 const Plane *planes = frustum.getPlanes();
00421
00422 Line lines[2];
00423
00424
00425 planes[3].intersect(planes[4], lines[0]);
00426
00427
00428 planes[2].intersect(planes[5], lines[1]);
00429
00430 Pnt3f pointA;
00431 Pnt3f pointB;
00432
00433 if(!planes[0].intersectInfinite(lines[0],pointA))
00434 std::cout << "This should never happen (A)!!!!";
00435
00436 if(!planes[1].intersectInfinite(lines[1],pointB))
00437 std::cout << "This should never happen (B)!!!!";
00438
00439 faces[0].point = pointA;
00440 faces[0].inner_vector = pointB - pointA;
00441
00442 faces[1].point = pointB;
00443 faces[1].inner_vector = pointA - pointB;
00444
00445 faces[2].point = pointB;
00446 faces[2].inner_vector = pointA - pointB;
00447
00448 faces[3].point = pointA;
00449 faces[3].inner_vector = pointB - pointA;
00450
00451 faces[4].point = pointA;
00452 faces[4].inner_vector = pointB - pointA;
00453
00454 faces[5].point = pointB;
00455 faces[5].inner_vector = pointA - pointB;
00456
00457 for(Int32 i = 0; i < 6; i++)
00458 {
00459 faces[i].inner_normal=planes[i].getNormal();
00460
00461 if(faces[i].inner_normal.dot(faces[i].inner_vector) < 0.f)
00462 faces[i].inner_normal=-faces[i].inner_normal;
00463
00464 Vec3f test_enp = enter_point - faces[i].point;
00465 Vec3f test_exp = exit_point - faces[i].point;
00466
00467 Real32 value_enp = test_enp.dot(faces[i].inner_normal);
00468 Real32 value_exp = test_exp.dot(faces[i].inner_normal);
00469
00470 if(value_enp < 0.f && value_exp < 0.f)
00471 return false;
00472
00473 if(value_enp > 0.f && value_exp < 0.f)
00474 planes[i].intersect(*this, exit_point );
00475
00476 if(value_enp < 0.f && value_exp > 0.f)
00477 planes[i].intersect(*this, enter_point);
00478 }
00479
00480 Real32 a;
00481
00482 if((a = (enter_point - _pos).dot(_dir)) != 0.f)
00483 {
00484 enter = (enter_point - _pos).dot(enter_point - _pos) / a;
00485 }
00486 else
00487 {
00488 enter = 0.f;
00489 }
00490
00491 if((a = (exit_point - _pos).dot(_dir)) != 0.f)
00492 {
00493 exit = (exit_point - _pos).dot(exit_point - _pos) / a;
00494 }
00495 else
00496 {
00497 enter = 0.f;
00498 }
00499
00500 return true;
00501 }
00502
00503
00507 bool Line::intersect(const BoxVolume &box,
00508 Real32 &enter,
00509 Real32 &exit ) const
00510 {
00511 Pnt3f low;
00512 Pnt3f high;
00513
00514 box.getBounds(low, high);
00515
00516 Real32 r;
00517 Real32 te;
00518 Real32 tl;
00519
00520 Real32 in = 0.f;
00521 Real32 out = Inf;
00522
00523 if(_dir[0] > Eps)
00524 {
00525 r = 1.f / _dir[0];
00526
00527 te = (low [0] - _pos[0]) * r;
00528 tl = (high[0] - _pos[0]) * r;
00529
00530 if(tl < out)
00531 out = tl;
00532
00533 if(te > in)
00534 in = te;
00535 }
00536 else if(_dir[0] < -Eps)
00537 {
00538 r = 1.f / _dir[0];
00539
00540 te = (high[0] - _pos[0]) * r;
00541 tl = (low [0] - _pos[0]) * r;
00542
00543 if(tl < out)
00544 out = tl;
00545
00546 if(te > in)
00547 in = te;
00548 }
00549 else if(_pos[0] < low[0] || _pos[0] > high[0])
00550 {
00551 return false;
00552 }
00553
00554 if(_dir[1] > Eps)
00555 {
00556 r = 1.f / _dir[1];
00557
00558 te = (low [1] - _pos[1]) * r;
00559 tl = (high[1] - _pos[1]) * r;
00560
00561 if(tl < out)
00562 out = tl;
00563
00564 if(te > in)
00565 in = te;
00566
00567 if(in-out >= Eps)
00568 return false;
00569 }
00570 else if(_dir[1] < -Eps)
00571 {
00572 r = 1.f / _dir[1];
00573
00574 te = (high[1] - _pos[1]) * r;
00575 tl = (low [1] - _pos[1]) * r;
00576
00577 if(tl < out)
00578 out = tl;
00579
00580 if(te > in)
00581 in = te;
00582
00583 if(in-out >= Eps)
00584 return false;
00585 }
00586 else if(_pos[1] < low[1] || _pos[1] > high[1])
00587 {
00588 return false;
00589 }
00590
00591 if(_dir[2] > Eps)
00592 {
00593 r = 1.f / _dir[2];
00594
00595 te = (low [2] - _pos[2]) * r;
00596 tl = (high[2] - _pos[2]) * r;
00597
00598 if(tl < out)
00599 out = tl;
00600
00601 if(te > in)
00602 in = te;
00603 }
00604 else if(_dir[2] < -Eps)
00605 {
00606 r = 1.f / _dir[2];
00607
00608 te = (high[2] - _pos[2]) * r;
00609 tl = (low [2] - _pos[2]) * r;
00610
00611 if(tl < out)
00612 out = tl;
00613
00614 if(te > in)
00615 in = te;
00616 }
00617 else if(_pos[2] < low[2] || _pos[2] > high[2])
00618 {
00619 return false;
00620 }
00621
00622 enter = in;
00623 exit = out;
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 return in-out < Eps;
00639
00640
00641
00642
00643
00644 }
00645
00646 #ifdef __sgi
00647 #pragma set woff 1209
00648 #endif
00649
00653 bool Line::intersect( Real32 OSG_CHECK_ARG(angle),
00654 const BoxVolume &OSG_CHECK_ARG(box )) const
00655 {
00656
00657 assert(false);
00658 return false;
00659 }
00660
00664 bool Line::intersect( Real32 OSG_CHECK_ARG(angle),
00665 const Vec3f &OSG_CHECK_ARG(point)) const
00666 {
00667
00668 assert(false);
00669 return false;
00670 }
00671
00675 bool Line::intersect( Real32 OSG_CHECK_ARG(angle),
00676 const Vec3f &OSG_CHECK_ARG(v0 ),
00677 const Vec3f &OSG_CHECK_ARG(v1 ),
00678 Vec3f &OSG_CHECK_ARG(pt )) const
00679 {
00680
00681 assert(false);
00682 return false;
00683 }
00684
00685 #ifdef __sgi
00686 #pragma reset woff 1209
00687 #endif
00688
00692 bool Line::intersect(const Pnt3f &v0,
00693 const Pnt3f &v1,
00694 const Pnt3f &v2,
00695 Real32 &t,
00696 Vec3f *norm) const
00697 {
00698
00699 static const Real32 sEps = 1E-10f;
00700
00701
00702 Vec3f edge1 = v1 - v0;
00703 Vec3f edge2 = v2 - v0;
00704
00705
00706 Vec3f pvec = _dir.cross(edge2);
00707
00708
00709 Real32 det = edge1.dot(pvec);
00710 Vec3f qvec;
00711
00712 if(det > sEps)
00713 {
00714
00715 Vec3f tvec = _pos - v0;
00716
00717
00718 Real32 u = tvec.dot(pvec);
00719
00720 if(u < 0.0 || u > det)
00721 return false;
00722
00723
00724 qvec = tvec.cross(edge1);
00725
00726
00727 Real32 v = _dir.dot(qvec);
00728
00729 if(v < 0.0 || u + v > det)
00730 return false;
00731 }
00732 else if(det < -sEps)
00733 {
00734
00735 Vec3f tvec = _pos - v0;
00736
00737
00738 Real32 u = tvec.dot(pvec);
00739
00740 if(u > 0.0 || u < det)
00741 return false;
00742
00743
00744 qvec = tvec.cross(edge1);
00745
00746
00747 Real32 v = _dir.dot(qvec);
00748
00749 if(v > 0.0 || u + v < det)
00750 return false;
00751 }
00752 else
00753 return false;
00754
00755 Real32 inv_det = 1.0 / det;
00756
00757
00758 t = edge2.dot(qvec) * inv_det;
00759
00760 if(norm != NULL)
00761 {
00762 *norm = edge1.cross(edge2);
00763 norm->normalize();
00764 }
00765
00766 return true;
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00800
00801
00802
00803
00804