basic/geometry/geo_rangesensor/MgcIntrLin3Cyln.cpp

Go to the documentation of this file.
00001 
00002 // Magic Software, Inc.
00003 // http://www.magic-software.com
00004 // Copyright (c) 2000, All Rights Reserved
00005 //
00006 // Source code from Magic Software is supplied under the terms of a license
00007 // agreement and may not be copied or disclosed except in accordance with the
00008 // terms of that agreement.  The various license agreements may be found at
00009 // the Magic Software web site.  This file is subject to the license
00010 //
00011 // FREE SOURCE CODE
00012 // http://www.magic-software.com/License.html/free.pdf
00013 
00014 #include "MgcDistLin3Lin3.h"
00015 #include "MgcIntrLin3Cyln.h"
00016 #include "MgcRTLib.h"
00017 
00018 static const MgcReal gs_fEpsilon = 1e-12;
00019 
00020 //----------------------------------------------------------------------------
00021 bool MgcTestIntersection (const MgcSegment3& rkSegment,
00022     const MgcCylinder& rkCylinder)
00023 {
00024     MgcSegment3 kCylnSeg = rkCylinder.GetSegment();
00025     MgcReal fSqrDist = MgcSqrDistance(rkSegment,kCylnSeg);
00026     if ( fSqrDist > rkCylinder.Radius() )
00027         return false;
00028 
00029     // For Dot(N,D) not zero, line P+t*D intersects bottom plane of cylinder
00030     // at t0 = [Dot(N,C-P)+h/2]/Dot(N,D) where C is cylinder center and h is
00031     // cylinder height.  Line intersects top plane of cylinder at
00032     // t1 = [Dot(N,C-P)+h/2]/Dot(N,D).  Intersection occurs if and only
00033     // if [0,1] and [t0,t1] overlap.  Thus, intersection occurs when t0 >= 0
00034     // and t1 <= 1.  The implementation avoids the division by Dot(N,D) by
00035     // multiplying through by that term.  When Dot(N,D) is zero, the segment
00036     // and cylinder intersect when |Dot(N,C-P)| <= h/2.  The test for
00037     // Dot(N,D) > 0 degenerates to the test for Dot(N,D) = 0, so no special
00038     // handling must be done to trap Dot(N,D) within 'epsilon' of zero.
00039 
00040     MgcReal fNdD = rkCylinder.Direction().Dot(rkSegment.Direction());
00041     MgcVector3 kDiff = rkCylinder.Center() - rkSegment.Origin();
00042     MgcReal fTest  = kDiff.Dot(rkCylinder.Direction());
00043     MgcReal fHalfHeight = 0.5*rkCylinder.Height();
00044     if ( fNdD >= 0.0 )
00045         return -fHalfHeight <= fTest && fTest <= fNdD + fHalfHeight;
00046     else
00047         return fNdD - fHalfHeight <= fTest && fTest <= fHalfHeight;
00048 }
00049 //----------------------------------------------------------------------------
00050 bool MgcTestIntersection (const MgcRay3& rkRay, const MgcCylinder& rkCylinder)
00051 {
00052     MgcSegment3 kCylnSeg = rkCylinder.GetSegment();
00053     MgcReal fSqrDist = MgcSqrDistance(rkRay,kCylnSeg);
00054     if ( fSqrDist > rkCylinder.Radius() )
00055         return false;
00056 
00057     MgcReal fNdD = rkCylinder.Direction().Dot(rkRay.Direction());
00058     MgcVector3 kDiff = rkCylinder.Center() - rkRay.Origin();
00059     MgcReal fTest  = kDiff.Dot(rkCylinder.Direction());
00060     MgcReal fHalfHeight = 0.5*rkCylinder.Height();
00061     if ( fNdD > 0.0 )
00062         return fTest >= -fHalfHeight;
00063     else if ( fNdD < 0.0 )
00064         return fTest <= fHalfHeight;
00065     else
00066         return MgcMath::Abs(fTest) <= fHalfHeight;
00067 }
00068 //----------------------------------------------------------------------------
00069 bool MgcTestIntersection (const MgcLine3& rkLine,
00070     const MgcCylinder& rkCylinder)
00071 {
00072     MgcSegment3 kCylnSeg = rkCylinder.GetSegment();
00073     MgcReal fSqrDist = MgcSqrDistance(rkLine,kCylnSeg);
00074     return fSqrDist <= rkCylinder.Radius();
00075 }
00076 //----------------------------------------------------------------------------
00077 static int FindIntersection (const MgcVector3& rkOrigin,
00078     const MgcVector3& rkDirection, const MgcCylinder& rkCylinder,
00079     MgcReal afT[2])
00080 {
00081     // set up quadratic Q(t) = a*t^2 + 2*b*t + c
00082     MgcVector3 kU, kV, kW = rkCylinder.Direction();
00083     MgcVector3::GenerateOrthonormalBasis(kU,kV,kW);
00084     MgcVector3 kD(kU.Dot(rkDirection),kV.Dot(rkDirection),
00085         kW.Dot(rkDirection));
00086     MgcReal fDLength = kD.Unitize();
00087     MgcReal fInvDLength = 1.0/fDLength;
00088     MgcVector3 kDiff = rkOrigin - rkCylinder.Center();
00089     MgcVector3 kP(kU.Dot(kDiff),kV.Dot(kDiff),kW.Dot(kDiff));
00090     MgcReal fHalfHeight = 0.5*rkCylinder.Height();
00091     MgcReal fRadiusSqr = rkCylinder.Radius()*rkCylinder.Radius();
00092 
00093     MgcReal fInv, fA, fB, fC, fDiscr, fRoot, fT, fT0, fT1, fTmp0, fTmp1;
00094 
00095     if ( MgcMath::Abs(kD.z) >= 1.0 - gs_fEpsilon )
00096     {
00097         // line is parallel to cylinder axis
00098         if ( kP.x*kP.x+kP.y*kP.y <= fRadiusSqr )
00099         {
00100             fTmp0 = fInvDLength/kD.z;
00101             afT[0] = (+fHalfHeight - kP.z)*fTmp0;
00102             afT[1] = (-fHalfHeight - kP.z)*fTmp0;
00103             return 2;
00104         }
00105         else
00106         {
00107             return 0;
00108         }
00109     }
00110 
00111     if ( MgcMath::Abs(kD.z) <= gs_fEpsilon )
00112     {
00113         // line is perpendicular to axis of cylinder
00114         if ( MgcMath::Abs(kP.z) > fHalfHeight )
00115         {
00116             // line is outside the planar caps of cylinder
00117             return 0;
00118         }
00119 
00120         fA = kD.x*kD.x + kD.y*kD.y;
00121         fB = kP.x*kD.x + kP.y*kD.y;
00122         fC = kP.x*kP.x + kP.y*kP.y - fRadiusSqr;
00123         fDiscr = fB*fB - fA*fC;
00124         if ( fDiscr < 0.0 )
00125         {
00126             // line does not intersect cylinder wall
00127             return 0;
00128         }
00129         else if ( fDiscr > 0.0 )
00130         {
00131             fRoot = MgcMath::Sqrt(fDiscr);
00132             fTmp0 = fInvDLength/fA;
00133             afT[0] = (-fB - fRoot)*fTmp0;
00134             afT[1] = (-fB + fRoot)*fTmp0;
00135             return 2;
00136         }
00137         else
00138         {
00139             afT[0] = -fB*fInvDLength/fA;
00140             return 1;
00141         }
00142     }
00143 
00144     // test plane intersections first
00145     int iQuantity = 0;
00146     fInv = 1.0/kD.z;
00147     fT0 = (+fHalfHeight - kP.z)*fInv;
00148     fTmp0 = kP.x + fT0*kD.x;
00149     fTmp1 = kP.y + fT0*kD.y;
00150     if ( fTmp0*fTmp0 + fTmp1*fTmp1 <= fRadiusSqr )
00151         afT[iQuantity++] = fT0*fInvDLength;
00152 
00153     fT1 = (-fHalfHeight - kP.z)*fInv;
00154     fTmp0 = kP.x + fT1*kD.x;
00155     fTmp1 = kP.y + fT1*kD.y;
00156     if ( fTmp0*fTmp0 + fTmp1*fTmp1 <= fRadiusSqr )
00157         afT[iQuantity++] = fT1*fInvDLength;
00158 
00159     if ( iQuantity == 2 )
00160     {
00161         // line intersects both top and bottom
00162         return 2;
00163     }
00164 
00165     // If iQuantity == 1, then line must intersect cylinder wall
00166     // somewhere between caps in a single point.  This case is detected
00167     // in the following code that tests for intersection between line and
00168     // cylinder wall.
00169 
00170     fA = kD.x*kD.x + kD.y*kD.y;
00171     fB = kP.x*kD.x + kP.y*kD.y;
00172     fC = kP.x*kP.x + kP.y*kP.y - fRadiusSqr;
00173     fDiscr = fB*fB - fA*fC;
00174     if ( fDiscr < 0.0 )
00175     {
00176         // line does not intersect cylinder wall
00177         assert( iQuantity == 0 );
00178         return 0;
00179     }
00180     else if ( fDiscr > 0.0 )
00181     {
00182         fRoot = MgcMath::Sqrt(fDiscr);
00183         fInv = 1.0/fA;
00184         fT = (-fB - fRoot)*fInv;
00185         if ( fT0 <= fT1 )
00186         {
00187             if ( fT0 <= fT && fT <= fT1 )
00188                 afT[iQuantity++] = fT*fInvDLength;
00189         }
00190         else
00191         {
00192             if ( fT1 <= fT && fT <= fT0 )
00193                 afT[iQuantity++] = fT*fInvDLength;
00194         }
00195 
00196         if ( iQuantity == 2 )
00197         {
00198             // Line intersects one of top/bottom of cylinder and once on
00199             // cylinder wall.
00200             return 2;
00201         }
00202 
00203         fT = (-fB + fRoot)*fInv;
00204         if ( fT0 <= fT1 )
00205         {
00206             if ( fT0 <= fT && fT <= fT1 )
00207                 afT[iQuantity++] = fT*fInvDLength;
00208         }
00209         else
00210         {
00211             if ( fT1 <= fT && fT <= fT0 )
00212                 afT[iQuantity++] = fT*fInvDLength;
00213         }
00214     }
00215     else
00216     {
00217         fT = -fB/fA;
00218         if ( fT0 <= fT1 )
00219         {
00220             if ( fT0 <= fT && fT <= fT1 )
00221                 afT[iQuantity++] = fT*fInvDLength;
00222         }
00223         else
00224         {
00225             if ( fT1 <= fT && fT <= fT0 )
00226                 afT[iQuantity++] = fT*fInvDLength;
00227         }
00228     }
00229 
00230     return iQuantity;
00231 }
00232 //----------------------------------------------------------------------------
00233 bool MgcFindIntersection (const MgcSegment3& rkSegment,
00234     const MgcCylinder& rkCylinder, int& riQuantity, MgcVector3 akPoint[2])
00235 {
00236     MgcReal afT[2];
00237     riQuantity = FindIntersection(rkSegment.Origin(),
00238         rkSegment.Direction(),rkCylinder,afT);
00239 
00240     int iClipQuantity = 0;
00241     for (int i = 0; i < riQuantity; i++)
00242     {
00243         if ( 0.0 <= afT[i] && afT[i] <= 1.0 )
00244         {
00245             akPoint[iClipQuantity++] = rkSegment.Origin() +
00246                 afT[i]*rkSegment.Direction();
00247         }
00248     }
00249 
00250     riQuantity = iClipQuantity;
00251     return riQuantity > 0;
00252 }
00253 //----------------------------------------------------------------------------
00254 bool MgcFindIntersection (const MgcRay3& rkRay,
00255     const MgcCylinder& rkCylinder, double &t)
00256 {
00257     MgcReal afT[2];
00258     int riQuantity;
00259     int retvalue = 0;
00260 
00261     riQuantity = FindIntersection(rkRay.Origin(),rkRay.Direction(),
00262         rkCylinder,afT);
00263 
00264     t = DBL_MAX;
00265 
00266         for (int i = 0; i < riQuantity; i++)
00267     {
00268         if (( afT[i] > 0 ) && (afT[i] < t))
00269         {
00270            t = afT[i];
00271            retvalue++;
00272         }
00273     }
00274 
00275     return (retvalue > 0);
00276 }
00277 //----------------------------------------------------------------------------
00278 bool MgcFindIntersection2 (const MgcRay3& rkRay,
00279     const MgcCylinder& rkCylinder, int& riQuantity, MgcVector3 akPoint[2])
00280 {
00281     MgcReal afT[2];
00282     riQuantity = FindIntersection(rkRay.Origin(),rkRay.Direction(),
00283         rkCylinder,afT);
00284 
00285     int iClipQuantity = 0;
00286     for (int i = 0; i < riQuantity; i++)
00287     {
00288         if ( afT[i] >= 0.0 )
00289         {
00290             akPoint[iClipQuantity++] = rkRay.Origin() +
00291                 afT[i]*rkRay.Direction();
00292         }
00293     }
00294 
00295     riQuantity = iClipQuantity;
00296     return riQuantity > 0;
00297 }
00298 //----------------------------------------------------------------------------
00299 bool MgcFindIntersection (const MgcLine3& rkLine,
00300     const MgcCylinder& rkCylinder, int& riQuantity, MgcVector3 akPoint[2])
00301 {
00302     MgcReal afT[2];
00303     riQuantity = FindIntersection(rkLine.Origin(),rkLine.Direction(),
00304         rkCylinder,afT);
00305 
00306     for (int i = 0; i < riQuantity; i++)
00307         akPoint[i] = rkLine.Origin() + afT[i]*rkLine.Direction();
00308 
00309     return riQuantity > 0;
00310 }
00311 //----------------------------------------------------------------------------

Generated on Sat Apr 1 21:30:31 2006 for Motion Planning Kernel by  doxygen 1.4.6-NO