// Precalculations for intersection testing speed void ViewableParallelogram::PreCalcInfo() { VectorR3 EdgeAB = VertexB - VertexA; VectorR3 EdgeBC = VertexC - VertexB; LengthAB = EdgeAB.Norm(); LengthBC = EdgeBC.Norm(); VertexD = VertexA; VertexD += EdgeBC; // The fourth vertex EdgeAB /= LengthAB; // Normalize EdgeBC /= LengthBC; // Normalize Normal = EdgeAB*EdgeBC; double mag = Normal.Norm(); if ( mag>0.0 && LengthAB>0.0 && LengthBC>0.0 ) { Normal /= mag; // Unit Vector to parallelogram } else { Normal.SetZero(); // In this case, the parallelogram is malformed. } PlaneCoef = VertexB^Normal; NormalAB = Normal*EdgeAB; // Normal in from edge AB NormalBC = Normal*EdgeBC; // Normal in from edge BC NormalAB.ReNormalize(); // Just in case NormalBC.ReNormalize(); CoefAB = VertexA^NormalAB; // Coef. for edge AB. CoefBC = VertexB^NormalBC; CoefCD = VertexC^NormalAB; CoefDA = VertexA^NormalBC; }
// RotateToMap returns a rotation map which rotates fromVec to have the // same direction as toVec. // fromVec and toVec should be unit vectors RotationMapR3 RotateToMap(const VectorR3& fromVec, const VectorR3& toVec) { VectorR3 crossVec = fromVec; crossVec *= toVec; double sintheta = crossVec.Norm(); double costheta = fromVec ^ toVec; if (sintheta <= 1.0e-40) { if (costheta > 0.0) { return (RotationMapR3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)); } else { GetOrtho(toVec, crossVec); // Get arbitrary orthonormal vector return (VrRotate(costheta, sintheta, crossVec)); } } else { crossVec /= sintheta; // Normalize the vector return (VrRotate(costheta, sintheta, crossVec)); } }
RotationMapR3 VrRotateAlign( const VectorR3& fromVec, const VectorR3& toVec) { VectorR3 crossVec = fromVec; crossVec *= toVec; double sinetheta = crossVec.Norm(); // Not yet normalized! if ( sinetheta < 1.0e-40 ) { return ( RotationMapR3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) ); } crossVec /= sinetheta; // Normalize the vector double scale = 1.0/sqrt(fromVec.NormSq()*toVec.NormSq()); sinetheta *= scale; double cosinetheta = (fromVec^toVec)*scale; return ( VrRotate( cosinetheta, sinetheta, crossVec) ); }
void NffFileLoader::ProcessConeCylNFF( const VectorR3& baseCenter, double baseRadius, const VectorR3& topCenter, double topRadius ) { bool isCone = (topRadius==0.0); if ( !isCone && topRadius!=baseRadius ) { UnsupportedTruncatedCone(); if ( topRadius<0.5*baseRadius ) { isCone = true; // Render as a true code } else { topRadius = baseRadius; // Render as a cylinder } } VectorR3 centerLine = topCenter; centerLine -= baseCenter; double height = centerLine.Norm(); if ( height==0.0 ) { return; // We do not support zero height cylinders (Nor does NFF!) } centerLine /= height; // Normalize if ( isCone ) { ViewableCone* vc = new ViewableCone(); vc->SetApex(topCenter); vc->SetCenterAxis(centerLine); vc->SetSlope( baseRadius/height ); vc->SetHeight( height ); ScenePtr->AddViewable(vc); } else { // Create a cylinder ViewableCylinder* vc = new ViewableCylinder(); vc->SetCenterAxis(centerLine); centerLine = topCenter; centerLine += baseCenter; centerLine *= 0.5; vc->SetCenter( centerLine ); vc->SetRadius( baseRadius ); vc->SetHeight( height ); ScenePtr->AddViewable(vc); } }
bool ViewableTorus::FindIntersectionNT ( const VectorR3& viewPos, const VectorR3& viewDir, double maxDistance, double *intersectDistance, VisiblePoint& returnedPoint ) const { // Precheck for collisions by // checking if passes to within a bounding box bool insideFlag = true; // Whether viewPos is inside bounding box double minDistBack = DBL_MAX; // min. distance to a backplane bounding the box double maxDistFront= -DBL_MAX; // mix. distance to a frontplane bounding the box double pdotn; double alpha; pdotn = (viewPos^AxisC) - CenterCoefC; alpha = viewDir^AxisC; if ( !CollideTwoPlanes(pdotn, alpha, MinorRadius, &insideFlag, &minDistBack, &maxDistFront) ) { return false; } pdotn = (viewPos^AxisA) - CenterCoefA; alpha = viewDir^AxisA; if ( !CollideTwoPlanes(pdotn, alpha, OuterRadius, &insideFlag, &minDistBack, &maxDistFront) ) { return false; } pdotn = (viewPos^AxisB) - CenterCoefB; alpha = viewDir^AxisB; if ( !CollideTwoPlanes(pdotn, alpha, OuterRadius, &insideFlag, &minDistBack, &maxDistFront) ) { return false; } assert ( minDistBack>=maxDistFront ); assert ( insideFlag || maxDistFront>=0.0 ); assert ( maxDistFront < 1000.0 ); if (maxDistFront>maxDistance) { return false; } // Bounding box precheck is done. Now do the actual intersection test. // Set up the degree 4 polynomial for the torus intersection // Coefficients are: // A = 1 // B = 4 u \cdot p // C = 4(u\cdot p)^2 + 2(p\cdot p) - 2(M^2+m^2) + 4M^2(u_C \cdot u) // D = 4[(p \cdot p)(u \cdot p) - (M^2+m^2)(u \cdot p) + 2M^2(u_C \dot p)^2] // E = ((p \cdot p)^2 - 2(M^2+m^2)(p \cdot p) + 4M^2(u_C\cdot p)^2 +(M^2-m^2)^2 double moveFwdDist = Max(0.0,maxDistFront); double coefs[5]; double roots[4]; double &A=coefs[0], &B=coefs[1], &C=coefs[2], &D=coefs[3], &E=coefs[4]; A = 1; VectorR3 viewPosRel; viewPosRel = viewDir; viewPosRel *= moveFwdDist; // Move forward distance moveFwdDist viewPosRel += viewPos; viewPosRel -= Center; // Position relative to center double udotp = (viewDir^viewPosRel); B = 4.0*udotp; double MSq = Square(MajorRadius); double mSq = Square(MinorRadius); double RadiiSqSum = MSq + mSq; double ucdotp = (AxisC^viewPosRel); double ucdotu = (AxisC^viewDir); double pSq = (viewPosRel^viewPosRel); C = 4.0*udotp*udotp + 2.0*pSq - 2.0*RadiiSqSum + 4.0*MSq*ucdotu*ucdotu; D = 4.0 * ( (pSq-RadiiSqSum)*udotp + 2.0*MSq*ucdotp*ucdotu ); E = (pSq - 2.0*RadiiSqSum)*pSq + 4.0*MSq*ucdotp*ucdotp + Square(MSq-mSq); int numRoots = PolySolveReal( 4, coefs, roots ); for ( int i=0; i<numRoots; i++ ) { roots[i] += moveFwdDist; // Restate as distance from viewPos if ( roots[i] >= maxDistance ) { return false; } if ( roots[i]>0.0 ) { // Return this visible point *intersectDistance = roots[i]; VectorR3 Point = viewDir; Point *= roots[i]; Point += viewPos; returnedPoint.SetPosition(Point); // Intersection position (not relative to center) if ( i & 0x01 ) { returnedPoint.SetBackFace(); // Orientation returnedPoint.SetMaterial( *InnerMaterial ); // Material } else { returnedPoint.SetFrontFace(); // Orientation returnedPoint.SetMaterial( *OuterMaterial ); // Material } // Outward normal Point -= Center; // Now its the relative point double xCoord = Point^AxisA; // forward axis double yCoord = Point^AxisB; // rightward axis double zCoord = Point^AxisC; // upward axis VectorR3 outN = AxisC; outN *= -zCoord; outN += Point; // Project point down to plane of torus center double outNnorm = outN.Norm(); outN *= MajorRadius/(-outNnorm); // Negative point projected to center path of torus outN += Point; // Displacement of point from center path of torus outN /= MinorRadius; // Should be outward unit vector outN.ReNormalize(); // Fix roundoff error problems returnedPoint.SetNormal(outN); // Outward normal // u - v coordinates double u = atan2( yCoord, xCoord ); u = u*PI2inv+0.5; double bVal = outNnorm-MajorRadius; double v = atan2( zCoord, bVal ); v = v*PI2inv+0.5; returnedPoint.SetUV(u , v); returnedPoint.SetFaceNumber( 0 ); return true; } } return false; }