MassSpringArbitrary<Real,TVector>::~MassSpringArbitrary () { delete1(mSprings); delete1(mAdjacent); }
GridGraph2<Real>::~GridGraph2 () { delete1( mVertices ); delete1( mPath ); delete1( mPending ); }
//---------------------------------------------------------------------------- void SceneBuilder::PackVertices (UniMaterialMesh* uniMesh, Mesh* maxMesh, std::vector<int>& faceIndexParts, PX2::Float3 *normalsAll) { // 对Max的网格进行分割,(根据三角形顶点面的索引),将顶点数据打包进uniMesh。 // // uniMesh // 到打包到的UniMaterialMesh // maxMesh // 顶点数据来源 // faceIndexParts // 从此获得面,再根据面获得顶点索引 // normalsAll // 法线数据来源 // 通过Set获取max中的顶点索引 // Stl的set按照递增顺序插入元素 std::set<int> vertexIndexs; // Set int i, j; for (i=0; i<(int)faceIndexParts.size(); i++) { Face &face = maxMesh->faces[faceIndexParts[i]]; for (j = 0; j < 3; j++) { vertexIndexs.insert(face.v[j]); } } if (vertexIndexs.size() == 0) return; // vMap要足够大,去容纳可能的j,这依赖于Stl::set递增插入元素 // vMap[k] == -1 表示max中的k顶点不在这个Phoenix网格中 int indexMax = *vertexIndexs.rbegin(); int *vMap = new1<int>(indexMax+1);// max vertex index -> Phoenix vertex index memset(vMap, 0xFF, (indexMax+1)*sizeof(int)); uniMesh->VQuantity() = (int)vertexIndexs.size(); uniMesh->VertexMap() = new1<PX2::Float3>(uniMesh->VQuantity()); uniMesh->NormalMap() = new1<PX2::Float3>(uniMesh->VQuantity()); std::set<int>::iterator iter = vertexIndexs.begin(); for (i=0; i<(int)vertexIndexs.size(); i++, iter++) { j = *iter; // max vertex index vMap[j] = i; // max vertex index -> Phoenix vertex index (uniMesh->VertexMap()[i])[0] = maxMesh->verts[j].x; (uniMesh->VertexMap()[i])[1] = maxMesh->verts[j].y; (uniMesh->VertexMap()[i])[2] = maxMesh->verts[j].z; if (normalsAll) uniMesh->NormalMap()[i] = normalsAll[j]; } // 建立Phoenix2网格,面的顶点索引 uniMesh->FQuantity() = (int)faceIndexParts.size(); uniMesh->Face() = new1<int>(3*uniMesh->FQuantity()); for (i = 0; i < (int)faceIndexParts.size(); i++) { Face &face = maxMesh->faces[faceIndexParts[i]]; for (j = 0; j < 3; j++) { uniMesh->Face()[3*i+j] = vMap[face.v[j]]; } } delete1(vMap); }
//---------------------------------------------------------------------------- PX2::Movable *SceneBuilder::BuildMesh(INode *maxNode, PX2::Node *relatParentOrEqualNode) { // 将Max的三角形网格数据转换到一个或者更多的等价的Phoenix2三角形网格。 // // maxNode: // Max场景图中的Mesh节点。 // relatParentOrEqualNode: // 在Phoenix2场景图系统中最新创建的父亲节点。 // 返回在Phoenix2场景中指向新的孩子节点的指针,这个指针直接指向TriMesh物体; // 或者是一个“link”节点,“link”的多个孩子TriMesh代表Max中的多个孩子mesh。 bool needDel = false; TriObject *triObject = GetTriObject(maxNode, &needDel); if (!triObject) { return 0; } Mesh *maxMesh = &triObject->GetMesh(); Mtl *mtl = maxNode->GetMtl(); int mtlIndex = mMtls.GetIndex(mtl); // 判断这个Max的几何图形节点是否有“子几何图形节点”,如果有子几何图形节点 // isEqualNode为真,反之为假。 // 如果名称相等,就不是relatParentOrEqualNode了,而是equalNode PX2::Movable *link = 0; bool isEqualNode = (relatParentOrEqualNode->GetName().length()>0 && strcmp(maxNode->GetName(), relatParentOrEqualNode->GetName().c_str()) == 0); // maxName char *maxName = maxNode->GetName(); // 如果只需要一个Phoenix的Mesh表示Max的Mesh,直接将Phoenix的Mesh链接到 // Phoenix的场景图中;否则,创建一个"link"节点,将按照材质分割的子Mesh // 放在"link"下。 int i; std::vector<UniMaterialMesh*> uMeshs; SplitGeometry(maxMesh, mtlIndex, uMeshs); if ((int)uMeshs.size() > 1) { if (!isEqualNode) { link = BuildNode(maxNode, relatParentOrEqualNode); } else { link = relatParentOrEqualNode; } assertion(link->IsDerived(PX2::Node::TYPE), "link must be a Node."); for (i=0; i<(int)uMeshs.size(); i++) { PX2::TriMesh *triMesh = uMeshs[i]->ToTriMesh(); if (triMesh) { char meshNumber[6]; sprintf_s(meshNumber, 6, "_%d", i+1); size_t size = strlen(maxName) + strlen(meshNumber) + 1; char *tdName = new1<char>((int)size); strcpy_s(tdName, size, maxName); strcat_s(tdName, size, meshNumber); triMesh->SetName(tdName); delete1(tdName); ((PX2::Node*)link)->AttachChild(triMesh); } } } else if ((int)uMeshs.size() == 1) { PX2::TriMesh *triMesh = uMeshs[0]->ToTriMesh(); if (triMesh) { if (!isEqualNode) { triMesh->SetName(maxName); triMesh->LocalTransform = GetLocalTransform(maxNode, mTimeStart); } else { size_t size = strlen(maxName) + 3; char *tdName = new1<char>((int)size); strcpy_s(tdName, size, maxName); strcat_s(tdName, size, "_1"); triMesh->SetName(tdName); delete1(tdName); } assertion(relatParentOrEqualNode->IsDerived(PX2::Node::TYPE), "relatParentOrEqualNode must be a Node."); relatParentOrEqualNode->AttachChild(triMesh); link = triMesh; } } for (i=0; i<(int)uMeshs.size(); i++) { delete0(uMeshs[i]); } if (needDel) { delete0(triObject); } return link; }
//---------------------------------------------------------------------------- void WaterDropFormation::Configuration1 () { delete1(mTargets); mTargets = 0; const int numCtrlPoints = 14; const int degree = 2; delete1(mCtrlPoints); mCtrlPoints = new1<Vector2f>(numCtrlPoints); float* weights = new1<float>(numCtrlPoints); // spline mCtrlPoints[0] = mSpline->GetControlPoint(0); mCtrlPoints[1] = mSpline->GetControlPoint(1); mCtrlPoints[2] = 0.5f*(mSpline->GetControlPoint(1) + mSpline->GetControlPoint(2)); mCtrlPoints[3] = mSpline->GetControlPoint(11); mCtrlPoints[4] = mSpline->GetControlPoint(12); // circle int i, j; for (i = 2, j = 5; i <= 10; ++i, ++j) { mCtrlPoints[j] = mSpline->GetControlPoint(i); } mCtrlPoints[5] = 0.5f*(mCtrlPoints[2] + mCtrlPoints[5]); mCtrlPoints[13] = mCtrlPoints[5]; for (i = 0; i < numCtrlPoints; ++i) { weights[i] = 1.0f; } weights[ 6] = mSpline->GetControlWeight(3); weights[ 8] = mSpline->GetControlWeight(5); weights[10] = mSpline->GetControlWeight(7); weights[12] = mSpline->GetControlWeight(9); delete0(mSpline); mSpline = new0 NURBSCurve2f(5, mCtrlPoints, weights ,degree, false, true); // Restrict evaluation to a subinterval of the domain. mSpline->SetTimeInterval(0.5f, 1.0f); mWaterSurface->SetCurve(mSpline); mCircle = new0 NURBSCurve2f(9, &mCtrlPoints[5], &weights[5], degree, true, false); delete1(weights); // Restrict evaluation to a subinterval of the domain. Why 0.375? The // circle NURBS is a loop and not open. The curve is constructed with // iDegree (2) replicated control points. Although the curve is // geometrically symmetric about the vertical axis, it is not symmetric // in t about the half way point (0.5) of the domain [0,1]. mCircle->SetTimeInterval(0.375f, 1.0f); // Create water drop. The outside view value is set to 'false' because // the curve (x(t),z(t)) has the property dz/dt < 0. If the curve // instead had the property dz/dt > 0, then 'true' is the correct value // for the outside view. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); mWaterDrop = new0 RevolutionSurface(mCircle, mCtrlPoints[9].X(), RevolutionSurface::REV_SPHERE_TOPOLOGY, 32, 16, false, false, vformat); mWaterDrop->SetEffectInstance( mWaterEffect->CreateInstance(mWaterTexture)); mWaterRoot->AttachChild(mWaterDrop); }
//---------------------------------------------------------------------------- void SceneBuilder::SplitGeometry(Mesh *maxMesh, int mtlIndex, std::vector<UniMaterialMesh*> &uMeshes) { // 如果这个Mesh有多个material并且使用两个或者多个material。这个网格需要 // 被拆分,因为Phoenix2是一个物体只对应一个material。 // // maxMesh: // 要分割的Max网格。 // mtlIndex: // 材质ID // uMeshes: // UniMaterialMesh集合,Max的mesh被拆分后放里面。 int i, j; PX2::Float3 *normalsAll = 0; if (mSettings->IncludeNormals) { maxMesh->buildNormals(); normalsAll = new1<PX2::Float3>(maxMesh->numVerts); for (i=0; i<maxMesh->numFaces; i++) { Face &face = maxMesh->faces[i]; for (j=0; j<3; j++) { int vertexIndex = face.getVert(j); normalsAll[vertexIndex] = GetVertexNormal(maxMesh, i, vertexIndex); } } } // 没有材质 if (mtlIndex < 0) { UniMaterialMesh *triMesh = new0 UniMaterialMesh; triMesh->SetMaterialInstance(PX2::VertexColor4Material::CreateUniqueInstance()); std::vector<int> faceIndexs; int faceIndex = -1; for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { faceIndexs.push_back(faceIndex); } PackVertices(triMesh, maxMesh, faceIndexs, normalsAll); if (mSettings->IncludeVertexColors && maxMesh->numCVerts>0) { PackColors(triMesh, maxMesh, faceIndexs); } if (mSettings->IncludeTargentBiNormal && maxMesh->numTVerts>0) { triMesh->SetExportTargentBinormal(true); } else { triMesh->SetExportTargentBinormal(false); } if (mSettings->IncludeTexCoords && maxMesh->numTVerts>0) { triMesh->SetNumTexcoordToExport(mSettings->NumTexCoords); PackTextureCoords(triMesh, maxMesh, faceIndexs); } uMeshes.push_back(triMesh); triMesh->DuplicateGeometry(); } else { // 获得Mtl的子材质数量 MtlTree &tree = mMtlTreeList[mtlIndex]; int subQuantity = 0; // 子材质数量 if (mtlIndex >= 0) { subQuantity = tree.GetMChildQuantity(); } // 计算几何图形所使用的最大附加材质索引 int faceIndex, subID, maxSubID = -1; for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { subID = maxMesh->faces[faceIndex].getMatID(); if (subID >= subQuantity) { if (subQuantity > 0) { subID = subID % subQuantity; } else { subID = 0; } } if (subID > maxSubID) { maxSubID = subID; } } // 根据material ID,将每个三角形面分类 std::vector<int> *faceIndexPartByMtl = new1<std::vector<int> >(maxSubID+1); for (faceIndex=0; faceIndex<maxMesh->numFaces; faceIndex++) { subID = maxMesh->faces[faceIndex].getMatID(); if (subID >= subQuantity) { if (subQuantity > 0) { subID = subID % subQuantity; } else { subID = 0; } } // 将每个面按照材质分类 faceIndexPartByMtl[subID].push_back(faceIndex); } // 对每种材质类型,分配网格 for (subID=0; subID<=maxSubID; subID++) { if (faceIndexPartByMtl[subID].size() == 0) { // 这种材质没有三角形面 continue; } // 为每种材质新建一个mesh UniMaterialMesh *triMesh = new0 UniMaterialMesh; if (mtlIndex >= 0) { if (subQuantity > 0) { MtlTree &subtree = tree.GetMChild(subID); triMesh->SetShineProperty(subtree.GetShine()); triMesh->SetMaterialInstance(subtree.GetMaterialInstance()); } else { triMesh->SetShineProperty(tree.GetShine()); triMesh->SetMaterialInstance(tree.GetMaterialInstance()); } } PackVertices(triMesh, maxMesh, faceIndexPartByMtl[subID], normalsAll); if (mSettings->IncludeVertexColors && maxMesh->numCVerts>0) { PackColors(triMesh, maxMesh, faceIndexPartByMtl[subID]); } if (mSettings->IncludeTargentBiNormal && maxMesh->numTVerts>0) { triMesh->SetExportTargentBinormal(true); } else { triMesh->SetExportTargentBinormal(false); } if (mSettings->IncludeTexCoords && maxMesh->numTVerts>0) { triMesh->SetNumTexcoordToExport(mSettings->NumTexCoords); PackTextureCoords(triMesh, maxMesh, faceIndexPartByMtl[subID]); } uMeshes.push_back(triMesh); } delete1(faceIndexPartByMtl); for (i=0; i<(int)uMeshes.size(); i++) { uMeshes[i]->DuplicateGeometry(); } } delete1(normalsAll); }
void ContEllipse2MinCR<Real>::MaxProduct (std::vector<Vector2<Real> >& A, Real D[2]) { // Keep track of which constraint lines have already been used in the // search. int numConstraints = (int)A.size(); bool* used = new1<bool>(numConstraints); memset(used, 0, numConstraints*sizeof(bool)); // Find the constraint line whose y-intercept (0,ymin) is closest to the // origin. This line contributes to the convex hull of the constraints // and the search for the maximum starts here. Also find the constraint // line whose x-intercept (xmin,0) is closest to the origin. This line // contributes to the convex hull of the constraints and the search for // the maximum terminates before or at this line. int i, iYMin = -1; int iXMin = -1; Real axMax = (Real)0, ayMax = (Real)0; // A[i] >= (0,0) by design for (i = 0; i < numConstraints; ++i) { // The minimum x-intercept is 1/A[iXMin].X() for A[iXMin].X() the // maximum of the A[i].X(). if (A[i].X() > axMax) { axMax = A[i].X(); iXMin = i; } // The minimum y-intercept is 1/A[iYMin].Y() for A[iYMin].Y() the // maximum of the A[i].Y(). if (A[i].Y() > ayMax) { ayMax = A[i].Y(); iYMin = i; } } assertion(iXMin != -1 && iYMin != -1, "Unexpected condition\n"); WM5_UNUSED(iXMin); used[iYMin] = true; // The convex hull is searched in a clockwise manner starting with the // constraint line constructed above. The next vertex of the hull occurs // as the closest point to the first vertex on the current constraint // line. The following loop finds each consecutive vertex. Real x0 = (Real)0, xMax = ((Real)1)/axMax; int j; for (j = 0; j < numConstraints; ++j) { // Find the line whose intersection with the current line is closest // to the last hull vertex. The last vertex is at (x0,y0) on the // current line. Real x1 = xMax; int line = -1; for (i = 0; i < numConstraints; ++i) { if (!used[i]) { // This line not yet visited, process it. Given current // constraint line a0*x+b0*y =1 and candidate line // a1*x+b1*y = 1, find the point of intersection. The // determinant of the system is d = a0*b1-a1*b0. We only // care about lines that have more negative slope than the // previous one, that is, -a1/b1 < -a0/b0, in which case we // process only lines for which d < 0. Real det = A[iYMin].DotPerp(A[i]); if (det < (Real)0) // TO DO. Need epsilon test here? { // Compute the x-value for the point of intersection, // (x1,y1). There may be floating point error issues in // the comparision 'D[0] <= fX1'. Consider modifying to // 'D[0] <= fX1+epsilon'. D[0] = (A[i].Y() - A[iYMin].Y())/det; if (x0 < D[0] && D[0] <= x1) { line = i; x1 = D[0]; } } } } // Next vertex is at (x1,y1) whose x-value was computed above. First // check for the maximum of x*y on the current line for x in [x0,x1]. // On this interval the function is f(x) = x*(1-a0*x)/b0. The // derivative is f'(x) = (1-2*a0*x)/b0 and f'(r) = 0 when // r = 1/(2*a0). The three candidates for the maximum are f(x0), // f(r), and f(x1). Comparisons are made between r and the end points // x0 and x1. Since a0 = 0 is possible (constraint line is horizontal // and f is increasing on line), the division in r is not performed // and the comparisons are made between 1/2 = a0*r and a0*x0 or a0*x1. // Compare r < x0. if ((Real)0.5 < A[iYMin].X()*x0) { // The maximum is f(x0) since the quadratic f decreases for // x > r. D[0] = x0; D[1] = ((Real)1 - A[iYMin].X()*D[0])/A[iYMin].Y(); // = f(x0) break; } // Compare r < x1. if ((Real)0.5 < A[iYMin].X()*x1) { // The maximum is f(r). The search ends here because the // current line is tangent to the level curve of f(x)=f(r) // and x*y can therefore only decrease as we traverse further // around the hull in the clockwise direction. D[0] = ((Real)0.5)/A[iYMin].X(); D[1] = ((Real)0.5)/A[iYMin].Y(); // = f(r) break; } // The maximum is f(x1). The function x*y is potentially larger // on the next line, so continue the search. assertion(line != -1, "Unexpected condition\n"); x0 = x1; x1 = xMax; used[line] = true; iYMin = line; } assertion(j < numConstraints, "Unexpected condition\n"); delete1(used); }
MeshCurvature<Real>::MeshCurvature (int numVertices, const Vector3<Real>* vertices, int numTriangles, const int* indices) { mNumVertices = numVertices; mVertices = vertices; mNumTriangles = numTriangles; mIndices = indices; // Compute normal vectors. mNormals = new1<Vector3<Real> >(mNumVertices); memset(mNormals, 0, mNumVertices*sizeof(Vector3<Real>)); int i, v0, v1, v2; for (i = 0; i < mNumTriangles; ++i) { // Get vertex indices. v0 = *indices++; v1 = *indices++; v2 = *indices++; // Compute the normal (length provides a weighted sum). Vector3<Real> edge1 = mVertices[v1] - mVertices[v0]; Vector3<Real> edge2 = mVertices[v2] - mVertices[v0]; Vector3<Real> normal = edge1.Cross(edge2); mNormals[v0] += normal; mNormals[v1] += normal; mNormals[v2] += normal; } for (i = 0; i < mNumVertices; ++i) { mNormals[i].Normalize(); } // Compute the matrix of normal derivatives. Matrix3<Real>* DNormal = new1<Matrix3<Real> >(mNumVertices); Matrix3<Real>* WWTrn = new1<Matrix3<Real> >(mNumVertices); Matrix3<Real>* DWTrn = new1<Matrix3<Real> >(mNumVertices); bool* DWTrnZero = new1<bool>(mNumVertices); memset(WWTrn, 0, mNumVertices*sizeof(Matrix3<Real>)); memset(DWTrn, 0, mNumVertices*sizeof(Matrix3<Real>)); memset(DWTrnZero, 0, mNumVertices*sizeof(bool)); int row, col; indices = mIndices; for (i = 0; i < mNumTriangles; ++i) { // Get vertex indices. int V[3]; V[0] = *indices++; V[1] = *indices++; V[2] = *indices++; for (int j = 0; j < 3; j++) { v0 = V[j]; v1 = V[(j+1)%3]; v2 = V[(j+2)%3]; // Compute edge from V0 to V1, project to tangent plane of vertex, // and compute difference of adjacent normals. Vector3<Real> E = mVertices[v1] - mVertices[v0]; Vector3<Real> W = E - (E.Dot(mNormals[v0]))*mNormals[v0]; Vector3<Real> D = mNormals[v1] - mNormals[v0]; for (row = 0; row < 3; ++row) { for (col = 0; col < 3; ++col) { WWTrn[v0][row][col] += W[row]*W[col]; DWTrn[v0][row][col] += D[row]*W[col]; } } // Compute edge from V0 to V2, project to tangent plane of vertex, // and compute difference of adjacent normals. E = mVertices[v2] - mVertices[v0]; W = E - (E.Dot(mNormals[v0]))*mNormals[v0]; D = mNormals[v2] - mNormals[v0]; for (row = 0; row < 3; ++row) { for (col = 0; col < 3; ++col) { WWTrn[v0][row][col] += W[row]*W[col]; DWTrn[v0][row][col] += D[row]*W[col]; } } } } // Add in N*N^T to W*W^T for numerical stability. In theory 0*0^T gets // added to D*W^T, but of course no update is needed in the // implementation. Compute the matrix of normal derivatives. for (i = 0; i < mNumVertices; ++i) { for (row = 0; row < 3; ++row) { for (col = 0; col < 3; ++col) { WWTrn[i][row][col] = ((Real)0.5)*WWTrn[i][row][col] + mNormals[i][row]*mNormals[i][col]; DWTrn[i][row][col] *= (Real)0.5; } } // Compute the max-abs entry of D*W^T. If this entry is (nearly) // zero, flag the DNormal matrix as singular. Real maxAbs = (Real)0; for (row = 0; row < 3; ++row) { for (col = 0; col < 3; ++col) { Real absEntry = Math<Real>::FAbs(DWTrn[i][row][col]); if (absEntry > maxAbs) { maxAbs = absEntry; } } } if (maxAbs < (Real)1e-07) { DWTrnZero[i] = true; } DNormal[i] = DWTrn[i]*WWTrn[i].Inverse(); } delete1(WWTrn); delete1(DWTrn); // If N is a unit-length normal at a vertex, let U and V be unit-length // tangents so that {U, V, N} is an orthonormal set. Define the matrix // J = [U | V], a 3-by-2 matrix whose columns are U and V. Define J^T // to be the transpose of J, a 2-by-3 matrix. Let dN/dX denote the // matrix of first-order derivatives of the normal vector field. The // shape matrix is // S = (J^T * J)^{-1} * J^T * dN/dX * J = J^T * dN/dX * J // where the superscript of -1 denotes the inverse. (The formula allows // for J built from non-perpendicular vectors.) The matrix S is 2-by-2. // The principal curvatures are the eigenvalues of S. If k is a principal // curvature and W is the 2-by-1 eigenvector corresponding to it, then // S*W = k*W (by definition). The corresponding 3-by-1 tangent vector at // the vertex is called the principal direction for k, and is J*W. mMinCurvatures = new1<Real>(mNumVertices); mMaxCurvatures = new1<Real>(mNumVertices); mMinDirections = new1<Vector3<Real> >(mNumVertices); mMaxDirections = new1<Vector3<Real> >(mNumVertices); for (i = 0; i < mNumVertices; ++i) { // Compute U and V given N. Vector3<Real> U, V; Vector3<Real>::GenerateComplementBasis(U, V, mNormals[i]); if (DWTrnZero[i]) { // At a locally planar point. mMinCurvatures[i] = (Real)0; mMaxCurvatures[i] = (Real)0; mMinDirections[i] = U; mMaxDirections[i] = V; continue; } // Compute S = J^T * dN/dX * J. In theory S is symmetric, but // because we have estimated dN/dX, we must slightly adjust our // calculations to make sure S is symmetric. Real s01 = U.Dot(DNormal[i]*V); Real s10 = V.Dot(DNormal[i]*U); Real sAvr = ((Real)0.5)*(s01 + s10); Matrix2<Real> S ( U.Dot(DNormal[i]*U), sAvr, sAvr, V.Dot(DNormal[i]*V) ); // Compute the eigenvalues of S (min and max curvatures). Real trace = S[0][0] + S[1][1]; Real det = S[0][0]*S[1][1] - S[0][1]*S[1][0]; Real discr = trace*trace - ((Real)4.0)*det; Real rootDiscr = Math<Real>::Sqrt(Math<Real>::FAbs(discr)); mMinCurvatures[i] = ((Real)0.5)*(trace - rootDiscr); mMaxCurvatures[i] = ((Real)0.5)*(trace + rootDiscr); // Compute the eigenvectors of S. Vector2<Real> W0(S[0][1], mMinCurvatures[i] - S[0][0]); Vector2<Real> W1(mMinCurvatures[i] - S[1][1], S[1][0]); if (W0.SquaredLength() >= W1.SquaredLength()) { W0.Normalize(); mMinDirections[i] = W0.X()*U + W0.Y()*V; } else { W1.Normalize(); mMinDirections[i] = W1.X()*U + W1.Y()*V; } W0 = Vector2<Real>(S[0][1], mMaxCurvatures[i] - S[0][0]); W1 = Vector2<Real>(mMaxCurvatures[i] - S[1][1], S[1][0]); if (W0.SquaredLength() >= W1.SquaredLength()) { W0.Normalize(); mMaxDirections[i] = W0.X()*U + W0.Y()*V; } else { W1.Normalize(); mMaxDirections[i] = W1.X()*U + W1.Y()*V; } } delete1(DWTrnZero); delete1(DNormal); }
void NaturalSpline3<Real>::CreateFreeSpline () { Real* dt = new1<Real>(mNumSegments); int i; for (i = 0; i < mNumSegments; ++i) { dt[i] = mTimes[i+1] - mTimes[i]; } Real* d2t = new1<Real>(mNumSegments); for (i = 1; i < mNumSegments; ++i) { d2t[i] = mTimes[i+1] - mTimes[i-1]; } Vector3<Real>* alpha = new1<Vector3<Real> >(mNumSegments); for (i = 1; i < mNumSegments; ++i) { Vector3<Real> numer = ((Real)3)*(dt[i-1]*mA[i+1] - d2t[i]*mA[i] + dt[i]*mA[i-1]); Real invDenom = ((Real)1)/(dt[i-1]*dt[i]); alpha[i] = invDenom*numer; } Real* ell = new1<Real>(mNumSegments + 1); Real* mu = new1<Real>(mNumSegments); Vector3<Real>* z = new1<Vector3<Real> >(mNumSegments + 1); Real inv; ell[0] = (Real)1; mu[0] = (Real)0; z[0] = Vector3<Real>::ZERO; for (i = 1; i < mNumSegments; ++i) { ell[i] = ((Real)2)*d2t[i] - dt[i-1]*mu[i-1]; inv = ((Real)1)/ell[i]; mu[i] = inv*dt[i]; z[i] = inv*(alpha[i] - dt[i-1]*z[i-1]); } ell[mNumSegments] = (Real)1; z[mNumSegments] = Vector3<Real>::ZERO; mB = new1<Vector3<Real> >(mNumSegments); mC = new1<Vector3<Real> >(mNumSegments + 1); mD = new1<Vector3<Real> >(mNumSegments); mC[mNumSegments] = Vector3<Real>::ZERO; const Real oneThird = ((Real)1)/(Real)3; for (i = mNumSegments-1; i >= 0; --i) { mC[i] = z[i] - mu[i]*mC[i+1]; inv = ((Real)1)/dt[i]; mB[i] = inv*(mA[i+1] - mA[i]) - oneThird*dt[i]*(mC[i+1] + ((Real)2)*mC[i]); mD[i] = oneThird*inv*(mC[i+1] - mC[i]); } delete1(dt); delete1(d2t); delete1(alpha); delete1(ell); delete1(mu); delete1(z); }
MassSpringCurve<Real,TVector>::~MassSpringCurve () { delete1(mConstants); delete1(mLengths); }
void NaturalSpline3<Real>::CreateClosedSpline () { // TO DO. A general linear system solver is used here. The matrix // corresponding to this case is actually "cyclic banded", so a faster // linear solver can be used. The current linear system code does not // have such a solver. Real* dt = new1<Real>(mNumSegments); int i; for (i = 0; i < mNumSegments; ++i) { dt[i] = mTimes[i+1] - mTimes[i]; } // Construct matrix of system. GMatrix<Real> mat(mNumSegments + 1, mNumSegments + 1); mat[0][0] = (Real)1; mat[0][mNumSegments] = (Real)-1; for (i = 1; i <= mNumSegments-1; ++i) { mat[i][i-1] = dt[i-1]; mat[i][i ] = ((Real)2)*(dt[i-1] + dt[i]); mat[i][i+1] = dt[i]; } mat[mNumSegments][mNumSegments - 1] = dt[mNumSegments - 1]; mat[mNumSegments][0] = ((Real)2)*(dt[mNumSegments - 1] + dt[0]); mat[mNumSegments][1] = dt[0]; // Construct right-hand side of system. mC = new1<Vector3<Real> >(mNumSegments + 1); mC[0] = Vector3<Real>::ZERO; Real inv0, inv1; for (i = 1; i <= mNumSegments-1; ++i) { inv0 = ((Real)1)/dt[i]; inv1 = ((Real)1)/dt[i-1]; mC[i] = ((Real)3)*(inv0*(mA[i+1] - mA[i]) - inv1*(mA[i] - mA[i-1])); } inv0 = ((Real)1)/dt[0]; inv1 = ((Real)1)/dt[mNumSegments-1]; mC[mNumSegments] = ((Real)3)*(inv0*(mA[1] - mA[0]) - inv1*(mA[0] - mA[mNumSegments-1])); // Solve the linear systems. Real* input = new1<Real>(mNumSegments + 1); Real* output = new1<Real>(mNumSegments + 1); for (i = 0; i <= mNumSegments; ++i) { input[i] = mC[i].X(); } LinearSystem<Real>().Solve(mat, input, output); for (i = 0; i <= mNumSegments; ++i) { mC[i].X() = output[i]; } for (i = 0; i <= mNumSegments; ++i) { input[i] = mC[i].Y(); } LinearSystem<Real>().Solve(mat, input, output); for (i = 0; i <= mNumSegments; ++i) { mC[i].Y() = output[i]; } for (i = 0; i <= mNumSegments; ++i) { input[i] = mC[i].Z(); } LinearSystem<Real>().Solve(mat, input, output); for (i = 0; i <= mNumSegments; ++i) { mC[i].Z() = output[i]; } delete1(input); delete1(output); // End linear system solving. const Real oneThird = ((Real)1)/(Real)3; mB = new1<Vector3<Real> >(mNumSegments); mD = new1<Vector3<Real> >(mNumSegments); for (i = 0; i < mNumSegments; ++i) { inv0 = ((Real)1)/dt[i]; mB[i] = inv0*(mA[i+1] - mA[i]) - oneThird*(mC[i+1] + ((Real)2)*mC[i])*dt[i]; mD[i] = oneThird*inv0*(mC[i+1] - mC[i]); } delete1(dt); }
void NaturalSpline3<Real>::CreateClampedSpline ( const Vector3<Real>& derivativeStart, const Vector3<Real>& derivativeFinal) { Real* dt = new1<Real>(mNumSegments); int i; for (i = 0; i < mNumSegments; ++i) { dt[i] = mTimes[i+1] - mTimes[i]; } Real* d2t = new1<Real>(mNumSegments); for (i = 1; i < mNumSegments; ++i) { d2t[i] = mTimes[i+1] - mTimes[i-1]; } Vector3<Real>* alpha = new1<Vector3<Real> >(mNumSegments + 1); Real inv = ((Real)1)/dt[0]; alpha[0] = ((Real)3)*(inv*(mA[1] - mA[0]) - derivativeStart); inv = ((Real)1)/dt[mNumSegments-1]; alpha[mNumSegments] = ((Real)3)*(derivativeFinal - inv*(mA[mNumSegments] - mA[mNumSegments-1])); for (i = 1; i < mNumSegments; ++i) { Vector3<Real> numer = ((Real)3)*(dt[i-1]*mA[i+1] - d2t[i]*mA[i] + dt[i]*mA[i-1]); Real invDenom = ((Real)1)/(dt[i-1]*dt[i]); alpha[i] = invDenom*numer; } Real* ell = new1<Real>(mNumSegments + 1); Real* mu = new1<Real>(mNumSegments); Vector3<Real>* z = new1<Vector3<Real> >(mNumSegments + 1); ell[0] = ((Real)2)*dt[0]; mu[0] = (Real)0.5; inv = ((Real)1)/ell[0]; z[0] = inv*alpha[0]; for (i = 1; i < mNumSegments; ++i) { ell[i] = ((Real)2)*d2t[i] - dt[i-1]*mu[i-1]; inv = ((Real)1)/ell[i]; mu[i] = inv*dt[i]; z[i] = inv*(alpha[i] - dt[i-1]*z[i-1]); } ell[mNumSegments] = dt[mNumSegments-1]*(((Real)2) - mu[mNumSegments-1]); inv = ((Real)1)/ell[mNumSegments]; z[mNumSegments] = inv*(alpha[mNumSegments] - dt[mNumSegments-1]* z[mNumSegments-1]); mB = new1<Vector3<Real> >(mNumSegments); mC = new1<Vector3<Real> >(mNumSegments + 1); mD = new1<Vector3<Real> >(mNumSegments); mC[mNumSegments] = z[mNumSegments]; const Real oneThird = ((Real)1)/(Real)3; for (i = mNumSegments-1; i >= 0; --i) { mC[i] = z[i] - mu[i]*mC[i+1]; inv = ((Real)1)/dt[i]; mB[i] = inv*(mA[i+1] - mA[i]) - oneThird*dt[i]*(mC[i+1] + ((Real)2)*mC[i]); mD[i] = oneThird*inv*(mC[i+1] - mC[i]); } delete1(dt); delete1(d2t); delete1(alpha); delete1(ell); delete1(mu); delete1(z); }
EigenDecomposition<Real>::~EigenDecomposition () { delete1(mDiagonal); delete1(mSubdiagonal); }
MinBox3<Real>::MinBox3 (int numPoints, const Vector3<Real>* points, Real epsilon, Query::Type queryType) { // Get the convex hull of the points. ConvexHull3<Real> kHull(numPoints,(Vector3<Real>*)points, epsilon, false, queryType); int hullDim = kHull.GetDimension(); if (hullDim == 0) { mMinBox.Center = points[0]; mMinBox.Axis[0] = Vector3<Real>::UNIT_X; mMinBox.Axis[1] = Vector3<Real>::UNIT_Y; mMinBox.Axis[2] = Vector3<Real>::UNIT_Z; mMinBox.Extent[0] = (Real)0; mMinBox.Extent[1] = (Real)0; mMinBox.Extent[2] = (Real)0; return; } if (hullDim == 1) { ConvexHull1<Real>* pkHull1 = kHull.GetConvexHull1(); const int* hullIndices = pkHull1->GetIndices(); mMinBox.Center = ((Real)0.5)*(points[hullIndices[0]] + points[hullIndices[1]]); Vector3<Real> diff = points[hullIndices[1]] - points[hullIndices[0]]; mMinBox.Extent[0] = ((Real)0.5)*diff.Normalize(); mMinBox.Extent[1] = (Real)0; mMinBox.Extent[2] = (Real)0; mMinBox.Axis[0] = diff; Vector3<Real>::GenerateComplementBasis(mMinBox.Axis[1], mMinBox.Axis[2], mMinBox.Axis[0]); delete0(pkHull1); return; } int i, j; Vector3<Real> origin, diff, U, V, W; Vector2<Real>* points2; Box2<Real> box2; if (hullDim == 2) { // When ConvexHull3 reports that the point set is 2-dimensional, the // caller is responsible for projecting the points onto a plane and // calling ConvexHull2. ConvexHull3 does provide information about // the plane of the points. In this application, we need only // project the input points onto that plane and call ContMinBox in // two dimensions. // Get a coordinate system relative to the plane of the points. origin = kHull.GetPlaneOrigin(); W = kHull.GetPlaneDirection(0).Cross(kHull.GetPlaneDirection(1)); Vector3<Real>::GenerateComplementBasis(U, V, W); // Project the input points onto the plane. points2 = new1<Vector2<Real> >(numPoints); for (i = 0; i < numPoints; ++i) { diff = points[i] - origin; points2[i].X() = U.Dot(diff); points2[i].Y() = V.Dot(diff); } // Compute the minimum area box in 2D. box2 = MinBox2<Real>(numPoints, points2, epsilon, queryType, false); delete1(points2); // Lift the values into 3D. mMinBox.Center = origin + box2.Center.X()*U + box2.Center.Y()*V; mMinBox.Axis[0] = box2.Axis[0].X()*U + box2.Axis[0].Y()*V; mMinBox.Axis[1] = box2.Axis[1].X()*U + box2.Axis[1].Y()*V; mMinBox.Axis[2] = W; mMinBox.Extent[0] = box2.Extent[0]; mMinBox.Extent[1] = box2.Extent[1]; mMinBox.Extent[2] = (Real)0; return; } int hullQuantity = kHull.GetNumSimplices(); const int* hullIndices = kHull.GetIndices(); Real volume, minVolume = Math<Real>::MAX_REAL; // Create the unique set of hull vertices to minimize the time spent // projecting vertices onto planes of the hull faces. std::set<int> uniqueIndices; for (i = 0; i < 3*hullQuantity; ++i) { uniqueIndices.insert(hullIndices[i]); } // Use the rotating calipers method on the projection of the hull onto // the plane of each face. Also project the hull onto the normal line // of each face. The minimum area box in the plane and the height on // the line produce a containing box. If its volume is smaller than the // current volume, this box is the new candidate for the minimum volume // box. The unique edges are accumulated into a set for use by a later // step in the algorithm. const int* currentHullIndex = hullIndices; Real height, minHeight, maxHeight; std::set<EdgeKey> edges; points2 = new1<Vector2<Real> >(uniqueIndices.size()); for (i = 0; i < hullQuantity; ++i) { // Get the triangle. int v0 = *currentHullIndex++; int v1 = *currentHullIndex++; int v2 = *currentHullIndex++; // Save the edges for later use. edges.insert(EdgeKey(v0, v1)); edges.insert(EdgeKey(v1, v2)); edges.insert(EdgeKey(v2, v0)); // Get 3D coordinate system relative to plane of triangle. origin = (points[v0] + points[v1] + points[v2])/(Real)3.0; Vector3<Real> edge1 = points[v1] - points[v0]; Vector3<Real> edge2 = points[v2] - points[v0]; W = edge2.UnitCross(edge1); // inner-pointing normal if (W == Vector3<Real>::ZERO) { // The triangle is needle-like, so skip it. continue; } Vector3<Real>::GenerateComplementBasis(U, V, W); // Project points onto plane of triangle, onto normal line of plane. // TO DO. In theory, minHeight should be zero since W points to the // interior of the hull. However, the snap rounding used in the 3D // convex hull finder involves loss of precision, which in turn can // cause a hull facet to have the wrong ordering (clockwise instead // of counterclockwise when viewed from outside the hull). The // height calculations here trap that problem (the incorrectly ordered // face will not affect the minimum volume box calculations). minHeight = (Real)0; maxHeight = (Real)0; j = 0; std::set<int>::const_iterator iter = uniqueIndices.begin(); while (iter != uniqueIndices.end()) { int index = *iter++; diff = points[index] - origin; points2[j].X() = U.Dot(diff); points2[j].Y() = V.Dot(diff); height = W.Dot(diff); if (height > maxHeight) { maxHeight = height; } else if (height < minHeight) { minHeight = height; } j++; } if (-minHeight > maxHeight) { maxHeight = -minHeight; } // Compute minimum area box in 2D. box2 = MinBox2<Real>((int)uniqueIndices.size(), points2, epsilon, queryType, false); // Update current minimum-volume box (if necessary). volume = maxHeight*box2.Extent[0]*box2.Extent[1]; if (volume < minVolume) { minVolume = volume; // Lift the values into 3D. mMinBox.Extent[0] = box2.Extent[0]; mMinBox.Extent[1] = box2.Extent[1]; mMinBox.Extent[2] = ((Real)0.5)*maxHeight; mMinBox.Axis[0] = box2.Axis[0].X()*U + box2.Axis[0].Y()*V; mMinBox.Axis[1] = box2.Axis[1].X()*U + box2.Axis[1].Y()*V; mMinBox.Axis[2] = W; mMinBox.Center = origin + box2.Center.X()*U + box2.Center.Y()*V + mMinBox.Extent[2]*W; } } // The minimum-volume box can also be supported by three mutually // orthogonal edges of the convex hull. For each triple of orthogonal // edges, compute the minimum-volume box for that coordinate frame by // projecting the points onto the axes of the frame. std::set<EdgeKey>::const_iterator e2iter; for (e2iter = edges.begin(); e2iter != edges.end(); e2iter++) { W = points[e2iter->V[1]] - points[e2iter->V[0]]; W.Normalize(); std::set<EdgeKey>::const_iterator e1iter = e2iter; for (++e1iter; e1iter != edges.end(); e1iter++) { V = points[e1iter->V[1]] - points[e1iter->V[0]]; V.Normalize(); Real dot = V.Dot(W); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } std::set<EdgeKey>::const_iterator e0iter = e1iter; for (++e0iter; e0iter != edges.end(); e0iter++) { U = points[e0iter->V[1]] - points[e0iter->V[0]]; U.Normalize(); dot = U.Dot(V); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } dot = U.Dot(W); if (Math<Real>::FAbs(dot) > Math<Real>::ZERO_TOLERANCE) { continue; } // The three edges are mutually orthogonal. Project the // hull points onto the lines containing the edges. Use // hull point zero as the origin. Real umin = (Real)0, umax = (Real)0; Real vmin = (Real)0, vmax = (Real)0; Real wmin = (Real)0, wmax = (Real)0; origin = points[hullIndices[0]]; std::set<int>::const_iterator iter = uniqueIndices.begin(); while (iter != uniqueIndices.end()) { int index = *iter++; diff = points[index] - origin; Real fU = U.Dot(diff); if (fU < umin) { umin = fU; } else if (fU > umax) { umax = fU; } Real fV = V.Dot(diff); if (fV < vmin) { vmin = fV; } else if (fV > vmax) { vmax = fV; } Real fW = W.Dot(diff); if (fW < wmin) { wmin = fW; } else if (fW > wmax) { wmax = fW; } } Real uExtent = ((Real)0.5)*(umax - umin); Real vExtent = ((Real)0.5)*(vmax - vmin); Real wExtent = ((Real)0.5)*(wmax - wmin); // Update current minimum-volume box (if necessary). volume = uExtent*vExtent*wExtent; if (volume < minVolume) { minVolume = volume; mMinBox.Extent[0] = uExtent; mMinBox.Extent[1] = vExtent; mMinBox.Extent[2] = wExtent; mMinBox.Axis[0] = U; mMinBox.Axis[1] = V; mMinBox.Axis[2] = W; mMinBox.Center = origin + ((Real)0.5)*(umin+umax)*U + ((Real)0.5)*(vmin+vmax)*V + ((Real)0.5)*(wmin+wmax)*W; } } } } delete1(points2); }
ExtremalQuery3BSP<Real>::~ExtremalQuery3BSP () { delete1(mNodes); }
//---------------------------------------------------------------------------- Castle::~Castle () { delete1(mCos); delete1(mSin); delete1(mTolerance); }
PolynomialFit2<Real>::~PolynomialFit2 () { delete1(mPowers); delete1(mXPowers); delete1(mCoefficients); }
void MeshSmoother<Real>::Destroy () { delete1(mNormals); delete1(mMeans); delete1(mNeighborCounts); }
//---------------------------------------------------------------------------- void WaterDropFormation::Configuration0 () { // Application loops between Configuration0() and Configuration1(). // Delete all the objects from "1" when restarting with "0". delete1(mCtrlPoints); delete1(mTargets); delete0(mSpline); delete0(mCircle); mCircle = 0; mSimTime = 0.0f; mSimDelta = 0.05f; mWaterRoot->DetachChildAt(0); mWaterRoot->DetachChildAt(1); mWaterSurface = 0; mWaterDrop = 0; // Create water surface curve of revolution. const int numCtrlPoints = 13; const int degree = 2; mCtrlPoints = new1<Vector2f>(numCtrlPoints); mTargets = new1<Vector2f>(numCtrlPoints); int i; for (i = 0; i < numCtrlPoints; ++i) { mCtrlPoints[i] = Vector2f(0.125f + 0.0625f*i, 0.0625f); } float h = 0.5f; float d = 0.0625f; float extra = 0.1f; mTargets[ 0] = mCtrlPoints[ 0]; mTargets[ 1] = mCtrlPoints[ 6]; mTargets[ 2] = Vector2f(mCtrlPoints[6].X(), h - d - extra); mTargets[ 3] = Vector2f(mCtrlPoints[5].X(), h - d - extra); mTargets[ 4] = Vector2f(mCtrlPoints[5].X(), h); mTargets[ 5] = Vector2f(mCtrlPoints[5].X(), h + d); mTargets[ 6] = Vector2f(mCtrlPoints[6].X(), h + d); mTargets[ 7] = Vector2f(mCtrlPoints[7].X(), h + d); mTargets[ 8] = Vector2f(mCtrlPoints[7].X(), h); mTargets[ 9] = Vector2f(mCtrlPoints[7].X(), h - d - extra); mTargets[10] = Vector2f(mCtrlPoints[6].X(), h - d - extra); mTargets[11] = mCtrlPoints[ 6]; mTargets[12] = mCtrlPoints[12]; float* weights = new1<float>(numCtrlPoints); for (i = 0; i < numCtrlPoints; ++i) { weights[i] = 1.0f; } const float modWeight = 0.3f; weights[3] = modWeight; weights[5] = modWeight; weights[7] = modWeight; weights[9] = modWeight; mSpline = new0 NURBSCurve2f(numCtrlPoints, mCtrlPoints, weights, degree, false, true); // Restrict evaluation to a subinterval of the domain. mSpline->SetTimeInterval(0.5f, 1.0f); delete1(weights); // Create the water surface. VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); mWaterSurface = new0 RevolutionSurface(mSpline, mCtrlPoints[6].X(), RevolutionSurface::REV_DISK_TOPOLOGY, 32, 16, false, true, vformat); mWaterSurface->SetEffectInstance( mWaterEffect->CreateInstance(mWaterTexture)); mWaterRoot->AttachChild(mWaterSurface); mWaterRoot->Update(); }