Vector ClosestPointCylinder ( Vector const & V, Cylinder const & C ) { Vector delta = V - C.getBase(); delta.y = 0.0f; real dist = delta.magnitude(); Vector point = V; // clamp the x-z coords of the point so they're inside the tube IGNORE_RETURN( delta.normalize() ); delta *= std::min( C.getRadius(), dist ); point = C.getBase() + delta; // and clamp the y coord so it's inside also real min = C.getBase().y; real max = min + C.getHeight(); point.y = clamp( min, V.y, max ); return point; }
ContainmentResult TestCylinderCylinder ( Cylinder const & A, Cylinder const & B ) { Vector delta = B.getBase() - A.getBase(); delta.y = 0; real dist = delta.magnitude(); Range AD( dist - A.getRadius(), dist + A.getRadius() ); Range BD( -B.getRadius(), B.getRadius() ); ContainmentResult hTest = Containment1d::TestRangeRange( AD, BD ); ContainmentResult vTest = Containment1d::TestRangeRange( A.getRangeY(), B.getRangeY() ); // ---------- return Containment::ComposeAxisTests(hTest,vTest); }
ContainmentResult TestPointCylinder ( Vector const & V, Cylinder const & C ) { Vector delta = V - C.getBase(); delta.y = 0; real dist = delta.magnitude(); real radius = C.getRadius(); ContainmentResult rTest = Containment1d::TestFloatLess(dist,radius); ContainmentResult vTest = Containment1d::TestFloatRange(V.y, C.getRangeY()); // ---------- return Containment::ComposeAxisTests(rTest,vTest); }
bool TestYLineCylinder ( Vector const & V, Cylinder const & C ) { return Distance2d::Distance2PointPoint(V,C.getBase()) < sqr(C.getRadius()); }
ContainmentResult TestSphereCylinder ( Sphere const & S, Cylinder const & C ) { Vector delta = C.getBase() - S.getCenter(); delta.y = 0; real dist = delta.magnitude(); Range SD( dist - S.getRadius(), dist + S.getRadius() ); Range CD( -C.getRadius(), C.getRadius() ); ContainmentResult hTest = Containment1d::TestRangeRange( SD, CD ); ContainmentResult hTest2 = Containment1d::TestFloatRange( dist, CD ); ContainmentResult vTest = Containment1d::TestRangeRange( S.getRangeY(), C.getRangeY() ); ContainmentResult cTest = Containment1d::TestFloatRange( S.getCenter().y, C.getRangeY() ); // ---------- if(hTest == CR_Outside) { // Sphere can't possibly touch the cylinder return CR_Outside; } else if((hTest == CR_TouchingOutside) || (hTest == CR_Boundary)) { // Sphere is touching the outside of the cylinder's tube if its // center is inside the vertical range of the cylinder if((cTest == CR_Inside) || (cTest == CR_Boundary)) { return CR_TouchingOutside; } else { return CR_Outside; } } else if((hTest == CR_Inside) || (hTest == CR_TouchingInside)) { // Sphere is in the tube of the cylinder. It touches the cylinder // if its vertical range touches the vertical range of the cylinder return Containment::ComposeAxisTests(hTest,vTest); } else { // hTest == CR_Overlap if(vTest == CR_Outside) { return CR_Outside; } else if((vTest == CR_Inside) || (vTest == CR_TouchingInside)) { return CR_Overlap; } else if (vTest == CR_Boundary) { // This really shouldn't be happening return CR_Boundary; } else if (vTest == CR_TouchingOutside) { if(hTest2 == CR_Inside) { // Sphere is touching a cap of the cylinder return CR_TouchingOutside; } else if(hTest2 == CR_Boundary) { // Sphere is touching the edge of the cap of the cylinder return CR_TouchingOutside; } else { // Sphere isn't touching the cap return CR_Outside; } } else { // vTest == CR_Overlap if((cTest == CR_Inside) || (cTest == CR_Boundary)) { // The ranges overlap vertically and horizontally, and the center of // the sphere is inside the vertical range - the sphere overlaps the // cylinder return CR_Overlap; } else { // The sphere is inside both ranges, but its center is outside both // ranges. The sphere overlaps the cylinder if the closest point // on the cylinder is inside the sphere. Vector closestPoint = Distance3d::ClosestPointCylinder(S.getCenter(),C); ContainmentResult result = TestPointSphere(closestPoint,S); if(result == CR_Outside) { return CR_Outside; } else if(result == CR_Boundary) { return CR_TouchingOutside; } else { return CR_Overlap; } } } } }