예제 #1
0
        private TEdge AddBoundsToLML(TEdge e)
        {
            Contract.Requires(e != null);
            Contract.Requires(e.Next != null);

            //Starting at the top of one bound we progress to the bottom where there's
            //a local minima. We then go to the top of the next bound. These two bounds
            //form the left and right (or right and left) bounds of the local minima.
            e.NextInLML = null;
            e = e.Next;
            for (; ; )
            {
                if (e.Dx == HORIZONTAL)
                {
                    //nb: proceed through horizontals when approaching from their right,
                    //    but break on horizontal minima if approaching from their left.
                    //    This ensures 'local minima' are always on the left of horizontals.
                    if (e.Next.YTop < e.YTop && e.Next.XBot > e.Prev.XBot)
                        break;
                    if (e.XTop != e.Prev.XBot)
                        SwapX(e);
                    e.NextInLML = e.Prev;
                }
                else if (e.YCurr == e.Prev.YCurr)
                    break;
                else
                    e.NextInLML = e.Prev;
                e = e.Next;
            }

            //e and e.prev are now at a local minima ...
            var newLm = new LocalMinima { Next = null, Y = e.Prev.YBot };

            if (e.Dx == HORIZONTAL) //horizontal edges never start a left bound
            {
                if (e.XBot != e.Prev.XBot)
                    SwapX(e);
                newLm.LeftBound = e.Prev;
                newLm.RightBound = e;
            }
            else if (e.Dx < e.Prev.Dx)
            {
                newLm.LeftBound = e.Prev;
                newLm.RightBound = e;
            }
            else
            {
                newLm.LeftBound = e;
                newLm.RightBound = e.Prev;
            }
            newLm.LeftBound.Side = EdgeSide.Left;
            newLm.RightBound.Side = EdgeSide.Right;
            InsertLocalMinima(newLm);

            for (; ; )
            {
                if (e.Next.YTop == e.YTop && e.Next.Dx != HORIZONTAL)
                    break;
                e.NextInLML = e.Next;
                e = e.Next;
                if (e.Dx == HORIZONTAL && e.XBot != e.Prev.XTop)
                    SwapX(e);
            }
            return e.Next;
        }
예제 #2
0
        private void AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e2 != null);

            TEdge e, prevE;
            if (e2.Dx == HORIZONTAL || (e1.Dx > e2.Dx))
            {
                AddOutPt(e1, pt);
                e2.OutIdx = e1.OutIdx;
                e1.Side = EdgeSide.Left;
                e2.Side = EdgeSide.Right;
                e = e1;
                prevE = e.PrevInAEL == e2 ? e2.PrevInAEL : e.PrevInAEL;
            }
            else
            {
                AddOutPt(e2, pt);
                e1.OutIdx = e2.OutIdx;
                e1.Side = EdgeSide.Right;
                e2.Side = EdgeSide.Left;
                e = e2;
                prevE = e.PrevInAEL == e1 ? e1.PrevInAEL : e.PrevInAEL;
            }

            if (prevE != null && prevE.OutIdx >= 0 &&
                (TopX(prevE, pt.Y) == TopX(e, pt.Y)) &&
                InternalHelpers.SlopesEqual(e, prevE))
                AddJoin(e, prevE, -1, -1);
        }
