コード例 #1
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal bool Pt3IsBetweenPt1AndPt2(IntPoint pt1, IntPoint pt2, IntPoint pt3)
        {
            if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true;
            else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X);
            else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y);
        }
コード例 #2
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFulllongRange)
        {
            OutPt pp2 = pp;
            bool result = false;
            if (UseFulllongRange)
            {
                do
                {
                    if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) ||
                        ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) &&
                        new Int128(pt.X - pp2.pt.X) <
                        Int128.Int128Mul(pp2.prev.pt.X - pp2.pt.X, pt.Y - pp2.pt.Y) /
                        new Int128(pp2.prev.pt.Y - pp2.pt.Y))
                        result = !result;
                    pp2 = pp2.next;
                }
                while (pp2 != pp);
            }
            else
            {
                do
                {
                    if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) ||
                      ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) &&
                      (pt.X - pp2.pt.X < (pp2.prev.pt.X - pp2.pt.X) * (pt.Y - pp2.pt.Y) /
                      (pp2.prev.pt.Y - pp2.pt.Y))) result = !result;
                    pp2 = pp2.next;
                }
                while (pp2 != pp);
            }
            return result;
        }
コード例 #3
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        void RangeTest(IntPoint pt, ref Int64 maxrange)
        {
            if (pt.X > maxrange)
            {
                if (pt.X > hiRange)
                    throw new ClipperException("Coordinate exceeds range bounds");
                else maxrange = hiRange;
            }
            if (pt.Y > maxrange)
            {
                if (pt.Y > hiRange)
                    throw new ClipperException("Coordinate exceeds range bounds");
                else maxrange = hiRange;
            }
        }
コード例 #4
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        protected static bool PointsEqual(IntPoint pt1, IntPoint pt2)
        {
            return (pt1.X == pt2.X && pt1.Y == pt2.Y);
        }
コード例 #5
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal bool PointOnLineSegment(IntPoint pt,
            IntPoint linePt1, IntPoint linePt2, bool UseFullInt64Range)
        {
            if (UseFullInt64Range)
                return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
                  ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
                  (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
                  ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
                  ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) ==
                  Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))));
            else
                return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
                  ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
                  (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
                  ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
                  ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) ==
                    (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)));
        }
コード例 #6
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private static DoublePoint ClosestPointOnLine(IntPoint pt, IntPoint linePt1, IntPoint linePt2)
        {
            double dx = ((double)linePt2.X - linePt1.X);
            double dy = ((double)linePt2.Y - linePt1.Y);
            if (dx == 0 && dy == 0)
                return new DoublePoint(linePt1.X, linePt1.Y);
            double q = ((pt.X - linePt1.X) * dx + (pt.Y - linePt1.Y) * dy) / (dx * dx + dy * dy);
            return new DoublePoint(
                (1 - q) * linePt1.X + q * linePt2.X,
                (1 - q) * linePt1.Y + q * linePt2.Y);
        }
コード例 #7
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private static bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
        {
            double dx = (double)pt1.X - pt2.X;
            double dy = (double)pt1.Y - pt2.Y;
            return ((dx * dx) + (dy * dy) <= distSqrd);
        }
コード例 #8
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private bool IntersectPoint(TEdge edge1, TEdge edge2, ref IntPoint ip)
        {
            double b1, b2;
            if (SlopesEqual(edge1, edge2, m_UseFullRange))
            {
                if (edge2.ybot > edge1.ybot)
                    ip.Y = edge2.ybot;
                else
                    ip.Y = edge1.ybot;
                return false;
            }
            else if (edge1.dx == 0)
            {
                ip.X = edge1.xbot;
                if (edge2.dx == horizontal)
                {
                    ip.Y = edge2.ybot;
                }
                else
                {
                    b2 = edge2.ybot - (edge2.xbot / edge2.dx);
                    ip.Y = Round(ip.X / edge2.dx + b2);
                }
            }
            else if (edge2.dx == 0)
            {
                ip.X = edge2.xbot;
                if (edge1.dx == horizontal)
                {
                    ip.Y = edge1.ybot;
                }
                else
                {
                    b1 = edge1.ybot - (edge1.xbot / edge1.dx);
                    ip.Y = Round(ip.X / edge1.dx + b1);
                }
            }
            else
            {
                b1 = edge1.xbot - edge1.ybot * edge1.dx;
                b2 = edge2.xbot - edge2.ybot * edge2.dx;
                double q = (b2 - b1) / (edge1.dx - edge2.dx);
                ip.Y = Round(q);
                if (Math.Abs(edge1.dx) < Math.Abs(edge2.dx))
                    ip.X = Round(edge1.dx * q + b1);
                else
                    ip.X = Round(edge2.dx * q + b2);
            }

            if (ip.Y < edge1.ytop || ip.Y < edge2.ytop)
            {
                if (edge1.ytop > edge2.ytop)
                {
                    ip.X = edge1.xtop;
                    ip.Y = edge1.ytop;
                    return TopX(edge2, edge1.ytop) < edge1.xtop;
                }
                else
                {
                    ip.X = edge2.xtop;
                    ip.Y = edge2.ytop;
                    return TopX(edge1, edge2.ytop) > edge2.xtop;
                }
            }
            else
                return true;
        }
