void ComplexMesh::ImplicitMeanCurvatureFlow(float TimeStep) { Vector<double> VertexAreas(_Vertices.Length()); Vector<Vec3f> NewVertexPositions(_Vertices.Length()); NewVertexPositions.Clear(Vec3f::Origin); SparseMatrix<double> M(_Vertices.Length()); for(UINT VertexIndex = 0; VertexIndex < _Vertices.Length(); VertexIndex++) { Vertex &CurVertex = _Vertices[VertexIndex]; VertexAreas[VertexIndex] = CurVertex.ComputeTriangleArea(); M.PushElement(VertexIndex, VertexIndex, VertexAreas[VertexIndex]); //M.PushElement(VertexIndex, VertexIndex, 1.0f); for(UINT EdgeIndex = 0; EdgeIndex < CurVertex.Vertices().Length(); EdgeIndex++) { Vertex &OtherVertex = *(CurVertex.Vertices()[EdgeIndex]); FullEdge &CurEdge = CurVertex.GetSharedEdge(OtherVertex); double ConstantFactor = CurEdge.GetCotanTerm() / 4.0f; Assert(ConstantFactor == ConstantFactor, "ConstantFactor invalid"); M.PushElement(VertexIndex, VertexIndex, TimeStep * ConstantFactor); M.PushElement(VertexIndex, OtherVertex.Index(), -TimeStep * ConstantFactor); } } BiCGLinearSolver<double> Solver; Solver.LoadMatrix(&M); const double ErrorTolerance = 1e-6; Solver.SetParamaters(1000, ErrorTolerance); Solver.Factor(); for(UINT ElementIndex = 0; ElementIndex < 3; ElementIndex++) { Vector<double> x, b(_Vertices.Length()); for(UINT VertexIndex = 0; VertexIndex < _Vertices.Length(); VertexIndex++) { b[VertexIndex] = _Vertices[VertexIndex].Pos()[ElementIndex] * VertexAreas[VertexIndex]; //b[VertexIndex] = _Vertices[VertexIndex].Pos().Element(ElementIndex); } Solver.Solve(x, b); Console::WriteLine(Solver.GetOutputString()); double Error = Solver.ComputeError(x, b); Console::WriteLine(String("Mean curvature error: ") + String(Error)); if(Error < ErrorTolerance) { for(UINT VertexIndex = 0; VertexIndex < _Vertices.Length(); VertexIndex++) { NewVertexPositions[VertexIndex][ElementIndex] = float(x[VertexIndex]); } } } float AverageDelta = 0.0f; for(UINT VertexIndex = 0; VertexIndex < _Vertices.Length(); VertexIndex++) { Vec3f Delta = NewVertexPositions[VertexIndex] - _Vertices[VertexIndex].Pos(); AverageDelta += Delta.Length(); } AverageDelta /= _Vertices.Length(); for(UINT VertexIndex = 0; VertexIndex < _Vertices.Length(); VertexIndex++) { Vertex &CurVertex = _Vertices[VertexIndex]; Vec3f Delta = NewVertexPositions[VertexIndex] - _Vertices[VertexIndex].Pos(); if(Delta.Length() > 2.0f * AverageDelta) { Delta.SetLength(2.0f * AverageDelta); } CurVertex.Pos() += Delta; } }
bool Plane::FitToPoints(const Vector<Vec4f> &Points, Vec3f &Basis1, Vec3f &Basis2, float &NormalEigenvalue, float &ResidualError) { Vec3f Centroid, Normal; float ScatterMatrix[3][3]; int Order[3]; float DiagonalMatrix[3]; float OffDiagonalMatrix[3]; // Find centroid Centroid = Vec3f::Origin; float TotalWeight = 0.0f; for(UINT i = 0; i < Points.Length(); i++) { TotalWeight += Points[i].w; Centroid += Vec3f(Points[i].x, Points[i].y, Points[i].z) * Points[i].w; } Centroid /= TotalWeight; // Compute scatter matrix Find_ScatterMatrix(Points, Centroid, ScatterMatrix, Order); tred2(ScatterMatrix,DiagonalMatrix,OffDiagonalMatrix); tqli(DiagonalMatrix,OffDiagonalMatrix,ScatterMatrix); /* ** Find the smallest eigenvalue first. */ float Min = DiagonalMatrix[0]; float Max = DiagonalMatrix[0]; UINT MinIndex = 0; UINT MiddleIndex = 0; UINT MaxIndex = 0; for(UINT i = 1; i < 3; i++) { if(DiagonalMatrix[i] < Min) { Min = DiagonalMatrix[i]; MinIndex = i; } if(DiagonalMatrix[i] > Max) { Max = DiagonalMatrix[i]; MaxIndex = i; } } for(UINT i = 0; i < 3; i++) { if(MinIndex != i && MaxIndex != i) { MiddleIndex = i; } } /* ** The normal of the plane is the smallest eigenvector. */ for(UINT i = 0; i < 3; i++) { Normal[Order[i]] = ScatterMatrix[i][MinIndex]; Basis1[Order[i]] = ScatterMatrix[i][MiddleIndex]; Basis2[Order[i]] = ScatterMatrix[i][MaxIndex]; } NormalEigenvalue = Math::Abs(DiagonalMatrix[MinIndex]); Basis1.SetLength(DiagonalMatrix[MiddleIndex]); Basis2.SetLength(DiagonalMatrix[MaxIndex]); if(!Basis1.Valid() || !Basis2.Valid() || !Normal.Valid()) { *this = ConstructFromPointNormal(Centroid, Vec3f::eX); Basis1 = Vec3f::eY; Basis2 = Vec3f::eZ; } else { *this = ConstructFromPointNormal(Centroid, Normal); } ResidualError = 0.0f; for(UINT i = 0; i < Points.Length(); i++) { ResidualError += UnsignedDistance(Vec3f(Points[i].x, Points[i].y, Points[i].z)); } ResidualError /= Points.Length(); return true; }