Exemplo n.º 1
0
        private static bool SlicePolygonInternal(Polygon p, Circle c, out List <Polygon> output)
        {
            // Our approach:
            // (1) Find the intersection points, and splice them into the polygon. (splicing in is the main diff from old algorithm.)
            // (2) From each intersection point, walk the polygon.
            // (3) When you are at an intersection point, always turn left, which may involve adding a new segment of the slicing circle.
            // (4) We'll have to check for duplicate polygons in the resulting list, and remove them.

            output = new List <Polygon>();

            // We must be a digon at a minimum.
            if (p.NumSides < 2)
            {
                return(false);
            }

            // XXX - Code assumes well-formed polygon: closed (has connected segments),
            //		 no repeated vertices.  Assert all this?
            // Code also assumes CCW orientation.
            if (!p.Orientation)
            {
                p.Reverse();
            }

            // Cycle through our segments and splice in all the intersection points.
            Polygon diced = new Polygon();
            List <IntersectionPoint> iPoints = new List <IntersectionPoint>();

            for (int i = 0; i < p.NumSides; i++)
            {
                Segment    s             = p.Segments[i];
                Vector3D[] intersections = c.GetIntersectionPoints(s);
                if (intersections == null)
                {
                    continue;
                }

                switch (intersections.Length)
                {
                case 0:
                {
                    diced.Segments.Add(s);
                    break;
                }

                case 1:
                {
                    // ZZZ - check here to see if it is a tangent iPoint?  Not sure if we need to do this.
                    diced.Segments.Add(SplitHelper(s, intersections[0], diced, iPoints));
                    break;
                }

                case 2:
                {
                    // We need to ensure the intersection points are ordered correctly on the segment.
                    Vector3D i1 = intersections[0], i2 = intersections[1];
                    if (!s.Ordered(i1, i2))
                    {
                        Utils.SwapPoints(ref i1, ref i2);
                    }

                    Segment secondToSplit = SplitHelper(s, i1, diced, iPoints);
                    Segment segmentToAdd  = SplitHelper(secondToSplit, i2, diced, iPoints);
                    diced.Segments.Add(segmentToAdd);
                    break;
                }

                default:
                    Debug.Assert(false);
                    return(false);
                }
            }

            // NOTE: We've been careful to avoid adding duplicates to iPoints.

            // Are we done? (no intersections)
            if (0 == iPoints.Count)
            {
                output.Add(p);
                return(true);
            }

            // We don't yet deal with tangengies,
            // but we're going to let this case slip through as unsliced.
            if (1 == iPoints.Count)
            {
                output.Add(p);
                return(true);
            }

            // We don't yet deal with tangencies.
            // We're going to fail on this case, because it could be more problematic.
            if (Utils.Odd(iPoints.Count))
            {
                Debug.Assert(false);
                return(false);
            }

            if (iPoints.Count > 2)
            {
                // We may need our intersection points to all be reorded by 1.
                // This is so that when walking from i1 -> i2 along c, we will be moving through the interior of the polygon.
                // ZZZ - This may need to change when hack in SplicedArc is improved.
                int      dummy    = 0;
                Segment  testArc  = SmallerSplicedArc(c, iPoints, ref dummy, true, ref dummy);
                Vector3D midpoint = testArc.Midpoint;

                if (!p.IsPointInsideParanoid(midpoint))
                {
                    IntersectionPoint t = iPoints[0];
                    iPoints.RemoveAt(0);
                    iPoints.Add(t);
                }
            }

            //
            // From each intersection point, walk the polygon.
            //
            int numPairs = iPoints.Count / 2;

            for (int i = 0; i < numPairs; i++)
            {
                int pair = i;
                output.Add(WalkPolygon(p, diced, c, pair, iPoints, true));
                output.Add(WalkPolygon(p, diced, c, pair, iPoints, false));
            }

            //
            // Recalc centers.
            //
            foreach (Polygon poly in output)
            {
                poly.Center = poly.CentroidApprox;
            }

            //
            // Remove duplicate polygons.
            //
            output = output.Distinct(new PolygonEqualityComparer()).ToList();

            return(true);
        }