Example #1
0
        //------------------------------------------------------------------------------

        private void AddOutPt(TEdge e, IntPoint pt)
        {
          bool ToFront = (e.side == EdgeSide.esLeft);
          if(  e.outIdx < 0 )
          {
              OutRec outRec = CreateOutRec();
              m_PolyOuts.Add(outRec);
              outRec.idx = m_PolyOuts.Count -1;
              e.outIdx = outRec.idx;
              OutPt op = new OutPt();
              outRec.pts = op;
              outRec.bottomPt = op;
              op.pt = pt;
              op.idx = outRec.idx;
              op.next = op;
              op.prev = op;
              SetHoleState(e, outRec);
          } else
          {
              OutRec outRec = m_PolyOuts[e.outIdx];
              OutPt op = outRec.pts, op2, opBot;
              if (ToFront && PointsEqual(pt, op.pt) || 
                  (!ToFront && PointsEqual(pt, op.prev.pt))) return;

              if ((e.side | outRec.sides) != outRec.sides)
              {
                  //check for 'rounding' artefacts ...
                  if (outRec.sides == EdgeSide.esNeither && pt.Y == op.pt.Y)
                      if (ToFront)
                      {
                          if (pt.X == op.pt.X + 1) return;    //ie wrong side of bottomPt
                      }
                      else if (pt.X == op.pt.X - 1) return; //ie wrong side of bottomPt

                  outRec.sides = (EdgeSide)(outRec.sides | e.side);
                  if (outRec.sides == EdgeSide.esBoth)
                  {
                    //A vertex from each side has now been added.
                    //Vertices of one side of an output polygon are quite commonly close to
                    //or even 'touching' edges of the other side of the output polygon.
                    //Very occasionally vertices from one side can 'cross' an edge on the
                    //the other side. The distance 'crossed' is always less that a unit
                    //and is purely an artefact of coordinate rounding. Nevertheless, this
                    //results in very tiny self-intersections. Because of the way
                    //orientation is calculated, even tiny self-intersections can cause
                    //the Orientation function to return the wrong result. Therefore, it's
                    //important to ensure that any self-intersections close to BottomPt are
                    //detected and removed before orientation is assigned.

                    if (ToFront)
                    {
                      opBot = outRec.pts;
                      op2 = opBot.next; //op2 == right side
                      if (opBot.pt.Y != op2.pt.Y && opBot.pt.Y != pt.Y &&
                        ((opBot.pt.X - pt.X) / (opBot.pt.Y - pt.Y) <
                        (opBot.pt.X - op2.pt.X) / (opBot.pt.Y - op2.pt.Y)))
                          outRec.bottomFlag = opBot;
                    }
                    else
                    {
                      opBot = outRec.pts.prev;
                      op2 = opBot.next; //op2 == left side
                      if (opBot.pt.Y != op2.pt.Y && opBot.pt.Y != pt.Y &&
                        ((opBot.pt.X - pt.X) / (opBot.pt.Y - pt.Y) >
                        (opBot.pt.X - op2.pt.X) / (opBot.pt.Y - op2.pt.Y)))
                          outRec.bottomFlag = opBot;
                    }
                  }
              }

              op2 = new OutPt();
              op2.pt = pt;
              op2.idx = outRec.idx;
              if (op2.pt.Y == outRec.bottomPt.pt.Y &&
                op2.pt.X < outRec.bottomPt.pt.X)
                  outRec.bottomPt = op2;
              op2.next = op;
              op2.prev = op.prev;
              op2.prev.next = op2;
              op.prev = op2;
              if (ToFront) outRec.pts = op2;
          }
        }
Example #2
0
        //------------------------------------------------------------------------------

        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;
        }
Example #3
0
        //------------------------------------------------------------------------------

        protected 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;
        }
Example #4
0
            //------------------------------------------------------------------------------

            internal void DoSquare(double mul)
            {
                IntPoint pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X + normals[m_k].X * delta),
                    (Int64)Round(pts[m_i][m_j].Y + normals[m_k].Y * delta));
                IntPoint pt2 = 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));
                if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * 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(delta * mul);
                    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(pts[m_i][m_j]);
                    AddPoint(pt2);
                }
            }
