/// <summary> /// Returns a list of arrays of 3 vertices, each representing a triangle in the mesh. /// Faces are taken from the first FaceSet in the mesh with the given flags, /// using None by default for the highest detail mesh. If not found, the first FaceSet is used. /// </summary> public List <FLVER.Vertex[]> GetFaces(FaceSet.FSFlags fsFlags = FaceSet.FSFlags.None) { if (FaceSets.Count == 0) { return(new List <FLVER.Vertex[]>()); } else { FaceSet faceSet = FaceSets.Find(fs => fs.Flags == fsFlags) ?? FaceSets[0]; List <int> indices = faceSet.Triangulate(Vertices.Count < ushort.MaxValue); var vertices = new List <FLVER.Vertex[]>(indices.Count); for (int i = 0; i < indices.Count - 2; i += 3) { int vi1 = indices[i]; int vi2 = indices[i + 1]; int vi3 = indices[i + 2]; vertices.Add(new FLVER.Vertex[] { Vertices[vi1], Vertices[vi2], Vertices[vi3] }); } return(vertices); } }
/// <summary> /// Reduce an instance of Set Cover using safe reduction rules /// </summary> /// <param name="U">The universe</param> /// <param name="F">The familiy of sets</param> /// <returns> /// (U, F, delta), where U and F are "irreducible" and /// delta is the number of sets that must be included /// </returns> private static Tuple <HashSet <int>, Dictionary <int, HashSet <int> >, List <int> > Reduce(HashSet <int> U, Dictionary <int, HashSet <int> > F) { // EdgeSets : Edges -> 2^Faces var EdgeSets = new Dictionary <int, HashSet <int> >(); // deep copy foreach (var edge in F.Keys) { foreach (var face in F[edge]) { if (EdgeSets.ContainsKey(edge)) { EdgeSets[edge].Add(face); } else { EdgeSets.Add(edge, new HashSet <int> { face }); } } } // FaceSets : Faces -> 2^Edges var FaceSets = new Dictionary <int, HashSet <int> >(); foreach (var edge in EdgeSets.Keys) { foreach (var face in EdgeSets[edge]) { if (FaceSets.ContainsKey(face)) { FaceSets[face].Add(edge); } else { FaceSets.Add(face, new HashSet <int> { edge }); } } } // main reduction loop // whether the solution changed at all var reduced = false; // whether the solution changed this iteration var changed = true; var delta = new List <int>(); do { changed = false; // last face was removed if (FaceSets.Count() == 0) { return(Tuple.Create(new HashSet <int>(), new Dictionary <int, HashSet <int> >(), delta)); } // remove duplicates var noDups = RemoveDuplicates(EdgeSets); if (noDups.Item1) { reduced = true; changed = true; EdgeSets = noDups.Item2; FaceSets = new Dictionary <int, HashSet <int> >(); foreach (var key in EdgeSets.Keys) { foreach (var edge in EdgeSets[key]) { if (FaceSets.ContainsKey(edge)) { FaceSets[edge].Add(key); } else { FaceSets.Add(edge, new HashSet <int> { key }); } } } continue; } //remove isolated faces var isolated = from set in FaceSets where (set.Value.Count == 1) select set.Key; if (isolated.Count() > 0) { reduced = true; changed = true; // collect all faces of sets which include the isolated faces var coveredFaces = new HashSet <int>(); var coveredEdges = new HashSet <int>(); var selectedEdges = new HashSet <int>(); foreach (var face in isolated) { // only one set that includes the face var edge = FaceSets[face].ElementAt(0); selectedEdges.Add(edge); foreach (var f in EdgeSets[edge]) { coveredFaces.Add(f); } coveredEdges.Add(edge); } delta.AddRange(selectedEdges); // build new FaceSets var newFaceSets = new Dictionary <int, HashSet <int> >(); foreach (var pair in FaceSets) { if (!coveredFaces.Contains(pair.Key)) { newFaceSets.Add(pair.Key, pair.Value); } } FaceSets = newFaceSets; // build new EdgeSets var newEdgeSets = new Dictionary <int, HashSet <int> >(); foreach (var pair in EdgeSets) { if (!coveredEdges.Contains(pair.Key)) { var faces = pair.Value; faces.ExceptWith(coveredFaces); newEdgeSets.Add(pair.Key, faces); } } // remove empty sets EdgeSets = new Dictionary <int, HashSet <int> >(); foreach (var pair in newEdgeSets) { if (pair.Value.Count > 0) { EdgeSets.Add(pair.Key, pair.Value); } } continue; } // find the first completely included subsets and remove it for (int i = 0; i < EdgeSets.Count && !changed; i++) { var edge = EdgeSets.ElementAt(i).Key; var A = EdgeSets.ElementAt(i).Value; for (int j = 0; j < EdgeSets.Count; j++) { if (i == j) { continue; } bool complete = true; var B = EdgeSets.ElementAt(j).Value; foreach (var x in A) { if (!B.Contains(x)) { complete = false; } } if (complete) { foreach (var face in A) { // face no longer occurs in Vis(edge) FaceSets[face].Remove(edge); } // remove empty sets var newFaceSets = new Dictionary <int, HashSet <int> >(); foreach (var pair in FaceSets) { if (pair.Value.Count > 0) { newFaceSets.Add(pair.Key, pair.Value); } } FaceSets = newFaceSets; EdgeSets.Remove(edge); reduced = true; changed = true; break; } } } if (changed) { continue; } // remove the first face which is present in every set var redundant = false; var redundantFace = 0; foreach (var face in FaceSets.Keys) { if (FaceSets[face].Count == EdgeSets.Keys.Count) { // no isolated faces redundant = true; redundantFace = face; break; } } if (redundant) { reduced = true; changed = true; FaceSets.Remove(redundantFace); foreach (var pair in EdgeSets) { pair.Value.Remove(redundantFace); } } } while (changed); // recover the instance if (reduced) { var new_U = new HashSet <int>(); foreach (var face in FaceSets.Keys) { new_U.Add(face); } return(Tuple.Create(new_U, FaceSets, delta)); } else { return(Tuple.Create(U, F, delta)); } }