コード例 #9
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private void ProcessEdgesAtTopOfScanbeam(Int64 topY)
        {
            TEdge e = m_ActiveEdges;
            while (e != null)
            {
                //1. process maxima, treating them as if they're 'bent' horizontal edges,
                //   but exclude maxima with horizontal edges. nb: e can't be a horizontal.
                if (IsMaxima(e, topY) && GetMaximaPair(e).dx != horizontal)
                {
                    //'e' might be removed from AEL, as may any following edges so ...
                    TEdge ePrev = e.prevInAEL;
                    DoMaxima(e, topY);
                    if (ePrev == null) e = m_ActiveEdges;
                    else e = ePrev.nextInAEL;
                }
                else
                {
                    bool intermediateVert = IsIntermediate(e, topY);
                    //2. promote horizontal edges, otherwise update xcurr and ycurr ...
                    if (intermediateVert && e.nextInLML.dx == horizontal)
                    {
                        if (e.outIdx >= 0)
                        {
                            AddOutPt(e, new IntPoint(e.xtop, e.ytop));

                            for (int i = 0; i < m_HorizJoins.Count; ++i)
                            {
                                IntPoint pt = new IntPoint(), pt2 = new IntPoint();
                                HorzJoinRec hj = m_HorizJoins[i];
                                if (GetOverlapSegment(new IntPoint(hj.edge.xbot, hj.edge.ybot),
                                    new IntPoint(hj.edge.xtop, hj.edge.ytop),
                                    new IntPoint(e.nextInLML.xbot, e.nextInLML.ybot),
                                    new IntPoint(e.nextInLML.xtop, e.nextInLML.ytop), ref pt, ref pt2))
                                    AddJoin(hj.edge, e.nextInLML, hj.savedIdx, e.outIdx);
                            }

                            AddHorzJoin(e.nextInLML, e.outIdx);
                        }
                        UpdateEdgeIntoAEL(ref e);
                        AddEdgeToSEL(e);
                    }
                    else
                    {
                        e.xcurr = TopX(e, topY);
                        e.ycurr = topY;
                        if (m_ForceSimple && e.prevInAEL != null &&
                          e.prevInAEL.xcurr == e.xcurr &&
                          e.outIdx >= 0 && e.prevInAEL.outIdx >= 0)
                        {
                            if (intermediateVert)
                                AddOutPt(e.prevInAEL, new IntPoint(e.xcurr, topY));
                            else
                                AddOutPt(e, new IntPoint(e.xcurr, topY));
                        }
                    }
                    e = e.nextInAEL;
                }
            }

            //3. Process horizontals at the top of the scanbeam ...
            ProcessHorizontals();

            //4. Promote intermediate vertices ...
            e = m_ActiveEdges;
            while (e != null)
            {
                if (IsIntermediate(e, topY))
                {
                    if (e.outIdx >= 0) AddOutPt(e, new IntPoint(e.xtop, e.ytop));
                    UpdateEdgeIntoAEL(ref e);

                    //if output polygons share an edge, they'll need joining later ...
                    TEdge ePrev = e.prevInAEL;
                    TEdge eNext = e.nextInAEL;
                    if (ePrev != null && ePrev.xcurr == e.xbot &&
                      ePrev.ycurr == e.ybot && e.outIdx >= 0 &&
                      ePrev.outIdx >= 0 && ePrev.ycurr > ePrev.ytop &&
                      SlopesEqual(e, ePrev, m_UseFullRange))
                    {
                        AddOutPt(ePrev, new IntPoint(e.xbot, e.ybot));
                        AddJoin(e, ePrev, -1, -1);
                    }
                    else if (eNext != null && eNext.xcurr == e.xbot &&
                      eNext.ycurr == e.ybot && e.outIdx >= 0 &&
                      eNext.outIdx >= 0 && eNext.ycurr > eNext.ytop &&
                      SlopesEqual(e, eNext, m_UseFullRange))
                    {
                        AddOutPt(eNext, new IntPoint(e.xbot, e.ybot));
                        AddJoin(e, eNext, -1, -1);
                    }
                }
                e = e.nextInAEL;
            }
        }
