// Helper routine for SVD conversion from bidiagonal to diagonal bool MatrixRmn::UpdateBidiagIndices( long *firstBidiagIdx, long *lastBidiagIdx, VectorRn& w, VectorRn& superDiag, double eps ) { long lastIdx = *lastBidiagIdx; double* sdPtr = superDiag.GetPtr( lastIdx-1 ); // Entry above the last diagonal entry while ( NearZero(*sdPtr, eps) ) { *(sdPtr--) = 0.0; lastIdx--; if ( lastIdx == 0 ) { return false; } } *lastBidiagIdx = lastIdx; long firstIdx = lastIdx-1; double* wPtr = w.GetPtr( firstIdx ); while ( firstIdx > 0 ) { if ( NearZero( *wPtr, eps ) ) { // If this diagonal entry (near) zero *wPtr = 0.0; break; } if ( NearZero(*(--sdPtr), eps) ) { // If the entry above the diagonal entry is (near) zero *sdPtr = 0.0; break; } wPtr--; firstIdx--; } *firstBidiagIdx = firstIdx; return true; }
float4 float4::normalize() const { f32 lsqr = LengthSquared(); if(NearZero(lsqr)) { return ZERO; }; f32 recip = InvSqrt(lsqr); return float4(vec[0]*recip, vec[1]*recip, vec[2]*recip, vec[3]*recip); };
// This is called when there is a zero diagonal entry, with a non-zero superdiagonal entry in the same column. // We use Givens rotations to "chase" the non-zero entry up the column; when it reaches the last // column, it is finally zeroed away. // wPtr points to the zero entry on the diagonal. sdPtr points to the non-zero superdiagonal entry in the same column. void MatrixRmn::ClearColumnWithDiagonalZero( long endIdx, MatrixRmn& V, double *wPtr, double *sdPtr, double eps ) { double curSd = *sdPtr; // Value being chased up the column *sdPtr = 0.0; long i = endIdx-1; while ( true ) { double c, s; CalcGivensValues( *(--wPtr), curSd, &c, &s ); V.PostApplyGivens( c, -s, i, endIdx ); *wPtr = c*(*wPtr) - s*curSd; if ( i==0 ) { break; } curSd = s*(*(--sdPtr)); // New value pops up one row above if ( NearZero( curSd, eps ) ) { break; } *sdPtr = c*(*sdPtr); i--; } }
// set origin of pResult to the intersecting point // of pL1, and pL2 assuming they are not skew int FindIntersection( PVECTOR presult, PVECTOR s1, PVECTOR o1, PVECTOR s2, PVECTOR o2 ) { VECTOR R1, R2, denoms; RCOORD t1, t2, denom; #define a (o1[0]) #define b (o1[1]) #define c (o1[2]) #define d (o2[0]) #define e (o2[1]) #define f (o2[2]) #define na (s1[0]) #define nb (s1[1]) #define nc (s1[2]) #define nd (s2[0]) #define ne (s2[1]) #define nf (s2[2]) crossproduct( denoms, s1, s2 ); denom = denoms[2]; // denom = ( nd * nb ) - ( ne * na ); if( NearZero( denom ) ) { denom = denoms[1]; // denom = ( nd * nc ) - (nf * na ); if( NearZero( denom ) ) { denom = denoms[0]; // denom = ( ne * nc ) - ( nb * nf ); if( NearZero( denom ) ) { SetPoint( presult, VectorConst_0 ); return FALSE; } else { t1 = ( ne * ( f - c ) + nf * ( e - b ) ) / -denom; t2 = ( nb * ( c - f ) + nc * ( b - e ) ) / denom; } } else { t1 = ( nd * ( f - c ) + nf * ( d - a ) ) / -denom; t2 = ( na * ( c - f ) + nc * ( a - d ) ) / denom; } } else { t1 = ( nd * ( e - b ) + ne * ( d - a ) ) / -denom; t2 = ( na * ( b - e ) + nb * ( a - d ) ) / denom; } scale( R1, s1, t1 ); add ( R1, R1 , o1 ); scale( R2, s2, t2 ); add ( R2, R2 , o2 ); if( ( !COMPARE(R1[0] , R2[0]) ) || ( !COMPARE(R1[1] , R2[1]) ) || ( !COMPARE(R1[2] , R2[2]) ) ) { SetPoint( presult, VectorConst_0 ); return FALSE; } SetPoint( presult, R1); return TRUE; #undef a #undef b #undef c #undef d #undef e #undef f #undef na #undef nb #undef nc #undef nd #undef ne #undef nf }
int FindIntersectionTime( RCOORD *pT1, PVECTOR s1, PVECTOR o1 , RCOORD *pT2, PVECTOR s2, PVECTOR o2 ) { VECTOR R1, R2, denoms; RCOORD t1, t2, denom; #define a (o1[0]) #define b (o1[1]) #define c (o1[2]) #define d (o2[0]) #define e (o2[1]) #define f (o2[2]) #define na (s1[0]) #define nb (s1[1]) #define nc (s1[2]) #define nd (s2[0]) #define ne (s2[1]) #define nf (s2[2]) crossproduct(denoms, s1, s2 ); // - result... denom = denoms[2]; // denom = ( nd * nb ) - ( ne * na ); if( NearZero( denom ) ) { denom = denoms[1]; // denom = ( nd * nc ) - (nf * na ); if( NearZero( denom ) ) { denom = denoms[0]; // denom = ( ne * nc ) - ( nb * nf ); if( NearZero( denom ) ) { #ifdef FULL_DEBUG sprintf( (char*)byBuffer,"Bad!-------------------------------------------\n"); Log( (char*)byBuffer ); #endif return FALSE; } else { DebugBreak(); t1 = ( ne * ( c - f ) + nf * ( b - e ) ) / denom; t2 = ( nb * ( c - f ) + nc * ( b - e ) ) / denom; } } else { DebugBreak(); t1 = ( nd * ( c - f ) + nf * ( d - a ) ) / denom; t2 = ( na * ( c - f ) + nc * ( d - a ) ) / denom; } } else { // this one has been tested....... t1 = ( nd * ( b - e ) + ne * ( d - a ) ) / denom; t2 = ( na * ( b - e ) + nb * ( d - a ) ) / denom; } R1[0] = a + na * t1; R1[1] = b + nb * t1; R1[2] = c + nc * t1; R2[0] = d + nd * t2; R2[1] = e + ne * t2; R2[2] = f + nf * t2; if( ( !COMPARE(R1[0],R2[0]) ) || ( !COMPARE(R1[1],R2[1]) ) || ( !COMPARE(R1[2],R2[2]) ) ) { return FALSE; } *pT2 = t2; *pT1 = t1; return TRUE; #undef a #undef b #undef c #undef d #undef e #undef f #undef na #undef nb #undef nc #undef nd #undef ne #undef nf }
RENDER_NAMESPACE // intersection of lines - assuming lines are // relative on the same plane.... //int FindIntersectionTime( RCOORD *pT1, LINESEG pL1, RCOORD *pT2, PLINE pL2 ) int FindIntersectionTime( RCOORD *pT1, PVECTOR s1, PVECTOR o1 , RCOORD *pT2, PVECTOR s2, PVECTOR o2 ) { VECTOR R1, R2, denoms; RCOORD t1, t2, denom; #define a (o1[0]) #define b (o1[1]) #define c (o1[2]) #define d (o2[0]) #define e (o2[1]) #define f (o2[2]) #define na (s1[0]) #define nb (s1[1]) #define nc (s1[2]) #define nd (s2[0]) #define ne (s2[1]) #define nf (s2[2]) crossproduct(denoms, s1, s2 ); // - result... PrintVector( denoms ); denom = denoms[2]; // denom = ( nd * nb ) - ( ne * na ); if( NearZero( denom ) ) { denom = denoms[1]; // denom = ( nd * nc ) - (nf * na ); if( NearZero( denom ) ) { denom = denoms[0]; // denom = ( ne * nc ) - ( nb * nf ); if( NearZero( denom ) ) { #ifdef FULL_DEBUG lprintf("Bad!-------------------------------------------\n"); #endif return FALSE; } else { DebugBreak(); t1 = ( ne * ( c - f ) + nf * ( b - e ) ) / denom; t2 = ( nb * ( c - f ) + nc * ( b - e ) ) / denom; } } else { DebugBreak(); t1 = ( nd * ( c - f ) + nf * ( d - a ) ) / denom; t2 = ( na * ( c - f ) + nc * ( d - a ) ) / denom; } } else { // this one has been tested....... t1 = ( nd * ( b - e ) + ne * ( d - a ) ) / denom; t2 = ( na * ( b - e ) + nb * ( d - a ) ) / denom; } R1[0] = a + na * t1; R1[1] = b + nb * t1; R1[2] = c + nc * t1; R2[0] = d + nd * t2; R2[1] = e + ne * t2; R2[2] = f + nf * t2; if( ( !COMPARE(R1[0],R2[0]) ) || ( !COMPARE(R1[1],R2[1]) ) || ( !COMPARE(R1[2],R2[2]) ) ) { PrintVector( R1 ); PrintVector( R2 ); lprintf( WIDE("too far from the same... %g %g "), t1, t2 ); return FALSE; } *pT2 = t2; *pT1 = t1; return TRUE; #undef a #undef b #undef c #undef d #undef e #undef f #undef na #undef nb #undef nc #undef nd #undef ne #undef nf }
// **************** ConvertBidiagToDiagonal *********************************************** // Do the iterative transformation from bidiagonal form to diagonal form using // Givens transformation. (Golub-Reinsch) // U and V are square. Size of U less than or equal to that of U. void MatrixRmn::ConvertBidiagToDiagonal( MatrixRmn& U, MatrixRmn& V, VectorRn& w, VectorRn& superDiag ) const { // These two index into the last bidiagonal block (last in the matrix, it will be // first one handled. long lastBidiagIdx = V.NumRows-1; long firstBidiagIdx = 0; double eps = 1.0e-15 * Max(w.MaxAbs(), superDiag.MaxAbs()); while ( true ) { bool workLeft = UpdateBidiagIndices( &firstBidiagIdx, &lastBidiagIdx, w, superDiag, eps ); if ( !workLeft ) { break; } // Get ready for first Givens rotation // Push non-zero to M[2,1] with Givens transformation double* wPtr = w.x+firstBidiagIdx; double* sdPtr = superDiag.x+firstBidiagIdx; double extraOffDiag=0.0; if ( (*wPtr)==0.0 ) { ClearRowWithDiagonalZero( firstBidiagIdx, lastBidiagIdx, U, wPtr, sdPtr, eps ); if ( firstBidiagIdx>0 ) { if ( NearZero( *(--sdPtr), eps ) ) { *sdPtr = 0.0; } else { ClearColumnWithDiagonalZero( firstBidiagIdx, V, wPtr, sdPtr, eps ); } } continue; } // Estimate an eigenvalue from bottom four entries of M // This gives a lambda value which will shift the Givens rotations // Last four entries of M^T * M are ( ( A, B ), ( B, C ) ). double A; A = (firstBidiagIdx<lastBidiagIdx-1) ? Square(superDiag[lastBidiagIdx-2]): 0.0; double BSq = Square(w[lastBidiagIdx-1]); A += BSq; // The "A" entry of M^T * M double C = Square(superDiag[lastBidiagIdx-1]); BSq *= C; // The squared "B" entry C += Square(w[lastBidiagIdx]); // The "C" entry double lambda; // lambda will hold the estimated eigenvalue lambda = sqrt( Square((A-C)*0.5) + BSq ); // Use the lambda value that is closest to C. if ( A > C ) { lambda = -lambda; } lambda += (A+C)*0.5; // Now lambda equals the estimate for the last eigenvalue double t11 = Square(w[firstBidiagIdx]); double t12 = w[firstBidiagIdx]*superDiag[firstBidiagIdx]; double c, s; CalcGivensValues( t11-lambda, t12, &c, &s ); ApplyGivensCBTD( c, s, wPtr, sdPtr, &extraOffDiag, wPtr+1 ); V.PostApplyGivens( c, -s, firstBidiagIdx ); long i; for ( i=firstBidiagIdx; i<lastBidiagIdx-1; i++ ) { // Push non-zero from M[i+1,i] to M[i,i+2] CalcGivensValues( *wPtr, extraOffDiag, &c, &s ); ApplyGivensCBTD( c, s, wPtr, sdPtr, &extraOffDiag, extraOffDiag, wPtr+1, sdPtr+1 ); U.PostApplyGivens( c, -s, i ); // Push non-zero from M[i,i+2] to M[1+2,i+1] CalcGivensValues( *sdPtr, extraOffDiag, &c, &s ); ApplyGivensCBTD( c, s, sdPtr, wPtr+1, &extraOffDiag, extraOffDiag, sdPtr+1, wPtr+2 ); V.PostApplyGivens( c, -s, i+1 ); wPtr++; sdPtr++; } // Push non-zero value from M[i+1,i] to M[i,i+1] for i==lastBidiagIdx-1 CalcGivensValues( *wPtr, extraOffDiag, &c, &s ); ApplyGivensCBTD( c, s, wPtr, &extraOffDiag, sdPtr, wPtr+1 ); U.PostApplyGivens( c, -s, i ); // DEBUG // DebugCalcBidiagCheck( V, w, superDiag, U ); } }
void SeasonalWindow::OnKeyboard(i32 key, bool down) { if(key == VK_ESCAPE && down) { Close(); } i32 _key = tolower(key); f32 dt = (f32)gxbase::App::GetDeltaTime(); dt = min(dt, 0.02f); // workaround to help remove any jitters when dt jumps f32 cameraSpeed = 35; // Up, down, left and right arrows can be held. We use dt // to impact speed of rotations switch(_key) { case 37: // left arrow { scn.SetCameraRotation(scn.GetCameraRotation() - dt * cameraSpeed); break; } case 39: // right arrow { scn.SetCameraRotation(scn.GetCameraRotation() + dt * cameraSpeed); break; } case 38: // up arrow { scn.SetCameraAngle(scn.GetCameraAngle() - dt * cameraSpeed); break; } case 40: // down arrow { scn.SetCameraAngle(scn.GetCameraAngle() + dt * cameraSpeed); break; } } if(down) // all other keys must be released before they are registered { return; } switch(_key) { case 'h': { displayHelpMenu = !displayHelpMenu; } break; case 187: //+ scn.SetDtMultiplier(scn.GetMultiplier() + 0.1); break; case 189: //- scn.SetDtMultiplier(scn.GetMultiplier() - 0.1); break; case 'p': { // application class as paused when dt multiplier 0 (accounting for floating point errors) // this is a better solution than an isPaused boolean variable, as the user can press + or - // to unpause the application, incrementing/ decrementing the multiplier by 0.1 if(NearZero((f32)scn.GetMultiplier())) { scn.SetDtMultiplier(1); } else { scn.SetDtMultiplier(0); } } break; case 'm': { scn.SetTreeShadeMode(scn.GetNextTreeShadeMode()); } break; case 's': { // Order: Directional - Spotlight - Ambient - Directional const LightingMode lm = scn.GetLightingMode(); switch(lm) { case Directional: { scn.SetLightingMode(Spotlights); break; } case Spotlights: { scn.SetLightingMode(Ambient); break; } case Ambient: { scn.SetLightingMode(Directional); break; } } } break; case 't': { scn.SetPolygonMode(scn.GetNextPolygonMode(scn.GetPolygonMode())); }; } };