#include "munga.h" #pragma hdrstop #include "boxsolid.h" #include "origin.h" #include "linmtrx.h" #include "line.h" //############################################################################# //############################## BoxedSphere ############################ //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSphere::BoxedSphere( const ExtentBox &extents, BoxedSolid::Material material, Simulation *owner, BoxedSolid *next_solid ): BoxedSolid(extents, SphereType, material, owner, next_solid) { Check_Pointer(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSphere::~BoxedSphere() { Check_Pointer(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSphere::IntersectsBounded(const ExtentBox &extents) { Check(this); Check(&extents); Verify(minX <= extents.minX); Verify(maxX >= extents.maxX); Verify(minY <= extents.minY); Verify(maxY >= extents.maxY); Verify(minZ <= extents.minZ); Verify(maxZ >= extents.maxZ); // //---------------------------------------------- // Find the centerpoint and radius of the sphere //---------------------------------------------- // Point3D center; center.x = (minX + maxX) * 0.5f; center.y = (minY + maxY) * 0.5f; center.z = (minZ + maxZ) * 0.5f; Scalar radius = maxX - center.x; // //-------------------------------------------------------------------------- // Constrain the centerpoint of the sphere to be within the bounded extents. // Then see if the constrained point is within the radius of the sphere. If // so, it is an intersection //-------------------------------------------------------------------------- // Point3D closest = center; extents.Constrain(&closest); closest -= center; return radius*radius >= closest.LengthSquared(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSphere::ContainsBounded(const Point3D &point) { Check(this); Check(&point); Verify(minX <= point.x); Verify(maxX >= point.x); Verify(minY <= point.y); Verify(maxY >= point.y); Verify(minZ <= point.z); Verify(maxZ >= point.z); // //---------------------------------------------- // Find the centerpoint and radius of the sphere //---------------------------------------------- // Point3D center; center.x = (minX + maxX) * 0.5f; center.y = (minY + maxY) * 0.5f; center.z = (minZ + maxZ) * 0.5f; Scalar radius = maxX - center.x; // //------------------------------------------------------------------------- // translate the test point into the sphere's frame of reference and see if // it is close enough //------------------------------------------------------------------------- // center -= point; return radius*radius >= center.LengthSquared(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar BoxedSphere::FindDistanceBelowBounded(const Point3D &point) { Check(this); Check(&point); Verify(minX <= point.x); Verify(maxX >= point.x); Verify(minY <= point.y); Verify(minZ <= point.z); Verify(maxZ >= point.z); // //---------------------------------------------- // Find the centerpoint and radius of the sphere //---------------------------------------------- // Point3D center; center.x = (minX + maxX) * 0.5f; center.y = (minY + maxY) * 0.5f; center.z = (minZ + maxZ) * 0.5f; Scalar radius = maxX - center.x; // //----------------------------------------------------------------------- // Convert the point to the coordinates of the sphere, putting the center // point of the sphere at the origin. Note that we are subtracting the // point from the center point as opposed to the normal way. This will // result in both X and Y being negated, but since we are squaring them, // this will not matter //----------------------------------------------------------------------- // Scalar x = center.x - point.x; Scalar z = center.z - point.z; Scalar h = radius*radius - x*x - z*z; if (h < SMALL) { return -1.0f; } // //------------------------------------------------------------------- // If the point is in the XZ shadow of the sphere, then the height is // determined by the height of the sphere at that point //------------------------------------------------------------------- // Scalar height = point.y - (center.y + Sqrt(h)); return Abs(height); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSphere::HitByBounded( Line *line, Scalar enters, Scalar leaves ) { Check(this); Check(line); Verify(enters <= leaves); Verify(leaves >= 0.0f); // //---------------------------------------------- // Find the centerpoint and radius of the sphere //---------------------------------------------- // Point3D center; center.x = (minX + maxX) * 0.5f; center.y = (minY + maxY) * 0.5f; center.z = (minZ + maxZ) * 0.5f; Scalar radius = maxX - center.x; // //------------------------------------------------------------------------- // Find the point of closest approach to the center of the sphere, and make // sure that it is within the boundaries of the sphere //------------------------------------------------------------------------- // Scalar midlen = line->LengthToClosestPointTo(center); Point3D closest; line->Project(midlen, &closest); closest -= center; Scalar v = radius*radius - closest.LengthSquared(); if (v < 0.0f) { return False; } // //--------------------------------------------------------------------- // Find the closest possible length of ray traversal before hitting the // sphere //--------------------------------------------------------------------- // v = Sqrt(v); Scalar enter = midlen - v; if (enter > enters) { enters = enter; } Scalar leave = midlen + v; if (leave < leaves) { leaves = leave; } if (enters > leaves || enters > line->length || leaves < 0.0f) { return False; } line->length = Max(enters, 0.0f); return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSphere::TestInstance() const { return solidType == SphereType; }