Example #5
0
            //------------------------------------------------------------------------------

            internal void DoRound()
            {
                IntPoint pt1 = new IntPoint(Round(pts[m_i][m_j].X + normals[m_k].X * delta),
                    Round(pts[m_i][m_j].Y + normals[m_k].Y * delta));
                IntPoint pt2 = new IntPoint(Round(pts[m_i][m_j].X + normals[m_j].X * delta),
                    Round(pts[m_i][m_j].Y + normals[m_j].Y * 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) * 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 (delta > 0 && a2 < a1) a2 += Math.PI * 2;
                        else if (delta < 0 && a2 > a1) a2 -= Math.PI * 2;
                        Polygon arc = BuildArc(pts[m_i][m_j], a1, a2, delta);
                        for (int m = 0; m < arc.Count; m++)
                            AddPoint(arc[m]);
                    }
                }
                else
                    AddPoint(pts[m_i][m_j]);
                AddPoint(pt2);
            }
Example #6
0
        //----------------------------------------------------------------------

        private void JoinCommonEdges(bool fixHoleLinkages)
        {
          for (int i = 0; i < m_Joins.Count; i++)
          {
            JoinRec j = m_Joins[i];
            OutRec outRec1 = m_PolyOuts[j.poly1Idx];
            OutPt pp1a = outRec1.pts;
            OutRec outRec2 = m_PolyOuts[j.poly2Idx];
            OutPt pp2a = outRec2.pts;
            IntPoint pt1 = new IntPoint(j.pt2a);
            IntPoint pt2 = new IntPoint(j.pt2b);
            IntPoint pt3 = new IntPoint(j.pt1a);
            IntPoint pt4 = new IntPoint(j.pt1b);
            if (!FindSegment(ref pp1a, ref pt1, ref pt2)) continue;
            if (j.poly1Idx == j.poly2Idx)
            {
                //we're searching the same polygon for overlapping segments so
                //segment 2 mustn't be the same as segment 1 ...
                pp2a = pp1a.next;
                if (!FindSegment(ref pp2a, ref pt3, ref pt4) || (pp2a == pp1a)) continue;
            }
            else if (!FindSegment(ref pp2a, ref pt3, ref pt4)) continue;

            if (!GetOverlapSegment(pt1, pt2, pt3, pt4, ref pt1, ref pt2)) continue;

            OutPt p1, p2, p3, p4;
            OutPt prev = pp1a.prev;
            //get p1 & p2 polypts - the overlap start & endpoints on poly1
            
            if (PointsEqual(pp1a.pt, pt1)) p1 = pp1a;
            else if (PointsEqual(prev.pt, pt1)) p1 = prev;
            else p1 = InsertPolyPtBetween(pp1a, prev, pt1);

            if (PointsEqual(pp1a.pt, pt2)) p2 = pp1a;
            else if (PointsEqual(prev.pt, pt2)) p2 = prev;
            else if ((p1 == pp1a) || (p1 == prev))
                p2 = InsertPolyPtBetween(pp1a, prev, pt2);
            else if (Pt3IsBetweenPt1AndPt2(pp1a.pt, p1.pt, pt2))
                p2 = InsertPolyPtBetween(pp1a, p1, pt2); 
            else
                p2 = InsertPolyPtBetween(p1, prev, pt2);

            //get p3 & p4 polypts - the overlap start & endpoints on poly2
            prev = pp2a.prev;
            if (PointsEqual(pp2a.pt, pt1)) p3 = pp2a;
            else if (PointsEqual(prev.pt, pt1)) p3 = prev;
            else p3 = InsertPolyPtBetween(pp2a, prev, pt1);

            if (PointsEqual(pp2a.pt, pt2)) p4 = pp2a;
            else if (PointsEqual(prev.pt, pt2)) p4 = prev;
            else if ((p3 == pp2a) || (p3 == prev))
                p4 = InsertPolyPtBetween(pp2a, prev, pt2);
            else if (Pt3IsBetweenPt1AndPt2(pp2a.pt, p3.pt, pt2))
                p4 = InsertPolyPtBetween(pp2a, p3, pt2);
            else
                p4 = InsertPolyPtBetween(p3, prev, pt2);

            //p1.pt should equal p3.pt and p2.pt should equal p4.pt here, so ...
            //join p1 to p3 and p2 to p4 ...
            if (p1.next == p2 && p3.prev == p4)
            {
                p1.next = p3;
                p3.prev = p1;
                p2.prev = p4;
                p4.next = p2;
            }
            else if (p1.prev == p2 && p3.next == p4)
            {
                p1.prev = p3;
                p3.next = p1;
                p2.next = p4;
                p4.prev = p2;
            }
            else
                continue; //an orientation is probably wrong

            if (j.poly2Idx == j.poly1Idx)
            {
                //instead of joining two polygons, we've just created a new one by
                //splitting one polygon into two.
                outRec1.pts = GetBottomPt(p1);
                outRec1.bottomPt = outRec1.pts;
                outRec1.bottomPt.idx = outRec1.idx;
                outRec2 = CreateOutRec();
                m_PolyOuts.Add(outRec2);
                outRec2.idx = m_PolyOuts.Count - 1;
                j.poly2Idx = outRec2.idx;
                outRec2.pts = GetBottomPt(p2);
                outRec2.bottomPt = outRec2.pts;
                outRec2.bottomPt.idx = outRec2.idx;

                if (PointInPolygon(outRec2.pts.pt, outRec1.pts, m_UseFullRange))
                {
                    //outRec1 is contained by outRec2 ...
                    outRec2.isHole = !outRec1.isHole;
                    outRec2.FirstLeft = outRec1;
                    if (outRec2.isHole == Orientation(outRec2, m_UseFullRange)) 
                      ReversePolyPtLinks(outRec2.pts);
                }
                else if (PointInPolygon(outRec1.pts.pt, outRec2.pts, m_UseFullRange))
                {
                    //outRec2 is contained by outRec1 ...
                    outRec2.isHole = outRec1.isHole;
                    outRec1.isHole = !outRec2.isHole;
                    outRec2.FirstLeft = outRec1.FirstLeft;
                    outRec1.FirstLeft = outRec2;
                    if (outRec1.isHole == Orientation(outRec1, m_UseFullRange))
                      ReversePolyPtLinks(outRec1.pts);
                    //make sure any contained holes now link to the correct polygon ...
                    if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
                }
                else
                {
                    outRec2.isHole = outRec1.isHole;
                    outRec2.FirstLeft = outRec1.FirstLeft;
                    //make sure any contained holes now link to the correct polygon ...
                    if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
                }

                //now fixup any subsequent m_Joins that match this polygon
                for (int k = i + 1; k < m_Joins.Count; k++)
                {
                    JoinRec j2 = m_Joins[k];
                    if (j2.poly1Idx == j.poly1Idx && PointIsVertex(j2.pt1a, p2))
                        j2.poly1Idx = j.poly2Idx;
                    if (j2.poly2Idx == j.poly1Idx && PointIsVertex(j2.pt2a, p2))
                        j2.poly2Idx = j.poly2Idx;
                }
                
                //now cleanup redundant edges too ...
                FixupOutPolygon(outRec1);
                FixupOutPolygon(outRec2);
            }
            else
            {
                //joined 2 polygons together ...

                //make sure any holes contained by outRec2 now link to outRec1 ...
                if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2);

                //now cleanup redundant edges too ...
                FixupOutPolygon(outRec1);

                if (outRec1.pts != null)
                {
                    outRec1.isHole = !Orientation(outRec1, m_UseFullRange);
                    if (outRec1.isHole &&  outRec1.FirstLeft == null) 
                      outRec1.FirstLeft = outRec2.FirstLeft;
                }

                //delete the obsolete pointer ...
                int OKIdx = outRec1.idx;
                int ObsoleteIdx = outRec2.idx;
                outRec2.pts = null;
                outRec2.bottomPt = null;
                outRec2.AppendLink = outRec1;

                //now fixup any subsequent joins that match this polygon
                for (int k = i + 1; k < m_Joins.Count; k++)
                {
                    JoinRec j2 = m_Joins[k];
                    if (j2.poly1Idx == ObsoleteIdx) j2.poly1Idx = OKIdx;
                    if (j2.poly2Idx == ObsoleteIdx) j2.poly2Idx = OKIdx;
                }
            }
          }
        }
