Exemplo n.º 1
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);
        }
Exemplo n.º 2
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);
                    }
                }
            }
        }