コード例 #10
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private void BuildIntersectList(Int64 botY, Int64 topY)
        {
            if (m_ActiveEdges == null) return;

            //prepare for sorting ...
            TEdge e = m_ActiveEdges;
            m_SortedEdges = e;
            while (e != null)
            {
                e.prevInSEL = e.prevInAEL;
                e.nextInSEL = e.nextInAEL;
                e.xcurr = TopX(e, topY);
                e = e.nextInAEL;
            }

            //bubblesort ...
            bool isModified = true;
            while (isModified && m_SortedEdges != null)
            {
                isModified = false;
                e = m_SortedEdges;
                while (e.nextInSEL != null)
                {
                    TEdge eNext = e.nextInSEL;
                    IntPoint 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.Y = botY;
                            pt.X = TopX(e, pt.Y);
                        }
                        InsertIntersectNode(e, eNext, pt);
                        SwapPositionsInSEL(e, eNext);
                        isModified = true;
                    }
                    else
                        e = eNext;
                }
                if (e.prevInSEL != null) e.prevInSEL.nextInSEL = null;
                else break;
            }
            m_SortedEdges = null;
        }
コード例 #11
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private void InsertIntersectNode(TEdge e1, TEdge e2, IntPoint pt)
        {
            IntersectNode newNode = new IntersectNode();
            newNode.edge1 = e1;
            newNode.edge2 = e2;
            newNode.pt = pt;
            newNode.next = null;
            if (m_IntersectNodes == null) m_IntersectNodes = newNode;
            else if (newNode.pt.Y > m_IntersectNodes.pt.Y)
            {
                newNode.next = m_IntersectNodes;
                m_IntersectNodes = newNode;
            }
            else
            {
                IntersectNode iNode = m_IntersectNodes;
                while (iNode.next != null && newNode.pt.Y < iNode.next.pt.Y)
                    iNode = iNode.next;
                newNode.next = iNode.next;
                iNode.next = newNode;
            }
        }