예제 #3
0
        private void AppendPolygon(TEdge e1, TEdge e2)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e1.OutIdx >= 0 && e1.OutIdx < _polyOuts.Count);
            Contract.Requires(e2 != null);
            Contract.Requires(e2.OutIdx >= 0 && e2.OutIdx < _polyOuts.Count);

            //get the start and ends of both output polygons ...
            var outRec1 = _polyOuts[e1.OutIdx];
            var outRec2 = _polyOuts[e2.OutIdx];

            OutRec holeStateRec;
            if (Param1RightOfParam2(outRec1, outRec2))
                holeStateRec = outRec2;
            else if (Param1RightOfParam2(outRec2, outRec1))
                holeStateRec = outRec1;
            else
                holeStateRec = GetLowermostRec(outRec1, outRec2);

            var p1Lft = outRec1.Pts;
            var p1Rt = p1Lft.Prev;
            var p2Lft = outRec2.Pts;
            var p2Rt = p2Lft.Prev;

            EdgeSide side;
            //join e2 poly onto e1 poly and delete pointers to e2 ...
            if (e1.Side == EdgeSide.Left)
            {
                if (e2.Side == EdgeSide.Left)
                {
                    //z y x a b c
                    ReversePolyPtLinks(p2Lft);
                    p2Lft.Next = p1Lft;
                    p1Lft.Prev = p2Lft;
                    p1Rt.Next = p2Rt;
                    p2Rt.Prev = p1Rt;
                    outRec1.Pts = p2Rt;
                }
                else
                {
                    //x y z a b c
                    p2Rt.Next = p1Lft;
                    p1Lft.Prev = p2Rt;
                    p2Lft.Prev = p1Rt;
                    p1Rt.Next = p2Lft;
                    outRec1.Pts = p2Lft;
                }
                side = EdgeSide.Left;
            }
            else
            {
                if (e2.Side == EdgeSide.Right)
                {
                    //a b c z y x
                    ReversePolyPtLinks(p2Lft);
                    p1Rt.Next = p2Rt;
                    p2Rt.Prev = p1Rt;
                    p2Lft.Next = p1Lft;
                    p1Lft.Prev = p2Lft;
                }
                else
                {
                    //a b c x y z
                    p1Rt.Next = p2Lft;
                    p2Lft.Prev = p1Rt;
                    p1Lft.Prev = p2Rt;
                    p2Rt.Next = p1Lft;
                }
                side = EdgeSide.Right;
            }

            outRec1.BottomPt = null;
            if (holeStateRec == outRec2)
            {
                if (outRec2.FirstLeft != outRec1)
                    outRec1.FirstLeft = outRec2.FirstLeft;
                outRec1.IsHole = outRec2.IsHole;
            }
            outRec2.Pts = null;
            outRec2.BottomPt = null;

            outRec2.FirstLeft = outRec1;

            var okIdx = e1.OutIdx;
            var obsoleteIdx = e2.OutIdx;

            e1.OutIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly
            e2.OutIdx = -1;

            var e = _activeEdges;
            while (e != null)
            {
                if (e.OutIdx == obsoleteIdx)
                {
                    e.OutIdx = okIdx;
                    e.Side = side;
                    break;
                }
                e = e.NextInAEL;
            }
            outRec2.Idx = outRec1.Idx;
        }
예제 #4
0
        private void AddEdgeToSEL(TEdge edge)
        {
            Contract.Requires(edge != null);

            //SEL pointers in PEdge are reused to build a list of horizontal edges.
            //However, we don't need to worry about order with horizontal edge processing.
            if (_sortedEdges == null)
            {
                _sortedEdges = edge;
                edge.PrevInSEL = null;
                edge.NextInSEL = null;
            }
            else
            {
                edge.NextInSEL = _sortedEdges;
                edge.PrevInSEL = null;
                _sortedEdges.PrevInSEL = edge;
                _sortedEdges = edge;
            }
        }
예제 #5
0
        private void AddJoin(TEdge e1, TEdge e2, int e1OutIdx, int e2OutIdx)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e2 != null);

            var jr = new JoinRec {
                Poly1Idx = e1OutIdx >= 0 ? e1OutIdx : e1.OutIdx,
                Pt1A = new IntPoint(e1.XCurr, e1.YCurr),
                Pt1B = new IntPoint(e1.XTop, e1.YTop),
                Poly2Idx = e2OutIdx >= 0 ? e2OutIdx : e2.OutIdx,
                Pt2A = new IntPoint(e2.XCurr, e2.YCurr),
                Pt2B = new IntPoint(e2.XTop, e2.YTop)
            };
            _joins.Add(jr);
        }
예제 #6
0
        protected override void Reset()
        {
            base.Reset();

            _scanbeam = null;
            _activeEdges = null;
            _sortedEdges = null;

            DisposeAllPolyPts();
            var lm = MinimaList;
            while (lm != null)
            {
                InsertScanbeam(lm.Y);
                lm = lm.Next;
            }
        }
예제 #7
0
        private static bool IntersectPoint(TEdge edge1, TEdge edge2, ref IntPoint ip)
        {
            Contract.Requires(edge1 != null);
            Contract.Requires(edge2 != null);

            if (InternalHelpers.SlopesEqual(edge1, edge2))
            {
                ip = new IntPoint(
                    ip.X,
                    edge2.YBot > edge1.YBot ? edge2.YBot : edge1.YBot
                );

                return false;
            }
            else if (edge1.Dx == 0)
            {
                ip = new IntPoint(
                    edge1.XBot,
                    edge2.Dx == HORIZONTAL ? edge2.YBot : InternalHelpers.Round(ip.X / edge2.Dx + (edge2.YBot - edge2.XBot / edge2.Dx))
                );
            }
            else if (edge2.Dx == 0)
            {
                ip = new IntPoint(
                    edge2.XBot,
                    edge1.Dx == HORIZONTAL ? edge1.YBot : InternalHelpers.Round(ip.X / edge1.Dx + (edge1.YBot - edge1.XBot / edge1.Dx))
                );
            }
            else
            {
                var b1 = edge1.XBot - edge1.YBot * edge1.Dx;
                var b2 = edge2.XBot - edge2.YBot * edge2.Dx;
                var q = (b2 - b1) / (edge1.Dx - edge2.Dx);

                ip = new IntPoint(
                    Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx) ? InternalHelpers.Round(edge1.Dx * q + b1) : InternalHelpers.Round(edge2.Dx * q + b2),
                    InternalHelpers.Round(q)
                );
            }

            if (ip.Y < edge1.YTop || ip.Y < edge2.YTop)
            {
                if (edge1.YTop > edge2.YTop)
                {
                    ip = new IntPoint(
                        edge1.XTop,
                        edge1.YTop
                    );
                    return TopX(edge2, edge1.YTop) < edge1.XTop;
                }
                else
                {
                    ip = new IntPoint(
                        edge2.XTop,
                        edge2.YTop
                    );
                    return TopX(edge1, edge2.YTop) > edge2.XTop;
                }
            }
            else
                return true;
        }