Example #7
0
        //------------------------------------------------------------------------------

        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);
        }
Example #8
0
        //------------------------------------------------------------------------------

        private double GetDx(IntPoint pt1, IntPoint pt2)
        {
            if (pt1.Y == pt2.Y) return horizontal;
            else return (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y);
        }
Example #9
0
        //------------------------------------------------------------------------------

        private void DoBothEdges(TEdge edge1, TEdge edge2, IntPoint pt)
        {
            AddOutPt(edge1, pt);
            AddOutPt(edge2, pt);
            SwapSides(edge1, edge2);
            SwapPolyIndexes(edge1, edge2);
        }
Example #10
0
        //------------------------------------------------------------------------------

        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);
        }
Example #11
0
        //------------------------------------------------------------------------------

        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;
        }
Example #12
0
        //------------------------------------------------------------------------------

        private bool FindSegment(ref OutPt pp, 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, true) &&
                    SlopesEqual(pt1a, pt2a, pp.pt, true) &&
                    GetOverlapSegment(pt1a, pt2a, pp.pt, pp.prev.pt, ref pt1, ref pt2))
                        return true;
            pp = pp.next;
            }
            while (pp != pp2);
            return false;
        }
Example #13
0
        //------------------------------------------------------------------------------

        private bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
            IntPoint pt2b, ref IntPoint pt1, ref IntPoint pt2)
        {
            //precondition: segments are colinear.
            if ( pt1a.Y == pt1b.Y || Math.Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 )
            {
            if (pt1a.X > pt1b.X) SwapPoints(ref pt1a, ref pt1b);
            if (pt2a.X > pt2b.X) SwapPoints(ref pt2a, ref pt2b);
            if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
            if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
            return pt1.X < pt2.X;
            } else
            {
            if (pt1a.Y < pt1b.Y) SwapPoints(ref pt1a, ref pt1b);
            if (pt2a.Y < pt2b.Y) SwapPoints(ref pt2a, ref pt2b);
            if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
            if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
            return pt1.Y > pt2.Y;
            }
        }
