internal double ComputeFacePerimeter(int faceId, bool[] flags) { var perim = 0.0; var face = Face(faceId); for (var i = 0; i < 3; i++) { if (flags != null) { if (!flags[i]) { continue; } } var vi = Vertex(face[i]); var vj = Vertex(face[(i + 1) % 3]); var diff = new double[3]; MxVectorOps.Sub3(ref diff, vi.Pos, vj.Pos); perim += MxVectorOps.Length3(diff); } return(perim); }
internal void ComputeContraction(int vertId1, int vertId2, MxPairContraction conx, double[] newVert) { conx.VertId1 = vertId1; conx.VertId2 = vertId2; if (newVert != null) { MxVectorOps.Sub3(ref conx.DeltaV1, newVert, Vertex(vertId1).Pos); MxVectorOps.Sub3(ref conx.DeltaV2, newVert, Vertex(vertId2).Pos); } else { conx.DeltaV1 = new[] { 0.0, 0.0, 0.0 }; conx.DeltaV2 = new[] { 0.0, 0.0, 0.0 }; } conx.DeltaFaces.Clear(); conx.DeadFaces.Clear(); MarkNeighborhood(vertId2, 0x0); MarkNeighborhood(vertId1, 0x1); MarkNeighborhoodDelta(vertId2, 0x1); PartitionMarkedNeighbors(vertId1, 0x2, conx.DeltaFaces, conx.DeadFaces); conx.DeltaPivot = conx.DeltaFaces.Count; PartitionMarkedNeighbors(vertId2, 0x2, conx.DeltaFaces, conx.DeadFaces); }
internal double ComputeFaceArea(int faceId) { var normal = new double[3]; ComputeFaceNormal(faceId, ref normal, false); return(0.5 * MxVectorOps.Length3(normal)); }
internal void Contract(int vertId1, int vertId2, double[] newVert, MxPairContraction conx) { ComputeContraction(vertId1, vertId2, conx, null); MxVectorOps.Sub3(ref conx.DeltaV1, newVert, Vertex(vertId1).Pos); MxVectorOps.Sub3(ref conx.DeltaV2, newVert, Vertex(vertId2).Pos); ApplyContraction(conx); }
internal void ApplyExpansion(MxPairContraction conx) { var vertId1 = conx.VertId1; var vertId2 = conx.VertId2; var newPos1 = new double[3]; MxVectorOps.Sub3(ref newPos1, Vertex(vertId1).Pos, conx.DeltaV2); Vertex(vertId2).Pos = newPos1; var newPos2 = Vertex(vertId2).Pos; MxVectorOps.SubFrom3(ref newPos2, conx.DeltaV1); Vertex(vertId2).Pos = newPos2; foreach (var faceId in conx.DeadFaces) { FaceMarkValid(faceId); var face = Face(faceId); faceLinks[face[0]].Add(faceId); faceLinks[face[1]].Add(faceId); faceLinks[face[2]].Add(faceId); } for (var i = conx.DeltaPivot; i < conx.DeltaFaces.Count; i++) { var faceId = conx.DeltaFaces[i]; var face = Face(faceId); face.RemapVertex(vertId1, vertId2); faceLinks[vertId2].Add(faceId); faceLinks[vertId1].Remove(faceId); } if (NormalBinding == MxBinding.PerFace) { var nml = new double[3]; foreach (var faceId in conx.DeltaFaces) { ComputeFaceNormal(faceId, ref nml); Normal(faceId, new MxNormal(nml)); } foreach (var faceId in conx.DeadFaces) { ComputeFaceNormal(faceId, ref nml); Normal(faceId, new MxNormal(nml)); } } VertexMarkValid(vertId2); }
internal void ComputeFaceNormal(int faceId, ref double[] nml, bool willUnitize = true) { var v0 = Vertex(Face(faceId)[0]); var v1 = Vertex(Face(faceId)[1]); var v2 = Vertex(Face(faceId)[2]); var a = new[] { v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2] }; var b = new[] { v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2] }; MxVectorOps.Cross3(ref nml, a, b); if (willUnitize) { MxVectorOps.Unitize3(ref nml); } }
internal double ComputeCornerAngle(int faceId, int corner) { var cornerPrev = (corner == 0) ? 2 : (corner - 1); var cornerNext = (corner == 2) ? 0 : (corner + 1); var ePrev = new double[3]; MxVectorOps.Sub3(ref ePrev, Corner(faceId, cornerPrev).Pos, Corner(faceId, corner).Pos); MxVectorOps.Unitize3(ref ePrev); var eNext = new double[3]; MxVectorOps.Sub3(ref eNext, Corner(faceId, cornerNext).Pos, Corner(faceId, corner).Pos); MxVectorOps.Unitize3(ref eNext); return(Math.Acos(MxVectorOps.Dot3(ePrev, eNext))); }
internal int CheckLocalValidity(int vertId, double[] vNew) { var n1 = model.Neighbors(vertId); var nFailed = 0; foreach (var faceId in n1) { if (!model.FaceIsValid(faceId)) { continue; } var face = model.Face(faceId); var k = face.FindVertex(vertId); var x = face[(k + 1) % 3]; var y = face[(k + 2) % 3]; var vPos = model.Vertex(vertId).Pos; var xPos = model.Vertex(x).Pos; var yPos = model.Vertex(y).Pos; var dYX = new double[3]; MxVectorOps.Sub3(ref dYX, xPos, yPos); var dVX = new double[3]; MxVectorOps.Sub3(ref dVX, vPos, xPos); var dVNew = new double[3]; MxVectorOps.Sub3(ref dVNew, vNew, xPos); var fN = new double[3]; MxVectorOps.Cross3(ref fN, dYX, dVX); var nml = new double[3]; MxVectorOps.Cross3(ref nml, dYX, dVX); MxVectorOps.Unitize3(ref nml); if (MxVectorOps.Dot3(dVNew, nml) < LocalValidityThreshold * MxVectorOps.Dot3(dVX, nml)) { nFailed++; } } return(nFailed); }
internal void ComputeVertexNormal(int vertId, ref double[] nml) { for (var i = 0; i < 3; i++) { nml[i] = 0.0; } var star = faceLinks[vertId]; foreach (var faceId in star) { var faceNml = new double[3]; ComputeFaceNormal(faceId, ref faceNml, false); MxVectorOps.AddInto3(ref nml, faceNml); } if (star.Count > 1) { MxVectorOps.Unitize3(ref nml); } }
internal void ApplyContraction(MxPairContraction conx) { var vertId1 = conx.VertId1; var vertId2 = conx.VertId2; // Move vert1 to new position var pos = Vertex(vertId1).Pos; MxVectorOps.AddInto3(ref pos, conx.DeltaV1); Vertex(vertId1).Pos = pos; // Remove dead faces foreach (var faceId in conx.DeadFaces) { UnLinkFace(faceId); } // Modify changed faces for (var i = conx.DeltaPivot; i < conx.DeltaFaces.Count; i++) { var faceId = conx.DeltaFaces[i]; var face = Face(faceId); face.RemapVertex(vertId2, vertId1); faceLinks[vertId1].Add(faceId); } if (NormalBinding == MxBinding.PerFace) { var nml = new double[3]; foreach (var faceId in conx.DeltaFaces) { ComputeFaceNormal(faceId, ref nml); Normal(faceId, new MxNormal(nml)); } } // Remove v2 VertexMarkInvalid(vertId2); faceLinks[vertId2].Clear(); }
internal void ComputeFacePlane(int faceId, ref double[] plane, bool willUnitize = true) { ComputeFaceNormal(faceId, ref plane, willUnitize); plane[3] = -MxVectorOps.Dot3(plane, Corner(faceId, 0).Pos); }