예제 #1
0
        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);
        }
예제 #2
0
 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());
 }
예제 #3
0
 public Tri3(Tri3 t, int index)
 {
     A     = t.A;
     B     = t.B;
     C     = t.C;
     Index = index;
 }
예제 #4
0
        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);
        }
예제 #5
0
 public BothTri(Tri3 space, Transform spaceToPaper)
 {
     Space        = space;
     Index        = space.Index;
     Paper        = spaceToPaper.Apply(space).AsTri2();
     SpaceToPaper = spaceToPaper;
     paperToSpace = spaceToPaper.Inv();
 }
예제 #6
0
 internal Tri3 Apply(Tri3 t)
 {
     if (t == null)
     {
         return(t);
     }
     return(t
            .Apply(rot)
            .Translate(tran));
 }
예제 #7
0
        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);
        }
예제 #8
0
        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());
        }
예제 #9
0
        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];
        }
예제 #10
0
 private static IEnumerable <BothTri> Flatten(
     Mesh mesh,
     SpanningTree spanTree,
     Tri3 node)
 {
     return(FlattenWorker(
                mesh,
                spanTree,
                node,
                null,
                new HashSet <int>(),
                0));
 }
예제 #11
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);
        }
예제 #12
0
        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);
        }
예제 #13
0
 internal double Dist(Tri3 t)
 {
     return(AsTri3().Dist(t));
 }
예제 #14
0
 public SterileTri3(Tri3 source, int tabId, Vec3[] common) : base(source.A, source.B, source.C, -source.Index)
 {
     TabId  = tabId;
     Common = common;
 }
예제 #15
0
 public SpanningTree(Tri3 face)
 {
     Edges      = new DualEdge[0];
     Faces      = new Tri3[] { face };
     faceLookup = Faces.ToDictionary(p => p.Index, p => p);
 }
예제 #16
0
 public Tri3Ext(Tri3 t, int tabId) : base(t.A, t.B, t.C, t.Index)
 {
     TabId = tabId;
 }
예제 #17
0
 internal Tri3 Add(Tri3 t)
 {
     return(AddFace(t.A, t.B, t.C));
 }
예제 #18
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);
        }