Vector3f TrackballManipulator::SphereLineIntersection(const Vector3f& pStart, const Vector3f& pEnd, const Vector3f& pSpherePos, Float pRadius) { // pStart P1 coordinates (point of line) // pEnd P2 coordinates (point of line) // pSpherePos, pRadius P3 coordinates and radius (sphere) Vector3f interVector; Float a, b, c, mu, i ; a = (pEnd - pStart).GetLengthSqr(); b = 2 * ( (pEnd.x - pStart.x)*(pStart.x - pSpherePos.x) + (pEnd.y - pStart.y)*(pStart.y - pSpherePos.y) + (pEnd.z - pStart.z)*(pStart.z - pSpherePos.z) ); c = pSpherePos.GetLengthSqr() + pStart.GetLengthSqr() - 2 * ( pSpherePos | pStart ) - pRadius * pRadius; i = b * b - 4 * a * c ; if( i < 0.0 ) { // no intersection interVector = Closest(pStart, pEnd, pSpherePos); } if( i == 0.0 ) { // one intersection mu = -b/(2*a) ; interVector = pStart + ((pEnd - pStart) * mu); } if ( i > 0.0 ) { // two intersections // first intersection mu = (-b + Maths::Sqrt( b*b - 4*a*c )) / (2*a); Vector3f inter1 = pStart + ((pEnd - pStart) * mu); // second intersection mu = (-b - Maths::Sqrt( b*b - 4*a*c )) / (2*a); Vector3f inter2 = pStart + ((pEnd - pStart) * mu); // Get the camera. Camera* camera = mEditor->GetWorldManager().GetCurrentCamera(); if((inter1 - camera->GetPosition()).GetLength() < (inter2 - camera->GetPosition()).GetLength()) { interVector = inter1; } else { interVector = inter2; } } return interVector; }
// Return the closest point on the line segment start_end to point. Vector3f TrackballManipulator::Closest(const Vector3f& pStart, const Vector3f& pEnd, const Vector3f& pPoint) { // Acquire a vector from the start point to the point in question. Vector3f A; A.x = pPoint.x - pStart.x; A.y = pPoint.y - pStart.y; A.z = pPoint.z - pStart.z; // Acquire a vector from the start point to the end point. Vector3f B; B.x = pEnd.x - pStart.x; B.y = pEnd.y - pStart.y; B.z = pEnd.z - pStart.z; // Determine the length of the segment start_end. Float d = B.GetLengthSqr(); // Normalize the vector. B.Normalize(); // Calculate the dot product between the two vectors. Float t = A.x * B.x + A.y * B.y + A.z * B.z; // Rule out some special cases. // t <= 0, meaning behind the start point. if(t*t <= 0) return pStart; // t >= the length of start_end, meaning past the end point. else if(t*t >= d) // t squared, to avoid an unnecessary square root operation. return pEnd; // If the closest point on start_end to point is somewhere along the segment, determine exactly where. Vector3f C; C.x = B.x * t + pStart.x; C.y = B.y * t + pStart.y; C.z = B.z * t + pStart.z; // Return the final value. return C; }