예제 #8
0
        private void InsertIntersectNode(TEdge e1, TEdge e2, IntPoint pt)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e2 != null);

            var newNode = new IntersectNode {
                Edge1 = e1,
                Edge2 = e2,
                Pt = pt,
                Next = null
            };
            if (_intersectNodes == null)
                _intersectNodes = newNode;
            else if (newNode.Pt.Y > _intersectNodes.Pt.Y)
            {
                newNode.Next = _intersectNodes;
                _intersectNodes = newNode;
            }
            else
            {
                var iNode = _intersectNodes;
                while (iNode.Next != null && newNode.Pt.Y < iNode.Next.Pt.Y)
                    iNode = iNode.Next;
                newNode.Next = iNode.Next;
                iNode.Next = newNode;
            }
        }
예제 #9
0
        private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, Protects protects)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e2 != null);

            //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before
            //e2 in AEL except when e1 is being inserted at the intersection point ...

            var e1Stops = (Protects.Left & protects) == 0 && e1.NextInLML == null && e1.XTop == pt.X && e1.YTop == pt.Y;
            var e2Stops = (Protects.Right & protects) == 0 && e2.NextInLML == null && e2.XTop == pt.X && e2.YTop == pt.Y;
            var e1Contributing = e1.OutIdx >= 0;
            var e2Contributing = e2.OutIdx >= 0;

            //update winding counts...
            //assumes that e1 will be to the right of e2 ABOVE the intersection
            if (e1.PolyType == e2.PolyType)
            {
                if (IsEvenOddFillType(e1))
                {
                    var oldE1WindCnt = e1.WindCnt;
                    e1.WindCnt = e2.WindCnt;
                    e2.WindCnt = oldE1WindCnt;
                }
                else
                {
                    if (e1.WindCnt + e2.WindDelta == 0)
                        e1.WindCnt = -e1.WindCnt;
                    else
                        e1.WindCnt += e2.WindDelta;
                    if (e2.WindCnt - e1.WindDelta == 0)
                        e2.WindCnt = -e2.WindCnt;
                    else
                        e2.WindCnt -= e1.WindDelta;
                }
            }
            else
            {
                if (!IsEvenOddFillType(e2))
                    e1.WindCnt2 += e2.WindDelta;
                else
                    e1.WindCnt2 = e1.WindCnt2 == 0 ? 1 : 0;
                if (!IsEvenOddFillType(e1))
                    e2.WindCnt2 -= e1.WindDelta;
                else
                    e2.WindCnt2 = e2.WindCnt2 == 0 ? 1 : 0;
            }

            PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
            if (e1.PolyType == PolyType.Subject)
            {
                e1FillType = _subjFillType;
                e1FillType2 = _clipFillType;
            }
            else
            {
                e1FillType = _clipFillType;
                e1FillType2 = _subjFillType;
            }
            if (e2.PolyType == PolyType.Subject)
            {
                e2FillType = _subjFillType;
                e2FillType2 = _clipFillType;
            }
            else
            {
                e2FillType = _clipFillType;
                e2FillType2 = _subjFillType;
            }

            int e1Wc, e2Wc;
            switch (e1FillType)
            {
                case PolyFillType.Positive:
                    e1Wc = e1.WindCnt;
                    break;
                case PolyFillType.Negative:
                    e1Wc = -e1.WindCnt;
                    break;
                default:
                    e1Wc = Math.Abs(e1.WindCnt);
                    break;
            }
            switch (e2FillType)
            {
                case PolyFillType.Positive:
                    e2Wc = e2.WindCnt;
                    break;
                case PolyFillType.Negative:
                    e2Wc = -e2.WindCnt;
                    break;
                default:
                    e2Wc = Math.Abs(e2.WindCnt);
                    break;
            }

            if (e1Contributing && e2Contributing)
            {
                if (e1Stops || e2Stops ||
                    (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
                    (e1.PolyType != e2.PolyType && _clipType != ClipType.Xor))
                    AddLocalMaxPoly(e1, e2, pt);
                else
                {
                    AddOutPt(e1, pt);
                    AddOutPt(e2, pt);
                    InternalHelpers.Swap(ref e1.Side, ref e2.Side);
                    InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx);
                }
            }
            else if (e1Contributing)
            {
                if (e2Wc == 0 || e2Wc == 1)
                {
                    AddOutPt(e1, pt);
                    InternalHelpers.Swap(ref e1.Side, ref e2.Side);
                    InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx);
                }

            }
            else if (e2Contributing)
            {
                if (e1Wc == 0 || e1Wc == 1)
                {
                    AddOutPt(e2, pt);
                    InternalHelpers.Swap(ref e1.Side, ref e2.Side);
                    InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx);
                }
            }
            else if ((e1Wc == 0 || e1Wc == 1) &&
                     (e2Wc == 0 || e2Wc == 1) && !e1Stops && !e2Stops)
            {
                //neither edge is currently contributing ...
                long e1Wc2, e2Wc2;
                switch (e1FillType2)
                {
                    case PolyFillType.Positive:
                        e1Wc2 = e1.WindCnt2;
                        break;
                    case PolyFillType.Negative:
                        e1Wc2 = -e1.WindCnt2;
                        break;
                    default:
                        e1Wc2 = Math.Abs(e1.WindCnt2);
                        break;
                }
                switch (e2FillType2)
                {
                    case PolyFillType.Positive:
                        e2Wc2 = e2.WindCnt2;
                        break;
                    case PolyFillType.Negative:
                        e2Wc2 = -e2.WindCnt2;
                        break;
                    default:
                        e2Wc2 = Math.Abs(e2.WindCnt2);
                        break;
                }

                if (e1.PolyType != e2.PolyType)
                    AddLocalMinPoly(e1, e2, pt);
                else if (e1Wc == 1 && e2Wc == 1)
                    switch (_clipType)
                    {
                        case ClipType.Intersection:
                            if (e1Wc2 > 0 && e2Wc2 > 0)
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.Union:
                            if (e1Wc2 <= 0 && e2Wc2 <= 0)
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.Difference:
                            if (((e1.PolyType == PolyType.Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
                                ((e1.PolyType == PolyType.Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.Xor:
                            AddLocalMinPoly(e1, e2, pt);
                            break;
                    }
                else
                    InternalHelpers.Swap(ref e1.Side, ref e2.Side);
            }

            if ((e1Stops != e2Stops) &&
                ((e1Stops && (e1.OutIdx >= 0)) || (e2Stops && (e2.OutIdx >= 0))))
            {
                InternalHelpers.Swap(ref e1.Side, ref e2.Side);
                InternalHelpers.Swap(ref e1.OutIdx, ref e2.OutIdx);
            }

            //finally, delete any non-contributing maxima edges  ...
            if (e1Stops)
                DeleteFromAEL(e1);
            if (e2Stops)
                DeleteFromAEL(e2);
        }
예제 #10
0
        private void DoMaxima(TEdge e, long topY)
        {
            Contract.Requires(e != null);
            Contract.Requires(e.Next != null);

            var eMaxPair = InternalHelpers.GetMaximaPair(e);
            var x = e.XTop;
            var eNext = e.NextInAEL;
            while (eNext != eMaxPair)
            {
                if (eNext == null)
                    throw new ClipperException("DoMaxima error");
                IntersectEdges(e, eNext, new IntPoint(x, topY), Protects.Both);
                SwapPositionsInAEL(e, eNext);
                eNext = e.NextInAEL;
            }
            if (e.OutIdx < 0 && eMaxPair.OutIdx < 0)
            {
                DeleteFromAEL(e);
                DeleteFromAEL(eMaxPair);
            }
            else if (e.OutIdx >= 0 && eMaxPair.OutIdx >= 0)
            {
                IntersectEdges(e, eMaxPair, new IntPoint(x, topY), Protects.None);
            }
            else
                throw new ClipperException("DoMaxima error");
        }
예제 #11
0
        private void InsertEdgeIntoAEL(TEdge edge)
        {
            Contract.Requires(edge != null);

            edge.PrevInAEL = null;
            edge.NextInAEL = null;
            if (_activeEdges == null)
            {
                _activeEdges = edge;
            }
            else if (E2InsertsBeforeE1(_activeEdges, edge))
            {
                edge.NextInAEL = _activeEdges;
                _activeEdges.PrevInAEL = edge;
                _activeEdges = edge;
            }
            else
            {
                var e = _activeEdges;
                while (e.NextInAEL != null && !E2InsertsBeforeE1(e.NextInAEL, edge))
                    e = e.NextInAEL;
                edge.NextInAEL = e.NextInAEL;
                if (e.NextInAEL != null)
                    e.NextInAEL.PrevInAEL = edge;
                edge.PrevInAEL = e;
                e.NextInAEL = edge;
            }
        }
예제 #12
0
        private void DeleteFromSEL(TEdge e)
        {
            Contract.Requires(e != null);

            var selPrev = e.PrevInSEL;
            var selNext = e.NextInSEL;
            if (selPrev == null && selNext == null && (e != _sortedEdges))
                return; //already deleted
            if (selPrev != null)
                selPrev.NextInSEL = selNext;
            else
                _sortedEdges = selNext;
            if (selNext != null)
                selNext.PrevInSEL = selPrev;
            e.NextInSEL = null;
            e.PrevInSEL = null;
        }
예제 #13
0
        private void DeleteFromAEL(TEdge e)
        {
            Contract.Requires(e != null);

            var aelPrev = e.PrevInAEL;
            var aelNext = e.NextInAEL;
            if (aelPrev == null && aelNext == null && (e != _activeEdges))
                return; //already deleted
            if (aelPrev != null)
                aelPrev.NextInAEL = aelNext;
            else
                _activeEdges = aelNext;
            if (aelNext != null)
                aelNext.PrevInAEL = aelPrev;
            e.NextInAEL = null;
            e.PrevInAEL = null;
        }
예제 #14
0
 private void CopyAELToSEL()
 {
     var e = _activeEdges;
     _sortedEdges = e;
     while (e != null)
     {
         e.PrevInSEL = e.PrevInAEL;
         e.NextInSEL = e.NextInAEL;
         e = e.NextInAEL;
     }
 }
예제 #15
0
        private void SwapPositionsInSEL(TEdge edge1, TEdge edge2)
        {
            Contract.Requires(edge1 != null);
            Contract.Requires(edge2 != null);

            if (edge1.NextInSEL == null && edge1.PrevInSEL == null)
                return;
            if (edge2.NextInSEL == null && edge2.PrevInSEL == null)
                return;

            if (edge1.NextInSEL == edge2)
            {
                var next = edge2.NextInSEL;
                if (next != null)
                    next.PrevInSEL = edge1;
                var prev = edge1.PrevInSEL;
                if (prev != null)
                    prev.NextInSEL = edge2;
                edge2.PrevInSEL = prev;
                edge2.NextInSEL = edge1;
                edge1.PrevInSEL = edge2;
                edge1.NextInSEL = next;
            }
            else if (edge2.NextInSEL == edge1)
            {
                var next = edge1.NextInSEL;
                if (next != null)
                    next.PrevInSEL = edge2;
                var prev = edge2.PrevInSEL;
                if (prev != null)
                    prev.NextInSEL = edge1;
                edge1.PrevInSEL = prev;
                edge1.NextInSEL = edge2;
                edge2.PrevInSEL = edge1;
                edge2.NextInSEL = next;
            }
            else
            {
                var next = edge1.NextInSEL;
                var prev = edge1.PrevInSEL;
                edge1.NextInSEL = edge2.NextInSEL;
                if (edge1.NextInSEL != null)
                    edge1.NextInSEL.PrevInSEL = edge1;
                edge1.PrevInSEL = edge2.PrevInSEL;
                if (edge1.PrevInSEL != null)
                    edge1.PrevInSEL.NextInSEL = edge1;
                edge2.NextInSEL = next;
                if (edge2.NextInSEL != null)
                    edge2.NextInSEL.PrevInSEL = edge2;
                edge2.PrevInSEL = prev;
                if (edge2.PrevInSEL != null)
                    edge2.PrevInSEL.NextInSEL = edge2;
            }

            if (edge1.PrevInSEL == null)
                _sortedEdges = edge1;
            else if (edge2.PrevInSEL == null)
                _sortedEdges = edge2;
        }
예제 #16
0
        private bool IsContributing(TEdge edge)
        {
            Contract.Requires(edge != null);

            PolyFillType pft, pft2;
            if (edge.PolyType == PolyType.Subject)
            {
                pft = _subjFillType;
                pft2 = _clipFillType;
            }
            else
            {
                pft = _clipFillType;
                pft2 = _subjFillType;
            }

            switch (pft)
            {
                case PolyFillType.EvenOdd:
                case PolyFillType.NonZero:
                    if (Math.Abs(edge.WindCnt) != 1)
                        return false;
                    break;
                case PolyFillType.Positive:
                    if (edge.WindCnt != 1)
                        return false;
                    break;
                case PolyFillType.Negative:
                    if (edge.WindCnt != -1)
                        return false;
                    break;
                default:
                    throw new InvalidOperationException($"Unknown polyFillType '{pft}'");
            }

            switch (_clipType)
            {
                case ClipType.Intersection:
                    switch (pft2)
                    {
                        case PolyFillType.EvenOdd:
                        case PolyFillType.NonZero:
                            return edge.WindCnt2 != 0;
                        case PolyFillType.Positive:
                            return edge.WindCnt2 > 0;
                        default:
                            return edge.WindCnt2 < 0;
                    }
                case ClipType.Union:
                    switch (pft2)
                    {
                        case PolyFillType.EvenOdd:
                        case PolyFillType.NonZero:
                            return edge.WindCnt2 == 0;
                        case PolyFillType.Positive:
                            return edge.WindCnt2 <= 0;
                        default:
                            return edge.WindCnt2 >= 0;
                    }
                case ClipType.Difference:
                    if (edge.PolyType == PolyType.Subject)
                        switch (pft2)
                        {
                            case PolyFillType.EvenOdd:
                            case PolyFillType.NonZero:
                                return edge.WindCnt2 == 0;
                            case PolyFillType.Positive:
                                return edge.WindCnt2 <= 0;
                            default:
                                return edge.WindCnt2 >= 0;
                        }
                    else
                        switch (pft2)
                        {
                            case PolyFillType.EvenOdd:
                            case PolyFillType.NonZero:
                                return edge.WindCnt2 != 0;
                            case PolyFillType.Positive:
                                return edge.WindCnt2 > 0;
                            default:
                                return edge.WindCnt2 < 0;
                        }
            }
            return true;
        }
예제 #17
0
        private void UpdateEdgeIntoAEL(ref TEdge e)
        {
            Contract.Requires(e != null);

            if (e.NextInLML == null)
                throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
            var aelPrev = e.PrevInAEL;
            var aelNext = e.NextInAEL;
            e.NextInLML.OutIdx = e.OutIdx;
            if (aelPrev != null)
                aelPrev.NextInAEL = e.NextInLML;
            else
                _activeEdges = e.NextInLML;
            if (aelNext != null)
                aelNext.PrevInAEL = e.NextInLML;
            e.NextInLML.Side = e.Side;
            e.NextInLML.WindDelta = e.WindDelta;
            e.NextInLML.WindCnt = e.WindCnt;
            e.NextInLML.WindCnt2 = e.WindCnt2;
            e = e.NextInLML;
            e.PrevInAEL = aelPrev;
            e.NextInAEL = aelNext;
            if (e.Dx != HORIZONTAL)
                InsertScanbeam(e.YTop);
        }
예제 #18
0
        private bool IsEvenOddFillType(TEdge edge)
        {
            Contract.Requires(edge != null);

            if (edge.PolyType == PolyType.Subject)
                return _subjFillType == PolyFillType.EvenOdd;
            else
                return _clipFillType == PolyFillType.EvenOdd;
        }
예제 #19
0
        private static bool E2InsertsBeforeE1(TEdge e1, TEdge e2)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e2 != null);

            if (e2.XCurr == e1.XCurr)
            {
                if (e2.YTop > e1.YTop)
                    return e2.XTop < TopX(e1, e2.YTop);
                else
                    return e1.XTop > TopX(e2, e1.YTop);
            }
            else
                return e2.XCurr < e1.XCurr;
        }
예제 #20
0
 private bool IsTopHorz(TEdge horzEdge, double xPos)
 {
     var e = _sortedEdges;
     while (e != null)
     {
         if ((xPos >= Math.Min(e.XCurr, e.XTop)) && (xPos <= Math.Max(e.XCurr, e.XTop)))
             return false;
         e = e.NextInSEL;
     }
     return true;
 }
예제 #21
0
        private static long TopX(TEdge edge, long currentY)
        {
            Contract.Requires(edge != null);

            if (currentY == edge.YTop)
                return edge.XTop;
            return edge.XBot + InternalHelpers.Round(edge.Dx * (currentY - edge.YBot));
        }
예제 #22
0
        private void ProcessHorizontal(TEdge horzEdge)
        {
            Contract.Requires(horzEdge != null);

            Direction direction;
            long horzLeft, horzRight;

            if (horzEdge.XCurr < horzEdge.XTop)
            {
                horzLeft = horzEdge.XCurr;
                horzRight = horzEdge.XTop;
                direction = Direction.LeftToRight;
            }
            else
            {
                horzLeft = horzEdge.XTop;
                horzRight = horzEdge.XCurr;
                direction = Direction.RightToLeft;
            }

            var eMaxPair = horzEdge.NextInLML != null ? null : InternalHelpers.GetMaximaPair(horzEdge);

            var e = InternalHelpers.GetNextInAEL(horzEdge, direction);
            while (e != null)
            {
                if (e.XCurr == horzEdge.XTop && eMaxPair == null)
                {
                    if (InternalHelpers.SlopesEqual(e, horzEdge.NextInLML))
                    {
                        //if output polygons share an edge, they'll need joining later ...
                        if (horzEdge.OutIdx >= 0 && e.OutIdx >= 0)
                            AddJoin(horzEdge.NextInLML, e, horzEdge.OutIdx, -1);
                        break; //we've reached the end of the horizontal line
                    }
                    else if (e.Dx < horzEdge.NextInLML.Dx)
                        //we really have got to the end of the intermediate horz edge so quit.
                        //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal.
                        break;
                }

                var eNext = InternalHelpers.GetNextInAEL(e, direction);
                if (eMaxPair != null ||
                    ((direction == Direction.LeftToRight) && (e.XCurr < horzRight)) ||
                    ((direction == Direction.RightToLeft) && (e.XCurr > horzLeft)))
                {
                    //so far we're still in range of the horizontal edge

                    if (e == eMaxPair)
                    {
                        //horzEdge is evidently a maxima horizontal and we've arrived at its end.
                        if (direction == Direction.LeftToRight)
                            IntersectEdges(horzEdge, e, new IntPoint(e.XCurr, horzEdge.YCurr), 0);
                        else
                            IntersectEdges(e, horzEdge, new IntPoint(e.XCurr, horzEdge.YCurr), 0);
                        if (eMaxPair.OutIdx >= 0)
                            throw new ClipperException("ProcessHorizontal error");
                        return;
                    }
                    else if (e.Dx == HORIZONTAL && !InternalHelpers.IsMinima(e) && !(e.XCurr > e.XTop))
                    {
                        if (direction == Direction.LeftToRight)
                            IntersectEdges(horzEdge, e, new IntPoint(e.XCurr, horzEdge.YCurr),
                                IsTopHorz(horzEdge, e.XCurr) ? Protects.Left : Protects.Both);
                        else
                            IntersectEdges(e, horzEdge, new IntPoint(e.XCurr, horzEdge.YCurr),
                                IsTopHorz(horzEdge, e.XCurr) ? Protects.Right : Protects.Both);
                    }
                    else if (direction == Direction.LeftToRight)
                    {
                        IntersectEdges(horzEdge, e, new IntPoint(e.XCurr, horzEdge.YCurr),
                            IsTopHorz(horzEdge, e.XCurr) ? Protects.Left : Protects.Both);
                    }
                    else
                    {
                        IntersectEdges(e, horzEdge, new IntPoint(e.XCurr, horzEdge.YCurr),
                            IsTopHorz(horzEdge, e.XCurr) ? Protects.Right : Protects.Both);
                    }
                    SwapPositionsInAEL(horzEdge, e);
                }
                else if ((direction == Direction.LeftToRight && e.XCurr >= horzRight) || (direction == Direction.RightToLeft && e.XCurr <= horzLeft))
                    break;
                e = eNext;
            } //end while ( e )

            if (horzEdge.NextInLML != null)
            {
                if (horzEdge.OutIdx >= 0)
                    AddOutPt(horzEdge, new IntPoint(horzEdge.XTop, horzEdge.YTop));
                UpdateEdgeIntoAEL(ref horzEdge);
            }
            else
            {
                if (horzEdge.OutIdx >= 0)
                    IntersectEdges(horzEdge, eMaxPair, new IntPoint(horzEdge.XTop, horzEdge.YCurr), Protects.Both);
                DeleteFromAEL(eMaxPair);
                DeleteFromAEL(horzEdge);
            }
        }
예제 #23
0
 private void AddHorzJoin(TEdge e, int idx)
 {
     _horizJoins.Add(new HorzJoinRec {Edge = e, SavedIdx = idx});
 }
예제 #24
0
 private bool ProcessIntersections(long botY, long topY)
 {
     if (_activeEdges == null)
         return true;
     try
     {
         BuildIntersectList(botY, topY);
         if (_intersectNodes == null)
             return true;
         if (_intersectNodes.Next == null || FixupIntersectionOrder())
             ProcessIntersectList();
         else
             return false;
     }
     catch
     {
         _sortedEdges = null;
         DisposeIntersectNodes();
         throw new ClipperException("ProcessIntersections error");
     }
     _sortedEdges = null;
     return true;
 }
예제 #25
0
        private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt)
        {
            Contract.Requires(e1 != null);
            Contract.Requires(e1.OutIdx >= 0 && e1.OutIdx < _polyOuts.Count);
            Contract.Requires(e2 != null);

            AddOutPt(e1, pt);
            if (e1.OutIdx == e2.OutIdx)
            {
                e1.OutIdx = -1;
                e2.OutIdx = -1;
            }
            else if (e1.OutIdx < e2.OutIdx)
                AppendPolygon(e1, e2);
            else
                AppendPolygon(e2, e1);
        }
예제 #26
0
        private void SetHoleState(TEdge e, OutRec outRec)
        {
            Contract.Requires(e != null);

            var isHole = false;
            var e2 = e.PrevInAEL;
            while (e2 != null)
            {
                if (e2.OutIdx >= 0)
                {
                    isHole = !isHole;
                    if (outRec.FirstLeft == null)
                        outRec.FirstLeft = _polyOuts[e2.OutIdx];
                }
                e2 = e2.PrevInAEL;
            }
            if (isHole)
                outRec.IsHole = true;
        }
예제 #27
0
        private void AddOutPt(TEdge e, IntPoint pt)
        {
            Contract.Requires(e != null);
            Contract.Requires(e.OutIdx < 0 || e.OutIdx < _polyOuts.Count);

            var toFront = e.Side == EdgeSide.Left;
            if (e.OutIdx < 0)
            {
                var outRec = CreateOutRec();
                e.OutIdx = outRec.Idx;
                var op = new OutPt();
                outRec.Pts = op;
                op.Pt = pt;
                op.Next = op;
                op.Prev = op;
                SetHoleState(e, outRec);
            }
            else
            {
                var outRec = _polyOuts[e.OutIdx];
                var op = outRec.Pts;
                if (toFront && pt.Equals(op.Pt) ||
                    (!toFront && pt.Equals(op.Prev.Pt)))
                    return;

                var op2 = new OutPt {
                    Pt = pt,
                    Next = op,
                    Prev = op.Prev
                };
                op2.Prev.Next = op2;
                op.Prev = op2;
                if (toFront)
                    outRec.Pts = op2;
            }
        }
예제 #28
0
        private void SetWindingCount(TEdge edge)
        {
            Contract.Requires(edge != null);

            var e = edge.PrevInAEL;
            //find the edge of the same polytype that immediately preceeds 'edge' in AEL
            while (e != null && e.PolyType != edge.PolyType)
                e = e.PrevInAEL;
            if (e == null)
            {
                edge.WindCnt = edge.WindDelta;
                edge.WindCnt2 = 0;
                e = _activeEdges; //ie get ready to calc windCnt2
            }
            else if (IsEvenOddFillType(edge))
            {
                //even-odd filling ...
                edge.WindCnt = 1;
                edge.WindCnt2 = e.WindCnt2;
                e = e.NextInAEL; //ie get ready to calc windCnt2
            }
            else
            {
                //nonZero filling ...
                if (e.WindCnt * e.WindDelta < 0)
                {
                    if (Math.Abs(e.WindCnt) > 1)
                    {
                        if (e.WindDelta * edge.WindDelta < 0)
                            edge.WindCnt = e.WindCnt;
                        else
                            edge.WindCnt = e.WindCnt + edge.WindDelta;
                    }
                    else
                        edge.WindCnt = e.WindCnt + e.WindDelta + edge.WindDelta;
                }
                else
                {
                    if (Math.Abs(e.WindCnt) > 1 && e.WindDelta * edge.WindDelta < 0)
                        edge.WindCnt = e.WindCnt;
                    else if (e.WindCnt + edge.WindDelta == 0)
                        edge.WindCnt = e.WindCnt;
                    else
                        edge.WindCnt = e.WindCnt + edge.WindDelta;
                }
                edge.WindCnt2 = e.WindCnt2;
                e = e.NextInAEL; //ie get ready to calc windCnt2
            }

            //update windCnt2 ...
            if (IsEvenOddAltFillType(edge))
            {
                //even-odd filling ...
                while (e != edge)
                {
                    edge.WindCnt2 = edge.WindCnt2 == 0 ? 1 : 0;
                    e = e.NextInAEL;
                }
            }
            else
            {
                //nonZero filling ...
                while (e != edge)
                {
                    edge.WindCnt2 += e.WindDelta;
                    e = e.NextInAEL;
                }
            }
        }
예제 #29
0
        private void BuildIntersectList(long botY, long topY)
        {
            if (_activeEdges == null)
                return;

            //prepare for sorting ...
            var e = _activeEdges;
            _sortedEdges = e;
            while (e != null)
            {
                e.PrevInSEL = e.PrevInAEL;
                e.NextInSEL = e.NextInAEL;
                e.XCurr = TopX(e, topY);
                e = e.NextInAEL;
            }

            //bubblesort ...
            var isModified = true;
            while (isModified && _sortedEdges != null)
            {
                isModified = false;
                e = _sortedEdges;
                while (e.NextInSEL != null)
                {
                    var eNext = e.NextInSEL;
                    var pt = new IntPoint();
                    if (e.XCurr > eNext.XCurr)
                    {
                        if (!IntersectPoint(e, eNext, ref pt) && e.XCurr > eNext.XCurr + 1)
                            throw new ClipperException("Intersection error");
                        if (pt.Y > botY)
                        {
                            pt = new IntPoint(
                                TopX(e, pt.Y),
                                botY
                            );
                        }
                        InsertIntersectNode(e, eNext, pt);
                        SwapPositionsInSEL(e, eNext);
                        isModified = true;
                    }
                    else
                        e = eNext;
                }
                if (e.PrevInSEL != null)
                    e.PrevInSEL.NextInSEL = null;
                else
                    break;
            }
            _sortedEdges = null;
        }
예제 #30
0
        private static void SwapX(TEdge e)
        {
            Contract.Requires(e != null);

            //swap horizontal edges' top and bottom x's so they follow the natural
            //progression of the bounds - ie so their xbots will align with the
            //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
            e.XCurr = e.XTop;
            e.XTop = e.XBot;
            e.XBot = e.XCurr;
        }