ClothSimulation::Link ClothSimulation::createLink(const float4& posA, const float4& posB, u32 idxA, u32 idxB, float massA, float massB, float dampingFactor ) { Link link( idxA, idxB ); link.m_dampingFactor = dampingFactor; link.m_restLength = length3( posB-posA ); if( massA == FLT_MAX && massB == FLT_MAX ) { link.m_aWeight = 0; link.m_bWeight = 0; } else if( massA == FLT_MAX ) { link.m_aWeight = 0; link.m_bWeight = 1; } else if( massB == FLT_MAX ) { link.m_aWeight = 1; link.m_bWeight = 0; } else { float massAB = massA + massB; link.m_aWeight = massA/massAB; link.m_bWeight = massB/massAB; } return link; }
GLdouble dist3(GLdouble p[3], GLdouble q[3]) { GLdouble d[3]; diff3(p, q, d); return length3(d); }
// --------------------------------------------------------------------------- // // --------------------------------------------------------------------------- // void CAiwImagePrintIf::ConstructL() { TFileName file( KResource ); file = PathInfo::RomRootPath(); TBuf<KResource> length2(KResourceFile); file.SetLength(KDriver + length2.Length()); file.Replace(KDriver, length2.Length(), KResourceFile); BaflUtils::NearestLanguageFile( iEikEnv.FsSession(), file ); iResourceOffset = iEikEnv.AddResourceFileL( file ); iDRM = DRMCommon::NewL(); User::LeaveIfError( iDRM->Connect() ); iNumberOfUnSuppFiles = 0; TFileName printNameFile( KResource ); printNameFile = PathInfo::PhoneMemoryRootPath(); TBuf<KResource> length3(KParamFile); printNameFile.SetLength(KDriver + length3.Length()); printNameFile.Replace(KDriver, length3.Length(), KParamFile); iPrintFileName = HBufC::NewL(printNameFile.Length() ); iPrintFileName->Des().Copy(printNameFile); TFileName unSuppFile( KResource ); unSuppFile = PathInfo::PhoneMemoryRootPath(); TBuf<KResource> lengthUn(KUnSuppFile); unSuppFile.SetLength(KDriver + lengthUn.Length()); unSuppFile.Replace(KDriver, lengthUn.Length(), KUnSuppFile); iUnsuppFileName = HBufC::NewL(unSuppFile.Length() ); iUnsuppFileName->Des().Copy(unSuppFile); }
void ClothSimulation::solve( float4* v, const Link& link ) { float4 ab = v[link.m_b] - v[link.m_a]; float stretch = length3( ab ) - link.m_restLength; stretch *= (1.f-link.m_dampingFactor); float4 dx = stretch * normalize3( ab ); v[link.m_a] += dx*link.m_aWeight; v[link.m_b] -= dx*link.m_bWeight; }
VEC3 *normalized3(VEC3 *vec) { float length; length = length3(vec); vec->x /= length; vec->y /= length; vec->z /= length; return (vec); }
CL_Vec4<Type> &CL_Vec4<Type>::normalize3() { Type f = length3(); if (f!=0) { x /= f; y /= f; z /= f; } return *this; }
void ClothSimulation::volumeConstraint( float4* vtx, float* mass, const int4* tris, int nTris, float initVolume, float coeff ) { float vol = calcVolume( vtx, tris, nTris ); float force = (vol - initVolume)*coeff; int nVtx = 0; for(int i=0; i<nTris; i++) { nVtx = max2( nVtx, max2( tris[i].x, max2( tris[i].y, tris[i].z) ) ); } nVtx += 1; float4* disp = new float4[nVtx]; for(int i=0; i<nVtx; i++) disp[i] = make_float4(0,0,0,0); for(int i=0; i<nTris; i++) { const int4& t = tris[i]; float4& v0 = vtx[t.x]; float4& v1 = vtx[t.y]; float4& v2 = vtx[t.z]; const float4 n = cross3(v1-v0, v2-v0 ); float nl = length3( n ); float area = nl/2.f; // force = max2( 0.f, force ); force = min2( 0.f, force ); float4 f = force/3.f*(n/nl); if( mass[t.x] != FLT_MAX ) disp[t.x] += f; // v0 += f; if( mass[t.y] != FLT_MAX ) disp[t.y] += f; // v1 += f; if( mass[t.z] != FLT_MAX ) disp[t.z] += f; // v2 += f; } for(int i=0; i<nVtx; i++) vtx[i] += disp[i]; delete [] disp; }
void TestStyles::testCopyParagraphStyle() { QTextLength length1(QTextLength::FixedLength, 10.0); QTextLength length2(QTextLength::FixedLength, 20.0); QTextLength length3(QTextLength::FixedLength, 30.0); KoParagraphStyle style1; KoParagraphStyle style2; style2.setParentStyle(&style1); style1.setLeftMargin(length1); style1.setRightMargin(length3); style2.setRightMargin(length2); KoParagraphStyle newStyle; newStyle.copyProperties(&style2); QCOMPARE(newStyle.leftMargin(), 10.0); QCOMPARE(newStyle.rightMargin(), 20.0); }
static FuncResult set_objective_function( ObjectiveFunction objective_function, MatrixPair *matrix_pair) { int i; /* * Read the objective function from the first matrix on the list. * Recall from above that we want to maximize * * h = m00 + (m01 - m10)dx + (m02 - m20)dy + (m03 - m30)dz. * * Note that the object function is the same for matrix_pair[0] and * matrix_pair[1], because they are inverses. (This follows from the * rule for computing inverses in O(3,1) (see o31_invert() in * o31_matrices.c), as well as from the geometrical fact that an * isometry and its inverse must translate the basepoint equal amounts.) * * Return * func_OK if the objective function's derivative is nonzero, or * func_failed if it isn't. */ /* * Compute the objective function. */ for (i = 0; i < 3; i++) objective_function[i] = matrix_pair->m[0][0][i+1] - matrix_pair->m[0][i+1][0]; objective_function[3] = matrix_pair->m[0][0][0]; /* * Check whether the derivative is nonzero. */ if (length3(objective_function) > DERIVATIVE_EPSILON) return func_OK; else return func_failed; }
inline void projectedOnto3(vec3 * r, vec3 a, vec3 b) { mult3( r, a, dot3(a, b) ); invScale3( r, length3(a) * length3(b) ); }
int PP6Muon() { std::string muonFile; int resultCode(0); // Obtain filename from user std::cout << "Enter filename to analyse: "; muonFile = getString(); std::string runID("run4.dat"); int numberOfMuons(0), numberOfAntiMuons(0); // Count number of muons/antimuons in input file resultCode = countMuons(muonFile, runID, numberOfMuons, numberOfAntiMuons); if (resultCode) { std::cerr << "[PP6Muon:error] Failed to count muons in " << muonFile << std::endl; return resultCode; } //-------------------------------------------------------------------- // - Create arrays to hold muon data int *muonEventNumber(new int[numberOfMuons]); double *muonEnergy(new double[numberOfMuons]); double *muonPx(new double[numberOfMuons]); double *muonPy(new double[numberOfMuons]); double *muonPz(new double[numberOfMuons]); int *antimuonEventNumber(new int[numberOfAntiMuons]); double *antimuonEnergy(new double[numberOfAntiMuons]); double *antimuonPx(new double[numberOfAntiMuons]); double *antimuonPy(new double[numberOfAntiMuons]); double *antimuonPz(new double[numberOfAntiMuons]); // - Read in data int eventNumber(0); std::string particleName, dataID; double particlePx(0), particlePy(0), particlePz(0); double particlePtot(0); const double muonMass(0.105658366); FileReader muonReader(muonFile); int muonCounter(0); int antimuonCounter(0); while (muonReader.nextLine()) { // Valid lines should begin with an integer, continue without error // to skip header eventNumber = muonReader.getField<int>(1); if (muonReader.inputFailed()) continue; particleName = muonReader.getField<std::string>(2); if (muonReader.inputFailed()) { std::cerr << "[PP6Muon:error] Field 2 of " << muonFile << " is not a string" << std::endl; break; } dataID = muonReader.getField<std::string>(6); if (muonReader.inputFailed()) { std::cerr << "[PP6Muon:error] Field 6 of " << muonFile << " is not a string" << std::endl; break; } if (dataID == runID) { // Read the physics data particlePx = muonReader.getField<double>(3); if (muonReader.inputFailed()) { std::cerr << "[PP6Muon:error] Field 3 of " << muonFile << " is not a double" << std::endl; break; } particlePy = muonReader.getField<double>(4); if (muonReader.inputFailed()) { std::cerr << "[PP6Muon:error] Field 4 of " << muonFile << " is not a double" << std::endl; break; } particlePz = muonReader.getField<double>(5); if (muonReader.inputFailed()) { std::cerr << "[PP6Muon:error] Field 5 of " << muonFile << " is not a double" << std::endl; break; } if (particleName == "mu-") { // Fill muon data muonEventNumber[muonCounter] = eventNumber; muonPx[muonCounter] = particlePx; muonPy[muonCounter] = particlePy; muonPz[muonCounter] = particlePz; length3(particlePx, particlePy, particlePz, particlePtot); muonEnergy[muonCounter] = sqrt(particlePtot * particlePtot + muonMass*muonMass); ++muonCounter; } if (particleName == "mu+") { // Fill antimuon data antimuonEventNumber[antimuonCounter] = eventNumber; antimuonPx[antimuonCounter] = particlePx; antimuonPy[antimuonCounter] = particlePy; antimuonPz[antimuonCounter] = particlePz; length3(particlePx, particlePy, particlePz, particlePtot); antimuonEnergy[antimuonCounter] = sqrt(particlePtot * particlePtot + muonMass*muonMass); ++antimuonCounter; } } } if (muonReader.inputFailed()) { // - Clean up and return std::cerr << "[PP6Muon:error] Failed to extract physics data from " << muonFile << std::endl; delete [] muonEventNumber; delete [] muonEnergy; delete [] muonPx; delete [] muonPy; delete [] muonPz; delete [] antimuonEventNumber; delete [] antimuonEnergy; delete [] antimuonPx; delete [] antimuonPy; delete [] antimuonPz; return 1; } //-------------------------------------------------------------------- // - Analyse data... // Invariant mass and indexing array double *invariantMass(new double[numberOfMuons * numberOfAntiMuons]); int *muonPairIndex(new int[numberOfMuons * numberOfAntiMuons]); // - Loop over mu-/mu+ arrays, calculating invariant masses as we go for (int i(0); i < numberOfAntiMuons; ++i) { for (int j(0); j < numberOfMuons; ++j) { inv_mass(muonEnergy[i], muonPx[i], muonPy[i], muonPz[i], antimuonEnergy[j], antimuonPx[j], antimuonPy[j], antimuonPz[j], invariantMass[i*numberOfMuons + j]); muonPairIndex[i*numberOfMuons + j] = i*numberOfMuons + j; } } // Use associative sort to sort masses associative_sort(invariantMass, muonPairIndex, numberOfMuons * numberOfAntiMuons); //-------------------------------------------------------------------- // - Present results // std::cout << "Results:" << std::endl; std::cout << "========" << std::endl; std::cout << "Analysed File : " << muonFile << std::endl; std::cout << "Number of Muons = " << numberOfMuons << std::endl; std::cout << "Number of AntiMuons = " << numberOfAntiMuons << std::endl; std::cout << "----------------------------" << std::endl; for (int i(0); i < 10; ++i) { int muonIndex(muonPairIndex[i] % numberOfMuons); int antimuonIndex((muonPairIndex[i] - muonIndex) / numberOfMuons); std::cout << "{InvariantMass : " << invariantMass[muonPairIndex[i]] << ",\n\t" << "{Muon : " << "Event = " << muonEventNumber[muonIndex] << ", " << "(E, P) = (" << muonEnergy[muonIndex] << ", " << muonPx[muonIndex] << ", " << muonPy[muonIndex] << ", " << muonPz[muonIndex] << ")}\n\t" << "{AntiMuon : " << "Event = " << antimuonEventNumber[antimuonIndex] << ", " << "(E, P) = (" << antimuonEnergy[antimuonIndex] << ", " << antimuonPx[antimuonIndex] << ", " << antimuonPy[antimuonIndex] << ", " << antimuonPz[antimuonIndex] << ")}\n" << "}" << std::endl; } // - Clean up arrays delete [] muonEventNumber; delete [] muonEnergy; delete [] muonPx; delete [] muonPy; delete [] muonPz; delete [] antimuonEventNumber; delete [] antimuonEnergy; delete [] antimuonPx; delete [] antimuonPy; delete [] antimuonPz; delete [] invariantMass; delete [] muonPairIndex; return 0; }
Angle Vec4<Type>::angle3(const Vec4<Type>& v) const { return Angle(acosf(float(dot3(v) / (length3()*v.length3()))), angle_radians); }
inline void projectOnto3(vec3 a, vec3 * r) { scalar l = length3(a) * length3(*r); mult3( r, a, dot3(a, *r) ); invScale3( r, l ); }
CL_Angle CL_Vec4<Type>::angle3(const CL_Vec4<Type>& v) const { return CL_Angle(acosf(float(dot3(v)/(length3()*v.length3()))), cl_radians); }
static void regular_constraints( Constraint *constraints, MatrixPairList *gen_list, ObjectiveFunction objective_function, Boolean *may_be_saddle_point) { /* * The documentation at the top of this file shows that the image * height h corresponding to a matrix m is * * h = m00 + (m01 - m10)dx + (m02 - m20)dy + (m03 - m30)dz. * * Each regular constraint will say that the image height h for the * given matrix must remain greater than the image height h' of the * matrix used for the objective function. In symbols, h >= h'. * Since a Constraint says that some quantity must remain negative, * we express the constraint as h' - h <= 0. * * The Boolean *may_be_saddle_point will be set to TRUE if some * constraint suggests a saddle point. Otherwise it gets set to FALSE. */ int i; MatrixPair *matrix_pair; Constraint *constraint; double h[4], c; /* * Assume we're not at a saddle point unless we encounter * evidence to the contrary. */ *may_be_saddle_point = FALSE; /* * Skip the identity and the MatrixPair used to define the objective * function, and begin with the next MatrixPair on the list. * Write a constraint for it and each successive MatrixPair. * * Skip the first three Constraints in the constraints array. * They contain the step size constraints. */ for ( matrix_pair = gen_list->begin.next->next->next, constraint = constraints + 3; matrix_pair != &gen_list->end; matrix_pair = matrix_pair->next, constraint++) { /* * Compute h. (As explained in set_objective_function(), * it doesn't matter which of the two matrices we use.) */ for (i = 0; i < 3; i++) h[i] = matrix_pair->m[0][0][i+1] - matrix_pair->m[0][i+1][0]; h[3] = matrix_pair->m[0][0][0]; /* * Set the constraint to h' - h. * (The objective function is h' in the above notation.) */ for (i = 0; i < 4; i++) (*constraint)[i] = objective_function[i] - h[i]; /* * Does the constraint plane pass through the origin? */ if ((*constraint)[3] > - CONSTRAINT_EPSILON) { /* * Does the constraint have nonzero derivative? * If not, then h and h' must have equal but nonzero derivatives. * We know h' has nonzero derivative because we checked it * when we computed the objective function. * Its OK for h and h' to have equal but nonzero derivatives -- * it simply means that as we move avoid from the closest * translate of the basepoint, we're moving away from some * other translate as well -- be we don't want to divide by * length3(*constraint). */ if (length3(*constraint) > ZERO_DERIV_EPSILON) { /* * Check whether the constraint plane is parallel * to the level sets of the objective function. * * Use the formula <u,v> = |u| |v| cos(angle). */ c = inner3(objective_function, *constraint) / (length3(objective_function) * length3(*constraint)); /* * If it is parallel, set *may_be_saddle_point to TRUE. */ if (fabs(c) > 1.0 - SADDLE_EPSILON) *may_be_saddle_point = TRUE; /* * If necessary we could be more sophisticated at this point, * and check whether the gradients of h and h' are parallel * or antiparallel. Typically one expects them to be * antiparallel (the MatrixPairs are, after all, the face * pairings of a Dirichlet domain, so we don't have to worry * about squares of a matrix), but if they were parallel one * might want to ask which is longer (depending on which is * longer, you will or will not be able to move the basepoint * in that direction). */ } } } }
inline void normalize3(vec3 * r) { scalar l = length3( *r ); invScale3( r, l ); }
float sphere(vec3 p, float radius) { return length3(p) - radius; }
void maximize_the_injectivity_radius( MatrixPairList *gen_list, Boolean *basepoint_moved, DirichletInteractivity interactivity) { int num_matrix_pairs; double distance_moved, prev_distance_moved, total_distance_moved; Boolean keep_going; ObjectiveFunction objective_function; int num_constraints; Constraint *constraints; Solution solution; Boolean may_be_saddle_point, saddle_query_given; int choice; static const Solution zero_solution = {0.0, 0.0, 0.0}, small_displacement = {0.001734, 0.002035, 0.000721}; const static char *saddle_message = "The basepoint may be at a saddle point of the injectivity radius function."; const static int num_saddle_responses = 2; const static char *saddle_responses[2] = { "Continue On", "Stop Here and See Dirichlet Domain"}; const static int saddle_default = 1; const static char *zero_deriv_message = "The derivative of the distance to the closest translate of the basepoint is zero."; const static char num_zero_deriv_responses = 2; const static char *zero_deriv_responses[2] = { "Displace Basepoint and Continue On", "Stop Here and See Dirichlet Domain"}; const static int zero_deriv_default = 1; /* * Count the number of MatrixPairs. */ num_matrix_pairs = count_matrix_pairs(gen_list); /* * Make sure that * * (1) the identity and at least two other MatrixPairs are present, * * (2) the MatrixPairs are in order of increasing height. * * Technical notes: We don't really need to have the gen_list * completely sorted -- it would be enough to have the identity come * first and the element of lowest image height come immediately after. * But I think the algorithm will run a tad faster if all elements are * in order of increasing image height. That way we get to the * meaningful constraints first. */ verify_gen_list(gen_list, num_matrix_pairs); /* * Initialize *basepoint_moved to FALSE. * If we later move the basepoint, we'll set *basepoint_moved to TRUE. */ *basepoint_moved = FALSE; /* * Keep track of the total distance we've moved the basepoint. * We don't want to go too far without recomputing the Dirichlet * domain to get a fresh set of group elements. */ total_distance_moved = 0.0; /* * Some ad hoc code for handling low precision situations * needs to keep track of the prev_distance_moved. */ prev_distance_moved = DBL_MAX; /* * We don't want to bother the user with the saddle query * more than once. We initialize saddle_query_given to FALSE, * and then set it to TRUE if and when the query takes place. */ saddle_query_given = FALSE; /* * We want to move the basepoint to a local maximum of the injectivity * radius function. Solve the linear approximation to this problem, * and repeat until a solution is found. */ do { /* * Set the objective function using the first nonidentity matrix * on the list. If the derivative of the objective function is * nonzero, proceed normally. Otherwise ask the user how s/he * would like to proceed. */ if (set_objective_function(objective_function, gen_list->begin.next->next) == func_OK) { /* * Allocate space for the Constraints. * There'll be num_matrix_pairs - 2 regular constraints * (one for each MatrixPair, excluding the identity and the * MatrixPair used to define the objective function), * preceded by three constraints which limit the step size * to MAX_STEP_SIZE. */ num_constraints = (num_matrix_pairs - 2) + 3; constraints = NEW_ARRAY(num_constraints, Constraint); /* * Set up the three step size constraints. */ step_size_constraints(constraints, objective_function); /* * Set up the regular constraints. */ regular_constraints(constraints, gen_list, objective_function, &may_be_saddle_point); /* * If we're not near an apparent saddle point, * do the linear programming. */ if (may_be_saddle_point == FALSE) linear_programming(objective_function, num_constraints, constraints, solution); /* * Otherwise ask the user whether s/he would like * to continue on normally or stop here. */ else { switch (interactivity) { case Dirichlet_interactive: if (saddle_query_given == FALSE) { choice = uQuery( saddle_message, num_saddle_responses, saddle_responses, saddle_default); saddle_query_given = TRUE; } else choice = 0; /* continue on */ break; case Dirichlet_stop_here: choice = 1; /* stop here */ break; case Dirichlet_keep_going: choice = 0; /* continue on */ break; } switch (choice) { case 0: /* * Continue on normally. */ linear_programming(objective_function, num_constraints, constraints, solution); break; case 1: /* * Stop here, set *basepoint_moved to FALSE * to force an exit from the loop, and look at * the Dirichlet domain. */ copy3(solution, zero_solution); *basepoint_moved = FALSE; break; } } /* * Free the Constraint array. */ my_free(constraints); } else { /* * The derivative of the objective function is zero. * * Ask the user whether to use this basepoint, or move on in * search of a local maximum of the injectivity radius. */ switch (interactivity) { case Dirichlet_interactive: choice = uQuery( zero_deriv_message, num_zero_deriv_responses, zero_deriv_responses, zero_deriv_default); break; case Dirichlet_stop_here: choice = 1; /* stop here */ break; case Dirichlet_keep_going: choice = 0; /* continue on */ break; } switch (choice) { case 0: /* * Displace the basepoint and continue on. */ copy3(solution, small_displacement); break; case 1: /* * We want to stay at this point, so set the solution * to (0, 0, 0), and set *basepoint_moved to FALSE * to force an exit from the loop. */ copy3(solution, zero_solution); *basepoint_moved = FALSE; break; } } /* * Use the solution to conjugate the MatrixPairs. */ conjugate_matrices(gen_list, solution); /* * Resort the gen_list according to increasing image height. */ sort_gen_list(gen_list, num_matrix_pairs); /* * How far was the basepoint moved this time? */ distance_moved = length3(solution); /* * What is the total distance we've moved the basepoint? */ total_distance_moved += distance_moved; /* * If the basepoint moved any meaningful distance, * set *basepoint_moved to TRUE. */ if (distance_moved > BASEPOINT_EPSILON) { *basepoint_moved = TRUE; /* * If we move too far from the original basepoint, we should * recompute the Dirichlet domain to get a fresh set of * group elements. Otherwise we keep going. */ keep_going = (total_distance_moved < MAX_TOTAL_DISTANCE); } else keep_going = FALSE; /* * The preceding code works great when the constraints are * either in general position, or are given to moderately high * precision. But for low precision, non general position * constraints (e.g. for an 8-component circular chain with no * twist), the algorithm can knock around forever making * changes on the order of 1e-9. The following code lets the * algorithm terminate in those cases. */ if (prev_distance_moved < BIG_BASEPOINT_EPSILON && distance_moved < BIG_BASEPOINT_EPSILON) { /* * For sure we don't want to keep going after making * two fairly small changes in a row. */ keep_going = FALSE; /* * If the total_distance_moved is less than BIG_BASEPOINT_EPSILON, * then we want to set *basepoint_moved to FALSE to prevent * recomputation of the Dirichlet domain. Note that we still * allow the possibility that *basepoint_moved is TRUE even when * the total_distance_moved is greater than BIG_BASEPOINT_EPSILON, * as could happen if preceding code artificially set *basepoint_moved * to FALSE to force an exit from the loop. */ if (total_distance_moved < BIG_BASEPOINT_EPSILON) *basepoint_moved = FALSE; } prev_distance_moved = distance_moved; } while (keep_going == TRUE); }
static void step_size_constraints( Constraint *constraints, ObjectiveFunction objective_function) { int i, j, i0; double v[3][3], w[3][3], max_abs, length; /* * The three step size constraints will be faces of a cube, * with the vector for the objective_function pointing in the * direction of the cube's corner where the three faces intersect. */ /* * First find an orthonormal basis {v[0], v[1], v[2]} with * v[0] equal to the vector part of the objective function. */ /* * Let v[0] be the vector part of the objective function, * normalized to have length one. (Elsewhere we checked that * its length is at least DERIVATIVE_EPSILON.) */ length = length3(objective_function); for (i = 0; i < 3; i++) v[0][i] = objective_function[i] / length; /* * Let v[1] be a unit vector orthogonal to v[0]. */ /* * Let i0 be the index of the component of v[0] which has the greatest * absolute value. (In particular, its absolute value is sure to be * nonzero.) */ max_abs = 0.0; for (i = 0; i < 3; i++) if (fabs(v[0][i]) > max_abs) { i0 = i; max_abs = fabs(v[0][i]); } /* * Write down a nonzero v[1] orthogonal to v[0] . . . */ v[1][i0] = -v[0][(i0+1)%3] / v[0][i0]; v[1][(i0+1)%3] = 1.0; v[1][(i0+2)%3] = 0.0; /* * . . . and normalize its length to 1.0. */ length = length3(v[1]); for (i = 0; i < 3; i++) v[1][i] /= length; /* * Let v[2] = v[0] x v[1]. */ for (i = 0; i < 3; i++) v[2][i] = v[0][(i+1)%3] * v[1][(i+2)%3] - v[0][(i+2)%3] * v[1][(i+1)%3]; /* * Use the orthonormal basis {v[0], v[1], v[2]} to find another basis * {w[0], w[1], w[2]} whose elements symmetrically surround v[0]. * * w[0] = v[0] + v[1] * w[1] = v[0] + ( -1/2 v[1] + sqrt(3)/2 v[2] ) * w[2] = v[0] + ( -1/2 v[1] - sqrt(3)/2 v[2] ) */ for (j = 0; j < 3; j++) { w[0][j] = v[0][j] + v[1][j]; w[1][j] = v[0][j] + (-0.5*v[1][j] + ROOT3OVER2*v[2][j]); w[2][j] = v[0][j] + (-0.5*v[1][j] - ROOT3OVER2*v[2][j]); } /* * Use the basis {w[0], w[1], w[2]} to write down * the three step size constraints. * * Technical note: If you move in the direction of the objective * function vector v[0], the three constraints will be exactly * satisfied at a distance MAX_STEP_SIZE from the origin. That is, the * inner product of (MAX_STEP_SIZE, 0, 0) with with each of (1, 1, 0), * (1, -1/2, sqrt(3)/2) and (1, -1/2, -sqrt(3)/2) is exactly * MAX_STEP_SIZE. However, if you move to the side (orthogonally to * v[0]) it's possible to move a distance 2*MAX_STEP_SIZE. E.g. the * inner product of (0, -2*MAX_STEP_SIZE, 0) with with each of * (1, 1, 0), (1, -1/2, sqrt(3)/2) and (1, -1/2, -sqrt(3)/2) is * -2*MAX_STEP_SIZE, MAX_STEP_SIZE and MAX_STEP_SIZE, respectively, so * it satisfies all three constraints. But typically we won't be * moving to the side, and in any case all we really care about anyhow * is the order of magnitude of MAX_STEP_SIZE. A factor of two isn't * important. */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) constraints[i][j] = w[i][j]; constraints[i][3] = -MAX_STEP_SIZE; } }
inline void normalized3(vec3 * r, vec3 v) { scalar l = length3( v ); div3( r, v, l ); }