Example #14
0
        //------------------------------------------------------------------------------

        internal void SwapPoints(ref IntPoint pt1, ref IntPoint pt2)
        {
            IntPoint tmp = pt1;
            pt1 = pt2;
            pt2 = tmp;
        }
Example #15
0
        //------------------------------------------------------------------------------

        private bool Orientation(OutRec outRec, bool UseFull64BitRange)
        {
            //first make sure bottomPt is correctly assigned ...
            OutPt opBottom = outRec.pts, op = outRec.pts.next;
            while (op != outRec.pts) 
            {
	            if (op.pt.Y >= opBottom.pt.Y) 
	            {
		            if (op.pt.Y > opBottom.pt.Y || op.pt.X < opBottom.pt.X) 
		            opBottom = op;
	            }
	            op = op.next;
            }
            outRec.bottomPt = opBottom;
            opBottom.idx = outRec.idx;
            
            op = opBottom;
            //find vertices either side of bottomPt (skipping duplicate points) ....
            OutPt opPrev = op.prev;
            OutPt opNext = op.next;
            while (op != opPrev && PointsEqual(op.pt, opPrev.pt)) 
              opPrev = opPrev.prev;
            while (op != opNext && PointsEqual(op.pt, opNext.pt))
              opNext = opNext.next;

            IntPoint vec1 = new IntPoint(op.pt.X - opPrev.pt.X, op.pt.Y - opPrev.pt.Y);
            IntPoint vec2 = new IntPoint(opNext.pt.X - op.pt.X, opNext.pt.Y - op.pt.Y);

            if (UseFull64BitRange)
            {
                Int128 cross = Int128.Int128Mul(vec1.X, vec2.Y) - Int128.Int128Mul(vec2.X, vec1.Y);
                return !cross.IsNegative();
            }
            else
                return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;

        }
Example #16
0
        //------------------------------------------------------------------------------

        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
                    DoBothEdges(e1, e2, pt);
            }
            else if (e1Contributing)
            {
                if ((e2Wc == 0 || e2Wc == 1) && 
                  (m_ClipType != ClipType.ctIntersection || 
                    e2.polyType == PolyType.ptSubject || (e2.windCnt2 != 0))) 
                        DoEdge1(e1, e2, pt);
            }
            else if (e2contributing)
            {
                if ((e1Wc == 0 || e1Wc == 1) &&
                  (m_ClipType != ClipType.ctIntersection ||
                                e1.polyType == PolyType.ptSubject || (e1.windCnt2 != 0))) 
                        DoEdge2(e1, e2, pt);
            }
            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);
        }
Example #17
0
 public IntPoint(IntPoint pt)
 {
     this.X = pt.X; this.Y = pt.Y;
 }
Example #18
0
        //------------------------------------------------------------------------------

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

          //prepare for sorting ...
          TEdge e = m_ActiveEdges;
          e.tmpX = TopX( e, topY );
          m_SortedEdges = e;
          m_SortedEdges.prevInSEL = null;
          e = e.nextInAEL;
          while( e != null )
          {
            e.prevInSEL = e.prevInAEL;
            e.prevInSEL.nextInSEL = e;
            e.nextInSEL = null;
            e.tmpX = 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.tmpX > eNext.tmpX && IntersectPoint(e, eNext, ref pt))
              {
                  if (pt.Y > botY)
                  {
                      pt.Y = botY;
                      pt.X = TopX(e, pt.Y);
                  }
                  AddIntersectNode(e, eNext, pt);
                  SwapPositionsInSEL(e, eNext);
                  isModified = true;
              }
              else
                e = eNext;
            }
            if( e.prevInSEL != null ) e.prevInSEL.nextInSEL = null;
            else break;
          }
          m_SortedEdges = null;
        }
