예제 #1
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);
        }
예제 #2
0
 private static IEnumerable <BothTri> Flatten(
     Mesh mesh,
     SpanningTree spanTree,
     Tri3 node)
 {
     return(FlattenWorker(
                mesh,
                spanTree,
                node,
                null,
                new HashSet <int>(),
                0));
 }
예제 #3
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);
        }
예제 #4
0
        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);
        }