private static IEnumerable <DualEdge> GetTreeFromFace( IEnumerable <DualEdge> edges, HashSet <int> unvisited, Tri3 cur) { var ret = new List <DualEdge>(); if (!(cur is Tri3Ext) && unvisited.Contains(cur.Index)) { unvisited.Remove(cur.Index); var ww = edges.Where(p => p.VertexIndices.Contains(cur.Index)) .GroupBy(p => p.Index) .Select(p => p.Count() == 1 ? p.Single() : p.Select(q => new { q, o = q.Vertices[0] is Tri3Ext || q.Vertices[1] is Tri3Ext ? 0 : 1 }) .OrderBy(q => q.o) .First().q); // .Where(p => p.Count() > 1) // .Count(); //if (ww > 1) //{ //} foreach (var fi in ww) // edges.Where(p => p.VertexIndices.Contains(cur.Index))) { ret.Add(fi); var toFace = fi.Vertices.Single(p => p.Index != cur.Index); ret.AddRange(GetTreeFromFace(edges, unvisited, toFace)); } } return(ret); }
internal IEnumerable <Tri3> GetConnectedNodes(Tri3 node) { return(Edges .Where(p => p.VertexIndices.Contains(node.Index)) .Select(p => p.Vertices.Single(q => q.Index != node.Index)) .ToArray()); }
public Tri3(Tri3 t, int index) { A = t.A; B = t.B; C = t.C; Index = index; }
internal Tri3 AddFace(Vec3 a, Vec3 b, Vec3 c) { a = AddVertex(a); b = AddVertex(b); c = AddVertex(c); AddEdge(a, b); AddEdge(b, c); AddEdge(c, a); var t = new Tri3(a, b, c); var tIndices = t.Vertices.Select(q => q.Index).OrderBy(q => q).ToArray(); var match = faces.FirstOrDefault(p => { var dist = p.Vertices.Select(q => q.Index).OrderBy(q => q) .Zip(tIndices) .Select(q => (q.First - q.Second) * (q.First - q.Second)) .Sum(); return(dist == 0); }); if (match != null) { return(match); } var t2 = new Tri3(a, b, c, faces.Count()); faces.Add(t2); return(t2); }
public BothTri(Tri3 space, Transform spaceToPaper) { Space = space; Index = space.Index; Paper = spaceToPaper.Apply(space).AsTri2(); SpaceToPaper = spaceToPaper; paperToSpace = spaceToPaper.Inv(); }
internal Tri3 Apply(Tri3 t) { if (t == null) { return(t); } return(t .Apply(rot) .Translate(tran)); }
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); }
internal Vec3[] CommonEdge(Tri3 prev) { var vts1 = this.Vertices.Select(p => p.Index).ToArray(); var vts2 = prev.Vertices.Select(p => p.Index).ToArray(); var match = vts1.Where(p => vts2.Contains(p)).OrderBy(p => p); if (match.Count() != 2) { throw new InvalidOperationException(); } return(this.Vertices.Where(p => match.Contains(p.Index)).ToArray()); }
public DualEdge(Tri3 v1, Tri3 v2) { Vertices = new Tri3[] { v1, v2 }; VertexIndices = new int[] { v1.Index, v2.Index }; var x = VertexIndices.OrderBy(p => p).ToArray(); if (x[1] > 60000) { throw new ArgumentOutOfRangeException(); } Index = 60000 * x[0] + x[1]; }
private static IEnumerable <BothTri> Flatten( Mesh mesh, SpanningTree spanTree, Tri3 node) { return(FlattenWorker( mesh, spanTree, node, null, new HashSet <int>(), 0)); }
internal double Dist(Tri3 t) { var vert3 = Vertices.ToArray(); var vertexCombos = new List <Vec3[]>() { new Vec3[] { vert3[0], vert3[1], vert3[2] }, new Vec3[] { vert3[0], vert3[2], vert3[1] }, new Vec3[] { vert3[1], vert3[0], vert3[2] }, new Vec3[] { vert3[1], vert3[2], vert3[1] }, new Vec3[] { vert3[2], vert3[0], vert3[1] }, new Vec3[] { vert3[2], vert3[1], vert3[0] }, }; var tVert3 = t.Vertices.ToArray(); var minDelta = vertexCombos .Min(p => p[0].Subtract(tVert3[0]).LenSq + p[1].Subtract(tVert3[1]).LenSq + p[2].Subtract(tVert3[2]).LenSq); return(minDelta); }
private IEnumerable <Tri3> PathWorker(Tri3 cur, int destIndex, HashSet <int> visited) { if (!visited.Contains(cur.Index)) { visited.Add(cur.Index); var ret = new Tri3[] { cur }; if (cur.Index == destIndex) { return(ret); } foreach (var fi in GetConnectedNodes(cur)) { var p = PathWorker(fi, destIndex, visited); if (p != null) { return(ret.Union(p)); } } } return(null); }
internal double Dist(Tri3 t) { return(AsTri3().Dist(t)); }
public SterileTri3(Tri3 source, int tabId, Vec3[] common) : base(source.A, source.B, source.C, -source.Index) { TabId = tabId; Common = common; }
public SpanningTree(Tri3 face) { Edges = new DualEdge[0]; Faces = new Tri3[] { face }; faceLookup = Faces.ToDictionary(p => p.Index, p => p); }
public Tri3Ext(Tri3 t, int tabId) : base(t.A, t.B, t.C, t.Index) { TabId = tabId; }
internal Tri3 Add(Tri3 t) { return(AddFace(t.A, t.B, t.C)); }
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); }