コード例 #12
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt, Protects protects)
        {
            //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 ...

            bool e1stops = (Protects.ipLeft & protects) == 0 && e1.nextInLML == null &&
              e1.xtop == pt.X && e1.ytop == pt.Y;
            bool e2stops = (Protects.ipRight & protects) == 0 && e2.nextInLML == null &&
              e2.xtop == pt.X && e2.ytop == pt.Y;
            bool e1Contributing = (e1.outIdx >= 0);
            bool 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))
                {
                    int 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.ptSubject)
            {
                e1FillType = m_SubjFillType;
                e1FillType2 = m_ClipFillType;
            }
            else
            {
                e1FillType = m_ClipFillType;
                e1FillType2 = m_SubjFillType;
            }
            if (e2.polyType == PolyType.ptSubject)
            {
                e2FillType = m_SubjFillType;
                e2FillType2 = m_ClipFillType;
            }
            else
            {
                e2FillType = m_ClipFillType;
                e2FillType2 = m_SubjFillType;
            }

            int e1Wc, e2Wc;
            switch (e1FillType)
            {
                case PolyFillType.pftPositive: e1Wc = e1.windCnt; break;
                case PolyFillType.pftNegative: e1Wc = -e1.windCnt; break;
                default: e1Wc = Math.Abs(e1.windCnt); break;
            }
            switch (e2FillType)
            {
                case PolyFillType.pftPositive: e2Wc = e2.windCnt; break;
                case PolyFillType.pftNegative: 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 && m_ClipType != ClipType.ctXor))
                    AddLocalMaxPoly(e1, e2, pt);
                else
                {
                    AddOutPt(e1, pt);
                    AddOutPt(e2, pt);
                    SwapSides(e1, e2);
                    SwapPolyIndexes(e1, e2);
                }
            }
            else if (e1Contributing)
            {
                if (e2Wc == 0 || e2Wc == 1)
                {
                    AddOutPt(e1, pt);
                    SwapSides(e1, e2);
                    SwapPolyIndexes(e1, e2);
                }

            }
            else if (e2contributing)
            {
                if (e1Wc == 0 || e1Wc == 1)
                {
                    AddOutPt(e2, pt);
                    SwapSides(e1, e2);
                    SwapPolyIndexes(e1, e2);
                }
            }
            else if ((e1Wc == 0 || e1Wc == 1) &&
                (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops)
            {
                //neither edge is currently contributing ...
                Int64 e1Wc2, e2Wc2;
                switch (e1FillType2)
                {
                    case PolyFillType.pftPositive: e1Wc2 = e1.windCnt2; break;
                    case PolyFillType.pftNegative: e1Wc2 = -e1.windCnt2; break;
                    default: e1Wc2 = Math.Abs(e1.windCnt2); break;
                }
                switch (e2FillType2)
                {
                    case PolyFillType.pftPositive: e2Wc2 = e2.windCnt2; break;
                    case PolyFillType.pftNegative: 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 (m_ClipType)
                    {
                        case ClipType.ctIntersection:
                            if (e1Wc2 > 0 && e2Wc2 > 0)
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.ctUnion:
                            if (e1Wc2 <= 0 && e2Wc2 <= 0)
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.ctDifference:
                            if (((e1.polyType == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
                                ((e1.polyType == PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
                                AddLocalMinPoly(e1, e2, pt);
                            break;
                        case ClipType.ctXor:
                            AddLocalMinPoly(e1, e2, pt);
                            break;
                    }
                else
                    SwapSides(e1, e2);
            }

            if ((e1stops != e2stops) &&
              ((e1stops && (e1.outIdx >= 0)) || (e2stops && (e2.outIdx >= 0))))
            {
                SwapSides(e1, e2);
                SwapPolyIndexes(e1, e2);
            }

            //finally, delete any non-contributing maxima edges  ...
            if (e1stops) DeleteFromAEL(e1);
            if (e2stops) DeleteFromAEL(e2);
        }
コード例 #13
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private double GetDx(IntPoint pt1, IntPoint pt2)
        {
            if (pt1.Y == pt2.Y) return horizontal;
            else return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
        }
コード例 #14
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private OutPt InsertPolyPtBetween(OutPt p1, OutPt p2, IntPoint pt)
        {
            OutPt result = new OutPt();
            result.pt = pt;
            if (p2 == p1.next)
            {
                p1.next = result;
                p2.prev = result;
                result.next = p2;
                result.prev = p1;
            }
            else
            {
                p2.next = result;
                p1.prev = result;
                result.next = p1;
                result.prev = p2;
            }
            return result;
        }
コード例 #15
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        } //end PolyOffsetBuilder
        //------------------------------------------------------------------------------

        internal static bool UpdateBotPt(IntPoint pt, ref IntPoint botPt)
        {
            if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
            {
                botPt = pt;
                return true;
            }
            else return false;
        }
コード例 #16
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------
        // OffsetPolygon functions ...
        //------------------------------------------------------------------------------

        internal static PolygonClp BuildArc(IntPoint pt, double a1, double a2, double r, double limit)
        {
            //see notes in clipper.pas regarding steps
            double arcFrac = Math.Abs(a2 - a1) / (2 * Math.PI);
            int steps = (int)(arcFrac * Math.PI / Math.Acos(1 - limit / Math.Abs(r)));
            if (steps < 2)
                steps = 2;
            else if (steps > (int)(222.0 * arcFrac))
                steps = (int)(222.0 * arcFrac);

            double x = Math.Cos(a1);
            double y = Math.Sin(a1);
            double c = Math.Cos((a2 - a1) / steps);
            double s = Math.Sin((a2 - a1) / steps);
            PolygonClp result = new PolygonClp(steps + 1);
            for (int i = 0; i <= steps; ++i)
            {
                result.Add(new IntPoint(pt.X + Round(x * r), pt.Y + Round(y * r)));
                double x2 = x;
                x = x * c - s * y;  //cross product
                y = x2 * s + y * c; //dot product
            }
            return result;
        }
コード例 #17
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private static double DistanceSqrd(IntPoint pt1, IntPoint pt2)
        {
            double dx = ((double)pt1.X - pt2.X);
            double dy = ((double)pt1.Y - pt2.Y);
            return (dx * dx + dy * dy);
        }
コード例 #18
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal static DoublePoint GetUnitNormal(IntPoint pt1, IntPoint pt2)
        {
            double dx = (pt2.X - pt1.X);
            double dy = (pt2.Y - pt1.Y);
            if ((dx == 0) && (dy == 0)) return new DoublePoint();

            double f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy);
            dx *= f;
            dy *= f;

            return new DoublePoint(dy, -dx);
        }
コード例 #19
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private static bool SlopesNearColinear(IntPoint pt1,
            IntPoint pt2, IntPoint pt3, double distSqrd)
        {
            if (DistanceSqrd(pt1, pt2) > DistanceSqrd(pt1, pt3)) return false;
            DoublePoint cpol = ClosestPointOnLine(pt2, pt1, pt3);
            double dx = pt2.X - cpol.X;
            double dy = pt2.Y - cpol.Y;
            return (dx * dx + dy * dy) < distSqrd;
        }
コード例 #20
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
            //------------------------------------------------------------------------------

            public PolyOffsetBuilder(PolygonsClp pts, PolygonsClp solution, bool isPolygon, double delta,
                JoinType jointype, EndType endtype, double limit = 0)
            {
                //precondition: solution != pts

                if (delta == 0) { solution = pts; return; }
                m_p = pts;
                m_delta = delta;
                m_rmin = 0.5;

                if (jointype == JoinType.jtMiter)
                {
                    if (limit > 2) m_rmin = 2.0 / (limit * limit);
                    limit = 0.25; //just in case endtype == etRound
                }
                else
                {
                    if (limit <= 0) limit = 0.25;
                    else if (limit > Math.Abs(delta)) limit = Math.Abs(delta);
                }

                double deltaSq = delta * delta;
                solution.Clear();
                solution.Capacity = pts.Count;
                for (m_i = 0; m_i < pts.Count; m_i++)
                {
                    int len = pts[m_i].Count;
                    if (len == 0 || (len < 3 && delta <= 0))
                        continue;
                    else if (len == 1)
                    {
                        currentPoly = new PolygonClp();
                        currentPoly = BuildArc(pts[m_i][0], 0, 2 * Math.PI, delta, limit);
                        solution.Add(currentPoly);
                        continue;
                    }

                    bool forceClose = PointsEqual(pts[m_i][0], pts[m_i][len - 1]);
                    if (forceClose) len--;

                    //build normals ...
                    normals.Clear();
                    normals.Capacity = len;
                    for (int j = 0; j < len - 1; ++j)
                        normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j + 1]));
                    if (isPolygon || forceClose)
                        normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0]));
                    else
                        normals.Add(new DoublePoint(normals[len - 2]));

                    currentPoly = new PolygonClp();
                    if (isPolygon || forceClose)
                    {
                        m_k = len - 1;
                        for (m_j = 0; m_j < len; ++m_j)
                            OffsetPoint(jointype, limit);
                        solution.Add(currentPoly);
                        if (!isPolygon)
                        {
                            currentPoly = new PolygonClp();
                            m_delta = -m_delta;
                            m_k = len - 1;
                            for (m_j = 0; m_j < len; ++m_j)
                                OffsetPoint(jointype, limit);
                            m_delta = -m_delta;
                            currentPoly.Reverse();
                            solution.Add(currentPoly);
                        }
                    }
                    else
                    {
                        m_k = 0;
                        for (m_j = 1; m_j < len - 1; ++m_j)
                            OffsetPoint(jointype, limit);

                        IntPoint pt1;
                        if (endtype == EndType.etButt)
                        {
                            m_j = len - 1;
                            pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X + normals[m_j].X *
                              delta), (Int64)Round(pts[m_i][m_j].Y + normals[m_j].Y * delta));
                            AddPoint(pt1);
                            pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X - normals[m_j].X *
                              delta), (Int64)Round(pts[m_i][m_j].Y - normals[m_j].Y * delta));
                            AddPoint(pt1);
                        }
                        else
                        {
                            m_j = len - 1;
                            m_k = len - 2;
                            normals[m_j].X = -normals[m_j].X;
                            normals[m_j].Y = -normals[m_j].Y;
                            if (endtype == EndType.etSquare) DoSquare();
                            else DoRound(limit);
                        }

                        //re-build Normals ...
                        for (int j = len - 1; j > 0; j--)
                        {
                            normals[j].X = -normals[j - 1].X;
                            normals[j].Y = -normals[j - 1].Y;
                        }
                        normals[0].X = -normals[1].X;
                        normals[0].Y = -normals[1].Y;

                        m_k = len - 1;
                        for (m_j = m_k - 1; m_j > 0; --m_j)
                            OffsetPoint(jointype, limit);

                        if (endtype == EndType.etButt)
                        {
                            pt1 = new IntPoint((Int64)Round(pts[m_i][0].X - normals[0].X * delta),
                              (Int64)Round(pts[m_i][0].Y - normals[0].Y * delta));
                            AddPoint(pt1);
                            pt1 = new IntPoint((Int64)Round(pts[m_i][0].X + normals[0].X * delta),
                              (Int64)Round(pts[m_i][0].Y + normals[0].Y * delta));
                            AddPoint(pt1);
                        }
                        else
                        {
                            m_k = 1;
                            if (endtype == EndType.etSquare) DoSquare();
                            else DoRound(limit);
                        }
                        solution.Add(currentPoly);
                    }
                }

                //finally, clean up untidy corners ...
                Clipper clpr = new Clipper();
                clpr.AddPolygons(solution, PolyType.ptSubject);
                if (delta > 0)
                {
                    clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive);
                }
                else
                {
                    IntRect r = clpr.GetBounds();
                    PolygonClp outer = new PolygonClp(4);

                    outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
                    outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
                    outer.Add(new IntPoint(r.right + 10, r.top - 10));
                    outer.Add(new IntPoint(r.left - 10, r.top - 10));

                    clpr.AddPolygon(outer, PolyType.ptSubject);
                    clpr.ReverseSolution = true;
                    clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
                    if (solution.Count > 0) solution.RemoveAt(0);
                }
            }
