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 #include "cxutils/math/cxmath.h"
00041 #include <math.h>
00042
00043 using namespace CxUtils;
00044
00050 Segment3D::Segment3D()
00051 {
00052 mWidth = 0.0;
00053 }
00054
00055
00063 Segment3D::Segment3D(const Segment3D& segment)
00064 {
00065 mPoint1 = segment.mPoint1;
00066 mPoint2 = segment.mPoint2;
00067 mWidth = segment.mWidth;
00068 }
00069
00070
00082 Segment3D::Segment3D(const Point3D& p1,
00083 const Point3D& p2,
00084 const double width)
00085 {
00086 mPoint1 = p1;
00087 mPoint2 = p2;
00088 mWidth = width;
00089 }
00090
00091
00100 Segment3D Segment3D::Flip()
00101 {
00102 Point3D temp;
00103 temp = mPoint1;
00104 mPoint1 = mPoint2;
00105 mPoint2 = temp;
00106 return *this;
00107 }
00108
00109
00115 void Segment3D::Clear()
00116 {
00117 mPoint1.Clear();
00118 mPoint2.Clear();
00119 mWidth = 0.0;
00120 }
00121
00122
00123
00133 bool Segment3D::IsParallel(const Segment3D& segment) const
00134 {
00135 return IsParallel(*this, segment);
00136 }
00137
00138
00144 double Segment3D::GetDistanceX() const
00145 {
00146 return mPoint2.mX - mPoint1.mX;
00147 }
00148
00149
00155 double Segment3D::GetDistanceY() const
00156 {
00157 return mPoint2.mY - mPoint1.mY;
00158 }
00159
00165 double Segment3D::GetDistanceZ() const
00166 {
00167 return mPoint2.mZ - mPoint1.mZ;
00168 }
00169
00170
00176 double Segment3D::GetDotProduct() const
00177 {
00178 double dx, dy, dz;
00179 dx = GetDistanceX();
00180 dy = GetDistanceY();
00181 dz = GetDistanceZ();
00182
00183 return dx*dx + dy*dy + dz*dz;
00184 }
00185
00186
00192 double Segment3D::GetNorm() const
00193 {
00194 double dx, dy, dz;
00195 dx = GetDistanceX();
00196 dy = GetDistanceY();
00197 dz = GetDistanceZ();
00198
00199 return sqrt(dx*dx + dy*dy + dz*dz);
00200 }
00201
00202
00208 double Segment3D::GetMagnitude() const
00209 {
00210 double dx, dy, dz;
00211 dx = GetDistanceX();
00212 dy = GetDistanceY();
00213 dz = GetDistanceZ();
00214
00215 return sqrt(dx*dx + dy*dy + dz*dz);
00216 }
00217
00218
00224 double Segment3D::GetVolume() const
00225 {
00226 double rad = mWidth/2.0;
00227 return GetMagnitude()*CX_PI*rad*rad + 4.1887902*rad*rad*rad;
00228 }
00229
00230
00241 double Segment3D::GetAngleXY(const bool degrees) const
00242 {
00243 return (degrees) ?
00244 atan2(mPoint2.mY - mPoint1.mY, mPoint2.mX - mPoint1.mX)*57.2957795 :
00245 atan2(mPoint2.mY - mPoint1.mY, mPoint2.mX - mPoint1.mX);
00246
00247 }
00248
00249
00260 double Segment3D::GetAngleXZ(const bool degrees) const
00261 {
00262 return (degrees) ?
00263 atan2(mPoint2.mZ - mPoint1.mZ, mPoint2.mX - mPoint1.mX)*57.2957795 :
00264 atan2(mPoint2.mZ - mPoint1.mZ, mPoint2.mX - mPoint1.mX);
00265
00266 }
00267
00268
00279 double Segment3D::GetAngleYZ(const bool degrees) const
00280 {
00281 return (degrees) ?
00282 atan2(mPoint2.mZ - mPoint1.mZ, mPoint2.mY - mPoint1.mY)*57.2957795 :
00283 atan2(mPoint2.mZ - mPoint1.mZ, mPoint2.mY - mPoint1.mY);
00284
00285 }
00286
00287
00297 double Segment3D::GetDistanceToPoint(const Point3D& point) const
00298 {
00299 return GetDistanceToPoint(point, *this);
00300
00301 }
00302
00303
00304
00317 double Segment3D::GetDistanceToSegment(const Segment3D& segment) const
00318 {
00319 return GetDistanceToSegment(*this, segment);
00320
00321 }
00322
00332 Point3D Segment3D::GetClosestPointOnSegment(const Point3D& point) const
00333 {
00334 return GetClosestPointOnSegment(point,*this);
00335 }
00336
00345 Vector3D Segment3D::GetVector() const
00346 {
00347 return Vector3D(GetDistanceX(), GetDistanceY(), GetDistanceZ());
00348 }
00349
00350
00356 Point3D Segment3D::GetMidpoint() const
00357 {
00358 return Point3D( (mPoint1.mX + mPoint2.mX)/2.0,
00359 (mPoint1.mY + mPoint2.mY)/2.0,
00360 (mPoint1.mZ + mPoint2.mZ)/2.0 );
00361 }
00362
00363
00369 Segment3D Segment3D::GetProjectionXY() const
00370 {
00371 Segment3D segment(*this);
00372 segment.mPoint1.mZ = 0;
00373 segment.mPoint2.mZ = 0;
00374 return segment;
00375 }
00376
00377
00383 Segment3D Segment3D::GetProjectionXZ() const
00384 {
00385 Segment3D segment(*this);
00386 segment.mPoint1.mY = 0;
00387 segment.mPoint2.mY = 0;
00388 return segment;
00389 }
00390
00391
00397 Segment3D Segment3D::GetProjectionYZ() const
00398 {
00399 Segment3D segment(*this);
00400 segment.mPoint1.mX = 0;
00401 segment.mPoint2.mX = 0;
00402 return segment;
00403 }
00404
00405
00417 Segment3D Segment3D::Rotate(const double angle,
00418 const unsigned int axis,
00419 const bool angleInDegrees) const
00420 {
00421 Segment3D segment;
00422
00423 Quaternion rotation;
00424
00425 switch(axis)
00426 {
00427 case X:
00428 rotation.SetRotationX(angle, angleInDegrees);
00429 break;
00430 case Y:
00431 rotation.SetRotationY(angle, angleInDegrees);
00432 break;
00433 default:
00434 rotation.SetRotationZ(angle, angleInDegrees);
00435 break;
00436 }
00437
00438 segment.mPoint1 = rotation.Rotate(mPoint1);
00439 segment.mPoint2 = rotation.Rotate(mPoint2);
00440 segment.mWidth = mWidth;
00441 return segment;
00442 }
00443
00444
00457 Segment3D Segment3D::Rotate(const Point3D& pivot,
00458 const double angle,
00459 const unsigned int axis,
00460 const bool angleInDegrees) const
00461 {
00462 Point3D p1(mPoint1.mX - pivot.mX,
00463 mPoint1.mY - pivot.mY,
00464 mPoint1.mZ - pivot.mZ);
00465 Point3D p2(mPoint2.mX - pivot.mX,
00466 mPoint2.mY - pivot.mY,
00467 mPoint2.mZ - pivot.mZ);
00468 Quaternion rotation;
00469
00470 switch(axis)
00471 {
00472 case X:
00473 rotation.SetRotationX(angle, angleInDegrees);
00474 break;
00475 case Y:
00476 rotation.SetRotationY(angle, angleInDegrees);
00477 break;
00478 default:
00479 rotation.SetRotationZ(angle, angleInDegrees);
00480 break;
00481 }
00482
00483 p1 = rotation.Rotate(p1);
00484 p2 = rotation.Rotate(p1);
00485
00486 return Segment3D(p1 + pivot, p2 + pivot, mWidth);
00487 }
00488
00489
00500 bool Segment3D::DoesIntersect(const Segment3D& segment1,
00501 const Segment3D& segment2)
00502 {
00503 Point3D result;
00504 return DoesIntersect(segment1, segment2, result);
00505 }
00506
00507
00519 bool Segment3D::DoesIntersect(const Segment3D& segment1,
00520 const Segment3D& segment2,
00521 Point3D& intersectionPoint)
00522 {
00523 if(Point3D::IsCoplanar(segment1.mPoint1,
00524 segment1.mPoint2,
00525 segment2.mPoint1,
00526 segment2.mPoint2))
00527 {
00528
00529 if(DoesIntersectXY(segment1, segment2, intersectionPoint))
00530 {
00531
00532
00533
00534 Point3D v = segment2.mPoint2 - segment2.mPoint1;
00535 Point3D w = intersectionPoint - segment2.mPoint1;
00536 double c1 = w.Dot(v);
00537 if(c1 <= 0)
00538 {
00539 intersectionPoint.mZ = intersectionPoint.Distance(segment2.mPoint1);
00540
00541
00542
00543 if(segment2.mPoint1.mZ < 0.0)
00544 {
00545 intersectionPoint.mZ *= -1.0;
00546 }
00547 }
00548 else
00549 {
00550 double c2 = v.Dot(v);
00551 if(c2 <= c1)
00552 {
00553 intersectionPoint.mZ = intersectionPoint.Distance(segment2.mPoint2);
00554
00555
00556
00557 if(segment2.mPoint2.mZ < 0.0)
00558 {
00559 intersectionPoint.mZ *= -1.0;
00560 }
00561 }
00562 else
00563 {
00564 double b = c1 / (c2 + CX_EPSILON);
00565
00566
00567 Point3D pb = segment2.mPoint1 + v*b;
00568
00569 intersectionPoint.mZ = intersectionPoint.Distance(pb);
00570
00571
00572
00573 if(pb.mZ < 0.0)
00574 {
00575 intersectionPoint.mZ *= -1.0;
00576 }
00577 }
00578 }
00579
00580 return true;
00581 }
00582 }
00583
00584 intersectionPoint.mX = intersectionPoint.mY = intersectionPoint.mZ = 0.0;
00585
00586 return false;
00587 }
00588
00589
00601 bool Segment3D::DoesIntersectXY(const Segment3D& segment1,
00602 const Segment3D& segment2)
00603 {
00604 double upperX, upperY, lowerX, lowerY;
00605 double aX, bX, cX, aY, bY, cY, d, f, e;
00606 bool result = false;
00607
00608 aX = segment1.mPoint2.mX - segment1.mPoint1.mX;
00609 bX = segment2.mPoint1.mX - segment2.mPoint2.mX;
00610
00611 if (aX < 0.0)
00612 {
00613 lowerX = segment1.mPoint2.mX;
00614 upperX = segment1.mPoint1.mX;
00615 }
00616 else
00617 {
00618 upperX = segment1.mPoint2.mX;
00619 lowerX = segment1.mPoint1.mX;
00620 }
00621
00622 if (bX > 0.0)
00623 {
00624 if ((upperX < segment2.mPoint2.mX) || (segment2.mPoint1.mX < lowerX))
00625 {
00626 return result;
00627 }
00628
00629 }
00630 else if( (upperX < segment2.mPoint1.mX) || (segment2.mPoint2.mX < lowerX))
00631 {
00632 return result;
00633 }
00634
00635 aY = segment1.mPoint2.mY - segment1.mPoint1.mY;
00636 bY = segment2.mPoint1.mY - segment2.mPoint2.mY;
00637
00638 if(aY < 0.0)
00639 {
00640 lowerY = segment1.mPoint2.mY;
00641 upperY = segment1.mPoint1.mY;
00642 }
00643 else
00644 {
00645 upperY = segment1.mPoint2.mY;
00646 lowerY = segment1.mPoint1.mY;
00647 }
00648
00649 if(bY > 0.0)
00650 {
00651 if((upperY < segment2.mPoint2.mY) || (segment2.mPoint1.mY < lowerY))
00652 {
00653 return result;
00654 }
00655 }
00656 else if( (upperY < segment2.mPoint1.mY) || (segment2.mPoint2.mY < lowerY))
00657 {
00658 return result;
00659 }
00660
00661 cX = segment1.mPoint1.mX - segment2.mPoint1.mX;
00662 cY = segment1.mPoint1.mY - segment2.mPoint1.mY;
00663 d = (bY * cX) - (bX * cY);
00664 f = (aY * bX) - (aX * bY);
00665
00666 if(f > 0.0)
00667 {
00668 if(d < 0.0 || d > f)
00669 {
00670 return result;
00671 }
00672 }
00673 else if(d > 0.0 || d < f)
00674 {
00675 return result;
00676 }
00677
00678 e = (aX * cY) - (aY * cX);
00679
00680 if(f > 0.0)
00681 {
00682 if(e < 0.0 || e > f)
00683 {
00684 return result;
00685 }
00686 }
00687 else if(e > 0.0 || e < f)
00688 {
00689 return result;
00690 }
00691
00692 result = true;
00693
00694 return result;
00695 }
00696
00697
00711 bool Segment3D::DoesIntersectXY(const Segment3D& segment1,
00712 const Segment3D& segment2,
00713 Point3D& intersectionPoint)
00714 {
00715 intersectionPoint(0, 0, 0);
00716
00717 if(DoesIntersectXY(segment1, segment2))
00718 {
00719 double r, dx1, dx2, dx3, dy1, dy2, dy3;
00720
00721 dx1 = segment1.mPoint2.mX - segment1.mPoint1.mX;
00722 dx2 = segment2.mPoint2.mX - segment2.mPoint1.mX;
00723 dx3 = segment1.mPoint1.mX - segment2.mPoint1.mX;
00724 dy1 = segment1.mPoint2.mY - segment1.mPoint1.mY;
00725 dy2 = segment1.mPoint1.mY - segment2.mPoint1.mY;
00726 dy3 = segment2.mPoint2.mY - segment2.mPoint1.mY;
00727
00728 r = dx1 * dy3 - dy1 * dx2;
00729
00730 if(fabs(r) > CX_EPSILON)
00731 {
00732 r = (dy2 * (segment2.mPoint2.mX - segment2.mPoint1.mX) - dx3 * dy3) / (r + CX_EPSILON);
00733 intersectionPoint.mX = segment1.mPoint1.mX + r * dx1;
00734 intersectionPoint.mY = segment1.mPoint1.mY + r * dy1;
00735 }
00736 else
00737 {
00738 if( fabs((segment1.mPoint2.mX - segment1.mPoint1.mX) * (segment2.mPoint1.mY - segment1.mPoint1.mY) - (segment2.mPoint1.mX - segment1.mPoint1.mX) * (segment1.mPoint2.mY - segment1.mPoint1.mY)) < CX_EPSILON )
00739 {
00740 intersectionPoint.mX = segment2.mPoint1.mX;
00741 intersectionPoint.mY = segment2.mPoint1.mY;
00742 }
00743 else
00744 {
00745 intersectionPoint.mX = segment2.mPoint2.mX;
00746 intersectionPoint.mY = segment2.mPoint2.mY;
00747 }
00748 }
00749
00750 return true;
00751 }
00752
00753 return false;
00754 }
00755
00756
00769 bool Segment3D::DoesIntersect(const Segment3D& segment,
00770 const Point3D& p1,
00771 const Point3D& p2,
00772 const Point3D& p3)
00773 {
00774 Point3D u, v, n;
00775 Point3D dir, w0, w;
00776 Point3D i;
00777 double r, a, b;
00778
00779
00780 u = p2 - p1;
00781 v = p3 - p1;
00782 n = u*v;
00783 if(fabs(n.mX) < CX_EPSILON &&
00784 fabs(n.mY) < CX_EPSILON &&
00785 fabs(n.mZ) < CX_EPSILON)
00786 {
00787 return false;
00788 }
00789
00790 dir = segment.mPoint2 - segment.mPoint1;
00791 w0 = p1 - segment.mPoint1;
00792 a = -Point3D::Dot(n, w0);
00793 b = Point3D::Dot(n, dir);
00794 if(fabs(b) < CX_EPSILON)
00795 {
00796 if(fabs(a) < CX_EPSILON)
00797 {
00798
00799 return true;
00800 }
00801 else
00802 {
00803 return false;
00804 }
00805
00806 }
00807 r = a/b;
00808 if(fabs(r) < CX_EPSILON || r > 1.0)
00809 {
00810 return false;
00811 }
00812
00813 i = p1 + dir*r;
00814
00815
00816 double ss, tt;
00817 double uu, uv, vv, wu, wv, d;
00818 uu = Point3D::Dot(u, u);
00819 uv = Point3D::Dot(u, v);
00820 vv = Point3D::Dot(v, v);
00821 w = i - p1;
00822 wu = Point3D::Dot(w, u);
00823 wv = Point3D::Dot(w, v);
00824 d = uv*uv - uu*vv;
00825 ss = (uv*wv - vv*wu)/(d + CX_EPSILON);
00826 if(ss < 0.0 || ss > 1.0)
00827 {
00828 return false;
00829 }
00830 tt = (uv*wu - uu*wv)/(d + CX_EPSILON);
00831 if(tt < 0.0 || (ss + tt) > 1.0)
00832 {
00833 return false;
00834 }
00835 return true;
00836 }
00837
00838
00849 bool Segment3D::IsParallel(const Segment3D& segment1,
00850 const Segment3D& segment2)
00851 {
00852 double dx1, dx2;
00853 double dy1, dy2;
00854 double dz1, dz2;
00855
00856 dx1 = segment1.mPoint1.mX - segment1.mPoint2.mX;
00857 dx2 = segment2.mPoint1.mX - segment2.mPoint2.mX;
00858
00859 dy1 = segment1.mPoint1.mY - segment1.mPoint2.mY;
00860 dy2 = segment2.mPoint1.mY - segment2.mPoint2.mY;
00861
00862 dz1 = segment1.mPoint1.mZ - segment1.mPoint2.mZ;
00863 dz2 = segment2.mPoint1.mZ - segment2.mPoint2.mZ;
00864
00865 if(fabs(dy1/(dx1 + CX_EPSILON) - dy2/(dx2 + CX_EPSILON)) > CX_EPSILON)
00866 {
00867 return false;
00868 }
00869 if(fabs(dz1/(dy1 + CX_EPSILON) - dz2/(dy2 + CX_EPSILON)) > CX_EPSILON)
00870 {
00871 return false;
00872 }
00873 if(fabs(dx1/(dz1 + CX_EPSILON) - dx2/(dz2 + CX_EPSILON)) > CX_EPSILON)
00874 {
00875 return false;
00876 }
00877
00878 return true;
00879 }
00880
00881
00892 double Segment3D::GetDistanceToPoint(const Point3D& point,
00893 const Segment3D& segment)
00894 {
00895 Point3D v = segment.mPoint2 - segment.mPoint1;
00896 Point3D w = point - segment.mPoint1;
00897 double c1 = w.Dot(v);
00898 double magnitude = 0.0;
00899
00900 if(c1 <= 0)
00901 {
00902 magnitude = point.Distance(segment.mPoint1) - segment.mWidth/2.0;
00903 if(magnitude < 0.0)
00904 {
00905 magnitude = 0.0;
00906 }
00907 return magnitude;
00908 }
00909
00910 double c2 = v.Dot(v);
00911 if(c2 <= c1)
00912 {
00913 magnitude = point.Distance(segment.mPoint2) - segment.mWidth/2.0;
00914 if(magnitude < 0.0)
00915 {
00916 magnitude = 0.0;
00917 }
00918 return magnitude;
00919 }
00920
00921 double b = c1/(c2 + CX_EPSILON);
00922 Point3D pb = segment.mPoint1 + v*b;
00923 magnitude = point.Distance(pb) - segment.mWidth/2.0;
00924 if(magnitude < 0.0)
00925 {
00926 magnitude = 0.0;
00927 }
00928
00929 return magnitude;
00930 }
00931
00932
00946 double Segment3D::GetDistanceToSegment(const Segment3D& segment1,
00947 const Segment3D& segment2)
00948 {
00949
00950 Point3D u = segment1.mPoint2 - segment1.mPoint1;
00951 Point3D v = segment2.mPoint2 - segment2.mPoint1;
00952 Point3D w = segment1.mPoint1 - segment2.mPoint1;
00953 double a = u.Dot(u);
00954 double b = u.Dot(v);
00955 double c = v.Dot(v);
00956 double d = u.Dot(w);
00957 double e = v.Dot(w);
00958 double D = a*c - b*b;
00959 double sc, sN, sD = D;
00960 double tc, tN, tD = D;
00961
00962
00963 if (D < CX_EPSILON)
00964 {
00965
00966 sN = 0.0;
00967 sD = 1.0;
00968 tN = e;
00969 tD = c;
00970 }
00971 else
00972 {
00973
00974 sN = (b*e - c*d);
00975 tN = (a*e - b*d);
00976 if (sN < 0.0)
00977 {
00978 sN = 0.0;
00979 tN = e;
00980 tD = c;
00981 }
00982 else if (sN > sD)
00983 {
00984
00985 sN = sD;
00986 tN = e + b;
00987 tD = c;
00988 }
00989 }
00990
00991 if (tN < 0.0)
00992 {
00993
00994 tN = 0.0;
00995
00996 if (-d < 0.0)
00997 sN = 0.0;
00998 else if (-d > a)
00999 sN = sD;
01000 else
01001 {
01002 sN = -d;
01003 sD = a;
01004 }
01005 }
01006 else if (tN > tD)
01007 {
01008
01009 tN = tD;
01010
01011 if ((-d + b) < 0.0)
01012 sN = 0;
01013 else if ((-d + b) > a)
01014 sN = sD;
01015 else
01016 {
01017 sN = (-d + b);
01018 sD = a;
01019 }
01020 }
01021
01022 sc = (fabs(sN) < CX_EPSILON ? 0.0 : sN / sD);
01023 tc = (fabs(tN) < CX_EPSILON ? 0.0 : tN / tD);
01024
01025
01026 Point3D dP = w + (u*sc) - (v*tc);
01027
01028
01029
01030 double magnitude = dP.Distance() - segment1.mWidth/2.0 - segment2.mWidth/2.0;
01031 if(magnitude < 0.0)
01032 {
01033 magnitude = 0.0;
01034 }
01035 return magnitude;
01036 }
01037
01038
01049 Point3D Segment3D::GetClosestPointOnSegment(const Point3D& point, const Segment3D& segment)
01050 {
01051 Point3D v = segment.mPoint2 - segment.mPoint1;
01052 Point3D w = point - segment.mPoint1;
01053 double c1 = w.Dot(v);
01054 double magnitude = 0.0;
01055
01056 if(c1 <= 0)
01057 {
01058 return segment.mPoint1;
01059 }
01060
01061 double c2 = v.Dot(v);
01062 if(c2 <= c1)
01063 {
01064 return segment.mPoint2;
01065 }
01066
01067 double b = c1/(c2 + CX_EPSILON);
01068 return segment.mPoint1 + v*b;
01069 }
01070
01080 Segment3D& Segment3D::operator=(const Segment3D& segment)
01081 {
01082 mPoint1 = segment.mPoint1;
01083 mPoint2 = segment.mPoint2;
01084 mWidth = segment.mWidth;
01085 return *this;
01086 }
01087
01088
01089