Beispiel #1
0
        public static void TraceDifference(
            BLoop loopA,
            BLoop loopB,
            BLoop loopInto,
            bool removeInputs = true)
        {
            List <BNode> islsA = loopA.GetIslands(IslandTypeRequest.Closed);
            List <BNode> islsB = loopB.GetIslands(IslandTypeRequest.Closed);

            TraceDifference(islsA, islsB, loopInto, removeInputs);
        }
Beispiel #2
0
        public static void TraceIntersection(
            BLoop loopA,
            BLoop loopB,
            BLoop loopInto,
            List <BNode> outShapes,
            bool removeInputs = true)
        {
            List <BNode> islsA = loopA.GetIslands(IslandTypeRequest.Closed);
            List <BNode> islsB = loopB.GetIslands(IslandTypeRequest.Closed);

            TraceIntersection(islsA, islsB, loopInto, outShapes, removeInputs);
        }
Beispiel #3
0
        /// <summary>
        /// Performs a generic per-island operation between the islands contained in two loops.
        /// </summary>
        /// <remarks>Not a generic function - only meant for specific boolean reflow operations.</remarks>
        /// <param name="left">The collection of islands for the operation.</param>
        /// <param name="right">The other collection of islands for the operation.</param>
        /// <param name="op">Function delegate containing the boolean operation.</param>
        /// <param name="onIslA">An output node that exists on the remaining path(s).</param>
        /// <param name="removeRight">If true, remove the contents of the right loop parameter after
        /// the operation.</param>
        public static void PerIslandBoolean(BLoop left, BLoop right, BooleanImpl op, out BNode onIslA, bool removeRight)
        {
            if (left == right || left == null || right == null)
            {
                onIslA = left.nodes[0];
                return;
            }

            onIslA = null;

            // If we're doing a boolean, it's no longer a generated shape - even if it ends
            // up untouched.
            if (left.shape != null)
            {
                left.shape.shapeGenerator = null;
            }

            right.shape = null;

            List <BNode> islandsA = left.GetIslands(IslandTypeRequest.Closed);
            List <BNode> islandB  = right.GetIslands(IslandTypeRequest.Closed);


            foreach (BNode islA in islandsA)
            {
                onIslA = islA;
                foreach (BNode islB in islandB)
                {
                    List <BNode> islandSegsA = new List <BNode>(islA.Travel());
                    List <BNode> islandSegsB = new List <BNode>(islB.Travel());

                    op(left, islandSegsA, islandSegsB, out onIslA);
                }
            }
            if (removeRight == true)
            {
                RemoveLoop(right, true);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Given two loops, calculate information on where they collide with each other.
        ///
        /// Does not handle self intersections.
        /// </summary>
        /// <param name="loopA">The loop containing the geometry for the left path.</param>
        /// <param name="loopB">The loop containing the geometry for the right path.</param>
        /// <returns>The points where segments from the left path and the right path intersect
        /// each other.</returns>
        /// <remarks>The terms "left" path and "right" path do not specifically refer to left and right,
        /// but instead are used to different the two paths from each other.</remarks>
        public static List <Utils.BezierSubdivSample> GetLoopCollisionInfo(
            BLoop loopA,
            BLoop loopB)
        {
            List <BNode> islandsA = loopA.GetIslands();
            List <BNode> islandsB = loopB.GetIslands();

            List <Utils.BezierSubdivSample> collisions = new List <Utils.BezierSubdivSample>();

            foreach (BNode isA in islandsA)
            {
                BNode.EndpointQuery eqA = isA.GetPathLeftmost();
                // Only closed loops count
                if (eqA.result == BNode.EndpointResult.SuccessfulEdge)
                {
                    continue;
                }

                List <BNode> segsA = new List <BNode>(eqA.Enumerate());
                foreach (BNode isB in islandsB)
                {
                    BNode.EndpointQuery eqB = isB.GetPathLeftmost();
                    // Only closed loops count
                    if (eqB.result == BNode.EndpointResult.SuccessfulEdge)
                    {
                        continue;
                    }

                    List <BNode> segsB = new List <BNode>(eqB.Enumerate());

                    GetLoopCollisionInfo(segsA, segsB, collisions);
                }
            }

            Utils.BezierSubdivSample.CleanIntersectionList(collisions);
            return(collisions);
        }
Beispiel #5
0
        /// <summary>
        /// Perform an intersection operation between two islands using a reflow strategy.
        /// </summary>
        /// <param name="left">The collection of islands for the operation.</param>
        /// <param name="right">The other collection of islands for the operation.</param>
        /// <param name="onIslA">An output node that exists on the remaining path(s).</param>
        /// <param name="removeRight">If true, remove the contents of the right loop parameter after
        /// the operation.</param>
        public static void Intersection(BLoop left, BLoop right, out BNode onIslA, bool removeRight)
        {
            onIslA = null;
            // Sanity check on geometry, try to union each loop with its islands
            // so there's no overlapping regions within them.

            List <BNode> rightIslands = right.GetIslands();

            if (rightIslands.Count >= 2)
            {
                for (int i = 1; i < rightIslands.Count; ++i)
                {
                    List <BNode> RSegsA = new List <BNode>(rightIslands[0].Travel());
                    List <BNode> RSegsB = new List <BNode>(rightIslands[i].Travel());

                    Union(right, RSegsA, RSegsB, out onIslA, true);
                }
            }

            List <BNode> leftIslands = left.GetIslands();

            if (leftIslands.Count >= 2)
            {
                for (int i = 1; i < leftIslands.Count; ++i)
                {
                    List <BNode> LSegsA = new List <BNode>(leftIslands[0].Travel());
                    List <BNode> LSegsB = new List <BNode>(leftIslands[i].Travel());

                    Union(right, LSegsA, LSegsB, out onIslA, true);
                }
            }

            leftIslands  = left.GetIslands();
            rightIslands = right.GetIslands();

            foreach (BNode leftIsl in leftIslands)
            {
                List <BNode> leftIslandSegs = new List <BNode>(leftIsl.Travel());
                foreach (BNode rightIsl in rightIslands)
                {
                    List <BNode> rightIslandSegs = new List <BNode>(rightIsl.Travel());

                    Intersection(
                        left,
                        leftIslandSegs,
                        rightIslandSegs,
                        out onIslA);
                }
            }

            foreach (BNode bn in leftIslands)
            {
                bn.RemoveIsland(false);
            }

            foreach (BNode bn in rightIslands)
            {
                bn.RemoveIsland(false);
            }

            // TODO: For each island left, we need to see if there's
            // any shapes being fully contained by the other side.

            if (removeRight == true)
            {
                right.Clear();
                RemoveLoop(right, true);
            }
        }
Beispiel #6
0
        public static void Edgify(BLoop loop, float pushOut, float pullIn = 0.0f)
        {
            if (pushOut == 0.0f && pullIn == 0.0f)
            {
                return;
            }

            List <BNode> islands = loop.GetIslands();

            foreach (BNode bisl in islands)
            {
                // This will probably just give us bisl back, but it that's the case, then it should
                // be minimal overhead - just to be safe though, and to see what kind of connectivity we're dealing with.
                BNode.EndpointQuery eq = bisl.GetPathLeftmost();

                List <BNode>          origs      = new List <BNode>();
                List <BNode>          copies     = new List <BNode>();
                List <InflationCache> inflations = new List <InflationCache>();
                foreach (BNode it in eq.Enumerate())
                {
                    origs.Add(it);

                    BNode cpy = new BNode(loop, it, false, true);
                    copies.Add(cpy);

                    loop.nodes.Add(cpy);

                    InflationCache ic = new InflationCache();
                    it.GetInflateDirection(out ic.selfInf, out ic.inInf, out ic.outInf);
                    inflations.Add(ic);
                }

                // Stitch the new chain - it should have a reverse winding.
                //
                // The loop is a little backwards, but basically we sub instead of add to
                // treat the prev item in the array like the next in the chain.
                for (int i = 1; i < copies.Count; ++i)
                {
                    copies[i].next     = copies[i - 1];
                    copies[i - 1].prev = copies[i];
                }

                int lastIdx = copies.Count - 1;
                if (eq.result == BNode.EndpointResult.Cyclical)
                {
                    // If it was cyclical, it should close in on itself and it should
                    // never touch the original outline;
                    //
                    // Remember we're treating copies in reverse.
                    copies[lastIdx].prev = copies[0];
                    copies[0].next       = copies[lastIdx];
                }
                else
                {
                    // Or else the opposite ends connect to each other.
                    // Remember we're treating copies in reverse.
                    origs[0].prev  = copies[0];
                    copies[0].next = origs[0];

                    origs[lastIdx].next  = copies[lastIdx];
                    copies[lastIdx].prev = origs[lastIdx];

                    origs[0].UseTanIn        = false;
                    origs[lastIdx].UseTanOut = false;
                    copies[0].UseTanOut      = false;
                    copies[lastIdx].UseTanIn = false;
                }

                if (pushOut != 0.0f)
                {
                    // Now that we have copies and connectivity set up, it's time
                    // to apply the thickening
                    for (int i = 0; i < origs.Count; ++i)
                    {
                        // Push out the original
                        origs[i].Pos    += pushOut * inflations[i].selfInf;
                        origs[i].TanIn  += pushOut * (inflations[i].inInf - inflations[i].selfInf);
                        origs[i].TanOut += pushOut * (inflations[i].outInf - inflations[i].selfInf);
                    }
                }

                if (pullIn != 0.0f)
                {
                    // We can optionally pull in the copy
                    for (int i = 0; i < copies.Count; ++i)
                    {
                        copies[i].Pos    += pullIn * inflations[i].selfInf;
                        copies[i].TanIn  += pullIn * (inflations[i].inInf - inflations[i].selfInf);
                        copies[i].TanOut += pullIn * (inflations[i].outInf - inflations[i].selfInf);
                    }
                }
            }
        }