コード例 #21
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
 public IntPoint(IntPoint pt)
 {
     this.X = pt.X; this.Y = pt.Y;
 }
コード例 #22
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
            //------------------------------------------------------------------------------

            internal void AddPoint(IntPoint pt)
            {
                if (currentPoly.Count == currentPoly.Capacity)
                    currentPoly.Capacity += m_buffLength;
                currentPoly.Add(pt);
            }
コード例 #23
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal bool PointIsVertex(IntPoint pt, OutPt pp)
        {
            OutPt pp2 = pp;
            do
            {
                if (PointsEqual(pp2.pt, pt)) return true;
                pp2 = pp2.next;
            }
            while (pp2 != pp);
            return false;
        }
コード例 #24
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
            //------------------------------------------------------------------------------

            internal void DoSquare()
            {
                IntPoint pt1 = new IntPoint((Int64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
                    (Int64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
                IntPoint pt2 = new IntPoint((Int64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
                    (Int64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
                if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
                {
                    double a1 = Math.Atan2(normals[m_k].Y, normals[m_k].X);
                    double a2 = Math.Atan2(-normals[m_j].Y, -normals[m_j].X);
                    a1 = Math.Abs(a2 - a1);
                    if (a1 > Math.PI) a1 = Math.PI * 2 - a1;
                    double dx = Math.Tan((Math.PI - a1) / 4) * Math.Abs(m_delta);
                    pt1 = new IntPoint((Int64)(pt1.X - normals[m_k].Y * dx),
                        (Int64)(pt1.Y + normals[m_k].X * dx));
                    AddPoint(pt1);
                    pt2 = new IntPoint((Int64)(pt2.X + normals[m_j].Y * dx),
                        (Int64)(pt2.Y - normals[m_j].X * dx));
                    AddPoint(pt2);
                }
                else
                {
                    AddPoint(pt1);
                    AddPoint(m_p[m_i][m_j]);
                    AddPoint(pt2);
                }
            }
コード例 #25
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullInt64Range)
        {
            OutPt pp2 = pp;
            while (true)
            {
                if (PointOnLineSegment(pt, pp2.pt, pp2.next.pt, UseFullInt64Range))
                    return true;
                pp2 = pp2.next;
                if (pp2 == pp) break;
            }
            return false;
        }
コード例 #26
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
            //------------------------------------------------------------------------------

            internal void DoMiter()
            {
                if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
                {
                    double q = m_delta / m_r;
                    AddPoint(new IntPoint((Int64)Round(m_p[m_i][m_j].X +
                        (normals[m_k].X + normals[m_j].X) * q),
                        (Int64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
                }
                else
                {
                    IntPoint pt1 = new IntPoint((Int64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
                        (Int64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
                    IntPoint pt2 = new IntPoint((Int64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
                        (Int64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
                    AddPoint(pt1);
                    AddPoint(m_p[m_i][m_j]);
                    AddPoint(pt2);
                }
            }
コード例 #27
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        protected static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
            IntPoint pt3, IntPoint pt4, bool UseFullRange)
        {
            if (UseFullRange)
                return Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
                  Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
            else return
              (Int64)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (Int64)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0;
        }
コード例 #28
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
            //------------------------------------------------------------------------------

            internal void DoRound(double Limit)
            {
                IntPoint pt1 = new IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
                    Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
                IntPoint pt2 = new IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
                    Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
                AddPoint(pt1);
                //round off reflex angles (ie > 180 deg) unless almost flat (ie < 10deg).
                //cross product normals < 0 . angle > 180 deg.
                //dot product normals == 1 . no angle
                if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
                {
                    if ((normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y) < 0.985)
                    {
                        double a1 = Math.Atan2(normals[m_k].Y, normals[m_k].X);
                        double a2 = Math.Atan2(normals[m_j].Y, normals[m_j].X);
                        if (m_delta > 0 && a2 < a1) a2 += Math.PI * 2;
                        else if (m_delta < 0 && a2 > a1) a2 -= Math.PI * 2;
                        PolygonClp arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta, Limit);
                        for (int m = 0; m < arc.Count; m++)
                            AddPoint(arc[m]);
                    }
                }
                else
                    AddPoint(m_p[m_i][m_j]);
                AddPoint(pt2);
            }
コード例 #29
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private void InitEdge(TEdge e, TEdge eNext,
          TEdge ePrev, IntPoint pt, PolyType polyType)
        {
            e.next = eNext;
            e.prev = ePrev;
            e.xcurr = pt.X;
            e.ycurr = pt.Y;
            if (e.ycurr >= e.next.ycurr)
            {
                e.xbot = e.xcurr;
                e.ybot = e.ycurr;
                e.xtop = e.next.xcurr;
                e.ytop = e.next.ycurr;
                e.windDelta = 1;
            }
            else
            {
                e.xtop = e.xcurr;
                e.ytop = e.ycurr;
                e.xbot = e.next.xcurr;
                e.ybot = e.next.ycurr;
                e.windDelta = -1;
            }
            SetDx(e);
            e.polyType = polyType;
            e.outIdx = -1;
        }
コード例 #30
0
ファイル: Clipper.cs プロジェクト: charlierix/AsteroidMiner
        //------------------------------------------------------------------------------

        private bool FindSegment(ref OutPt pp, bool UseFullInt64Range,
            ref IntPoint pt1, ref IntPoint pt2)
        {
            if (pp == null) return false;
            OutPt pp2 = pp;
            IntPoint pt1a = new IntPoint(pt1);
            IntPoint pt2a = new IntPoint(pt2);
            do
            {
                if (SlopesEqual(pt1a, pt2a, pp.pt, pp.prev.pt, UseFullInt64Range) &&
                    SlopesEqual(pt1a, pt2a, pp.pt, UseFullInt64Range) &&
                    GetOverlapSegment(pt1a, pt2a, pp.pt, pp.prev.pt, ref pt1, ref pt2))
                    return true;
                pp = pp.next;
            }
            while (pp != pp2);
            return false;
        }