/// <summary> /// Joins vertex to the cheapest neighbour. /// </summary> /// <param name="vertex">The vertex to join.</param> /// <param name="type">The type of position join method.</param> /// <returns></returns> public bool JoinToNearestByCost(Vertex vertex, JoinPositionType type = JoinPositionType.Middle) { Debug.Assert(vertex != null); Vertex nearest = vertex.Neighbors.Min(); if (nearest != null) { Vector3 position; switch (type) { case JoinPositionType.Source: { position = vertex.Position; break; } case JoinPositionType.Target: { position = nearest.Position; break; } default: case JoinPositionType.Middle: { position = Vector3Extension.Mean(vertex.Position, nearest.Position); break; } } return(JoinVertices(vertex, nearest, position)); } return(false); }
/// <summary> /// Optimizes edge target. /// </summary> /// <param name="v1">The source edge vertex.</param> /// <param name="v2">The target edge vertex.</param> /// <param name="edge">The edge additional params.</param> /// <param name="policy">The used policy.</param> private void OptimizeEdgeTarget(ref Vertex v1, ref Vertex v2, ref Triangle.Edge edge, WeightPolicy policy) { ErrorMetric Q = (ErrorMetric)edge.Tag; double min_cost = double.MaxValue; Vector3 best; if (policy.HasFlag(WeightPolicy.Optmized) && Q.Optimize(out best)) { Q.ProposedPoint = best; min_cost = Q.VertexError(best); } else { double min1 = Q.VertexError(v1.Position); double min2 = Q.VertexError(v2.Position); if (min1 < min2) { min_cost = min1; best = v1.Position; } else { min_cost = min2; best = v2.Position; } if (policy.HasFlag(WeightPolicy.MiddlePoint)) { Vector3 middle = Vector3Extension.Mean(v1.Position, v2.Position); double cost_middle = Q.VertexError(middle); if (cost_middle < min_cost) { min_cost = cost_middle; best = middle; } } } if (policy.HasFlag(WeightPolicy.AverageTriangleArea)) { min_cost /= Q.Area; } edge.Cost = -min_cost; Q.ProposedPoint = best; edge.Tag = (object)Q; }
/// <summary> /// Joins vertex to the closest neighbour. /// </summary> /// <param name="vertex">The vertex to join.</param> /// /// <param name="type">The type of position join method.</param> /// <returns>true when successful, false otherwise.</returns> public bool JoinToNearestByDistance(Vertex vertex, JoinPositionType type = JoinPositionType.Middle) { Debug.Assert(vertex != null); Vertex nearest = null; float minDistance = float.MaxValue; var neighbors = vertex.Neighbors.ToList(); foreach (var neighbor in neighbors) { float distance = Vector3.Distance(vertex.Position, neighbor.Position); if (distance < minDistance) { minDistance = distance; nearest = neighbor; } } if (nearest != null) { Vector3 position; switch (type) { case JoinPositionType.Source: { position = vertex.Position; break; } case JoinPositionType.Target: { position = nearest.Position; break; } default: case JoinPositionType.Middle: { position = Vector3Extension.Mean(vertex.Position, nearest.Position); break; } } return(JoinVertices(vertex, nearest, position)); } return(false); }
public void Remesh(ref Mesh mesh, IProgressListener progress = null) { var triangles = mesh.Triangles; var vertices = mesh.Vertices; // Compute K matrices for initial triangles. foreach (var t in triangles) { t.UpdateGeometricData(); t.Tag = new ErrorMetric(t); } // Compute Q for intiial vertices. foreach (var v in vertices) { ComputeErrorMetricForVertex(v); } // Compute initial edge QEM-s foreach (var t in triangles) { ComputeErrorMetricForEdges(t); } foreach (var t in triangles) { ComputeEdgeCost(t); } foreach (var v in vertices) { v.Cost = 0.0; foreach (var t in v.Triangles) { v.Cost += Math.Max(Math.Max(t.Edge12.Cost, t.Edge23.Cost), t.Edge31.Cost); } } // Compute number of triangles after we stop int toRemove = (int)((m_Removed) * triangles.Count); int triangleLimit = triangles.Count - toRemove; #if TRACE_NANS int nansCount = 0; #endif int index = 0; for (int i = 0; (i < m_Removed) && (2 * m_Removed < triangles.Count); i += 2) { Vertex v1, v2; Triangle.Edge edge; if (SearchBestCandidate(ref mesh, out v1, out v2, out edge)) { if (edge != null) { ErrorMetric em = (ErrorMetric)edge.Tag; Vector3 v = em.ProposedPoint; #if false if (v.IsNaN()) { #if TRACE_NANS ++nansCount; #endif v = Vector3Extension.Mean(v1.Position, v2.Position); } #endif if (mesh.JoinVertices(v1, v2, v)) { // V1, since v2 is removed from now. UpdateVertexNeighbors(v1); } progress.OnProgress(index, toRemove); index += 2; } else { Trace.WriteLine("If you see this message more than once per second, I can't find any matching edge"); } } } #if TRACE_NANS Trace.WriteLine(string.Format("NaNs count: {0}", nansCount)); #endif }
/// <summary> /// Computes edge cost for triangle. /// </summary> /// <param name="t">The triangle.</param> private void ComputeEdgeCost(Triangle t) { #if false Vector3 P1 = E12.ComputePosition(); Vector3 P2 = E23.ComputePosition(); Vector3 P3 = E31.ComputePosition(); #if !DISABLE_QEM_COMPUTING double C12 = E12.Evaluate(P1); double C23 = E23.Evaluate(P2); double C31 = E31.Evaluate(P3); if (double.IsNaN(C12)) { #if DISABLE_MEAN_POINT E12.ProposedPoint = t.Vertex1.Position; #else E12.ProposedPoint = Vector3Extension.Mean( t.Vertex1.Position, t.Vertex2.Position); #endif C12 = E12.Evaluate(E12.ProposedPoint); } else { E12.ProposedPoint = P1; } if (double.IsNaN(C23)) { #if DISABLE_MEAN_POINT E23.ProposedPoint = t.Vertex2.Position; #else E23.ProposedPoint = Vector3Extension.Mean( t.Vertex2.Position, t.Vertex3.Position); C23 = E23.Evaluate(E23.ProposedPoint); #endif } else { E23.ProposedPoint = P2; } if (double.IsNaN(C31)) { #if DISABLE_MEAN_POINT E31.ProposedPoint = t.Vertex3.Position; #else E31.ProposedPoint = Vector3Extension.Mean( t.Vertex3.Position, t.Vertex1.Position); C31 = E31.Evaluate(E31.ProposedPoint); #endif } else { E31.ProposedPoint = P3; } #else double C12 = E12.Evaluate(t.Vertex1.Position); double C23 = E23.Evaluate(t.Vertex2.Position); double C31 = E31.Evaluate(t.Vertex3.Position); #endif t.Edge12.Cost = C12; t.Edge23.Cost = C23; t.Edge31.Cost = C31; #else WeightPolicy policy = (WeightPolicy.Optmized | WeightPolicy.AverageTriangleArea); OptimizeEdgeTarget(ref t.m_Vertex1, ref t.m_Vertex2, ref t.m_Edge12, policy); OptimizeEdgeTarget(ref t.m_Vertex2, ref t.m_Vertex3, ref t.m_Edge23, policy); OptimizeEdgeTarget(ref t.m_Vertex3, ref t.m_Vertex1, ref t.m_Edge31, policy); #endif t.Cost = Math.Min(t.Edge12.Cost, Math.Min(t.Edge23.Cost, t.Edge31.Cost)); }