Example #19
0
        //------------------------------------------------------------------------------
        // OffsetPolygon functions ...
        //------------------------------------------------------------------------------

        internal static Polygon BuildArc(IntPoint pt, double a1, double a2, double r)
        {
            int steps = Math.Max(6, (int)(Math.Sqrt(Math.Abs(r)) * Math.Abs(a2 - a1)));
            Polygon result = new Polygon(steps);
            int n = steps - 1;
            double da = (a2 - a1) / n;
            double a = a1;
            for (int i = 0; i < steps; ++i)
            {
                result.Add(new IntPoint(pt.X + Round(Math.Cos(a) * r), pt.Y + Round(Math.Sin(a) * r)));
                a += da;
            }
            return result;
        }
Example #20
0
        //------------------------------------------------------------------------------

        private Int64 TopX(IntPoint pt1, IntPoint pt2, Int64 currentY)
        {
          //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y
          if (currentY >= pt1.Y) return pt1.X;
          else if (currentY == pt2.Y) return pt2.X;
          else if (pt1.X == pt2.X) return pt1.X;
          else
          {
            double q = (pt1.X-pt2.X)/(pt1.Y-pt2.Y);
            return (Int64)Round(pt1.X + (currentY - pt1.Y) * q);
          }
        }
Example #21
0
 //------------------------------------------------------------------------------
 
 internal void AddPoint(IntPoint pt)
 {
     int len = currentPoly.Count;
     if (len == currentPoly.Capacity)
         currentPoly.Capacity = len + buffLength;
     currentPoly.Add(pt);
 }
Example #22
0
        //------------------------------------------------------------------------------

        private void AddIntersectNode(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( Process1Before2(newNode, m_IntersectNodes) )
          {
            newNode.next = m_IntersectNodes;
            m_IntersectNodes = newNode;
          }
          else
          {
            IntersectNode iNode = m_IntersectNodes;
            while( iNode.next != null  && Process1Before2(iNode.next, newNode) )
                iNode = iNode.next;
            newNode.next = iNode.next;
            iNode.next = newNode;
          }
        }
Example #23
0
            //------------------------------------------------------------------------------

            internal void DoMiter()
            {
                if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * delta >= 0)
                {
                    double q = delta / m_R;
                    AddPoint(new IntPoint((Int64)Round(pts[m_i][m_j].X + 
                        (normals[m_k].X + normals[m_j].X) * q),
                        (Int64)Round(pts[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
                }
                else
                {
                    IntPoint pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X + normals[m_k].X * delta),
                        (Int64)Round(pts[m_i][m_j].Y + normals[m_k].Y * delta));
                    IntPoint pt2 = 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);
                    AddPoint(pts[m_i][m_j]);
                    AddPoint(pt2);
                }
            }
Example #24
0
        //------------------------------------------------------------------------------

        private bool IntersectPoint(TEdge edge1, TEdge edge2, ref IntPoint ip)
        {
          double b1, b2;
          if (SlopesEqual(edge1, edge2, m_UseFullRange)) 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;
            b2 = (b2-b1)/(edge1.dx - edge2.dx);
            ip.Y = Round(b2);
            ip.X = Round(edge1.dx * b2 + b1);
          }

          return
            //can be *so close* to the top of one edge that the rounded Y equals one ytop ...
            (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) ||
            (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) ||
            (ip.Y > edge1.ytop && ip.Y > edge2.ytop);
        }
Example #25
0
        //------------------------------------------------------------------------------

        protected static bool PointsEqual(IntPoint pt1, IntPoint pt2)
        {
          return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
        }
