internal void UpdatePreContract(MxPairContraction conx) { var v1 = conx.VertId1; var v2 = conx.VertId2; var star = new List <int>(); foreach (var edge in edgeLinks[v1]) { star.Add(edge.OppositeVertex(v1)); } foreach (var edge in edgeLinks[v2]) { var vertU = (edge.V1 == v2) ? edge.V2 : edge.V1; Debug.Assert(edge.V1 == v2 || edge.V2 == v2); Debug.Assert(vertU != v2); if (vertU == v1 || star.Contains(vertU)) { edgeLinks[vertU].Remove(edge); heap.RemoveItem(edge); } else { edge.V1 = v1; edge.V2 = vertU; edgeLinks[v1].Add(edge); } } edgeLinks[v2].Clear(); }
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 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) { UpdatePreExpand(conx); model.ApplyExpansion(conx); ValidVerts++; ValidFaces += conx.DeadFaces.Count; quadrics[conx.VertId1] -= quadrics[conx.VertId2]; UpdatePostExpand(conx); }
internal MxPairContraction(MxPairContraction contraction) { VertId1 = contraction.VertId1; VertId2 = contraction.VertId2; DeltaV1 = (double[])contraction.DeltaV1.Clone(); DeltaV2 = (double[])contraction.DeltaV2.Clone(); DeltaFaces = new List <int>(contraction.DeltaFaces); DeadFaces = new List <int>(contraction.DeadFaces); DeltaPivot = contraction.DeltaPivot; }
internal MxPairContraction(MxPairContraction contraction) { VertId1 = contraction.VertId1; VertId2 = contraction.VertId2; DeltaV1 = (double[])contraction.DeltaV1.Clone(); DeltaV2 = (double[])contraction.DeltaV2.Clone(); DeltaFaces = new List<int>(contraction.DeltaFaces); DeadFaces = new List<int>(contraction.DeadFaces); DeltaPivot = contraction.DeltaPivot; }
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 override bool Decimate(int target) { while (ValidFaces > target) { var info = heap.Extract() as MxQSlimEdge; if (info == null) { return(false); } var v1 = info.V1; var v2 = info.V2; if (!model.VertexIsValid(v1) || !model.VertexIsValid(v2)) { continue; } var inversion = CheckLocalInversion(v1, info.vNew); if (inversion < 0.00) { continue; } inversion = CheckLocalInversion(v2, info.vNew); if (inversion < 0.00) { continue; } var conx = new MxPairContraction(); model.ComputeContraction(v1, v2, conx, info.vNew); if (WillJoinOnly && conx.DeadFaces.Count > 0) { continue; } var evt = Contracted; if (evt != null) { evt(conx, -info.HeapKey); } ApplyContraction(conx); } return(true); }
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 ApplyContraction(MxPairContraction conx) { ValidVerts--; ValidFaces -= conx.DeadFaces.Count; quadrics[conx.VertId1] += quadrics[conx.VertId2]; UpdatePreContract(conx); model.ApplyContraction(conx); UpdatePostContract(conx); foreach (var edge in edgeLinks[conx.VertId1]) { ComputeEdgeInfo(edge); } }
internal void UpdatePostExpand(MxPairContraction conx) { var v1 = conx.VertId1; var v2 = conx.VertId2; var star = new List <int>(); var star2 = new List <int>(); edgeLinks[conx.VertId2].Clear(); model.CollectVertexStar(conx.VertId1, star); model.CollectVertexStar(conx.VertId2, star2); var i = 0; while (i < edgeLinks[v1].Count) { var edge = edgeLinks[v1][i]; var vertU = (edge.V1 == v1) ? edge.V2 : edge.V1; Debug.Assert(edge.V1 == v1 || edge.V2 == v1); Debug.Assert(vertU != v1 && vertU != v2); var v1Linked = star.Contains(vertU); var v2Linked = star2.Contains(vertU); if (v1Linked) { if (v2Linked) { CreateEdge(v2, vertU); } i++; } else { edge.V1 = v2; edge.V2 = vertU; edgeLinks[v2].Add(edge); edgeLinks[v1].RemoveAt(i); } ComputeEdgeInfo(edge); } if (star.Contains(v2)) { CreateEdge(v1, v2); } }
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 ContractionCallback(MxPairContraction conx, float f) { }
internal void UpdatePostContract(MxPairContraction conx) { }
internal void UpdatePreExpand(MxPairContraction conx) { }
internal void UpdatePreContract(MxPairContraction conx) { var v1 = conx.VertId1; var v2 = conx.VertId2; var star = new List<int>(); foreach(var edge in edgeLinks[v1]) { star.Add(edge.OppositeVertex(v1)); } foreach (var edge in edgeLinks[v2]) { var vertU = (edge.V1 == v2) ? edge.V2 : edge.V1; Debug.Assert(edge.V1 == v2 || edge.V2 == v2); Debug.Assert(vertU != v2); if (vertU == v1 || star.Contains(vertU)) { edgeLinks[vertU].Remove(edge); heap.RemoveItem(edge); } else { edge.V1 = v1; edge.V2 = vertU; edgeLinks[v1].Add(edge); } } edgeLinks[v2].Clear(); }
internal void UpdatePostExpand(MxPairContraction conx) { var v1 = conx.VertId1; var v2 = conx.VertId2; var star = new List<int>(); var star2 = new List<int>(); edgeLinks[conx.VertId2].Clear(); model.CollectVertexStar(conx.VertId1, star); model.CollectVertexStar(conx.VertId2, star2); var i = 0; while (i < edgeLinks[v1].Count) { var edge = edgeLinks[v1][i]; var vertU = (edge.V1 == v1) ? edge.V2 : edge.V1; Debug.Assert(edge.V1 == v1 || edge.V2 == v1); Debug.Assert(vertU != v1 && vertU != v2); var v1Linked = star.Contains(vertU); var v2Linked = star2.Contains(vertU); if (v1Linked) { if (v2Linked) CreateEdge(v2, vertU); i++; } else { edge.V1 = v2; edge.V2 = vertU; edgeLinks[v2].Add(edge); edgeLinks[v1].RemoveAt(i); } ComputeEdgeInfo(edge); } if (star.Contains(v2)) CreateEdge(v1, v2); }
internal override bool Decimate(int target) { while(ValidFaces > target) { var info = heap.Extract() as MxQSlimEdge; if (info == null) return false; var v1 = info.V1; var v2 = info.V2; if (!model.VertexIsValid(v1) || !model.VertexIsValid(v2)) continue; var inversion = CheckLocalInversion(v1, info.vNew); if (inversion < 0.00) continue; inversion = CheckLocalInversion(v2, info.vNew); if (inversion < 0.00) continue; var conx = new MxPairContraction(); model.ComputeContraction(v1, v2, conx, info.vNew); if (WillJoinOnly && conx.DeadFaces.Count > 0) continue; var evt = Contracted; if (evt != null) { evt(conx, -info.HeapKey); } ApplyContraction(conx); } return true; }