private void NewMethod(List <SpanningTree> ret, int tabId, Tri3 v1, Tri3 v2) { var t1 = ret.Single(p => p.Faces.Any(q => q.Index == v1.Index)); var common = v1.Vertices.Where(p => v2.Vertices.Any(q => q.Index == p.Index)).ToArray(); var t1p = new SpanningTree(t1.Edges.Union(new[] { new DualEdge(v1, new SterileTri3(v2, tabId, common)) })); ret.Remove(t1); ret.Add(t1p); }
private static IEnumerable <BothTri> Flatten( Mesh mesh, SpanningTree spanTree, Tri3 node) { return(FlattenWorker( mesh, spanTree, node, null, new HashSet <int>(), 0)); }
private static IEnumerable <BothTri> FlattenWorker( Mesh mesh, SpanningTree spanTree, Tri3 curr, BothTri prev, HashSet <int> visitedNodes, int depth) { // Console.WriteLine("".PadLeft(depth, '.') + curr.Index); if (visitedNodes.Contains(curr.Index)) { return(new BothTri[0]); } visitedNodes.Add(curr.Index); var node = curr; Tri3 nodePrev = null; if (prev != null) { // Need to treat the common edge special. var ab = curr.CommonEdge(prev.Space); var abi = ab.Select(p => p.Index).ToArray(); var c = curr.Vertices.Where(p => !abi.Contains(p.Index)).Single(); var origOrder = curr.Vertices.Select(p => p.Index).ToArray(); var newOrder = new int[] { ab[0].Index, ab[1].Index, c.Index }; var curr2 = new Tri3(ab[0], ab[1], c, curr.Index); curr = new Tri3(ab[0], ab[1], c, curr.Index); node = prev.SpaceToPaper.Apply(curr); var c2 = prev.Space.Vertices.Where(p => !abi.Contains(p.Index)).Single(); nodePrev = new Tri3(ab[0], ab[1], c2); nodePrev = prev.SpaceToPaper.Apply(nodePrev); } var tri1 = node.Translate(node.A.Neg()); var BYtoX = tri1.B.GetXYRot(); var tri2 = tri1.Apply(BYtoX); var BZtoX = tri2.B.GetXZRot(); var tri3 = tri2.Apply(BZtoX); var CZtoY = tri3.C.GetYZRot(); var tri4 = tri3.Apply(CZtoY); nodePrev = nodePrev?.Translate(node.A.Neg()).Apply(BYtoX).Apply(BZtoX); // Need to check if rotation put tri4 over prev.Paper. This is easy because the common axis is along x, and z=0. if (prev != null) { // Need to determine which if (tri4.C.Y > 0 && nodePrev.C.Y > 0) { // overlap. Just need to do another rotation around xhat. CZtoY = Mat3.RotateYZ(Math.PI).Mult(CZtoY); } } Mat3 spaceToPaper = CZtoY.Mult(BZtoX.Mult(BYtoX)); if (prev != null) { // Need to restore angle of the common edge. spaceToPaper = BYtoX.Inv().Mult(BZtoX.Inv().Mult(spaceToPaper)); } Transform t; if (prev == null) { t = Transform.ContructRT(node.A.Neg(), spaceToPaper); } else { t = Transform.ContructTRT(node.A.Neg(), spaceToPaper); } if (prev != null) { // Apply atop previous transform t = t.Compose(prev.SpaceToPaper); } var test1 = t.Apply(curr); if (Math.Abs(test1.C.Z) > 1e-8) { throw new InvalidOperationException(); } var test4 = curr; BothTri bt = new BothTri(curr, t); var test0 = bt.Paper; var test2 = bt.SpaceToPaper.Apply(curr); var test3 = bt.PaperToSpace(bt.Paper); var test5 = bt.Space; if (test0.Dist(test1) > 1e-5) { throw new InvalidOperationException(); } if (test0.Dist(test2) > 1e-5) { throw new InvalidOperationException(); } if (test3.Dist(test4) > 1e-5) { throw new InvalidOperationException(); } if (test3.Dist(test5) > 1e-5) { throw new InvalidOperationException(); } var ret = new List <BothTri>() { bt }; foreach (Tri3 child in spanTree.GetConnectedNodes(curr)) { var cbt = FlattenWorker(mesh, spanTree, child, bt, visitedNodes, depth + 1); ret.AddRange(cbt); } return(ret); }
public static IEnumerable <IEnumerable <BothTri> > unfold(SpanningTree spanningTree, IEnumerable <BothTri> faces) { var epsilon = 1E-12; // accuracy var faceIntersections = new List <Tuple <int, int> >(); foreach (var face1 in faces) { foreach (var face2 in faces.Where(p => p.Index < face1.Index)) { if (face1.Paper.TriangleIntersection(face2.Paper, epsilon)) { faceIntersections.Add(new Tuple <int, int>(face1.Index, face2.Index)); } } } // Find all paths between intersecting triangles var edgepaths = new List <IEnumerable <DualEdge> >(); foreach (var intersection in faceIntersections) { edgepaths.Add(spanningTree.Path(intersection.Item1, intersection.Item2)); } // Count the number of times each edge occurs var allEdgesInPaths = edgepaths .SelectMany(p => p) .Select(p => p.Index) .Distinct() .Select(p => new { EdgeId = p, NumPaths = edgepaths.Where(q => q.Any(r => r.Index == p)).Count(), }) .ToArray(); // set of new cut edges var cuts = new List <int>(); //set of already covered paths var C = new List <IEnumerable <DualEdge> >(); while (C.Count != edgepaths.Count) { // Determine the edge with minimum average cost at which it covers new elements. var cutWeights = new double[allEdgesInPaths.Length]; for (int i = 0; i < allEdgesInPaths.Length; i++) { // Count how many of the paths where the // edge occurs have already been cut var numInC = C .Where(p => p .Select(q => q.Index) .Contains(allEdgesInPaths[i].EdgeId)) .Count(); // Determine the weight cutWeights[i] = ((allEdgesInPaths[i].NumPaths - numInC) > 0) ? 1.0 / (allEdgesInPaths[i].NumPaths - numInC) : double.MaxValue; } // Find the edge with the lowest weight var minimalIndex = cutWeights .Select((p, i) => new { p, i }) .OrderBy(p => p.p) .First().i; // np.argmin(cutWeights) cuts.Add(allEdgesInPaths[minimalIndex].EdgeId); // Find all paths where the edge occurs and add them to C. foreach (IEnumerable <DualEdge> path in edgepaths) { if (path .Select(p => p.Index) .Contains(allEdgesInPaths[minimalIndex].EdgeId) && !C.Contains(path)) { C.Add(path); } } } // Make the cuts in the spanning tree IEnumerable <SpanningTree> connectedComponents = spanningTree.MakeCuts(cuts); BothTri[][] splitFaces = connectedComponents .Select(p => p.Faces .Select(q => { if (q is SterileTri3 st) { return(new BothTri(faces.Single(r => r.Index == -q.Index), st.TabId, st.Common)); } else { return(faces.Single(r => r.Index == q.Index)); } }) .ToArray()) .Select(p => p) .ToArray(); return(splitFaces); }