Example #26
0
        //------------------------------------------------------------------------------

        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 ePrior = e.prevInAEL;
              DoMaxima(e, topY);
              if( ePrior == null ) e = m_ActiveEdges;
              else e = ePrior.nextInAEL;
            }
            else
            {
              //2. promote horizontal edges, otherwise update xcurr and ycurr ...
              if(  IsIntermediate(e, topY) && 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
              {
                //this just simplifies horizontal processing ...
                e.xcurr = TopX( e, topY );
                e.ycurr = 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 ...
              if (e.outIdx >= 0 && e.prevInAEL != null && e.prevInAEL.outIdx >= 0 &&
                e.prevInAEL.xcurr == e.xbot && e.prevInAEL.ycurr == e.ybot &&
                SlopesEqual(new IntPoint(e.xbot, e.ybot), new IntPoint(e.xtop, e.ytop),
                  new IntPoint(e.xbot, e.ybot),
                  new IntPoint(e.prevInAEL.xtop, e.prevInAEL.ytop), m_UseFullRange))
              {
                  AddOutPt(e.prevInAEL, new IntPoint(e.xbot, e.ybot));
                  AddJoin(e, e.prevInAEL, -1, -1);
              }
              else if (e.outIdx >= 0 && e.nextInAEL != null && e.nextInAEL.outIdx >= 0 &&
                e.nextInAEL.ycurr > e.nextInAEL.ytop &&
                e.nextInAEL.ycurr <= e.nextInAEL.ybot && 
                e.nextInAEL.xcurr == e.xbot && e.nextInAEL.ycurr == e.ybot &&
                SlopesEqual(new IntPoint(e.xbot, e.ybot), new IntPoint(e.xtop, e.ytop),
                  new IntPoint(e.xbot, e.ybot),
                  new IntPoint(e.nextInAEL.xtop, e.nextInAEL.ytop), m_UseFullRange))
              {
                  AddOutPt(e.nextInAEL, new IntPoint(e.xbot, e.ybot));
                  AddJoin(e, e.nextInAEL, -1, -1);
              }

            }
            e = e.nextInAEL;
          }
        }
Example #27
0
        //------------------------------------------------------------------------------

        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;
        }
Example #28
0
        //------------------------------------------------------------------------------

        public static bool Orientation(Polygon poly)
        {
            int highI = poly.Count -1;
            if (highI < 2) return false;
            int j = 0, jplus, jminus;
            for (int i = 0; i <= highI; ++i) 
            {
                if (poly[i].Y < poly[j].Y) continue;
                if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i;
            };
            if (j == highI) jplus = 0;
            else jplus = j +1;
            if (j == 0) jminus = highI;
            else jminus = j -1;

            //get cross product of vectors of the edges adjacent to highest point ...
            IntPoint vec1 = new IntPoint(poly[j].X - poly[jminus].X, poly[j].Y - poly[jminus].Y);
            IntPoint vec2 = new IntPoint(poly[jplus].X - poly[j].X, poly[jplus].Y - poly[j].Y);
            if (Math.Abs(vec1.X) > loRange || Math.Abs(vec1.Y) > loRange ||
                Math.Abs(vec2.X) > loRange || Math.Abs(vec2.Y) > loRange)
            {
                if (Math.Abs(vec1.X) > hiRange || Math.Abs(vec1.Y) > hiRange ||
                    Math.Abs(vec2.X) > hiRange || Math.Abs(vec2.Y) > hiRange)
                    throw new ClipperException("Coordinate exceeds range bounds.");
                Int128 cross = Int128.Int128Mul(vec1.X, vec2.Y) - Int128.Int128Mul(vec2.X, vec1.Y);
                return !cross.IsNegative();
            }
            else
                return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;
        }
Example #29
0
        //------------------------------------------------------------------------------

        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;
        }
Example #30
0
        //------------------------------------------------------------------------------

        private void AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt)
        {
            TEdge e, prevE;
            if (e2.dx == horizontal || (e1.dx > e2.dx))
            {
                AddOutPt(e1, pt);
                e2.outIdx = e1.outIdx;
                e1.side = EdgeSide.esLeft;
                e2.side = EdgeSide.esRight;
                e = e1;
                if (e.prevInAEL == e2)
                  prevE = e2.prevInAEL; 
                else
                  prevE = e.prevInAEL;
            }
            else
            {
                AddOutPt(e2, pt);
                e1.outIdx = e2.outIdx;
                e1.side = EdgeSide.esRight;
                e2.side = EdgeSide.esLeft;
                e = e2;
                if (e.prevInAEL == e1)
                    prevE = e1.prevInAEL;
                else
                    prevE = e.prevInAEL;
            }

            if (prevE != null && prevE.outIdx >= 0 &&
                (TopX(prevE, pt.Y) == TopX(e, pt.Y)) &&
                 SlopesEqual(e, prevE, m_UseFullRange))
                   AddJoin(e, prevE, -1, -1);

        }