/// <summary> /// Simplifies the model by merging the eliminating edges that are closer together /// than double the shortest edge length /// </summary> /// <param name="ts">The ts.</param> public static void SimplifyFlatPatches(this TessellatedSolid ts) { // throw new NotImplementedException(); var edgesToRemove = new List <Edge>(); var edgesToAdd = new List <Edge>(); var facesToRemove = new List <PolygonalFace>(); var facesToAdd = new List <PolygonalFace>(); var verticesToRemove = new List <Vertex>(); var flats = TVGL.MiscFunctions.FindFlats(ts.Faces); if (ts.Primitives == null) { ts.Primitives = new List <PrimitiveSurface>(); } foreach (var flat in flats) { if (flat.InnerEdges.Count < flat.Faces.Count) { continue; } var newFaces = new List <PolygonalFace>(); var outerEdgeHashSet = new HashSet <Edge>(flat.OuterEdges); facesToRemove.AddRange(flat.Faces); edgesToRemove.AddRange(flat.InnerEdges); var innerVertices = new HashSet <Vertex>(flat.InnerEdges.Select(e => e.To)); innerVertices.UnionWith(flat.InnerEdges.Select(e => e.From)); innerVertices.RemoveWhere(v => outerEdgeHashSet.Overlaps(v.Edges)); verticesToRemove.AddRange(innerVertices); var vertexLoops = OrganizeIntoLoop(flat.OuterEdges, flat.Normal); List <List <Vertex[]> > triangulatedListofLists = TriangulatePolygon.Run(new[] { vertexLoops }, flat.Normal); var triangulatedList = triangulatedListofLists.SelectMany(tl => tl).ToList(); var oldEdgeDictionary = flat.OuterEdges.ToDictionary(TessellatedSolid.SetAndGetEdgeChecksum); Dictionary <long, Edge> newEdgeDictionary = new Dictionary <long, Edge>(); foreach (var triangle in triangulatedList) { var newFace = new PolygonalFace(triangle, flat.Normal); if (newFace.Area.IsNegligible() && newFace.Normal.Any(double.IsNaN)) { continue; } newFaces.Add(newFace); for (var j = 0; j < 3; j++) { var fromVertex = newFace.Vertices[j]; var toVertex = newFace.NextVertexCCW(fromVertex); var checksum = TessellatedSolid.GetEdgeChecksum(fromVertex, toVertex); if (oldEdgeDictionary.ContainsKey(checksum)) { //fix up old outer edge. var edge = oldEdgeDictionary[checksum]; if (fromVertex == edge.From) { edge.OwnedFace = newFace; } else { edge.OtherFace = newFace; } newFace.AddEdge(edge); oldEdgeDictionary.Remove(checksum); } else if (newEdgeDictionary.ContainsKey(checksum)) { //Finish creating edge. var newEdge = newEdgeDictionary[checksum]; newEdge.OtherFace = newFace; newFace.AddEdge(newEdge); newEdgeDictionary.Remove(checksum); edgesToAdd.Add(newEdge); } else { newEdgeDictionary.Add(checksum, new Edge(fromVertex, toVertex, newFace, null, false, checksum)); } } } ts.Primitives.Add(new Flat(newFaces)); } ts.RemoveVertices(verticesToRemove); //todo: check if the order of these five commands ts.RemoveFaces(facesToRemove); // matters. There may be an ordering that is more efficient ts.AddFaces(facesToAdd); ts.RemoveEdges(edgesToRemove); ts.AddEdges(edgesToAdd); }
private static IEnumerable <Tuple <Edge, List <PolygonalFace> > > CreateMissingEdgesAndFaces( List <Tuple <List <Edge>, double[]> > loops, out List <PolygonalFace> newFaces, out List <Edge> remainingEdges) { var completedEdges = new List <Tuple <Edge, List <PolygonalFace> > >(); newFaces = new List <PolygonalFace>(); remainingEdges = new List <Edge>(); foreach (var tuple in loops) { var edges = tuple.Item1; var normal = tuple.Item2; //if a simple triangle, create a new face from vertices if (edges.Count == 3) { var newFace = new PolygonalFace(edges.Select(e => e.To), normal); foreach (var edge in edges) { completedEdges.Add(new Tuple <Edge, List <PolygonalFace> >(edge, new List <PolygonalFace> { edge.OwnedFace, newFace })); } newFaces.Add(newFace); } //Else, use the triangulate function else { Dictionary <long, Edge> edgeDic = new Dictionary <long, Edge>(); foreach (var edge in edges) { var checksum = GetEdgeChecksum(edge.From, edge.To); if (!edgeDic.ContainsKey(checksum)) { edgeDic.Add(checksum, edge); } } List <List <Vertex[]> > triangleFaceList = null; try { triangleFaceList = TriangulatePolygon.Run(new List <List <Vertex> > { edges.Select(e => e.To).ToList() }, normal); } catch { continue; } var triangles = triangleFaceList.SelectMany(tl => tl).ToList(); if (triangles.Any()) { Message.output("loop successfully repaired with " + triangles.Count, 5); foreach (var triangle in triangles) { var newFace = new PolygonalFace(triangle, normal); if (newFace.Area.IsNegligible() && newFace.Normal.Any(double.IsNaN)) { continue; } newFaces.Add(newFace); for (var j = 0; j < 3; j++) { var fromVertex = newFace.Vertices[j]; var toVertex = newFace.NextVertexCCW(fromVertex); var checksum = GetEdgeChecksum(fromVertex, toVertex); if (edgeDic.ContainsKey(checksum)) { //Finish creating edge. var edge = edgeDic[checksum]; completedEdges.Add(new Tuple <Edge, List <PolygonalFace> >(edge, new List <PolygonalFace> { edge.OwnedFace, newFace })); edgeDic.Remove(checksum); } else { edgeDic.Add(checksum, new Edge(fromVertex, toVertex, newFace, null, false, checksum)); } } } } else { remainingEdges.AddRange(edges); } } } return(completedEdges); }