00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00030
00031
00032
00033
00034
00035
00036
00037
00038
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
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
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
00114 if ( MgcMath::Abs(kP.z) > fHalfHeight )
00115 {
00116
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
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
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
00162 return 2;
00163 }
00164
00165
00166
00167
00168
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
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
00199
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