Advertisement
Guest User

Untitled

a guest
Oct 17th, 2018
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 156.09 KB | None | 0 0
  1. #define use_lines
  2.  
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Drawing;
  6. using System.Linq;
  7.  
  8. namespace Polygon
  9. {
  10.  
  11. #if use_int32
  12.   using cInt = Int32;
  13. #else
  14.     using cInt = Int64;
  15. #endif
  16.  
  17.     using Path = List<IntPoint>;
  18.     using Paths = List<List<IntPoint>>;
  19.  
  20.     public struct DoublePoint
  21.     {
  22.         public double X;
  23.         public double Y;
  24.  
  25.         public DoublePoint(double x = 0, double y = 0)
  26.         {
  27.             X = x; Y = y;
  28.         }
  29.         public DoublePoint(DoublePoint dp)
  30.         {
  31.             X = dp.X; Y = dp.Y;
  32.         }
  33.         public DoublePoint(IntPoint ip)
  34.         {
  35.             X = ip.X; Y = ip.Y;
  36.         }
  37.     };
  38.  
  39.  
  40.  
  41.     public class PolyTree : PolyNode
  42.     {
  43.         internal List<PolyNode> m_AllPolys = new List<PolyNode>();
  44.  
  45.  
  46.         public void Clear()
  47.         {
  48.             for (int i = 0; i < m_AllPolys.Count; i++)
  49.                 m_AllPolys[i] = null;
  50.             m_AllPolys.Clear();
  51.             m_Childs.Clear();
  52.         }
  53.  
  54.         public PolyNode GetFirst()
  55.         {
  56.             if (m_Childs.Count > 0)
  57.                 return m_Childs[0];
  58.             else
  59.                 return null;
  60.         }
  61.  
  62.         public int Total
  63.         {
  64.             get
  65.             {
  66.                 int result = m_AllPolys.Count;
  67.                 if (result > 0 && m_Childs[0] != m_AllPolys[0]) result--;
  68.                 return result;
  69.             }
  70.         }
  71.  
  72.     }
  73.  
  74.     public class PolyNode
  75.     {
  76.         internal PolyNode m_Parent;
  77.         internal Path m_polygon = new Path();
  78.         internal int m_Index;
  79.         internal JoinType m_jointype;
  80.         internal EndType m_endtype;
  81.         internal List<PolyNode> m_Childs = new List<PolyNode>();
  82.  
  83.         private bool IsHoleNode()
  84.         {
  85.             bool result = true;
  86.             PolyNode node = m_Parent;
  87.             while (node != null)
  88.             {
  89.                 result = !result;
  90.                 node = node.m_Parent;
  91.             }
  92.             return result;
  93.         }
  94.  
  95.         public int ChildCount
  96.         {
  97.             get { return m_Childs.Count; }
  98.         }
  99.  
  100.         public Path Contour
  101.         {
  102.             get { return m_polygon; }
  103.         }
  104.  
  105.         internal void AddChild(PolyNode Child)
  106.         {
  107.             int cnt = m_Childs.Count;
  108.             m_Childs.Add(Child);
  109.             Child.m_Parent = this;
  110.             Child.m_Index = cnt;
  111.         }
  112.  
  113.         public PolyNode GetNext()
  114.         {
  115.             if (m_Childs.Count > 0)
  116.                 return m_Childs[0];
  117.             else
  118.                 return GetNextSiblingUp();
  119.         }
  120.  
  121.         internal PolyNode GetNextSiblingUp()
  122.         {
  123.             if (m_Parent == null)
  124.                 return null;
  125.             else if (m_Index == m_Parent.m_Childs.Count - 1)
  126.                 return m_Parent.GetNextSiblingUp();
  127.             else
  128.                 return m_Parent.m_Childs[m_Index + 1];
  129.         }
  130.  
  131.         public List<PolyNode> Childs
  132.         {
  133.             get { return m_Childs; }
  134.         }
  135.  
  136.         public PolyNode Parent
  137.         {
  138.             get { return m_Parent; }
  139.         }
  140.  
  141.         public bool IsHole
  142.         {
  143.             get { return IsHoleNode(); }
  144.         }
  145.  
  146.         public bool IsOpen { get; set; }
  147.     }
  148.  
  149.  
  150.  
  151.     internal struct Int128
  152.     {
  153.         private Int64 hi;
  154.         private UInt64 lo;
  155.  
  156.         public Int128(Int64 _lo)
  157.         {
  158.             lo = (UInt64)_lo;
  159.             if (_lo < 0) hi = -1;
  160.             else hi = 0;
  161.         }
  162.  
  163.         public Int128(Int64 _hi, UInt64 _lo)
  164.         {
  165.             lo = _lo;
  166.             hi = _hi;
  167.         }
  168.  
  169.         public Int128(Int128 val)
  170.         {
  171.             hi = val.hi;
  172.             lo = val.lo;
  173.         }
  174.  
  175.         public bool IsNegative()
  176.         {
  177.             return hi < 0;
  178.         }
  179.  
  180.         public static bool operator ==(Int128 val1, Int128 val2)
  181.         {
  182.             if ((object)val1 == (object)val2) return true;
  183.             else if ((object)val1 == null || (object)val2 == null) return false;
  184.             return (val1.hi == val2.hi && val1.lo == val2.lo);
  185.         }
  186.  
  187.         public static bool operator !=(Int128 val1, Int128 val2)
  188.         {
  189.             return !(val1 == val2);
  190.         }
  191.  
  192.         public override bool Equals(Object obj)
  193.         {
  194.             if (obj == null || !(obj is Int128))
  195.                 return false;
  196.             Int128 i128 = (Int128)obj;
  197.             return (i128.hi == hi && i128.lo == lo);
  198.         }
  199.  
  200.         public override int GetHashCode()
  201.         {
  202.             return hi.GetHashCode() ^ lo.GetHashCode();
  203.         }
  204.  
  205.         public static bool operator >(Int128 val1, Int128 val2)
  206.         {
  207.             if (val1.hi != val2.hi)
  208.                 return val1.hi > val2.hi;
  209.             else
  210.                 return val1.lo > val2.lo;
  211.         }
  212.  
  213.         public static bool operator <(Int128 val1, Int128 val2)
  214.         {
  215.             if (val1.hi != val2.hi)
  216.                 return val1.hi < val2.hi;
  217.             else
  218.                 return val1.lo < val2.lo;
  219.         }
  220.  
  221.         public static Int128 operator +(Int128 lhs, Int128 rhs)
  222.         {
  223.             lhs.hi += rhs.hi;
  224.             lhs.lo += rhs.lo;
  225.             if (lhs.lo < rhs.lo) lhs.hi++;
  226.             return lhs;
  227.         }
  228.  
  229.         public static Int128 operator -(Int128 lhs, Int128 rhs)
  230.         {
  231.             return lhs + -rhs;
  232.         }
  233.  
  234.         public static Int128 operator -(Int128 val)
  235.         {
  236.             if (val.lo == 0)
  237.                 return new Int128(-val.hi, 0);
  238.             else
  239.                 return new Int128(~val.hi, ~val.lo + 1);
  240.         }
  241.  
  242.         public static explicit operator double(Int128 val)
  243.         {
  244.             const double shift64 = 18446744073709551616.0; if (val.hi < 0)
  245.             {
  246.                 if (val.lo == 0)
  247.                     return (double)val.hi * shift64;
  248.                 else
  249.                     return -(double)(~val.lo + ~val.hi * shift64);
  250.             }
  251.             else
  252.                 return (double)(val.lo + val.hi * shift64);
  253.         }
  254.  
  255.  
  256.         public static Int128 Int128Mul(Int64 lhs, Int64 rhs)
  257.         {
  258.             bool negate = (lhs < 0) != (rhs < 0);
  259.             if (lhs < 0) lhs = -lhs;
  260.             if (rhs < 0) rhs = -rhs;
  261.             UInt64 int1Hi = (UInt64)lhs >> 32;
  262.             UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF;
  263.             UInt64 int2Hi = (UInt64)rhs >> 32;
  264.             UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF;
  265.  
  266.             UInt64 a = int1Hi * int2Hi;
  267.             UInt64 b = int1Lo * int2Lo;
  268.             UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi;
  269.  
  270.             UInt64 lo;
  271.             Int64 hi;
  272.             hi = (Int64)(a + (c >> 32));
  273.  
  274.             unchecked { lo = (c << 32) + b; }
  275.             if (lo < b) hi++;
  276.             Int128 result = new Int128(hi, lo);
  277.             return negate ? -result : result;
  278.         }
  279.  
  280.     };
  281.  
  282.  
  283.     public struct IntPoint
  284.     {
  285.         public cInt X;
  286.         public cInt Y;
  287. #if use_xyz
  288.     public cInt Z;
  289.    
  290.     public IntPoint(cInt x, cInt y, cInt z = 0)
  291.     {
  292.       this.X = x; this.Y = y; this.Z = z;
  293.     }
  294.    
  295.     public IntPoint(double x, double y, double z = 0)
  296.     {
  297.       this.X = (cInt)x; this.Y = (cInt)y; this.Z = (cInt)z;
  298.     }
  299.    
  300.     public IntPoint(DoublePoint dp)
  301.     {
  302.       this.X = (cInt)dp.X; this.Y = (cInt)dp.Y; this.Z = 0;
  303.     }
  304.  
  305.     public IntPoint(IntPoint pt)
  306.     {
  307.       this.X = pt.X; this.Y = pt.Y; this.Z = pt.Z;
  308.     }
  309. #else
  310.         public IntPoint(cInt X, cInt Y)
  311.         {
  312.             this.X = X; this.Y = Y;
  313.         }
  314.         public IntPoint(double x, double y)
  315.         {
  316.             X = (cInt)x; Y = (cInt)y;
  317.         }
  318.  
  319.         public IntPoint(IntPoint pt)
  320.         {
  321.             X = pt.X; Y = pt.Y;
  322.         }
  323. #endif
  324.  
  325.         public static bool operator ==(IntPoint a, IntPoint b)
  326.         {
  327.             return a.X == b.X && a.Y == b.Y;
  328.         }
  329.  
  330.         public static bool operator !=(IntPoint a, IntPoint b)
  331.         {
  332.             return a.X != b.X || a.Y != b.Y;
  333.         }
  334.  
  335.         public override bool Equals(object obj)
  336.         {
  337.             if (obj == null) return false;
  338.             if (obj is IntPoint)
  339.             {
  340.                 IntPoint a = (IntPoint)obj;
  341.                 return (X == a.X) && (Y == a.Y);
  342.             }
  343.             else return false;
  344.         }
  345.  
  346.         public override int GetHashCode()
  347.         {
  348.             return base.GetHashCode();
  349.         }
  350.  
  351.     }
  352.     public struct IntRect
  353.     {
  354.         public cInt left;
  355.         public cInt top;
  356.         public cInt right;
  357.         public cInt bottom;
  358.  
  359.         public IntRect(cInt l, cInt t, cInt r, cInt b)
  360.         {
  361.             left = l; top = t;
  362.             right = r; bottom = b;
  363.         }
  364.         public IntRect(IntRect ir)
  365.         {
  366.             left = ir.left; top = ir.top;
  367.             right = ir.right; bottom = ir.bottom;
  368.         }
  369.     }
  370.  
  371.     public enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
  372.     public enum PolyType { ptSubject, ptClip };
  373.  
  374.     public enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
  375.  
  376.     public enum JoinType { jtSquare, jtRound, jtMiter };
  377.     public enum EndType { etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound };
  378.  
  379.     internal enum EdgeSide { esLeft, esRight };
  380.     internal enum Direction { dRightToLeft, dLeftToRight };
  381.  
  382.     internal class TEdge
  383.     {
  384.         internal IntPoint Bot;
  385.         internal IntPoint Curr; internal IntPoint Top;
  386.         internal IntPoint Delta;
  387.         internal double Dx;
  388.         internal PolyType PolyTyp;
  389.         internal EdgeSide Side; internal int WindDelta; internal int WindCnt;
  390.         internal int WindCnt2; internal int OutIdx;
  391.         internal TEdge Next;
  392.         internal TEdge Prev;
  393.         internal TEdge NextInLML;
  394.         internal TEdge NextInAEL;
  395.         internal TEdge PrevInAEL;
  396.         internal TEdge NextInSEL;
  397.         internal TEdge PrevInSEL;
  398.     };
  399.  
  400.     public class IntersectNode
  401.     {
  402.         internal TEdge Edge1;
  403.         internal TEdge Edge2;
  404.         internal IntPoint Pt;
  405.     };
  406.  
  407.     public class MyIntersectNodeSort : IComparer<IntersectNode>
  408.     {
  409.         public int Compare(IntersectNode node1, IntersectNode node2)
  410.         {
  411.             cInt i = node2.Pt.Y - node1.Pt.Y;
  412.             if (i > 0) return 1;
  413.             else if (i < 0) return -1;
  414.             else return 0;
  415.         }
  416.     }
  417.  
  418.     internal class LocalMinima
  419.     {
  420.         internal cInt Y;
  421.         internal TEdge LeftBound;
  422.         internal TEdge RightBound;
  423.         internal LocalMinima Next;
  424.     };
  425.  
  426.     internal class Scanbeam
  427.     {
  428.         internal cInt Y;
  429.         internal Scanbeam Next;
  430.     };
  431.  
  432.     internal class Maxima
  433.     {
  434.         internal cInt X;
  435.         internal Maxima Next;
  436.         internal Maxima Prev;
  437.     };
  438.  
  439.     internal class OutRec
  440.     {
  441.         internal int Idx;
  442.         internal bool IsHole;
  443.         internal bool IsOpen;
  444.         internal OutRec FirstLeft; internal OutPt Pts;
  445.         internal OutPt BottomPt;
  446.         internal PolyNode PolyNode;
  447.     };
  448.  
  449.     internal class OutPt
  450.     {
  451.         internal int Idx;
  452.         internal IntPoint Pt;
  453.         internal OutPt Next;
  454.         internal OutPt Prev;
  455.     };
  456.  
  457.     internal class Join
  458.     {
  459.         internal OutPt OutPt1;
  460.         internal OutPt OutPt2;
  461.         internal IntPoint OffPt;
  462.     };
  463.  
  464.     public class ClipperBase
  465.     {
  466.         internal const double horizontal = -3.4E+38;
  467.         internal const int Skip = -2;
  468.         internal const int Unassigned = -1;
  469.         internal const double tolerance = 1.0E-20;
  470.         internal static bool near_zero(double val) { return (val > -tolerance) && (val < tolerance); }
  471.  
  472. #if use_int32
  473.     public const cInt loRange = 0x7FFF;
  474.     public const cInt hiRange = 0x7FFF;
  475. #else
  476.         public const cInt loRange = 0x3FFFFFFF;
  477.         public const cInt hiRange = 0x3FFFFFFFFFFFFFFFL;
  478. #endif
  479.  
  480.         internal LocalMinima m_MinimaList;
  481.         internal LocalMinima m_CurrentLM;
  482.         internal List<List<TEdge>> m_edges = new List<List<TEdge>>();
  483.         internal Scanbeam m_Scanbeam;
  484.         internal List<OutRec> m_PolyOuts;
  485.         internal TEdge m_ActiveEdges;
  486.         internal bool m_UseFullRange;
  487.         internal bool m_HasOpenPaths;
  488.  
  489.  
  490.         public bool PreserveCollinear
  491.         {
  492.             get;
  493.             set;
  494.         }
  495.  
  496.         public void Swap(ref cInt val1, ref cInt val2)
  497.         {
  498.             cInt tmp = val1;
  499.             val1 = val2;
  500.             val2 = tmp;
  501.         }
  502.  
  503.         internal static bool IsHorizontal(TEdge e)
  504.         {
  505.             return e.Delta.Y == 0;
  506.         }
  507.  
  508.         internal bool PointIsVertex(IntPoint pt, OutPt pp)
  509.         {
  510.             OutPt pp2 = pp;
  511.             do
  512.             {
  513.                 if (pp2.Pt == pt) return true;
  514.                 pp2 = pp2.Next;
  515.             }
  516.             while (pp2 != pp);
  517.             return false;
  518.         }
  519.  
  520.         internal bool PointOnLineSegment(IntPoint pt,
  521.             IntPoint linePt1, IntPoint linePt2, bool UseFullRange)
  522.         {
  523.             if (UseFullRange)
  524.                 return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
  525.                   ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
  526.                   (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
  527.                   ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
  528.                   ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) ==
  529.                   Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))));
  530.             else
  531.                 return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
  532.                   ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
  533.                   (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
  534.                   ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
  535.                   ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) ==
  536.                     (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)));
  537.         }
  538.  
  539.         internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullRange)
  540.         {
  541.             OutPt pp2 = pp;
  542.             while (true)
  543.             {
  544.                 if (PointOnLineSegment(pt, pp2.Pt, pp2.Next.Pt, UseFullRange))
  545.                     return true;
  546.                 pp2 = pp2.Next;
  547.                 if (pp2 == pp) break;
  548.             }
  549.             return false;
  550.         }
  551.  
  552.         internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange)
  553.         {
  554.             if (UseFullRange)
  555.                 return Int128.Int128Mul(e1.Delta.Y, e2.Delta.X) ==
  556.                     Int128.Int128Mul(e1.Delta.X, e2.Delta.Y);
  557.             else return (cInt)(e1.Delta.Y) * (e2.Delta.X) ==
  558.               (cInt)(e1.Delta.X) * (e2.Delta.Y);
  559.         }
  560.  
  561.         internal static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
  562.             IntPoint pt3, bool UseFullRange)
  563.         {
  564.             if (UseFullRange)
  565.                 return Int128.Int128Mul(pt1.Y - pt2.Y, pt2.X - pt3.X) ==
  566.                   Int128.Int128Mul(pt1.X - pt2.X, pt2.Y - pt3.Y);
  567.             else return
  568.               (cInt)(pt1.Y - pt2.Y) * (pt2.X - pt3.X) - (cInt)(pt1.X - pt2.X) * (pt2.Y - pt3.Y) == 0;
  569.         }
  570.  
  571.         internal static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
  572.             IntPoint pt3, IntPoint pt4, bool UseFullRange)
  573.         {
  574.             if (UseFullRange)
  575.                 return Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
  576.                   Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
  577.             else return
  578.               (cInt)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (cInt)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0;
  579.         }
  580.  
  581.         internal ClipperBase()
  582.         {
  583.             m_MinimaList = null;
  584.             m_CurrentLM = null;
  585.             m_UseFullRange = false;
  586.             m_HasOpenPaths = false;
  587.         }
  588.  
  589.         public virtual void Clear()
  590.         {
  591.             DisposeLocalMinimaList();
  592.             for (int i = 0; i < m_edges.Count; ++i)
  593.             {
  594.                 for (int j = 0; j < m_edges[i].Count; ++j) m_edges[i][j] = null;
  595.                 m_edges[i].Clear();
  596.             }
  597.             m_edges.Clear();
  598.             m_UseFullRange = false;
  599.             m_HasOpenPaths = false;
  600.         }
  601.  
  602.         private void DisposeLocalMinimaList()
  603.         {
  604.             while (m_MinimaList != null)
  605.             {
  606.                 LocalMinima tmpLm = m_MinimaList.Next;
  607.                 m_MinimaList = null;
  608.                 m_MinimaList = tmpLm;
  609.             }
  610.             m_CurrentLM = null;
  611.         }
  612.  
  613.         void RangeTest(IntPoint Pt, ref bool useFullRange)
  614.         {
  615.             if (useFullRange)
  616.             {
  617.                 if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
  618.                     throw new ClipperException("Coordinate outside allowed range");
  619.             }
  620.             else if (Pt.X > loRange || Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
  621.             {
  622.                 useFullRange = true;
  623.                 RangeTest(Pt, ref useFullRange);
  624.             }
  625.         }
  626.  
  627.         private void InitEdge(TEdge e, TEdge eNext,
  628.           TEdge ePrev, IntPoint pt)
  629.         {
  630.             e.Next = eNext;
  631.             e.Prev = ePrev;
  632.             e.Curr = pt;
  633.             e.OutIdx = Unassigned;
  634.         }
  635.  
  636.         private void InitEdge2(TEdge e, PolyType polyType)
  637.         {
  638.             if (e.Curr.Y >= e.Next.Curr.Y)
  639.             {
  640.                 e.Bot = e.Curr;
  641.                 e.Top = e.Next.Curr;
  642.             }
  643.             else
  644.             {
  645.                 e.Top = e.Curr;
  646.                 e.Bot = e.Next.Curr;
  647.             }
  648.             SetDx(e);
  649.             e.PolyTyp = polyType;
  650.         }
  651.  
  652.         private TEdge FindNextLocMin(TEdge E)
  653.         {
  654.             TEdge E2;
  655.             for (; ; )
  656.             {
  657.                 while (E.Bot != E.Prev.Bot || E.Curr == E.Top) E = E.Next;
  658.                 if (E.Dx != horizontal && E.Prev.Dx != horizontal) break;
  659.                 while (E.Prev.Dx == horizontal) E = E.Prev;
  660.                 E2 = E;
  661.                 while (E.Dx == horizontal) E = E.Next;
  662.                 if (E.Top.Y == E.Prev.Bot.Y) continue; if (E2.Prev.Bot.X < E.Bot.X) E = E2;
  663.                 break;
  664.             }
  665.             return E;
  666.         }
  667.  
  668.         private TEdge ProcessBound(TEdge E, bool LeftBoundIsForward)
  669.         {
  670.             TEdge EStart, Result = E;
  671.             TEdge Horz;
  672.  
  673.             if (Result.OutIdx == Skip)
  674.             {
  675.                 E = Result;
  676.                 if (LeftBoundIsForward)
  677.                 {
  678.                     while (E.Top.Y == E.Next.Bot.Y) E = E.Next;
  679.                     while (E != Result && E.Dx == horizontal) E = E.Prev;
  680.                 }
  681.                 else
  682.                 {
  683.                     while (E.Top.Y == E.Prev.Bot.Y) E = E.Prev;
  684.                     while (E != Result && E.Dx == horizontal) E = E.Next;
  685.                 }
  686.                 if (E == Result)
  687.                 {
  688.                     if (LeftBoundIsForward) Result = E.Next;
  689.                     else Result = E.Prev;
  690.                 }
  691.                 else
  692.                 {
  693.                     if (LeftBoundIsForward)
  694.                         E = Result.Next;
  695.                     else
  696.                         E = Result.Prev;
  697.                     LocalMinima locMin = new LocalMinima();
  698.                     locMin.Next = null;
  699.                     locMin.Y = E.Bot.Y;
  700.                     locMin.LeftBound = null;
  701.                     locMin.RightBound = E;
  702.                     E.WindDelta = 0;
  703.                     Result = ProcessBound(E, LeftBoundIsForward);
  704.                     InsertLocalMinima(locMin);
  705.                 }
  706.                 return Result;
  707.             }
  708.  
  709.             if (E.Dx == horizontal)
  710.             {
  711.                 if (LeftBoundIsForward) EStart = E.Prev;
  712.                 else EStart = E.Next;
  713.                 if (EStart.Dx == horizontal)
  714.                 {
  715.                     if (EStart.Bot.X != E.Bot.X && EStart.Top.X != E.Bot.X)
  716.                         ReverseHorizontal(E);
  717.                 }
  718.                 else if (EStart.Bot.X != E.Bot.X)
  719.                     ReverseHorizontal(E);
  720.             }
  721.  
  722.             EStart = E;
  723.             if (LeftBoundIsForward)
  724.             {
  725.                 while (Result.Top.Y == Result.Next.Bot.Y && Result.Next.OutIdx != Skip)
  726.                     Result = Result.Next;
  727.                 if (Result.Dx == horizontal && Result.Next.OutIdx != Skip)
  728.                 {
  729.                     Horz = Result;
  730.                     while (Horz.Prev.Dx == horizontal) Horz = Horz.Prev;
  731.                     if (Horz.Prev.Top.X > Result.Next.Top.X) Result = Horz.Prev;
  732.                 }
  733.                 while (E != Result)
  734.                 {
  735.                     E.NextInLML = E.Next;
  736.                     if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
  737.                         ReverseHorizontal(E);
  738.                     E = E.Next;
  739.                 }
  740.                 if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
  741.                     ReverseHorizontal(E);
  742.                 Result = Result.Next;
  743.             }
  744.             else
  745.             {
  746.                 while (Result.Top.Y == Result.Prev.Bot.Y && Result.Prev.OutIdx != Skip)
  747.                     Result = Result.Prev;
  748.                 if (Result.Dx == horizontal && Result.Prev.OutIdx != Skip)
  749.                 {
  750.                     Horz = Result;
  751.                     while (Horz.Next.Dx == horizontal) Horz = Horz.Next;
  752.                     if (Horz.Next.Top.X == Result.Prev.Top.X ||
  753.                         Horz.Next.Top.X > Result.Prev.Top.X) Result = Horz.Next;
  754.                 }
  755.  
  756.                 while (E != Result)
  757.                 {
  758.                     E.NextInLML = E.Prev;
  759.                     if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
  760.                         ReverseHorizontal(E);
  761.                     E = E.Prev;
  762.                 }
  763.                 if (E.Dx == horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
  764.                     ReverseHorizontal(E);
  765.                 Result = Result.Prev;
  766.             }
  767.             return Result;
  768.         }
  769.  
  770.  
  771.         public bool AddPath(Path pg, PolyType polyType, bool Closed)
  772.         {
  773. #if use_lines
  774.             if (!Closed && polyType == PolyType.ptClip)
  775.                 throw new ClipperException("AddPath: Open paths must be subject.");
  776. #else
  777.       if (!Closed)
  778.         throw new ClipperException("AddPath: Open paths have been disabled.");
  779. #endif
  780.  
  781.             int highI = (int)pg.Count - 1;
  782.             if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI;
  783.             while (highI > 0 && (pg[highI] == pg[highI - 1])) --highI;
  784.             if ((Closed && highI < 2) || (!Closed && highI < 1)) return false;
  785.  
  786.             List<TEdge> edges = new List<TEdge>(highI + 1);
  787.             for (int i = 0; i <= highI; i++) edges.Add(new TEdge());
  788.  
  789.             bool IsFlat = true;
  790.  
  791.             edges[1].Curr = pg[1];
  792.             RangeTest(pg[0], ref m_UseFullRange);
  793.             RangeTest(pg[highI], ref m_UseFullRange);
  794.             InitEdge(edges[0], edges[1], edges[highI], pg[0]);
  795.             InitEdge(edges[highI], edges[0], edges[highI - 1], pg[highI]);
  796.             for (int i = highI - 1; i >= 1; --i)
  797.             {
  798.                 RangeTest(pg[i], ref m_UseFullRange);
  799.                 InitEdge(edges[i], edges[i + 1], edges[i - 1], pg[i]);
  800.             }
  801.             TEdge eStart = edges[0];
  802.  
  803.             TEdge E = eStart, eLoopStop = eStart;
  804.             for (; ; )
  805.             {
  806.                 if (E.Curr == E.Next.Curr && (Closed || E.Next != eStart))
  807.                 {
  808.                     if (E == E.Next) break;
  809.                     if (E == eStart) eStart = E.Next;
  810.                     E = RemoveEdge(E);
  811.                     eLoopStop = E;
  812.                     continue;
  813.                 }
  814.                 if (E.Prev == E.Next)
  815.                     break;
  816.                 else if (Closed &&
  817. SlopesEqual(E.Prev.Curr, E.Curr, E.Next.Curr, m_UseFullRange) &&
  818. (!PreserveCollinear ||
  819. !Pt2IsBetweenPt1AndPt3(E.Prev.Curr, E.Curr, E.Next.Curr)))
  820.                 {
  821.                     if (E == eStart) eStart = E.Next;
  822.                     E = RemoveEdge(E);
  823.                     E = E.Prev;
  824.                     eLoopStop = E;
  825.                     continue;
  826.                 }
  827.                 E = E.Next;
  828.                 if ((E == eLoopStop) || (!Closed && E.Next == eStart)) break;
  829.             }
  830.  
  831.             if ((!Closed && (E == E.Next)) || (Closed && (E.Prev == E.Next)))
  832.                 return false;
  833.  
  834.             if (!Closed)
  835.             {
  836.                 m_HasOpenPaths = true;
  837.                 eStart.Prev.OutIdx = Skip;
  838.             }
  839.  
  840.             E = eStart;
  841.             do
  842.             {
  843.                 InitEdge2(E, polyType);
  844.                 E = E.Next;
  845.                 if (IsFlat && E.Curr.Y != eStart.Curr.Y) IsFlat = false;
  846.             }
  847.             while (E != eStart);
  848.  
  849.  
  850.             if (IsFlat)
  851.             {
  852.                 if (Closed) return false;
  853.                 E.Prev.OutIdx = Skip;
  854.                 LocalMinima locMin = new LocalMinima();
  855.                 locMin.Next = null;
  856.                 locMin.Y = E.Bot.Y;
  857.                 locMin.LeftBound = null;
  858.                 locMin.RightBound = E;
  859.                 locMin.RightBound.Side = EdgeSide.esRight;
  860.                 locMin.RightBound.WindDelta = 0;
  861.                 for (; ; )
  862.                 {
  863.                     if (E.Bot.X != E.Prev.Top.X) ReverseHorizontal(E);
  864.                     if (E.Next.OutIdx == Skip) break;
  865.                     E.NextInLML = E.Next;
  866.                     E = E.Next;
  867.                 }
  868.                 InsertLocalMinima(locMin);
  869.                 m_edges.Add(edges);
  870.                 return true;
  871.             }
  872.  
  873.             m_edges.Add(edges);
  874.             bool leftBoundIsForward;
  875.             TEdge EMin = null;
  876.  
  877.             if (E.Prev.Bot == E.Prev.Top) E = E.Next;
  878.  
  879.             for (; ; )
  880.             {
  881.                 E = FindNextLocMin(E);
  882.                 if (E == EMin) break;
  883.                 else if (EMin == null) EMin = E;
  884.  
  885.                 LocalMinima locMin = new LocalMinima();
  886.                 locMin.Next = null;
  887.                 locMin.Y = E.Bot.Y;
  888.                 if (E.Dx < E.Prev.Dx)
  889.                 {
  890.                     locMin.LeftBound = E.Prev;
  891.                     locMin.RightBound = E;
  892.                     leftBoundIsForward = false;
  893.                 }
  894.                 else
  895.                 {
  896.                     locMin.LeftBound = E;
  897.                     locMin.RightBound = E.Prev;
  898.                     leftBoundIsForward = true;
  899.                 }
  900.                 locMin.LeftBound.Side = EdgeSide.esLeft;
  901.                 locMin.RightBound.Side = EdgeSide.esRight;
  902.  
  903.                 if (!Closed) locMin.LeftBound.WindDelta = 0;
  904.                 else if (locMin.LeftBound.Next == locMin.RightBound)
  905.                     locMin.LeftBound.WindDelta = -1;
  906.                 else locMin.LeftBound.WindDelta = 1;
  907.                 locMin.RightBound.WindDelta = -locMin.LeftBound.WindDelta;
  908.  
  909.                 E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
  910.                 if (E.OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
  911.  
  912.                 TEdge E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
  913.                 if (E2.OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
  914.  
  915.                 if (locMin.LeftBound.OutIdx == Skip)
  916.                     locMin.LeftBound = null;
  917.                 else if (locMin.RightBound.OutIdx == Skip)
  918.                     locMin.RightBound = null;
  919.                 InsertLocalMinima(locMin);
  920.                 if (!leftBoundIsForward) E = E2;
  921.             }
  922.             return true;
  923.  
  924.         }
  925.  
  926.         public bool AddPaths(Paths ppg, PolyType polyType, bool closed)
  927.         {
  928.             bool result = false;
  929.             for (int i = 0; i < ppg.Count; ++i)
  930.                 if (AddPath(ppg[i], polyType, closed)) result = true;
  931.             return result;
  932.         }
  933.  
  934.         internal bool Pt2IsBetweenPt1AndPt3(IntPoint pt1, IntPoint pt2, IntPoint pt3)
  935.         {
  936.             if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) return false;
  937.             else if (pt1.X != pt3.X) return (pt2.X > pt1.X) == (pt2.X < pt3.X);
  938.             else return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
  939.         }
  940.  
  941.         TEdge RemoveEdge(TEdge e)
  942.         {
  943.             e.Prev.Next = e.Next;
  944.             e.Next.Prev = e.Prev;
  945.             TEdge result = e.Next;
  946.             e.Prev = null; return result;
  947.         }
  948.  
  949.         private void SetDx(TEdge e)
  950.         {
  951.             e.Delta.X = (e.Top.X - e.Bot.X);
  952.             e.Delta.Y = (e.Top.Y - e.Bot.Y);
  953.             if (e.Delta.Y == 0) e.Dx = horizontal;
  954.             else e.Dx = (double)(e.Delta.X) / (e.Delta.Y);
  955.         }
  956.  
  957.         private void InsertLocalMinima(LocalMinima newLm)
  958.         {
  959.             if (m_MinimaList == null)
  960.             {
  961.                 m_MinimaList = newLm;
  962.             }
  963.             else if (newLm.Y >= m_MinimaList.Y)
  964.             {
  965.                 newLm.Next = m_MinimaList;
  966.                 m_MinimaList = newLm;
  967.             }
  968.             else
  969.             {
  970.                 LocalMinima tmpLm = m_MinimaList;
  971.                 while (tmpLm.Next != null && (newLm.Y < tmpLm.Next.Y))
  972.                     tmpLm = tmpLm.Next;
  973.                 newLm.Next = tmpLm.Next;
  974.                 tmpLm.Next = newLm;
  975.             }
  976.         }
  977.  
  978.         internal Boolean PopLocalMinima(cInt Y, out LocalMinima current)
  979.         {
  980.             current = m_CurrentLM;
  981.             if (m_CurrentLM != null && m_CurrentLM.Y == Y)
  982.             {
  983.                 m_CurrentLM = m_CurrentLM.Next;
  984.                 return true;
  985.             }
  986.             return false;
  987.         }
  988.  
  989.         private void ReverseHorizontal(TEdge e)
  990.         {
  991.             Swap(ref e.Top.X, ref e.Bot.X);
  992. #if use_xyz
  993.       Swap(ref e.Top.Z, ref e.Bot.Z);
  994. #endif
  995.         }
  996.  
  997.         internal virtual void Reset()
  998.         {
  999.             m_CurrentLM = m_MinimaList;
  1000.             if (m_CurrentLM == null) return;
  1001.             m_Scanbeam = null;
  1002.             LocalMinima lm = m_MinimaList;
  1003.             while (lm != null)
  1004.             {
  1005.                 InsertScanbeam(lm.Y);
  1006.                 TEdge e = lm.LeftBound;
  1007.                 if (e != null)
  1008.                 {
  1009.                     e.Curr = e.Bot;
  1010.                     e.OutIdx = Unassigned;
  1011.                 }
  1012.                 e = lm.RightBound;
  1013.                 if (e != null)
  1014.                 {
  1015.                     e.Curr = e.Bot;
  1016.                     e.OutIdx = Unassigned;
  1017.                 }
  1018.                 lm = lm.Next;
  1019.             }
  1020.             m_ActiveEdges = null;
  1021.         }
  1022.  
  1023.         public static IntRect GetBounds(Paths paths)
  1024.         {
  1025.             int i = 0, cnt = paths.Count;
  1026.             while (i < cnt && paths[i].Count == 0) i++;
  1027.             if (i == cnt) return new IntRect(0, 0, 0, 0);
  1028.             IntRect result = new IntRect();
  1029.             result.left = paths[i][0].X;
  1030.             result.right = result.left;
  1031.             result.top = paths[i][0].Y;
  1032.             result.bottom = result.top;
  1033.             for (; i < cnt; i++)
  1034.                 for (int j = 0; j < paths[i].Count; j++)
  1035.                 {
  1036.                     if (paths[i][j].X < result.left) result.left = paths[i][j].X;
  1037.                     else if (paths[i][j].X > result.right) result.right = paths[i][j].X;
  1038.                     if (paths[i][j].Y < result.top) result.top = paths[i][j].Y;
  1039.                     else if (paths[i][j].Y > result.bottom) result.bottom = paths[i][j].Y;
  1040.                 }
  1041.             return result;
  1042.         }
  1043.  
  1044.         internal void InsertScanbeam(cInt Y)
  1045.         {
  1046.             if (m_Scanbeam == null)
  1047.             {
  1048.                 m_Scanbeam = new Scanbeam();
  1049.                 m_Scanbeam.Next = null;
  1050.                 m_Scanbeam.Y = Y;
  1051.             }
  1052.             else if (Y > m_Scanbeam.Y)
  1053.             {
  1054.                 Scanbeam newSb = new Scanbeam();
  1055.                 newSb.Y = Y;
  1056.                 newSb.Next = m_Scanbeam;
  1057.                 m_Scanbeam = newSb;
  1058.             }
  1059.             else
  1060.             {
  1061.                 Scanbeam sb2 = m_Scanbeam;
  1062.                 while (sb2.Next != null && (Y <= sb2.Next.Y)) sb2 = sb2.Next;
  1063.                 if (Y == sb2.Y) return; Scanbeam newSb = new Scanbeam();
  1064.                 newSb.Y = Y;
  1065.                 newSb.Next = sb2.Next;
  1066.                 sb2.Next = newSb;
  1067.             }
  1068.         }
  1069.  
  1070.         internal Boolean PopScanbeam(out cInt Y)
  1071.         {
  1072.             if (m_Scanbeam == null)
  1073.             {
  1074.                 Y = 0;
  1075.                 return false;
  1076.             }
  1077.             Y = m_Scanbeam.Y;
  1078.             m_Scanbeam = m_Scanbeam.Next;
  1079.             return true;
  1080.         }
  1081.  
  1082.         internal Boolean LocalMinimaPending()
  1083.         {
  1084.             return (m_CurrentLM != null);
  1085.         }
  1086.  
  1087.         internal OutRec CreateOutRec()
  1088.         {
  1089.             OutRec result = new OutRec();
  1090.             result.Idx = Unassigned;
  1091.             result.IsHole = false;
  1092.             result.IsOpen = false;
  1093.             result.FirstLeft = null;
  1094.             result.Pts = null;
  1095.             result.BottomPt = null;
  1096.             result.PolyNode = null;
  1097.             m_PolyOuts.Add(result);
  1098.             result.Idx = m_PolyOuts.Count - 1;
  1099.             return result;
  1100.         }
  1101.  
  1102.         internal void DisposeOutRec(int index)
  1103.         {
  1104.             OutRec outRec = m_PolyOuts[index];
  1105.             outRec.Pts = null;
  1106.             outRec = null;
  1107.             m_PolyOuts[index] = null;
  1108.         }
  1109.  
  1110.         internal void UpdateEdgeIntoAEL(ref TEdge e)
  1111.         {
  1112.             if (e.NextInLML == null)
  1113.                 throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
  1114.             TEdge AelPrev = e.PrevInAEL;
  1115.             TEdge AelNext = e.NextInAEL;
  1116.             e.NextInLML.OutIdx = e.OutIdx;
  1117.             if (AelPrev != null)
  1118.                 AelPrev.NextInAEL = e.NextInLML;
  1119.             else m_ActiveEdges = e.NextInLML;
  1120.             if (AelNext != null)
  1121.                 AelNext.PrevInAEL = e.NextInLML;
  1122.             e.NextInLML.Side = e.Side;
  1123.             e.NextInLML.WindDelta = e.WindDelta;
  1124.             e.NextInLML.WindCnt = e.WindCnt;
  1125.             e.NextInLML.WindCnt2 = e.WindCnt2;
  1126.             e = e.NextInLML;
  1127.             e.Curr = e.Bot;
  1128.             e.PrevInAEL = AelPrev;
  1129.             e.NextInAEL = AelNext;
  1130.             if (!IsHorizontal(e)) InsertScanbeam(e.Top.Y);
  1131.         }
  1132.  
  1133.         internal void SwapPositionsInAEL(TEdge edge1, TEdge edge2)
  1134.         {
  1135.             if (edge1.NextInAEL == edge1.PrevInAEL ||
  1136.   edge2.NextInAEL == edge2.PrevInAEL) return;
  1137.  
  1138.             if (edge1.NextInAEL == edge2)
  1139.             {
  1140.                 TEdge next = edge2.NextInAEL;
  1141.                 if (next != null)
  1142.                     next.PrevInAEL = edge1;
  1143.                 TEdge prev = edge1.PrevInAEL;
  1144.                 if (prev != null)
  1145.                     prev.NextInAEL = edge2;
  1146.                 edge2.PrevInAEL = prev;
  1147.                 edge2.NextInAEL = edge1;
  1148.                 edge1.PrevInAEL = edge2;
  1149.                 edge1.NextInAEL = next;
  1150.             }
  1151.             else if (edge2.NextInAEL == edge1)
  1152.             {
  1153.                 TEdge next = edge1.NextInAEL;
  1154.                 if (next != null)
  1155.                     next.PrevInAEL = edge2;
  1156.                 TEdge prev = edge2.PrevInAEL;
  1157.                 if (prev != null)
  1158.                     prev.NextInAEL = edge1;
  1159.                 edge1.PrevInAEL = prev;
  1160.                 edge1.NextInAEL = edge2;
  1161.                 edge2.PrevInAEL = edge1;
  1162.                 edge2.NextInAEL = next;
  1163.             }
  1164.             else
  1165.             {
  1166.                 TEdge next = edge1.NextInAEL;
  1167.                 TEdge prev = edge1.PrevInAEL;
  1168.                 edge1.NextInAEL = edge2.NextInAEL;
  1169.                 if (edge1.NextInAEL != null)
  1170.                     edge1.NextInAEL.PrevInAEL = edge1;
  1171.                 edge1.PrevInAEL = edge2.PrevInAEL;
  1172.                 if (edge1.PrevInAEL != null)
  1173.                     edge1.PrevInAEL.NextInAEL = edge1;
  1174.                 edge2.NextInAEL = next;
  1175.                 if (edge2.NextInAEL != null)
  1176.                     edge2.NextInAEL.PrevInAEL = edge2;
  1177.                 edge2.PrevInAEL = prev;
  1178.                 if (edge2.PrevInAEL != null)
  1179.                     edge2.PrevInAEL.NextInAEL = edge2;
  1180.             }
  1181.  
  1182.             if (edge1.PrevInAEL == null)
  1183.                 m_ActiveEdges = edge1;
  1184.             else if (edge2.PrevInAEL == null)
  1185.                 m_ActiveEdges = edge2;
  1186.         }
  1187.  
  1188.         internal void DeleteFromAEL(TEdge e)
  1189.         {
  1190.             TEdge AelPrev = e.PrevInAEL;
  1191.             TEdge AelNext = e.NextInAEL;
  1192.             if (AelPrev == null && AelNext == null && (e != m_ActiveEdges))
  1193.                 return; if (AelPrev != null)
  1194.                 AelPrev.NextInAEL = AelNext;
  1195.             else m_ActiveEdges = AelNext;
  1196.             if (AelNext != null)
  1197.                 AelNext.PrevInAEL = AelPrev;
  1198.             e.NextInAEL = null;
  1199.             e.PrevInAEL = null;
  1200.         }
  1201.  
  1202.     }
  1203.     public class Clipper : ClipperBase
  1204.     {
  1205.         public const int ioReverseSolution = 1;
  1206.         public const int ioStrictlySimple = 2;
  1207.         public const int ioPreserveCollinear = 4;
  1208.  
  1209.         private ClipType m_ClipType;
  1210.         private Maxima m_Maxima;
  1211.         private TEdge m_SortedEdges;
  1212.         private List<IntersectNode> m_IntersectList;
  1213.         IComparer<IntersectNode> m_IntersectNodeComparer;
  1214.         private bool m_ExecuteLocked;
  1215.         private PolyFillType m_ClipFillType;
  1216.         private PolyFillType m_SubjFillType;
  1217.         private List<Join> m_Joins;
  1218.         private List<Join> m_GhostJoins;
  1219.         private bool m_UsingPolyTree;
  1220. #if use_xyz
  1221.       public delegate void ZFillCallback(IntPoint bot1, IntPoint top1,
  1222.         IntPoint bot2, IntPoint top2, ref IntPoint pt);
  1223.       public ZFillCallback ZFillFunction { get; set; }
  1224. #endif
  1225.         public Clipper(int InitOptions = 0) : base()
  1226.         {
  1227.             m_Scanbeam = null;
  1228.             m_Maxima = null;
  1229.             m_ActiveEdges = null;
  1230.             m_SortedEdges = null;
  1231.             m_IntersectList = new List<IntersectNode>();
  1232.             m_IntersectNodeComparer = new MyIntersectNodeSort();
  1233.             m_ExecuteLocked = false;
  1234.             m_UsingPolyTree = false;
  1235.             m_PolyOuts = new List<OutRec>();
  1236.             m_Joins = new List<Join>();
  1237.             m_GhostJoins = new List<Join>();
  1238.             ReverseSolution = (ioReverseSolution & InitOptions) != 0;
  1239.             StrictlySimple = (ioStrictlySimple & InitOptions) != 0;
  1240.             PreserveCollinear = (ioPreserveCollinear & InitOptions) != 0;
  1241. #if use_xyz
  1242.           ZFillFunction = null;
  1243. #endif
  1244.         }
  1245.  
  1246.         private void InsertMaxima(cInt X)
  1247.         {
  1248.             Maxima newMax = new Maxima();
  1249.             newMax.X = X;
  1250.             if (m_Maxima == null)
  1251.             {
  1252.                 m_Maxima = newMax;
  1253.                 m_Maxima.Next = null;
  1254.                 m_Maxima.Prev = null;
  1255.             }
  1256.             else if (X < m_Maxima.X)
  1257.             {
  1258.                 newMax.Next = m_Maxima;
  1259.                 newMax.Prev = null;
  1260.                 m_Maxima = newMax;
  1261.             }
  1262.             else
  1263.             {
  1264.                 Maxima m = m_Maxima;
  1265.                 while (m.Next != null && (X >= m.Next.X)) m = m.Next;
  1266.                 if (X == m.X) return; newMax.Next = m.Next;
  1267.                 newMax.Prev = m;
  1268.                 if (m.Next != null) m.Next.Prev = newMax;
  1269.                 m.Next = newMax;
  1270.             }
  1271.         }
  1272.  
  1273.         public bool ReverseSolution
  1274.         {
  1275.             get;
  1276.             set;
  1277.         }
  1278.  
  1279.         public bool StrictlySimple
  1280.         {
  1281.             get;
  1282.             set;
  1283.         }
  1284.  
  1285.         public bool Execute(ClipType clipType, Paths solution,
  1286.             PolyFillType FillType = PolyFillType.pftEvenOdd)
  1287.         {
  1288.             return Execute(clipType, solution, FillType, FillType);
  1289.         }
  1290.  
  1291.         public bool Execute(ClipType clipType, PolyTree polytree,
  1292.             PolyFillType FillType = PolyFillType.pftEvenOdd)
  1293.         {
  1294.             return Execute(clipType, polytree, FillType, FillType);
  1295.         }
  1296.  
  1297.         public bool Execute(ClipType clipType, Paths solution,
  1298.             PolyFillType subjFillType, PolyFillType clipFillType)
  1299.         {
  1300.             if (m_ExecuteLocked) return false;
  1301.             if (m_HasOpenPaths) throw
  1302.               new ClipperException("Error: PolyTree struct is needed for open path clipping.");
  1303.  
  1304.             m_ExecuteLocked = true;
  1305.             solution.Clear();
  1306.             m_SubjFillType = subjFillType;
  1307.             m_ClipFillType = clipFillType;
  1308.             m_ClipType = clipType;
  1309.             m_UsingPolyTree = false;
  1310.             bool succeeded;
  1311.             try
  1312.             {
  1313.                 succeeded = ExecuteInternal();
  1314.                 if (succeeded) BuildResult(solution);
  1315.             }
  1316.             finally
  1317.             {
  1318.                 DisposeAllPolyPts();
  1319.                 m_ExecuteLocked = false;
  1320.             }
  1321.             return succeeded;
  1322.         }
  1323.  
  1324.         public bool Execute(ClipType clipType, PolyTree polytree,
  1325.             PolyFillType subjFillType, PolyFillType clipFillType)
  1326.         {
  1327.             if (m_ExecuteLocked) return false;
  1328.             m_ExecuteLocked = true;
  1329.             m_SubjFillType = subjFillType;
  1330.             m_ClipFillType = clipFillType;
  1331.             m_ClipType = clipType;
  1332.             m_UsingPolyTree = true;
  1333.             bool succeeded;
  1334.             try
  1335.             {
  1336.                 succeeded = ExecuteInternal();
  1337.                 if (succeeded) BuildResult2(polytree);
  1338.             }
  1339.             finally
  1340.             {
  1341.                 DisposeAllPolyPts();
  1342.                 m_ExecuteLocked = false;
  1343.             }
  1344.             return succeeded;
  1345.         }
  1346.  
  1347.         internal void FixHoleLinkage(OutRec outRec)
  1348.         {
  1349.             if (outRec.FirstLeft == null ||
  1350. (outRec.IsHole != outRec.FirstLeft.IsHole &&
  1351. outRec.FirstLeft.Pts != null)) return;
  1352.  
  1353.             OutRec orfl = outRec.FirstLeft;
  1354.             while (orfl != null && ((orfl.IsHole == outRec.IsHole) || orfl.Pts == null))
  1355.                 orfl = orfl.FirstLeft;
  1356.             outRec.FirstLeft = orfl;
  1357.         }
  1358.  
  1359.         private bool ExecuteInternal()
  1360.         {
  1361.             try
  1362.             {
  1363.                 Reset();
  1364.                 m_SortedEdges = null;
  1365.                 m_Maxima = null;
  1366.  
  1367.                 cInt botY, topY;
  1368.                 if (!PopScanbeam(out botY)) return false;
  1369.                 InsertLocalMinimaIntoAEL(botY);
  1370.                 while (PopScanbeam(out topY) || LocalMinimaPending())
  1371.                 {
  1372.                     ProcessHorizontals();
  1373.                     m_GhostJoins.Clear();
  1374.                     if (!ProcessIntersections(topY)) return false;
  1375.                     ProcessEdgesAtTopOfScanbeam(topY);
  1376.                     botY = topY;
  1377.                     InsertLocalMinimaIntoAEL(botY);
  1378.                 }
  1379.  
  1380.                 foreach (OutRec outRec in m_PolyOuts)
  1381.                 {
  1382.                     if (outRec.Pts == null || outRec.IsOpen) continue;
  1383.                     if ((outRec.IsHole ^ ReverseSolution) == (Area(outRec) > 0))
  1384.                         ReversePolyPtLinks(outRec.Pts);
  1385.                 }
  1386.  
  1387.                 JoinCommonEdges();
  1388.  
  1389.                 foreach (OutRec outRec in m_PolyOuts)
  1390.                 {
  1391.                     if (outRec.Pts == null)
  1392.                         continue;
  1393.                     else if (outRec.IsOpen)
  1394.                         FixupOutPolyline(outRec);
  1395.                     else
  1396.                         FixupOutPolygon(outRec);
  1397.                 }
  1398.  
  1399.                 if (StrictlySimple) DoSimplePolygons();
  1400.                 return true;
  1401.             }
  1402.             finally
  1403.             {
  1404.                 m_Joins.Clear();
  1405.                 m_GhostJoins.Clear();
  1406.             }
  1407.         }
  1408.  
  1409.         private void DisposeAllPolyPts()
  1410.         {
  1411.             for (int i = 0; i < m_PolyOuts.Count; ++i) DisposeOutRec(i);
  1412.             m_PolyOuts.Clear();
  1413.         }
  1414.  
  1415.         private void AddJoin(OutPt Op1, OutPt Op2, IntPoint OffPt)
  1416.         {
  1417.             Join j = new Join();
  1418.             j.OutPt1 = Op1;
  1419.             j.OutPt2 = Op2;
  1420.             j.OffPt = OffPt;
  1421.             m_Joins.Add(j);
  1422.         }
  1423.  
  1424.         private void AddGhostJoin(OutPt Op, IntPoint OffPt)
  1425.         {
  1426.             Join j = new Join();
  1427.             j.OutPt1 = Op;
  1428.             j.OffPt = OffPt;
  1429.             m_GhostJoins.Add(j);
  1430.         }
  1431.  
  1432. #if use_xyz
  1433.       internal void SetZ(ref IntPoint pt, TEdge e1, TEdge e2)
  1434.       {
  1435.         if (pt.Z != 0 || ZFillFunction == null) return;
  1436.         else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
  1437.         else if (pt == e1.Top) pt.Z = e1.Top.Z;
  1438.         else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
  1439.         else if (pt == e2.Top) pt.Z = e2.Top.Z;
  1440.         else ZFillFunction(e1.Bot, e1.Top, e2.Bot, e2.Top, ref pt);
  1441.       }
  1442. #endif
  1443.  
  1444.         private void InsertLocalMinimaIntoAEL(cInt botY)
  1445.         {
  1446.             LocalMinima lm;
  1447.             while (PopLocalMinima(botY, out lm))
  1448.             {
  1449.                 TEdge lb = lm.LeftBound;
  1450.                 TEdge rb = lm.RightBound;
  1451.  
  1452.                 OutPt Op1 = null;
  1453.                 if (lb == null)
  1454.                 {
  1455.                     InsertEdgeIntoAEL(rb, null);
  1456.                     SetWindingCount(rb);
  1457.                     if (IsContributing(rb))
  1458.                         Op1 = AddOutPt(rb, rb.Bot);
  1459.                 }
  1460.                 else if (rb == null)
  1461.                 {
  1462.                     InsertEdgeIntoAEL(lb, null);
  1463.                     SetWindingCount(lb);
  1464.                     if (IsContributing(lb))
  1465.                         Op1 = AddOutPt(lb, lb.Bot);
  1466.                     InsertScanbeam(lb.Top.Y);
  1467.                 }
  1468.                 else
  1469.                 {
  1470.                     InsertEdgeIntoAEL(lb, null);
  1471.                     InsertEdgeIntoAEL(rb, lb);
  1472.                     SetWindingCount(lb);
  1473.                     rb.WindCnt = lb.WindCnt;
  1474.                     rb.WindCnt2 = lb.WindCnt2;
  1475.                     if (IsContributing(lb))
  1476.                         Op1 = AddLocalMinPoly(lb, rb, lb.Bot);
  1477.                     InsertScanbeam(lb.Top.Y);
  1478.                 }
  1479.  
  1480.                 if (rb != null)
  1481.                 {
  1482.                     if (IsHorizontal(rb))
  1483.                     {
  1484.                         if (rb.NextInLML != null)
  1485.                             InsertScanbeam(rb.NextInLML.Top.Y);
  1486.                         AddEdgeToSEL(rb);
  1487.                     }
  1488.                     else
  1489.                         InsertScanbeam(rb.Top.Y);
  1490.                 }
  1491.  
  1492.                 if (lb == null || rb == null) continue;
  1493.  
  1494.                 if (Op1 != null && IsHorizontal(rb) &&
  1495.   m_GhostJoins.Count > 0 && rb.WindDelta != 0)
  1496.                 {
  1497.                     for (int i = 0; i < m_GhostJoins.Count; i++)
  1498.                     {
  1499.                         Join j = m_GhostJoins[i];
  1500.                         if (HorzSegmentsOverlap(j.OutPt1.Pt.X, j.OffPt.X, rb.Bot.X, rb.Top.X))
  1501.                             AddJoin(j.OutPt1, Op1, j.OffPt);
  1502.                     }
  1503.                 }
  1504.  
  1505.                 if (lb.OutIdx >= 0 && lb.PrevInAEL != null &&
  1506.                   lb.PrevInAEL.Curr.X == lb.Bot.X &&
  1507.                   lb.PrevInAEL.OutIdx >= 0 &&
  1508.                   SlopesEqual(lb.PrevInAEL.Curr, lb.PrevInAEL.Top, lb.Curr, lb.Top, m_UseFullRange) &&
  1509.                   lb.WindDelta != 0 && lb.PrevInAEL.WindDelta != 0)
  1510.                 {
  1511.                     OutPt Op2 = AddOutPt(lb.PrevInAEL, lb.Bot);
  1512.                     AddJoin(Op1, Op2, lb.Top);
  1513.                 }
  1514.  
  1515.                 if (lb.NextInAEL != rb)
  1516.                 {
  1517.  
  1518.                     if (rb.OutIdx >= 0 && rb.PrevInAEL.OutIdx >= 0 &&
  1519.                       SlopesEqual(rb.PrevInAEL.Curr, rb.PrevInAEL.Top, rb.Curr, rb.Top, m_UseFullRange) &&
  1520.                       rb.WindDelta != 0 && rb.PrevInAEL.WindDelta != 0)
  1521.                     {
  1522.                         OutPt Op2 = AddOutPt(rb.PrevInAEL, rb.Bot);
  1523.                         AddJoin(Op1, Op2, rb.Top);
  1524.                     }
  1525.  
  1526.                     TEdge e = lb.NextInAEL;
  1527.                     if (e != null)
  1528.                         while (e != rb)
  1529.                         {
  1530.                             IntersectEdges(rb, e, lb.Curr); e = e.NextInAEL;
  1531.                         }
  1532.                 }
  1533.             }
  1534.         }
  1535.  
  1536.         private void InsertEdgeIntoAEL(TEdge edge, TEdge startEdge)
  1537.         {
  1538.             if (m_ActiveEdges == null)
  1539.             {
  1540.                 edge.PrevInAEL = null;
  1541.                 edge.NextInAEL = null;
  1542.                 m_ActiveEdges = edge;
  1543.             }
  1544.             else if (startEdge == null && E2InsertsBeforeE1(m_ActiveEdges, edge))
  1545.             {
  1546.                 edge.PrevInAEL = null;
  1547.                 edge.NextInAEL = m_ActiveEdges;
  1548.                 m_ActiveEdges.PrevInAEL = edge;
  1549.                 m_ActiveEdges = edge;
  1550.             }
  1551.             else
  1552.             {
  1553.                 if (startEdge == null) startEdge = m_ActiveEdges;
  1554.                 while (startEdge.NextInAEL != null &&
  1555.                   !E2InsertsBeforeE1(startEdge.NextInAEL, edge))
  1556.                     startEdge = startEdge.NextInAEL;
  1557.                 edge.NextInAEL = startEdge.NextInAEL;
  1558.                 if (startEdge.NextInAEL != null) startEdge.NextInAEL.PrevInAEL = edge;
  1559.                 edge.PrevInAEL = startEdge;
  1560.                 startEdge.NextInAEL = edge;
  1561.             }
  1562.         }
  1563.  
  1564.         private bool E2InsertsBeforeE1(TEdge e1, TEdge e2)
  1565.         {
  1566.             if (e2.Curr.X == e1.Curr.X)
  1567.             {
  1568.                 if (e2.Top.Y > e1.Top.Y)
  1569.                     return e2.Top.X < TopX(e1, e2.Top.Y);
  1570.                 else return e1.Top.X > TopX(e2, e1.Top.Y);
  1571.             }
  1572.             else return e2.Curr.X < e1.Curr.X;
  1573.         }
  1574.  
  1575.         private bool IsEvenOddFillType(TEdge edge)
  1576.         {
  1577.             if (edge.PolyTyp == PolyType.ptSubject)
  1578.                 return m_SubjFillType == PolyFillType.pftEvenOdd;
  1579.             else
  1580.                 return m_ClipFillType == PolyFillType.pftEvenOdd;
  1581.         }
  1582.  
  1583.         private bool IsEvenOddAltFillType(TEdge edge)
  1584.         {
  1585.             if (edge.PolyTyp == PolyType.ptSubject)
  1586.                 return m_ClipFillType == PolyFillType.pftEvenOdd;
  1587.             else
  1588.                 return m_SubjFillType == PolyFillType.pftEvenOdd;
  1589.         }
  1590.  
  1591.         private bool IsContributing(TEdge edge)
  1592.         {
  1593.             PolyFillType pft, pft2;
  1594.             if (edge.PolyTyp == PolyType.ptSubject)
  1595.             {
  1596.                 pft = m_SubjFillType;
  1597.                 pft2 = m_ClipFillType;
  1598.             }
  1599.             else
  1600.             {
  1601.                 pft = m_ClipFillType;
  1602.                 pft2 = m_SubjFillType;
  1603.             }
  1604.  
  1605.             switch (pft)
  1606.             {
  1607.                 case PolyFillType.pftEvenOdd:
  1608.                     if (edge.WindDelta == 0 && edge.WindCnt != 1) return false;
  1609.                     break;
  1610.                 case PolyFillType.pftNonZero:
  1611.                     if (Math.Abs(edge.WindCnt) != 1) return false;
  1612.                     break;
  1613.                 case PolyFillType.pftPositive:
  1614.                     if (edge.WindCnt != 1) return false;
  1615.                     break;
  1616.                 default:
  1617.                     if (edge.WindCnt != -1) return false;
  1618.                     break;
  1619.             }
  1620.  
  1621.             switch (m_ClipType)
  1622.             {
  1623.                 case ClipType.ctIntersection:
  1624.                     switch (pft2)
  1625.                     {
  1626.                         case PolyFillType.pftEvenOdd:
  1627.                         case PolyFillType.pftNonZero:
  1628.                             return (edge.WindCnt2 != 0);
  1629.                         case PolyFillType.pftPositive:
  1630.                             return (edge.WindCnt2 > 0);
  1631.                         default:
  1632.                             return (edge.WindCnt2 < 0);
  1633.                     }
  1634.                 case ClipType.ctUnion:
  1635.                     switch (pft2)
  1636.                     {
  1637.                         case PolyFillType.pftEvenOdd:
  1638.                         case PolyFillType.pftNonZero:
  1639.                             return (edge.WindCnt2 == 0);
  1640.                         case PolyFillType.pftPositive:
  1641.                             return (edge.WindCnt2 <= 0);
  1642.                         default:
  1643.                             return (edge.WindCnt2 >= 0);
  1644.                     }
  1645.                 case ClipType.ctDifference:
  1646.                     if (edge.PolyTyp == PolyType.ptSubject)
  1647.                         switch (pft2)
  1648.                         {
  1649.                             case PolyFillType.pftEvenOdd:
  1650.                             case PolyFillType.pftNonZero:
  1651.                                 return (edge.WindCnt2 == 0);
  1652.                             case PolyFillType.pftPositive:
  1653.                                 return (edge.WindCnt2 <= 0);
  1654.                             default:
  1655.                                 return (edge.WindCnt2 >= 0);
  1656.                         }
  1657.                     else
  1658.                         switch (pft2)
  1659.                         {
  1660.                             case PolyFillType.pftEvenOdd:
  1661.                             case PolyFillType.pftNonZero:
  1662.                                 return (edge.WindCnt2 != 0);
  1663.                             case PolyFillType.pftPositive:
  1664.                                 return (edge.WindCnt2 > 0);
  1665.                             default:
  1666.                                 return (edge.WindCnt2 < 0);
  1667.                         }
  1668.                 case ClipType.ctXor:
  1669.                     if (edge.WindDelta == 0) switch (pft2)
  1670.                         {
  1671.                             case PolyFillType.pftEvenOdd:
  1672.                             case PolyFillType.pftNonZero:
  1673.                                 return (edge.WindCnt2 == 0);
  1674.                             case PolyFillType.pftPositive:
  1675.                                 return (edge.WindCnt2 <= 0);
  1676.                             default:
  1677.                                 return (edge.WindCnt2 >= 0);
  1678.                         }
  1679.                     else
  1680.                         return true;
  1681.             }
  1682.             return true;
  1683.         }
  1684.  
  1685.         private void SetWindingCount(TEdge edge)
  1686.         {
  1687.             TEdge e = edge.PrevInAEL;
  1688.             while (e != null && ((e.PolyTyp != edge.PolyTyp) || (e.WindDelta == 0))) e = e.PrevInAEL;
  1689.             if (e == null)
  1690.             {
  1691.                 PolyFillType pft;
  1692.                 pft = (edge.PolyTyp == PolyType.ptSubject ? m_SubjFillType : m_ClipFillType);
  1693.                 if (edge.WindDelta == 0) edge.WindCnt = (pft == PolyFillType.pftNegative ? -1 : 1);
  1694.                 else edge.WindCnt = edge.WindDelta;
  1695.                 edge.WindCnt2 = 0;
  1696.                 e = m_ActiveEdges;
  1697.             }
  1698.             else if (edge.WindDelta == 0 && m_ClipType != ClipType.ctUnion)
  1699.             {
  1700.                 edge.WindCnt = 1;
  1701.                 edge.WindCnt2 = e.WindCnt2;
  1702.                 e = e.NextInAEL;
  1703.             }
  1704.             else if (IsEvenOddFillType(edge))
  1705.             {
  1706.                 if (edge.WindDelta == 0)
  1707.                 {
  1708.                     bool Inside = true;
  1709.                     TEdge e2 = e.PrevInAEL;
  1710.                     while (e2 != null)
  1711.                     {
  1712.                         if (e2.PolyTyp == e.PolyTyp && e2.WindDelta != 0)
  1713.                             Inside = !Inside;
  1714.                         e2 = e2.PrevInAEL;
  1715.                     }
  1716.                     edge.WindCnt = (Inside ? 0 : 1);
  1717.                 }
  1718.                 else
  1719.                 {
  1720.                     edge.WindCnt = edge.WindDelta;
  1721.                 }
  1722.                 edge.WindCnt2 = e.WindCnt2;
  1723.                 e = e.NextInAEL;
  1724.             }
  1725.             else
  1726.             {
  1727.                 if (e.WindCnt * e.WindDelta < 0)
  1728.                 {
  1729.                     if (Math.Abs(e.WindCnt) > 1)
  1730.                     {
  1731.                         if (e.WindDelta * edge.WindDelta < 0) edge.WindCnt = e.WindCnt;
  1732.                         else edge.WindCnt = e.WindCnt + edge.WindDelta;
  1733.                     }
  1734.                     else
  1735.                         edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
  1736.                 }
  1737.                 else
  1738.                 {
  1739.                     if (edge.WindDelta == 0)
  1740.                         edge.WindCnt = (e.WindCnt < 0 ? e.WindCnt - 1 : e.WindCnt + 1);
  1741.                     else if (e.WindDelta * edge.WindDelta < 0)
  1742.                         edge.WindCnt = e.WindCnt;
  1743.                     else edge.WindCnt = e.WindCnt + edge.WindDelta;
  1744.                 }
  1745.                 edge.WindCnt2 = e.WindCnt2;
  1746.                 e = e.NextInAEL;
  1747.             }
  1748.  
  1749.             if (IsEvenOddAltFillType(edge))
  1750.             {
  1751.                 while (e != edge)
  1752.                 {
  1753.                     if (e.WindDelta != 0)
  1754.                         edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
  1755.                     e = e.NextInAEL;
  1756.                 }
  1757.             }
  1758.             else
  1759.             {
  1760.                 while (e != edge)
  1761.                 {
  1762.                     edge.WindCnt2 += e.WindDelta;
  1763.                     e = e.NextInAEL;
  1764.                 }
  1765.             }
  1766.         }
  1767.  
  1768.         private void AddEdgeToSEL(TEdge edge)
  1769.         {
  1770.             if (m_SortedEdges == null)
  1771.             {
  1772.                 m_SortedEdges = edge;
  1773.                 edge.PrevInSEL = null;
  1774.                 edge.NextInSEL = null;
  1775.             }
  1776.             else
  1777.             {
  1778.                 edge.NextInSEL = m_SortedEdges;
  1779.                 edge.PrevInSEL = null;
  1780.                 m_SortedEdges.PrevInSEL = edge;
  1781.                 m_SortedEdges = edge;
  1782.             }
  1783.         }
  1784.  
  1785.         internal Boolean PopEdgeFromSEL(out TEdge e)
  1786.         {
  1787.             e = m_SortedEdges;
  1788.             if (e == null) return false;
  1789.             TEdge oldE = e;
  1790.             m_SortedEdges = e.NextInSEL;
  1791.             if (m_SortedEdges != null) m_SortedEdges.PrevInSEL = null;
  1792.             oldE.NextInSEL = null;
  1793.             oldE.PrevInSEL = null;
  1794.             return true;
  1795.         }
  1796.  
  1797.         private void CopyAELToSEL()
  1798.         {
  1799.             TEdge e = m_ActiveEdges;
  1800.             m_SortedEdges = e;
  1801.             while (e != null)
  1802.             {
  1803.                 e.PrevInSEL = e.PrevInAEL;
  1804.                 e.NextInSEL = e.NextInAEL;
  1805.                 e = e.NextInAEL;
  1806.             }
  1807.         }
  1808.  
  1809.         private void SwapPositionsInSEL(TEdge edge1, TEdge edge2)
  1810.         {
  1811.             if (edge1.NextInSEL == null && edge1.PrevInSEL == null)
  1812.                 return;
  1813.             if (edge2.NextInSEL == null && edge2.PrevInSEL == null)
  1814.                 return;
  1815.  
  1816.             if (edge1.NextInSEL == edge2)
  1817.             {
  1818.                 TEdge next = edge2.NextInSEL;
  1819.                 if (next != null)
  1820.                     next.PrevInSEL = edge1;
  1821.                 TEdge prev = edge1.PrevInSEL;
  1822.                 if (prev != null)
  1823.                     prev.NextInSEL = edge2;
  1824.                 edge2.PrevInSEL = prev;
  1825.                 edge2.NextInSEL = edge1;
  1826.                 edge1.PrevInSEL = edge2;
  1827.                 edge1.NextInSEL = next;
  1828.             }
  1829.             else if (edge2.NextInSEL == edge1)
  1830.             {
  1831.                 TEdge next = edge1.NextInSEL;
  1832.                 if (next != null)
  1833.                     next.PrevInSEL = edge2;
  1834.                 TEdge prev = edge2.PrevInSEL;
  1835.                 if (prev != null)
  1836.                     prev.NextInSEL = edge1;
  1837.                 edge1.PrevInSEL = prev;
  1838.                 edge1.NextInSEL = edge2;
  1839.                 edge2.PrevInSEL = edge1;
  1840.                 edge2.NextInSEL = next;
  1841.             }
  1842.             else
  1843.             {
  1844.                 TEdge next = edge1.NextInSEL;
  1845.                 TEdge prev = edge1.PrevInSEL;
  1846.                 edge1.NextInSEL = edge2.NextInSEL;
  1847.                 if (edge1.NextInSEL != null)
  1848.                     edge1.NextInSEL.PrevInSEL = edge1;
  1849.                 edge1.PrevInSEL = edge2.PrevInSEL;
  1850.                 if (edge1.PrevInSEL != null)
  1851.                     edge1.PrevInSEL.NextInSEL = edge1;
  1852.                 edge2.NextInSEL = next;
  1853.                 if (edge2.NextInSEL != null)
  1854.                     edge2.NextInSEL.PrevInSEL = edge2;
  1855.                 edge2.PrevInSEL = prev;
  1856.                 if (edge2.PrevInSEL != null)
  1857.                     edge2.PrevInSEL.NextInSEL = edge2;
  1858.             }
  1859.  
  1860.             if (edge1.PrevInSEL == null)
  1861.                 m_SortedEdges = edge1;
  1862.             else if (edge2.PrevInSEL == null)
  1863.                 m_SortedEdges = edge2;
  1864.         }
  1865.  
  1866.  
  1867.         private void AddLocalMaxPoly(TEdge e1, TEdge e2, IntPoint pt)
  1868.         {
  1869.             AddOutPt(e1, pt);
  1870.             if (e2.WindDelta == 0) AddOutPt(e2, pt);
  1871.             if (e1.OutIdx == e2.OutIdx)
  1872.             {
  1873.                 e1.OutIdx = Unassigned;
  1874.                 e2.OutIdx = Unassigned;
  1875.             }
  1876.             else if (e1.OutIdx < e2.OutIdx)
  1877.                 AppendPolygon(e1, e2);
  1878.             else
  1879.                 AppendPolygon(e2, e1);
  1880.         }
  1881.  
  1882.         private OutPt AddLocalMinPoly(TEdge e1, TEdge e2, IntPoint pt)
  1883.         {
  1884.             OutPt result;
  1885.             TEdge e, prevE;
  1886.             if (IsHorizontal(e2) || (e1.Dx > e2.Dx))
  1887.             {
  1888.                 result = AddOutPt(e1, pt);
  1889.                 e2.OutIdx = e1.OutIdx;
  1890.                 e1.Side = EdgeSide.esLeft;
  1891.                 e2.Side = EdgeSide.esRight;
  1892.                 e = e1;
  1893.                 if (e.PrevInAEL == e2)
  1894.                     prevE = e2.PrevInAEL;
  1895.                 else
  1896.                     prevE = e.PrevInAEL;
  1897.             }
  1898.             else
  1899.             {
  1900.                 result = AddOutPt(e2, pt);
  1901.                 e1.OutIdx = e2.OutIdx;
  1902.                 e1.Side = EdgeSide.esRight;
  1903.                 e2.Side = EdgeSide.esLeft;
  1904.                 e = e2;
  1905.                 if (e.PrevInAEL == e1)
  1906.                     prevE = e1.PrevInAEL;
  1907.                 else
  1908.                     prevE = e.PrevInAEL;
  1909.             }
  1910.  
  1911.             if (prevE != null && prevE.OutIdx >= 0 && prevE.Top.Y < pt.Y && e.Top.Y < pt.Y)
  1912.             {
  1913.                 cInt xPrev = TopX(prevE, pt.Y);
  1914.                 cInt xE = TopX(e, pt.Y);
  1915.                 if ((xPrev == xE) && (e.WindDelta != 0) && (prevE.WindDelta != 0) &&
  1916.                   SlopesEqual(new IntPoint(xPrev, pt.Y), prevE.Top, new IntPoint(xE, pt.Y), e.Top, m_UseFullRange))
  1917.                 {
  1918.                     OutPt outPt = AddOutPt(prevE, pt);
  1919.                     AddJoin(result, outPt, e.Top);
  1920.                 }
  1921.             }
  1922.             return result;
  1923.         }
  1924.  
  1925.         private OutPt AddOutPt(TEdge e, IntPoint pt)
  1926.         {
  1927.             if (e.OutIdx < 0)
  1928.             {
  1929.                 OutRec outRec = CreateOutRec();
  1930.                 outRec.IsOpen = (e.WindDelta == 0);
  1931.                 OutPt newOp = new OutPt();
  1932.                 outRec.Pts = newOp;
  1933.                 newOp.Idx = outRec.Idx;
  1934.                 newOp.Pt = pt;
  1935.                 newOp.Next = newOp;
  1936.                 newOp.Prev = newOp;
  1937.                 if (!outRec.IsOpen)
  1938.                     SetHoleState(e, outRec);
  1939.                 e.OutIdx = outRec.Idx; return newOp;
  1940.             }
  1941.             else
  1942.             {
  1943.                 OutRec outRec = m_PolyOuts[e.OutIdx];
  1944.                 OutPt op = outRec.Pts;
  1945.                 bool ToFront = (e.Side == EdgeSide.esLeft);
  1946.                 if (ToFront && pt == op.Pt) return op;
  1947.                 else if (!ToFront && pt == op.Prev.Pt) return op.Prev;
  1948.  
  1949.                 OutPt newOp = new OutPt();
  1950.                 newOp.Idx = outRec.Idx;
  1951.                 newOp.Pt = pt;
  1952.                 newOp.Next = op;
  1953.                 newOp.Prev = op.Prev;
  1954.                 newOp.Prev.Next = newOp;
  1955.                 op.Prev = newOp;
  1956.                 if (ToFront) outRec.Pts = newOp;
  1957.                 return newOp;
  1958.             }
  1959.         }
  1960.  
  1961.         private OutPt GetLastOutPt(TEdge e)
  1962.         {
  1963.             OutRec outRec = m_PolyOuts[e.OutIdx];
  1964.             if (e.Side == EdgeSide.esLeft)
  1965.                 return outRec.Pts;
  1966.             else
  1967.                 return outRec.Pts.Prev;
  1968.         }
  1969.  
  1970.         internal void SwapPoints(ref IntPoint pt1, ref IntPoint pt2)
  1971.         {
  1972.             IntPoint tmp = new IntPoint(pt1);
  1973.             pt1 = pt2;
  1974.             pt2 = tmp;
  1975.         }
  1976.  
  1977.         private bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
  1978.         {
  1979.             if (seg1a > seg1b) Swap(ref seg1a, ref seg1b);
  1980.             if (seg2a > seg2b) Swap(ref seg2a, ref seg2b);
  1981.             return (seg1a < seg2b) && (seg2a < seg1b);
  1982.         }
  1983.  
  1984.         private void SetHoleState(TEdge e, OutRec outRec)
  1985.         {
  1986.             TEdge e2 = e.PrevInAEL;
  1987.             TEdge eTmp = null;
  1988.             while (e2 != null)
  1989.             {
  1990.                 if (e2.OutIdx >= 0 && e2.WindDelta != 0)
  1991.                 {
  1992.                     if (eTmp == null)
  1993.                         eTmp = e2;
  1994.                     else if (eTmp.OutIdx == e2.OutIdx)
  1995.                         eTmp = null;
  1996.                 }
  1997.                 e2 = e2.PrevInAEL;
  1998.             }
  1999.  
  2000.             if (eTmp == null)
  2001.             {
  2002.                 outRec.FirstLeft = null;
  2003.                 outRec.IsHole = false;
  2004.             }
  2005.             else
  2006.             {
  2007.                 outRec.FirstLeft = m_PolyOuts[eTmp.OutIdx];
  2008.                 outRec.IsHole = !outRec.FirstLeft.IsHole;
  2009.             }
  2010.         }
  2011.  
  2012.         private double GetDx(IntPoint pt1, IntPoint pt2)
  2013.         {
  2014.             if (pt1.Y == pt2.Y) return horizontal;
  2015.             else return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
  2016.         }
  2017.  
  2018.         private bool FirstIsBottomPt(OutPt btmPt1, OutPt btmPt2)
  2019.         {
  2020.             OutPt p = btmPt1.Prev;
  2021.             while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Prev;
  2022.             double dx1p = Math.Abs(GetDx(btmPt1.Pt, p.Pt));
  2023.             p = btmPt1.Next;
  2024.             while ((p.Pt == btmPt1.Pt) && (p != btmPt1)) p = p.Next;
  2025.             double dx1n = Math.Abs(GetDx(btmPt1.Pt, p.Pt));
  2026.  
  2027.             p = btmPt2.Prev;
  2028.             while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Prev;
  2029.             double dx2p = Math.Abs(GetDx(btmPt2.Pt, p.Pt));
  2030.             p = btmPt2.Next;
  2031.             while ((p.Pt == btmPt2.Pt) && (p != btmPt2)) p = p.Next;
  2032.             double dx2n = Math.Abs(GetDx(btmPt2.Pt, p.Pt));
  2033.  
  2034.             if (Math.Max(dx1p, dx1n) == Math.Max(dx2p, dx2n) &&
  2035.               Math.Min(dx1p, dx1n) == Math.Min(dx2p, dx2n))
  2036.                 return Area(btmPt1) > 0;
  2037.             else
  2038.                 return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
  2039.         }
  2040.  
  2041.         private OutPt GetBottomPt(OutPt pp)
  2042.         {
  2043.             OutPt dups = null;
  2044.             OutPt p = pp.Next;
  2045.             while (p != pp)
  2046.             {
  2047.                 if (p.Pt.Y > pp.Pt.Y)
  2048.                 {
  2049.                     pp = p;
  2050.                     dups = null;
  2051.                 }
  2052.                 else if (p.Pt.Y == pp.Pt.Y && p.Pt.X <= pp.Pt.X)
  2053.                 {
  2054.                     if (p.Pt.X < pp.Pt.X)
  2055.                     {
  2056.                         dups = null;
  2057.                         pp = p;
  2058.                     }
  2059.                     else
  2060.                     {
  2061.                         if (p.Next != pp && p.Prev != pp) dups = p;
  2062.                     }
  2063.                 }
  2064.                 p = p.Next;
  2065.             }
  2066.             if (dups != null)
  2067.             {
  2068.                 while (dups != p)
  2069.                 {
  2070.                     if (!FirstIsBottomPt(p, dups)) pp = dups;
  2071.                     dups = dups.Next;
  2072.                     while (dups.Pt != pp.Pt) dups = dups.Next;
  2073.                 }
  2074.             }
  2075.             return pp;
  2076.         }
  2077.  
  2078.         private OutRec GetLowermostRec(OutRec outRec1, OutRec outRec2)
  2079.         {
  2080.             if (outRec1.BottomPt == null)
  2081.                 outRec1.BottomPt = GetBottomPt(outRec1.Pts);
  2082.             if (outRec2.BottomPt == null)
  2083.                 outRec2.BottomPt = GetBottomPt(outRec2.Pts);
  2084.             OutPt bPt1 = outRec1.BottomPt;
  2085.             OutPt bPt2 = outRec2.BottomPt;
  2086.             if (bPt1.Pt.Y > bPt2.Pt.Y) return outRec1;
  2087.             else if (bPt1.Pt.Y < bPt2.Pt.Y) return outRec2;
  2088.             else if (bPt1.Pt.X < bPt2.Pt.X) return outRec1;
  2089.             else if (bPt1.Pt.X > bPt2.Pt.X) return outRec2;
  2090.             else if (bPt1.Next == bPt1) return outRec2;
  2091.             else if (bPt2.Next == bPt2) return outRec1;
  2092.             else if (FirstIsBottomPt(bPt1, bPt2)) return outRec1;
  2093.             else return outRec2;
  2094.         }
  2095.  
  2096.         bool OutRec1RightOfOutRec2(OutRec outRec1, OutRec outRec2)
  2097.         {
  2098.             do
  2099.             {
  2100.                 outRec1 = outRec1.FirstLeft;
  2101.                 if (outRec1 == outRec2) return true;
  2102.             } while (outRec1 != null);
  2103.             return false;
  2104.         }
  2105.  
  2106.         private OutRec GetOutRec(int idx)
  2107.         {
  2108.             OutRec outrec = m_PolyOuts[idx];
  2109.             while (outrec != m_PolyOuts[outrec.Idx])
  2110.                 outrec = m_PolyOuts[outrec.Idx];
  2111.             return outrec;
  2112.         }
  2113.  
  2114.         private void AppendPolygon(TEdge e1, TEdge e2)
  2115.         {
  2116.             OutRec outRec1 = m_PolyOuts[e1.OutIdx];
  2117.             OutRec outRec2 = m_PolyOuts[e2.OutIdx];
  2118.  
  2119.             OutRec holeStateRec;
  2120.             if (OutRec1RightOfOutRec2(outRec1, outRec2))
  2121.                 holeStateRec = outRec2;
  2122.             else if (OutRec1RightOfOutRec2(outRec2, outRec1))
  2123.                 holeStateRec = outRec1;
  2124.             else
  2125.                 holeStateRec = GetLowermostRec(outRec1, outRec2);
  2126.  
  2127.             OutPt p1_lft = outRec1.Pts;
  2128.             OutPt p1_rt = p1_lft.Prev;
  2129.             OutPt p2_lft = outRec2.Pts;
  2130.             OutPt p2_rt = p2_lft.Prev;
  2131.  
  2132.             if (e1.Side == EdgeSide.esLeft)
  2133.             {
  2134.                 if (e2.Side == EdgeSide.esLeft)
  2135.                 {
  2136.                     ReversePolyPtLinks(p2_lft);
  2137.                     p2_lft.Next = p1_lft;
  2138.                     p1_lft.Prev = p2_lft;
  2139.                     p1_rt.Next = p2_rt;
  2140.                     p2_rt.Prev = p1_rt;
  2141.                     outRec1.Pts = p2_rt;
  2142.                 }
  2143.                 else
  2144.                 {
  2145.                     p2_rt.Next = p1_lft;
  2146.                     p1_lft.Prev = p2_rt;
  2147.                     p2_lft.Prev = p1_rt;
  2148.                     p1_rt.Next = p2_lft;
  2149.                     outRec1.Pts = p2_lft;
  2150.                 }
  2151.             }
  2152.             else
  2153.             {
  2154.                 if (e2.Side == EdgeSide.esRight)
  2155.                 {
  2156.                     ReversePolyPtLinks(p2_lft);
  2157.                     p1_rt.Next = p2_rt;
  2158.                     p2_rt.Prev = p1_rt;
  2159.                     p2_lft.Next = p1_lft;
  2160.                     p1_lft.Prev = p2_lft;
  2161.                 }
  2162.                 else
  2163.                 {
  2164.                     p1_rt.Next = p2_lft;
  2165.                     p2_lft.Prev = p1_rt;
  2166.                     p1_lft.Prev = p2_rt;
  2167.                     p2_rt.Next = p1_lft;
  2168.                 }
  2169.             }
  2170.  
  2171.             outRec1.BottomPt = null;
  2172.             if (holeStateRec == outRec2)
  2173.             {
  2174.                 if (outRec2.FirstLeft != outRec1)
  2175.                     outRec1.FirstLeft = outRec2.FirstLeft;
  2176.                 outRec1.IsHole = outRec2.IsHole;
  2177.             }
  2178.             outRec2.Pts = null;
  2179.             outRec2.BottomPt = null;
  2180.  
  2181.             outRec2.FirstLeft = outRec1;
  2182.  
  2183.             int OKIdx = e1.OutIdx;
  2184.             int ObsoleteIdx = e2.OutIdx;
  2185.  
  2186.             e1.OutIdx = Unassigned; e2.OutIdx = Unassigned;
  2187.  
  2188.             TEdge e = m_ActiveEdges;
  2189.             while (e != null)
  2190.             {
  2191.                 if (e.OutIdx == ObsoleteIdx)
  2192.                 {
  2193.                     e.OutIdx = OKIdx;
  2194.                     e.Side = e1.Side;
  2195.                     break;
  2196.                 }
  2197.                 e = e.NextInAEL;
  2198.             }
  2199.             outRec2.Idx = outRec1.Idx;
  2200.         }
  2201.  
  2202.         private void ReversePolyPtLinks(OutPt pp)
  2203.         {
  2204.             if (pp == null) return;
  2205.             OutPt pp1;
  2206.             OutPt pp2;
  2207.             pp1 = pp;
  2208.             do
  2209.             {
  2210.                 pp2 = pp1.Next;
  2211.                 pp1.Next = pp1.Prev;
  2212.                 pp1.Prev = pp2;
  2213.                 pp1 = pp2;
  2214.             } while (pp1 != pp);
  2215.         }
  2216.  
  2217.         private static void SwapSides(TEdge edge1, TEdge edge2)
  2218.         {
  2219.             EdgeSide side = edge1.Side;
  2220.             edge1.Side = edge2.Side;
  2221.             edge2.Side = side;
  2222.         }
  2223.  
  2224.         private static void SwapPolyIndexes(TEdge edge1, TEdge edge2)
  2225.         {
  2226.             int outIdx = edge1.OutIdx;
  2227.             edge1.OutIdx = edge2.OutIdx;
  2228.             edge2.OutIdx = outIdx;
  2229.         }
  2230.  
  2231.         private void IntersectEdges(TEdge e1, TEdge e2, IntPoint pt)
  2232.         {
  2233.  
  2234.             bool e1Contributing = (e1.OutIdx >= 0);
  2235.             bool e2Contributing = (e2.OutIdx >= 0);
  2236.  
  2237. #if use_xyz
  2238.           SetZ(ref pt, e1, e2);
  2239. #endif
  2240.  
  2241. #if use_lines
  2242.             if (e1.WindDelta == 0 || e2.WindDelta == 0)
  2243.             {
  2244.                 if (e1.WindDelta == 0 && e2.WindDelta == 0) return;
  2245.                 else if (e1.PolyTyp == e2.PolyTyp &&
  2246.   e1.WindDelta != e2.WindDelta && m_ClipType == ClipType.ctUnion)
  2247.                 {
  2248.                     if (e1.WindDelta == 0)
  2249.                     {
  2250.                         if (e2Contributing)
  2251.                         {
  2252.                             AddOutPt(e1, pt);
  2253.                             if (e1Contributing) e1.OutIdx = Unassigned;
  2254.                         }
  2255.                     }
  2256.                     else
  2257.                     {
  2258.                         if (e1Contributing)
  2259.                         {
  2260.                             AddOutPt(e2, pt);
  2261.                             if (e2Contributing) e2.OutIdx = Unassigned;
  2262.                         }
  2263.                     }
  2264.                 }
  2265.                 else if (e1.PolyTyp != e2.PolyTyp)
  2266.                 {
  2267.                     if ((e1.WindDelta == 0) && Math.Abs(e2.WindCnt) == 1 &&
  2268.                       (m_ClipType != ClipType.ctUnion || e2.WindCnt2 == 0))
  2269.                     {
  2270.                         AddOutPt(e1, pt);
  2271.                         if (e1Contributing) e1.OutIdx = Unassigned;
  2272.                     }
  2273.                     else if ((e2.WindDelta == 0) && (Math.Abs(e1.WindCnt) == 1) &&
  2274.                       (m_ClipType != ClipType.ctUnion || e1.WindCnt2 == 0))
  2275.                     {
  2276.                         AddOutPt(e2, pt);
  2277.                         if (e2Contributing) e2.OutIdx = Unassigned;
  2278.                     }
  2279.                 }
  2280.                 return;
  2281.             }
  2282. #endif
  2283.  
  2284.             if (e1.PolyTyp == e2.PolyTyp)
  2285.             {
  2286.                 if (IsEvenOddFillType(e1))
  2287.                 {
  2288.                     int oldE1WindCnt = e1.WindCnt;
  2289.                     e1.WindCnt = e2.WindCnt;
  2290.                     e2.WindCnt = oldE1WindCnt;
  2291.                 }
  2292.                 else
  2293.                 {
  2294.                     if (e1.WindCnt + e2.WindDelta == 0) e1.WindCnt = -e1.WindCnt;
  2295.                     else e1.WindCnt += e2.WindDelta;
  2296.                     if (e2.WindCnt - e1.WindDelta == 0) e2.WindCnt = -e2.WindCnt;
  2297.                     else e2.WindCnt -= e1.WindDelta;
  2298.                 }
  2299.             }
  2300.             else
  2301.             {
  2302.                 if (!IsEvenOddFillType(e2)) e1.WindCnt2 += e2.WindDelta;
  2303.                 else e1.WindCnt2 = (e1.WindCnt2 == 0) ? 1 : 0;
  2304.                 if (!IsEvenOddFillType(e1)) e2.WindCnt2 -= e1.WindDelta;
  2305.                 else e2.WindCnt2 = (e2.WindCnt2 == 0) ? 1 : 0;
  2306.             }
  2307.  
  2308.             PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
  2309.             if (e1.PolyTyp == PolyType.ptSubject)
  2310.             {
  2311.                 e1FillType = m_SubjFillType;
  2312.                 e1FillType2 = m_ClipFillType;
  2313.             }
  2314.             else
  2315.             {
  2316.                 e1FillType = m_ClipFillType;
  2317.                 e1FillType2 = m_SubjFillType;
  2318.             }
  2319.             if (e2.PolyTyp == PolyType.ptSubject)
  2320.             {
  2321.                 e2FillType = m_SubjFillType;
  2322.                 e2FillType2 = m_ClipFillType;
  2323.             }
  2324.             else
  2325.             {
  2326.                 e2FillType = m_ClipFillType;
  2327.                 e2FillType2 = m_SubjFillType;
  2328.             }
  2329.  
  2330.             int e1Wc, e2Wc;
  2331.             switch (e1FillType)
  2332.             {
  2333.                 case PolyFillType.pftPositive: e1Wc = e1.WindCnt; break;
  2334.                 case PolyFillType.pftNegative: e1Wc = -e1.WindCnt; break;
  2335.                 default: e1Wc = Math.Abs(e1.WindCnt); break;
  2336.             }
  2337.             switch (e2FillType)
  2338.             {
  2339.                 case PolyFillType.pftPositive: e2Wc = e2.WindCnt; break;
  2340.                 case PolyFillType.pftNegative: e2Wc = -e2.WindCnt; break;
  2341.                 default: e2Wc = Math.Abs(e2.WindCnt); break;
  2342.             }
  2343.  
  2344.             if (e1Contributing && e2Contributing)
  2345.             {
  2346.                 if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
  2347.                   (e1.PolyTyp != e2.PolyTyp && m_ClipType != ClipType.ctXor))
  2348.                 {
  2349.                     AddLocalMaxPoly(e1, e2, pt);
  2350.                 }
  2351.                 else
  2352.                 {
  2353.                     AddOutPt(e1, pt);
  2354.                     AddOutPt(e2, pt);
  2355.                     SwapSides(e1, e2);
  2356.                     SwapPolyIndexes(e1, e2);
  2357.                 }
  2358.             }
  2359.             else if (e1Contributing)
  2360.             {
  2361.                 if (e2Wc == 0 || e2Wc == 1)
  2362.                 {
  2363.                     AddOutPt(e1, pt);
  2364.                     SwapSides(e1, e2);
  2365.                     SwapPolyIndexes(e1, e2);
  2366.                 }
  2367.  
  2368.             }
  2369.             else if (e2Contributing)
  2370.             {
  2371.                 if (e1Wc == 0 || e1Wc == 1)
  2372.                 {
  2373.                     AddOutPt(e2, pt);
  2374.                     SwapSides(e1, e2);
  2375.                     SwapPolyIndexes(e1, e2);
  2376.                 }
  2377.             }
  2378.             else if ((e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
  2379.             {
  2380.                 cInt e1Wc2, e2Wc2;
  2381.                 switch (e1FillType2)
  2382.                 {
  2383.                     case PolyFillType.pftPositive: e1Wc2 = e1.WindCnt2; break;
  2384.                     case PolyFillType.pftNegative: e1Wc2 = -e1.WindCnt2; break;
  2385.                     default: e1Wc2 = Math.Abs(e1.WindCnt2); break;
  2386.                 }
  2387.                 switch (e2FillType2)
  2388.                 {
  2389.                     case PolyFillType.pftPositive: e2Wc2 = e2.WindCnt2; break;
  2390.                     case PolyFillType.pftNegative: e2Wc2 = -e2.WindCnt2; break;
  2391.                     default: e2Wc2 = Math.Abs(e2.WindCnt2); break;
  2392.                 }
  2393.  
  2394.                 if (e1.PolyTyp != e2.PolyTyp)
  2395.                 {
  2396.                     AddLocalMinPoly(e1, e2, pt);
  2397.                 }
  2398.                 else if (e1Wc == 1 && e2Wc == 1)
  2399.                     switch (m_ClipType)
  2400.                     {
  2401.                         case ClipType.ctIntersection:
  2402.                             if (e1Wc2 > 0 && e2Wc2 > 0)
  2403.                                 AddLocalMinPoly(e1, e2, pt);
  2404.                             break;
  2405.                         case ClipType.ctUnion:
  2406.                             if (e1Wc2 <= 0 && e2Wc2 <= 0)
  2407.                                 AddLocalMinPoly(e1, e2, pt);
  2408.                             break;
  2409.                         case ClipType.ctDifference:
  2410.                             if (((e1.PolyTyp == PolyType.ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
  2411.                                 ((e1.PolyTyp == PolyType.ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
  2412.                                 AddLocalMinPoly(e1, e2, pt);
  2413.                             break;
  2414.                         case ClipType.ctXor:
  2415.                             AddLocalMinPoly(e1, e2, pt);
  2416.                             break;
  2417.                     }
  2418.                 else
  2419.                     SwapSides(e1, e2);
  2420.             }
  2421.         }
  2422.  
  2423.         private void DeleteFromSEL(TEdge e)
  2424.         {
  2425.             TEdge SelPrev = e.PrevInSEL;
  2426.             TEdge SelNext = e.NextInSEL;
  2427.             if (SelPrev == null && SelNext == null && (e != m_SortedEdges))
  2428.                 return; if (SelPrev != null)
  2429.                 SelPrev.NextInSEL = SelNext;
  2430.             else m_SortedEdges = SelNext;
  2431.             if (SelNext != null)
  2432.                 SelNext.PrevInSEL = SelPrev;
  2433.             e.NextInSEL = null;
  2434.             e.PrevInSEL = null;
  2435.         }
  2436.  
  2437.         private void ProcessHorizontals()
  2438.         {
  2439.             TEdge horzEdge; while (PopEdgeFromSEL(out horzEdge))
  2440.                 ProcessHorizontal(horzEdge);
  2441.         }
  2442.  
  2443.         void GetHorzDirection(TEdge HorzEdge, out Direction Dir, out cInt Left, out cInt Right)
  2444.         {
  2445.             if (HorzEdge.Bot.X < HorzEdge.Top.X)
  2446.             {
  2447.                 Left = HorzEdge.Bot.X;
  2448.                 Right = HorzEdge.Top.X;
  2449.                 Dir = Direction.dLeftToRight;
  2450.             }
  2451.             else
  2452.             {
  2453.                 Left = HorzEdge.Top.X;
  2454.                 Right = HorzEdge.Bot.X;
  2455.                 Dir = Direction.dRightToLeft;
  2456.             }
  2457.         }
  2458.  
  2459.         private void ProcessHorizontal(TEdge horzEdge)
  2460.         {
  2461.             Direction dir;
  2462.             cInt horzLeft, horzRight;
  2463.             bool IsOpen = horzEdge.WindDelta == 0;
  2464.  
  2465.             GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight);
  2466.  
  2467.             TEdge eLastHorz = horzEdge, eMaxPair = null;
  2468.             while (eLastHorz.NextInLML != null && IsHorizontal(eLastHorz.NextInLML))
  2469.                 eLastHorz = eLastHorz.NextInLML;
  2470.             if (eLastHorz.NextInLML == null)
  2471.                 eMaxPair = GetMaximaPair(eLastHorz);
  2472.  
  2473.             Maxima currMax = m_Maxima;
  2474.             if (currMax != null)
  2475.             {
  2476.                 if (dir == Direction.dLeftToRight)
  2477.                 {
  2478.                     while (currMax != null && currMax.X <= horzEdge.Bot.X)
  2479.                         currMax = currMax.Next;
  2480.                     if (currMax != null && currMax.X >= eLastHorz.Top.X)
  2481.                         currMax = null;
  2482.                 }
  2483.                 else
  2484.                 {
  2485.                     while (currMax.Next != null && currMax.Next.X < horzEdge.Bot.X)
  2486.                         currMax = currMax.Next;
  2487.                     if (currMax.X <= eLastHorz.Top.X) currMax = null;
  2488.                 }
  2489.             }
  2490.  
  2491.             OutPt op1 = null;
  2492.             for (; ; )
  2493.             {
  2494.                 bool IsLastHorz = (horzEdge == eLastHorz);
  2495.                 TEdge e = GetNextInAEL(horzEdge, dir);
  2496.                 while (e != null)
  2497.                 {
  2498.  
  2499.                     if (currMax != null)
  2500.                     {
  2501.                         if (dir == Direction.dLeftToRight)
  2502.                         {
  2503.                             while (currMax != null && currMax.X < e.Curr.X)
  2504.                             {
  2505.                                 if (horzEdge.OutIdx >= 0 && !IsOpen)
  2506.                                     AddOutPt(horzEdge, new IntPoint(currMax.X, horzEdge.Bot.Y));
  2507.                                 currMax = currMax.Next;
  2508.                             }
  2509.                         }
  2510.                         else
  2511.                         {
  2512.                             while (currMax != null && currMax.X > e.Curr.X)
  2513.                             {
  2514.                                 if (horzEdge.OutIdx >= 0 && !IsOpen)
  2515.                                     AddOutPt(horzEdge, new IntPoint(currMax.X, horzEdge.Bot.Y));
  2516.                                 currMax = currMax.Prev;
  2517.                             }
  2518.                         }
  2519.                     };
  2520.  
  2521.                     if ((dir == Direction.dLeftToRight && e.Curr.X > horzRight) ||
  2522.                       (dir == Direction.dRightToLeft && e.Curr.X < horzLeft)) break;
  2523.  
  2524.                     if (e.Curr.X == horzEdge.Top.X && horzEdge.NextInLML != null &&
  2525. e.Dx < horzEdge.NextInLML.Dx) break;
  2526.  
  2527.                     if (horzEdge.OutIdx >= 0 && !IsOpen)
  2528.                     {
  2529. #if use_xyz
  2530.                   if (dir == Direction.dLeftToRight) SetZ(ref e.Curr, horzEdge, e);
  2531.                   else SetZ(ref e.Curr, e, horzEdge);
  2532. #endif
  2533.  
  2534.                         op1 = AddOutPt(horzEdge, e.Curr);
  2535.                         TEdge eNextHorz = m_SortedEdges;
  2536.                         while (eNextHorz != null)
  2537.                         {
  2538.                             if (eNextHorz.OutIdx >= 0 &&
  2539.                               HorzSegmentsOverlap(horzEdge.Bot.X,
  2540.                               horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X))
  2541.                             {
  2542.                                 OutPt op2 = GetLastOutPt(eNextHorz);
  2543.                                 AddJoin(op2, op1, eNextHorz.Top);
  2544.                             }
  2545.                             eNextHorz = eNextHorz.NextInSEL;
  2546.                         }
  2547.                         AddGhostJoin(op1, horzEdge.Bot);
  2548.                     }
  2549.  
  2550.                     if (e == eMaxPair && IsLastHorz)
  2551.                     {
  2552.                         if (horzEdge.OutIdx >= 0)
  2553.                             AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge.Top);
  2554.                         DeleteFromAEL(horzEdge);
  2555.                         DeleteFromAEL(eMaxPair);
  2556.                         return;
  2557.                     }
  2558.  
  2559.                     if (dir == Direction.dLeftToRight)
  2560.                     {
  2561.                         IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y);
  2562.                         IntersectEdges(horzEdge, e, Pt);
  2563.                     }
  2564.                     else
  2565.                     {
  2566.                         IntPoint Pt = new IntPoint(e.Curr.X, horzEdge.Curr.Y);
  2567.                         IntersectEdges(e, horzEdge, Pt);
  2568.                     }
  2569.                     TEdge eNext = GetNextInAEL(e, dir);
  2570.                     SwapPositionsInAEL(horzEdge, e);
  2571.                     e = eNext;
  2572.                 }
  2573.                 if (horzEdge.NextInLML == null || !IsHorizontal(horzEdge.NextInLML)) break;
  2574.  
  2575.                 UpdateEdgeIntoAEL(ref horzEdge);
  2576.                 if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Bot);
  2577.                 GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight);
  2578.  
  2579.             }
  2580.             if (horzEdge.OutIdx >= 0 && op1 == null)
  2581.             {
  2582.                 op1 = GetLastOutPt(horzEdge);
  2583.                 TEdge eNextHorz = m_SortedEdges;
  2584.                 while (eNextHorz != null)
  2585.                 {
  2586.                     if (eNextHorz.OutIdx >= 0 &&
  2587.                       HorzSegmentsOverlap(horzEdge.Bot.X,
  2588.                       horzEdge.Top.X, eNextHorz.Bot.X, eNextHorz.Top.X))
  2589.                     {
  2590.                         OutPt op2 = GetLastOutPt(eNextHorz);
  2591.                         AddJoin(op2, op1, eNextHorz.Top);
  2592.                     }
  2593.                     eNextHorz = eNextHorz.NextInSEL;
  2594.                 }
  2595.                 AddGhostJoin(op1, horzEdge.Top);
  2596.             }
  2597.  
  2598.             if (horzEdge.NextInLML != null)
  2599.             {
  2600.                 if (horzEdge.OutIdx >= 0)
  2601.                 {
  2602.                     op1 = AddOutPt(horzEdge, horzEdge.Top);
  2603.  
  2604.                     UpdateEdgeIntoAEL(ref horzEdge);
  2605.                     if (horzEdge.WindDelta == 0) return;
  2606.                     TEdge ePrev = horzEdge.PrevInAEL;
  2607.                     TEdge eNext = horzEdge.NextInAEL;
  2608.                     if (ePrev != null && ePrev.Curr.X == horzEdge.Bot.X &&
  2609.                       ePrev.Curr.Y == horzEdge.Bot.Y && ePrev.WindDelta != 0 &&
  2610.                       (ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y &&
  2611.                       SlopesEqual(horzEdge, ePrev, m_UseFullRange)))
  2612.                     {
  2613.                         OutPt op2 = AddOutPt(ePrev, horzEdge.Bot);
  2614.                         AddJoin(op1, op2, horzEdge.Top);
  2615.                     }
  2616.                     else if (eNext != null && eNext.Curr.X == horzEdge.Bot.X &&
  2617.                       eNext.Curr.Y == horzEdge.Bot.Y && eNext.WindDelta != 0 &&
  2618.                       eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y &&
  2619.                       SlopesEqual(horzEdge, eNext, m_UseFullRange))
  2620.                     {
  2621.                         OutPt op2 = AddOutPt(eNext, horzEdge.Bot);
  2622.                         AddJoin(op1, op2, horzEdge.Top);
  2623.                     }
  2624.                 }
  2625.                 else
  2626.                     UpdateEdgeIntoAEL(ref horzEdge);
  2627.             }
  2628.             else
  2629.             {
  2630.                 if (horzEdge.OutIdx >= 0) AddOutPt(horzEdge, horzEdge.Top);
  2631.                 DeleteFromAEL(horzEdge);
  2632.             }
  2633.         }
  2634.  
  2635.         private TEdge GetNextInAEL(TEdge e, Direction Direction)
  2636.         {
  2637.             return Direction == Direction.dLeftToRight ? e.NextInAEL : e.PrevInAEL;
  2638.         }
  2639.  
  2640.         private bool IsMinima(TEdge e)
  2641.         {
  2642.             return e != null && (e.Prev.NextInLML != e) && (e.Next.NextInLML != e);
  2643.         }
  2644.  
  2645.         private bool IsMaxima(TEdge e, double Y)
  2646.         {
  2647.             return (e != null && e.Top.Y == Y && e.NextInLML == null);
  2648.         }
  2649.  
  2650.         private bool IsIntermediate(TEdge e, double Y)
  2651.         {
  2652.             return (e.Top.Y == Y && e.NextInLML != null);
  2653.         }
  2654.  
  2655.         internal TEdge GetMaximaPair(TEdge e)
  2656.         {
  2657.             if ((e.Next.Top == e.Top) && e.Next.NextInLML == null)
  2658.                 return e.Next;
  2659.             else if ((e.Prev.Top == e.Top) && e.Prev.NextInLML == null)
  2660.                 return e.Prev;
  2661.             else
  2662.                 return null;
  2663.         }
  2664.  
  2665.         internal TEdge GetMaximaPairEx(TEdge e)
  2666.         {
  2667.             TEdge result = GetMaximaPair(e);
  2668.             if (result == null || result.OutIdx == Skip ||
  2669.               ((result.NextInAEL == result.PrevInAEL) && !IsHorizontal(result))) return null;
  2670.             return result;
  2671.         }
  2672.  
  2673.         private bool ProcessIntersections(cInt topY)
  2674.         {
  2675.             if (m_ActiveEdges == null) return true;
  2676.             try
  2677.             {
  2678.                 BuildIntersectList(topY);
  2679.                 if (m_IntersectList.Count == 0) return true;
  2680.                 if (m_IntersectList.Count == 1 || FixupIntersectionOrder())
  2681.                     ProcessIntersectList();
  2682.                 else
  2683.                     return false;
  2684.             }
  2685.             catch
  2686.             {
  2687.                 m_SortedEdges = null;
  2688.                 m_IntersectList.Clear();
  2689.                 throw new ClipperException("ProcessIntersections error");
  2690.             }
  2691.             m_SortedEdges = null;
  2692.             return true;
  2693.         }
  2694.  
  2695.         private void BuildIntersectList(cInt topY)
  2696.         {
  2697.             if (m_ActiveEdges == null) return;
  2698.  
  2699.             TEdge e = m_ActiveEdges;
  2700.             m_SortedEdges = e;
  2701.             while (e != null)
  2702.             {
  2703.                 e.PrevInSEL = e.PrevInAEL;
  2704.                 e.NextInSEL = e.NextInAEL;
  2705.                 e.Curr.X = TopX(e, topY);
  2706.                 e = e.NextInAEL;
  2707.             }
  2708.  
  2709.             bool isModified = true;
  2710.             while (isModified && m_SortedEdges != null)
  2711.             {
  2712.                 isModified = false;
  2713.                 e = m_SortedEdges;
  2714.                 while (e.NextInSEL != null)
  2715.                 {
  2716.                     TEdge eNext = e.NextInSEL;
  2717.                     IntPoint pt;
  2718.                     if (e.Curr.X > eNext.Curr.X)
  2719.                     {
  2720.                         IntersectPoint(e, eNext, out pt);
  2721.                         if (pt.Y < topY)
  2722.                             pt = new IntPoint(TopX(e, topY), topY);
  2723.                         IntersectNode newNode = new IntersectNode();
  2724.                         newNode.Edge1 = e;
  2725.                         newNode.Edge2 = eNext;
  2726.                         newNode.Pt = pt;
  2727.                         m_IntersectList.Add(newNode);
  2728.  
  2729.                         SwapPositionsInSEL(e, eNext);
  2730.                         isModified = true;
  2731.                     }
  2732.                     else
  2733.                         e = eNext;
  2734.                 }
  2735.                 if (e.PrevInSEL != null) e.PrevInSEL.NextInSEL = null;
  2736.                 else break;
  2737.             }
  2738.             m_SortedEdges = null;
  2739.         }
  2740.  
  2741.         private bool EdgesAdjacent(IntersectNode inode)
  2742.         {
  2743.             return (inode.Edge1.NextInSEL == inode.Edge2) ||
  2744.               (inode.Edge1.PrevInSEL == inode.Edge2);
  2745.         }
  2746.  
  2747.         private static int IntersectNodeSort(IntersectNode node1, IntersectNode node2)
  2748.         {
  2749.             return (int)(node2.Pt.Y - node1.Pt.Y);
  2750.         }
  2751.  
  2752.         private bool FixupIntersectionOrder()
  2753.         {
  2754.             m_IntersectList.Sort(m_IntersectNodeComparer);
  2755.  
  2756.             CopyAELToSEL();
  2757.             int cnt = m_IntersectList.Count;
  2758.             for (int i = 0; i < cnt; i++)
  2759.             {
  2760.                 if (!EdgesAdjacent(m_IntersectList[i]))
  2761.                 {
  2762.                     int j = i + 1;
  2763.                     while (j < cnt && !EdgesAdjacent(m_IntersectList[j])) j++;
  2764.                     if (j == cnt) return false;
  2765.  
  2766.                     IntersectNode tmp = m_IntersectList[i];
  2767.                     m_IntersectList[i] = m_IntersectList[j];
  2768.                     m_IntersectList[j] = tmp;
  2769.  
  2770.                 }
  2771.                 SwapPositionsInSEL(m_IntersectList[i].Edge1, m_IntersectList[i].Edge2);
  2772.             }
  2773.             return true;
  2774.         }
  2775.  
  2776.         private void ProcessIntersectList()
  2777.         {
  2778.             for (int i = 0; i < m_IntersectList.Count; i++)
  2779.             {
  2780.                 IntersectNode iNode = m_IntersectList[i];
  2781.                 {
  2782.                     IntersectEdges(iNode.Edge1, iNode.Edge2, iNode.Pt);
  2783.                     SwapPositionsInAEL(iNode.Edge1, iNode.Edge2);
  2784.                 }
  2785.             }
  2786.             m_IntersectList.Clear();
  2787.         }
  2788.  
  2789.         internal static cInt Round(double value)
  2790.         {
  2791.             return value < 0 ? (cInt)(value - 0.5) : (cInt)(value + 0.5);
  2792.         }
  2793.  
  2794.         private static cInt TopX(TEdge edge, cInt currentY)
  2795.         {
  2796.             if (currentY == edge.Top.Y)
  2797.                 return edge.Top.X;
  2798.             return edge.Bot.X + Round(edge.Dx * (currentY - edge.Bot.Y));
  2799.         }
  2800.  
  2801.         private void IntersectPoint(TEdge edge1, TEdge edge2, out IntPoint ip)
  2802.         {
  2803.             ip = new IntPoint();
  2804.             double b1, b2;
  2805.             if (edge1.Dx == edge2.Dx)
  2806.             {
  2807.                 ip.Y = edge1.Curr.Y;
  2808.                 ip.X = TopX(edge1, ip.Y);
  2809.                 return;
  2810.             }
  2811.  
  2812.             if (edge1.Delta.X == 0)
  2813.             {
  2814.                 ip.X = edge1.Bot.X;
  2815.                 if (IsHorizontal(edge2))
  2816.                 {
  2817.                     ip.Y = edge2.Bot.Y;
  2818.                 }
  2819.                 else
  2820.                 {
  2821.                     b2 = edge2.Bot.Y - (edge2.Bot.X / edge2.Dx);
  2822.                     ip.Y = Round(ip.X / edge2.Dx + b2);
  2823.                 }
  2824.             }
  2825.             else if (edge2.Delta.X == 0)
  2826.             {
  2827.                 ip.X = edge2.Bot.X;
  2828.                 if (IsHorizontal(edge1))
  2829.                 {
  2830.                     ip.Y = edge1.Bot.Y;
  2831.                 }
  2832.                 else
  2833.                 {
  2834.                     b1 = edge1.Bot.Y - (edge1.Bot.X / edge1.Dx);
  2835.                     ip.Y = Round(ip.X / edge1.Dx + b1);
  2836.                 }
  2837.             }
  2838.             else
  2839.             {
  2840.                 b1 = edge1.Bot.X - edge1.Bot.Y * edge1.Dx;
  2841.                 b2 = edge2.Bot.X - edge2.Bot.Y * edge2.Dx;
  2842.                 double q = (b2 - b1) / (edge1.Dx - edge2.Dx);
  2843.                 ip.Y = Round(q);
  2844.                 if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx))
  2845.                     ip.X = Round(edge1.Dx * q + b1);
  2846.                 else
  2847.                     ip.X = Round(edge2.Dx * q + b2);
  2848.             }
  2849.  
  2850.             if (ip.Y < edge1.Top.Y || ip.Y < edge2.Top.Y)
  2851.             {
  2852.                 if (edge1.Top.Y > edge2.Top.Y)
  2853.                     ip.Y = edge1.Top.Y;
  2854.                 else
  2855.                     ip.Y = edge2.Top.Y;
  2856.                 if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx))
  2857.                     ip.X = TopX(edge1, ip.Y);
  2858.                 else
  2859.                     ip.X = TopX(edge2, ip.Y);
  2860.             }
  2861.             if (ip.Y > edge1.Curr.Y)
  2862.             {
  2863.                 ip.Y = edge1.Curr.Y;
  2864.                 if (Math.Abs(edge1.Dx) > Math.Abs(edge2.Dx))
  2865.                     ip.X = TopX(edge2, ip.Y);
  2866.                 else
  2867.                     ip.X = TopX(edge1, ip.Y);
  2868.             }
  2869.         }
  2870.  
  2871.         private void ProcessEdgesAtTopOfScanbeam(cInt topY)
  2872.         {
  2873.             TEdge e = m_ActiveEdges;
  2874.             while (e != null)
  2875.             {
  2876.                 bool IsMaximaEdge = IsMaxima(e, topY);
  2877.  
  2878.                 if (IsMaximaEdge)
  2879.                 {
  2880.                     TEdge eMaxPair = GetMaximaPairEx(e);
  2881.                     IsMaximaEdge = (eMaxPair == null || !IsHorizontal(eMaxPair));
  2882.                 }
  2883.  
  2884.                 if (IsMaximaEdge)
  2885.                 {
  2886.                     if (StrictlySimple) InsertMaxima(e.Top.X);
  2887.                     TEdge ePrev = e.PrevInAEL;
  2888.                     DoMaxima(e);
  2889.                     if (ePrev == null) e = m_ActiveEdges;
  2890.                     else e = ePrev.NextInAEL;
  2891.                 }
  2892.                 else
  2893.                 {
  2894.                     if (IsIntermediate(e, topY) && IsHorizontal(e.NextInLML))
  2895.                     {
  2896.                         UpdateEdgeIntoAEL(ref e);
  2897.                         if (e.OutIdx >= 0)
  2898.                             AddOutPt(e, e.Bot);
  2899.                         AddEdgeToSEL(e);
  2900.                     }
  2901.                     else
  2902.                     {
  2903.                         e.Curr.X = TopX(e, topY);
  2904.                         e.Curr.Y = topY;
  2905. #if use_xyz
  2906.               if (e.Top.Y == topY) e.Curr.Z = e.Top.Z;
  2907.               else if (e.Bot.Y == topY) e.Curr.Z = e.Bot.Z;
  2908.               else e.Curr.Z = 0;
  2909. #endif
  2910.                     }
  2911.                     if (StrictlySimple)
  2912.                     {
  2913.                         TEdge ePrev = e.PrevInAEL;
  2914.                         if ((e.OutIdx >= 0) && (e.WindDelta != 0) && ePrev != null &&
  2915.                           (ePrev.OutIdx >= 0) && (ePrev.Curr.X == e.Curr.X) &&
  2916.                           (ePrev.WindDelta != 0))
  2917.                         {
  2918.                             IntPoint ip = new IntPoint(e.Curr);
  2919. #if use_xyz
  2920.                 SetZ(ref ip, ePrev, e);
  2921. #endif
  2922.                             OutPt op = AddOutPt(ePrev, ip);
  2923.                             OutPt op2 = AddOutPt(e, ip);
  2924.                             AddJoin(op, op2, ip);
  2925.                         }
  2926.                     }
  2927.  
  2928.                     e = e.NextInAEL;
  2929.                 }
  2930.             }
  2931.  
  2932.             ProcessHorizontals();
  2933.             m_Maxima = null;
  2934.  
  2935.             e = m_ActiveEdges;
  2936.             while (e != null)
  2937.             {
  2938.                 if (IsIntermediate(e, topY))
  2939.                 {
  2940.                     OutPt op = null;
  2941.                     if (e.OutIdx >= 0)
  2942.                         op = AddOutPt(e, e.Top);
  2943.                     UpdateEdgeIntoAEL(ref e);
  2944.  
  2945.                     TEdge ePrev = e.PrevInAEL;
  2946.                     TEdge eNext = e.NextInAEL;
  2947.                     if (ePrev != null && ePrev.Curr.X == e.Bot.X &&
  2948.                       ePrev.Curr.Y == e.Bot.Y && op != null &&
  2949.                       ePrev.OutIdx >= 0 && ePrev.Curr.Y > ePrev.Top.Y &&
  2950.                       SlopesEqual(e.Curr, e.Top, ePrev.Curr, ePrev.Top, m_UseFullRange) &&
  2951.                       (e.WindDelta != 0) && (ePrev.WindDelta != 0))
  2952.                     {
  2953.                         OutPt op2 = AddOutPt(ePrev, e.Bot);
  2954.                         AddJoin(op, op2, e.Top);
  2955.                     }
  2956.                     else if (eNext != null && eNext.Curr.X == e.Bot.X &&
  2957.                       eNext.Curr.Y == e.Bot.Y && op != null &&
  2958.                       eNext.OutIdx >= 0 && eNext.Curr.Y > eNext.Top.Y &&
  2959.                       SlopesEqual(e.Curr, e.Top, eNext.Curr, eNext.Top, m_UseFullRange) &&
  2960.                       (e.WindDelta != 0) && (eNext.WindDelta != 0))
  2961.                     {
  2962.                         OutPt op2 = AddOutPt(eNext, e.Bot);
  2963.                         AddJoin(op, op2, e.Top);
  2964.                     }
  2965.                 }
  2966.                 e = e.NextInAEL;
  2967.             }
  2968.         }
  2969.  
  2970.         private void DoMaxima(TEdge e)
  2971.         {
  2972.             TEdge eMaxPair = GetMaximaPairEx(e);
  2973.             if (eMaxPair == null)
  2974.             {
  2975.                 if (e.OutIdx >= 0)
  2976.                     AddOutPt(e, e.Top);
  2977.                 DeleteFromAEL(e);
  2978.                 return;
  2979.             }
  2980.  
  2981.             TEdge eNext = e.NextInAEL;
  2982.             while (eNext != null && eNext != eMaxPair)
  2983.             {
  2984.                 IntersectEdges(e, eNext, e.Top);
  2985.                 SwapPositionsInAEL(e, eNext);
  2986.                 eNext = e.NextInAEL;
  2987.             }
  2988.  
  2989.             if (e.OutIdx == Unassigned && eMaxPair.OutIdx == Unassigned)
  2990.             {
  2991.                 DeleteFromAEL(e);
  2992.                 DeleteFromAEL(eMaxPair);
  2993.             }
  2994.             else if (e.OutIdx >= 0 && eMaxPair.OutIdx >= 0)
  2995.             {
  2996.                 if (e.OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e.Top);
  2997.                 DeleteFromAEL(e);
  2998.                 DeleteFromAEL(eMaxPair);
  2999.             }
  3000. #if use_lines
  3001.             else if (e.WindDelta == 0)
  3002.             {
  3003.                 if (e.OutIdx >= 0)
  3004.                 {
  3005.                     AddOutPt(e, e.Top);
  3006.                     e.OutIdx = Unassigned;
  3007.                 }
  3008.                 DeleteFromAEL(e);
  3009.  
  3010.                 if (eMaxPair.OutIdx >= 0)
  3011.                 {
  3012.                     AddOutPt(eMaxPair, e.Top);
  3013.                     eMaxPair.OutIdx = Unassigned;
  3014.                 }
  3015.                 DeleteFromAEL(eMaxPair);
  3016.             }
  3017. #endif
  3018.             else throw new ClipperException("DoMaxima error");
  3019.         }
  3020.  
  3021.         public static void ReversePaths(Paths polys)
  3022.         {
  3023.             foreach (var poly in polys) { poly.Reverse(); }
  3024.         }
  3025.  
  3026.         public static bool Orientation(Path poly)
  3027.         {
  3028.             return Area(poly) >= 0;
  3029.         }
  3030.  
  3031.         private int PointCount(OutPt pts)
  3032.         {
  3033.             if (pts == null) return 0;
  3034.             int result = 0;
  3035.             OutPt p = pts;
  3036.             do
  3037.             {
  3038.                 result++;
  3039.                 p = p.Next;
  3040.             }
  3041.             while (p != pts);
  3042.             return result;
  3043.         }
  3044.  
  3045.         private void BuildResult(Paths polyg)
  3046.         {
  3047.             polyg.Clear();
  3048.             polyg.Capacity = m_PolyOuts.Count;
  3049.             for (int i = 0; i < m_PolyOuts.Count; i++)
  3050.             {
  3051.                 OutRec outRec = m_PolyOuts[i];
  3052.                 if (outRec.Pts == null) continue;
  3053.                 OutPt p = outRec.Pts.Prev;
  3054.                 int cnt = PointCount(p);
  3055.                 if (cnt < 2) continue;
  3056.                 Path pg = new Path(cnt);
  3057.                 for (int j = 0; j < cnt; j++)
  3058.                 {
  3059.                     pg.Add(p.Pt);
  3060.                     p = p.Prev;
  3061.                 }
  3062.                 polyg.Add(pg);
  3063.             }
  3064.         }
  3065.  
  3066.         private void BuildResult2(PolyTree polytree)
  3067.         {
  3068.             polytree.Clear();
  3069.  
  3070.             polytree.m_AllPolys.Capacity = m_PolyOuts.Count;
  3071.             for (int i = 0; i < m_PolyOuts.Count; i++)
  3072.             {
  3073.                 OutRec outRec = m_PolyOuts[i];
  3074.                 int cnt = PointCount(outRec.Pts);
  3075.                 if ((outRec.IsOpen && cnt < 2) ||
  3076.                   (!outRec.IsOpen && cnt < 3)) continue;
  3077.                 FixHoleLinkage(outRec);
  3078.                 PolyNode pn = new PolyNode();
  3079.                 polytree.m_AllPolys.Add(pn);
  3080.                 outRec.PolyNode = pn;
  3081.                 pn.m_polygon.Capacity = cnt;
  3082.                 OutPt op = outRec.Pts.Prev;
  3083.                 for (int j = 0; j < cnt; j++)
  3084.                 {
  3085.                     pn.m_polygon.Add(op.Pt);
  3086.                     op = op.Prev;
  3087.                 }
  3088.             }
  3089.  
  3090.             polytree.m_Childs.Capacity = m_PolyOuts.Count;
  3091.             for (int i = 0; i < m_PolyOuts.Count; i++)
  3092.             {
  3093.                 OutRec outRec = m_PolyOuts[i];
  3094.                 if (outRec.PolyNode == null) continue;
  3095.                 else if (outRec.IsOpen)
  3096.                 {
  3097.                     outRec.PolyNode.IsOpen = true;
  3098.                     polytree.AddChild(outRec.PolyNode);
  3099.                 }
  3100.                 else if (outRec.FirstLeft != null &&
  3101.                   outRec.FirstLeft.PolyNode != null)
  3102.                     outRec.FirstLeft.PolyNode.AddChild(outRec.PolyNode);
  3103.                 else
  3104.                     polytree.AddChild(outRec.PolyNode);
  3105.             }
  3106.         }
  3107.  
  3108.         private void FixupOutPolyline(OutRec outrec)
  3109.         {
  3110.             OutPt pp = outrec.Pts;
  3111.             OutPt lastPP = pp.Prev;
  3112.             while (pp != lastPP)
  3113.             {
  3114.                 pp = pp.Next;
  3115.                 if (pp.Pt == pp.Prev.Pt)
  3116.                 {
  3117.                     if (pp == lastPP) lastPP = pp.Prev;
  3118.                     OutPt tmpPP = pp.Prev;
  3119.                     tmpPP.Next = pp.Next;
  3120.                     pp.Next.Prev = tmpPP;
  3121.                     pp = tmpPP;
  3122.                 }
  3123.             }
  3124.             if (pp == pp.Prev) outrec.Pts = null;
  3125.         }
  3126.  
  3127.         private void FixupOutPolygon(OutRec outRec)
  3128.         {
  3129.             OutPt lastOK = null;
  3130.             outRec.BottomPt = null;
  3131.             OutPt pp = outRec.Pts;
  3132.             bool preserveCol = PreserveCollinear || StrictlySimple;
  3133.             for (; ; )
  3134.             {
  3135.                 if (pp.Prev == pp || pp.Prev == pp.Next)
  3136.                 {
  3137.                     outRec.Pts = null;
  3138.                     return;
  3139.                 }
  3140.                 if ((pp.Pt == pp.Next.Pt) || (pp.Pt == pp.Prev.Pt) ||
  3141.   (SlopesEqual(pp.Prev.Pt, pp.Pt, pp.Next.Pt, m_UseFullRange) &&
  3142.   (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp.Prev.Pt, pp.Pt, pp.Next.Pt))))
  3143.                 {
  3144.                     lastOK = null;
  3145.                     pp.Prev.Next = pp.Next;
  3146.                     pp.Next.Prev = pp.Prev;
  3147.                     pp = pp.Prev;
  3148.                 }
  3149.                 else if (pp == lastOK) break;
  3150.                 else
  3151.                 {
  3152.                     if (lastOK == null) lastOK = pp;
  3153.                     pp = pp.Next;
  3154.                 }
  3155.             }
  3156.             outRec.Pts = pp;
  3157.         }
  3158.  
  3159.         OutPt DupOutPt(OutPt outPt, bool InsertAfter)
  3160.         {
  3161.             OutPt result = new OutPt();
  3162.             result.Pt = outPt.Pt;
  3163.             result.Idx = outPt.Idx;
  3164.             if (InsertAfter)
  3165.             {
  3166.                 result.Next = outPt.Next;
  3167.                 result.Prev = outPt;
  3168.                 outPt.Next.Prev = result;
  3169.                 outPt.Next = result;
  3170.             }
  3171.             else
  3172.             {
  3173.                 result.Prev = outPt.Prev;
  3174.                 result.Next = outPt;
  3175.                 outPt.Prev.Next = result;
  3176.                 outPt.Prev = result;
  3177.             }
  3178.             return result;
  3179.         }
  3180.  
  3181.         bool GetOverlap(cInt a1, cInt a2, cInt b1, cInt b2, out cInt Left, out cInt Right)
  3182.         {
  3183.             if (a1 < a2)
  3184.             {
  3185.                 if (b1 < b2) { Left = Math.Max(a1, b1); Right = Math.Min(a2, b2); }
  3186.                 else { Left = Math.Max(a1, b2); Right = Math.Min(a2, b1); }
  3187.             }
  3188.             else
  3189.             {
  3190.                 if (b1 < b2) { Left = Math.Max(a2, b1); Right = Math.Min(a1, b2); }
  3191.                 else { Left = Math.Max(a2, b2); Right = Math.Min(a1, b1); }
  3192.             }
  3193.             return Left < Right;
  3194.         }
  3195.  
  3196.         bool JoinHorz(OutPt op1, OutPt op1b, OutPt op2, OutPt op2b,
  3197.           IntPoint Pt, bool DiscardLeft)
  3198.         {
  3199.             Direction Dir1 = (op1.Pt.X > op1b.Pt.X ?
  3200.               Direction.dRightToLeft : Direction.dLeftToRight);
  3201.             Direction Dir2 = (op2.Pt.X > op2b.Pt.X ?
  3202.               Direction.dRightToLeft : Direction.dLeftToRight);
  3203.             if (Dir1 == Dir2) return false;
  3204.  
  3205.             if (Dir1 == Direction.dLeftToRight)
  3206.             {
  3207.                 while (op1.Next.Pt.X <= Pt.X &&
  3208.                   op1.Next.Pt.X >= op1.Pt.X && op1.Next.Pt.Y == Pt.Y)
  3209.                     op1 = op1.Next;
  3210.                 if (DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next;
  3211.                 op1b = DupOutPt(op1, !DiscardLeft);
  3212.                 if (op1b.Pt != Pt)
  3213.                 {
  3214.                     op1 = op1b;
  3215.                     op1.Pt = Pt;
  3216.                     op1b = DupOutPt(op1, !DiscardLeft);
  3217.                 }
  3218.             }
  3219.             else
  3220.             {
  3221.                 while (op1.Next.Pt.X >= Pt.X &&
  3222.                   op1.Next.Pt.X <= op1.Pt.X && op1.Next.Pt.Y == Pt.Y)
  3223.                     op1 = op1.Next;
  3224.                 if (!DiscardLeft && (op1.Pt.X != Pt.X)) op1 = op1.Next;
  3225.                 op1b = DupOutPt(op1, DiscardLeft);
  3226.                 if (op1b.Pt != Pt)
  3227.                 {
  3228.                     op1 = op1b;
  3229.                     op1.Pt = Pt;
  3230.                     op1b = DupOutPt(op1, DiscardLeft);
  3231.                 }
  3232.             }
  3233.  
  3234.             if (Dir2 == Direction.dLeftToRight)
  3235.             {
  3236.                 while (op2.Next.Pt.X <= Pt.X &&
  3237.                   op2.Next.Pt.X >= op2.Pt.X && op2.Next.Pt.Y == Pt.Y)
  3238.                     op2 = op2.Next;
  3239.                 if (DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next;
  3240.                 op2b = DupOutPt(op2, !DiscardLeft);
  3241.                 if (op2b.Pt != Pt)
  3242.                 {
  3243.                     op2 = op2b;
  3244.                     op2.Pt = Pt;
  3245.                     op2b = DupOutPt(op2, !DiscardLeft);
  3246.                 };
  3247.             }
  3248.             else
  3249.             {
  3250.                 while (op2.Next.Pt.X >= Pt.X &&
  3251.                   op2.Next.Pt.X <= op2.Pt.X && op2.Next.Pt.Y == Pt.Y)
  3252.                     op2 = op2.Next;
  3253.                 if (!DiscardLeft && (op2.Pt.X != Pt.X)) op2 = op2.Next;
  3254.                 op2b = DupOutPt(op2, DiscardLeft);
  3255.                 if (op2b.Pt != Pt)
  3256.                 {
  3257.                     op2 = op2b;
  3258.                     op2.Pt = Pt;
  3259.                     op2b = DupOutPt(op2, DiscardLeft);
  3260.                 };
  3261.             };
  3262.  
  3263.             if ((Dir1 == Direction.dLeftToRight) == DiscardLeft)
  3264.             {
  3265.                 op1.Prev = op2;
  3266.                 op2.Next = op1;
  3267.                 op1b.Next = op2b;
  3268.                 op2b.Prev = op1b;
  3269.             }
  3270.             else
  3271.             {
  3272.                 op1.Next = op2;
  3273.                 op2.Prev = op1;
  3274.                 op1b.Prev = op2b;
  3275.                 op2b.Next = op1b;
  3276.             }
  3277.             return true;
  3278.         }
  3279.  
  3280.         private bool JoinPoints(Join j, OutRec outRec1, OutRec outRec2)
  3281.         {
  3282.             OutPt op1 = j.OutPt1, op1b;
  3283.             OutPt op2 = j.OutPt2, op2b;
  3284.  
  3285.             bool isHorizontal = (j.OutPt1.Pt.Y == j.OffPt.Y);
  3286.  
  3287.             if (isHorizontal && (j.OffPt == j.OutPt1.Pt) && (j.OffPt == j.OutPt2.Pt))
  3288.             {
  3289.                 if (outRec1 != outRec2) return false;
  3290.                 op1b = j.OutPt1.Next;
  3291.                 while (op1b != op1 && (op1b.Pt == j.OffPt))
  3292.                     op1b = op1b.Next;
  3293.                 bool reverse1 = (op1b.Pt.Y > j.OffPt.Y);
  3294.                 op2b = j.OutPt2.Next;
  3295.                 while (op2b != op2 && (op2b.Pt == j.OffPt))
  3296.                     op2b = op2b.Next;
  3297.                 bool reverse2 = (op2b.Pt.Y > j.OffPt.Y);
  3298.                 if (reverse1 == reverse2) return false;
  3299.                 if (reverse1)
  3300.                 {
  3301.                     op1b = DupOutPt(op1, false);
  3302.                     op2b = DupOutPt(op2, true);
  3303.                     op1.Prev = op2;
  3304.                     op2.Next = op1;
  3305.                     op1b.Next = op2b;
  3306.                     op2b.Prev = op1b;
  3307.                     j.OutPt1 = op1;
  3308.                     j.OutPt2 = op1b;
  3309.                     return true;
  3310.                 }
  3311.                 else
  3312.                 {
  3313.                     op1b = DupOutPt(op1, true);
  3314.                     op2b = DupOutPt(op2, false);
  3315.                     op1.Next = op2;
  3316.                     op2.Prev = op1;
  3317.                     op1b.Prev = op2b;
  3318.                     op2b.Next = op1b;
  3319.                     j.OutPt1 = op1;
  3320.                     j.OutPt2 = op1b;
  3321.                     return true;
  3322.                 }
  3323.             }
  3324.             else if (isHorizontal)
  3325.             {
  3326.                 op1b = op1;
  3327.                 while (op1.Prev.Pt.Y == op1.Pt.Y && op1.Prev != op1b && op1.Prev != op2)
  3328.                     op1 = op1.Prev;
  3329.                 while (op1b.Next.Pt.Y == op1b.Pt.Y && op1b.Next != op1 && op1b.Next != op2)
  3330.                     op1b = op1b.Next;
  3331.                 if (op1b.Next == op1 || op1b.Next == op2) return false;
  3332.                 op2b = op2;
  3333.                 while (op2.Prev.Pt.Y == op2.Pt.Y && op2.Prev != op2b && op2.Prev != op1b)
  3334.                     op2 = op2.Prev;
  3335.                 while (op2b.Next.Pt.Y == op2b.Pt.Y && op2b.Next != op2 && op2b.Next != op1)
  3336.                     op2b = op2b.Next;
  3337.                 if (op2b.Next == op2 || op2b.Next == op1) return false;
  3338.                 cInt Left, Right;
  3339.                 if (!GetOverlap(op1.Pt.X, op1b.Pt.X, op2.Pt.X, op2b.Pt.X, out Left, out Right))
  3340.                     return false;
  3341.  
  3342.                 IntPoint Pt;
  3343.                 bool DiscardLeftSide;
  3344.                 if (op1.Pt.X >= Left && op1.Pt.X <= Right)
  3345.                 {
  3346.                     Pt = op1.Pt; DiscardLeftSide = (op1.Pt.X > op1b.Pt.X);
  3347.                 }
  3348.                 else if (op2.Pt.X >= Left && op2.Pt.X <= Right)
  3349.                 {
  3350.                     Pt = op2.Pt; DiscardLeftSide = (op2.Pt.X > op2b.Pt.X);
  3351.                 }
  3352.                 else if (op1b.Pt.X >= Left && op1b.Pt.X <= Right)
  3353.                 {
  3354.                     Pt = op1b.Pt; DiscardLeftSide = op1b.Pt.X > op1.Pt.X;
  3355.                 }
  3356.                 else
  3357.                 {
  3358.                     Pt = op2b.Pt; DiscardLeftSide = (op2b.Pt.X > op2.Pt.X);
  3359.                 }
  3360.                 j.OutPt1 = op1;
  3361.                 j.OutPt2 = op2;
  3362.                 return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
  3363.             }
  3364.             else
  3365.             {
  3366.  
  3367.                 op1b = op1.Next;
  3368.                 while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Next;
  3369.                 bool Reverse1 = ((op1b.Pt.Y > op1.Pt.Y) ||
  3370.                   !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange));
  3371.                 if (Reverse1)
  3372.                 {
  3373.                     op1b = op1.Prev;
  3374.                     while ((op1b.Pt == op1.Pt) && (op1b != op1)) op1b = op1b.Prev;
  3375.                     if ((op1b.Pt.Y > op1.Pt.Y) ||
  3376.                       !SlopesEqual(op1.Pt, op1b.Pt, j.OffPt, m_UseFullRange)) return false;
  3377.                 };
  3378.                 op2b = op2.Next;
  3379.                 while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Next;
  3380.                 bool Reverse2 = ((op2b.Pt.Y > op2.Pt.Y) ||
  3381.                   !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange));
  3382.                 if (Reverse2)
  3383.                 {
  3384.                     op2b = op2.Prev;
  3385.                     while ((op2b.Pt == op2.Pt) && (op2b != op2)) op2b = op2b.Prev;
  3386.                     if ((op2b.Pt.Y > op2.Pt.Y) ||
  3387.                       !SlopesEqual(op2.Pt, op2b.Pt, j.OffPt, m_UseFullRange)) return false;
  3388.                 }
  3389.  
  3390.                 if ((op1b == op1) || (op2b == op2) || (op1b == op2b) ||
  3391.                   ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false;
  3392.  
  3393.                 if (Reverse1)
  3394.                 {
  3395.                     op1b = DupOutPt(op1, false);
  3396.                     op2b = DupOutPt(op2, true);
  3397.                     op1.Prev = op2;
  3398.                     op2.Next = op1;
  3399.                     op1b.Next = op2b;
  3400.                     op2b.Prev = op1b;
  3401.                     j.OutPt1 = op1;
  3402.                     j.OutPt2 = op1b;
  3403.                     return true;
  3404.                 }
  3405.                 else
  3406.                 {
  3407.                     op1b = DupOutPt(op1, true);
  3408.                     op2b = DupOutPt(op2, false);
  3409.                     op1.Next = op2;
  3410.                     op2.Prev = op1;
  3411.                     op1b.Prev = op2b;
  3412.                     op2b.Next = op1b;
  3413.                     j.OutPt1 = op1;
  3414.                     j.OutPt2 = op1b;
  3415.                     return true;
  3416.                 }
  3417.             }
  3418.         }
  3419.  
  3420.         public static int PointInPolygon(IntPoint pt, Path path)
  3421.         {
  3422.             int result = 0, cnt = path.Count;
  3423.             if (cnt < 3) return 0;
  3424.             IntPoint ip = path[0];
  3425.             for (int i = 1; i <= cnt; ++i)
  3426.             {
  3427.                 IntPoint ipNext = (i == cnt ? path[0] : path[i]);
  3428.                 if (ipNext.Y == pt.Y)
  3429.                 {
  3430.                     if ((ipNext.X == pt.X) || (ip.Y == pt.Y &&
  3431.                       ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1;
  3432.                 }
  3433.                 if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y))
  3434.                 {
  3435.                     if (ip.X >= pt.X)
  3436.                     {
  3437.                         if (ipNext.X > pt.X) result = 1 - result;
  3438.                         else
  3439.                         {
  3440.                             double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
  3441.                               (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
  3442.                             if (d == 0) return -1;
  3443.                             else if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
  3444.                         }
  3445.                     }
  3446.                     else
  3447.                     {
  3448.                         if (ipNext.X > pt.X)
  3449.                         {
  3450.                             double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
  3451.                               (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
  3452.                             if (d == 0) return -1;
  3453.                             else if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
  3454.                         }
  3455.                     }
  3456.                 }
  3457.                 ip = ipNext;
  3458.             }
  3459.             return result;
  3460.         }
  3461.  
  3462.         private static int PointInPolygon(IntPoint pt, OutPt op)
  3463.         {
  3464.             int result = 0;
  3465.             OutPt startOp = op;
  3466.             cInt ptx = pt.X, pty = pt.Y;
  3467.             cInt poly0x = op.Pt.X, poly0y = op.Pt.Y;
  3468.             do
  3469.             {
  3470.                 op = op.Next;
  3471.                 cInt poly1x = op.Pt.X, poly1y = op.Pt.Y;
  3472.  
  3473.                 if (poly1y == pty)
  3474.                 {
  3475.                     if ((poly1x == ptx) || (poly0y == pty &&
  3476.                       ((poly1x > ptx) == (poly0x < ptx)))) return -1;
  3477.                 }
  3478.                 if ((poly0y < pty) != (poly1y < pty))
  3479.                 {
  3480.                     if (poly0x >= ptx)
  3481.                     {
  3482.                         if (poly1x > ptx) result = 1 - result;
  3483.                         else
  3484.                         {
  3485.                             double d = (double)(poly0x - ptx) * (poly1y - pty) -
  3486.                               (double)(poly1x - ptx) * (poly0y - pty);
  3487.                             if (d == 0) return -1;
  3488.                             if ((d > 0) == (poly1y > poly0y)) result = 1 - result;
  3489.                         }
  3490.                     }
  3491.                     else
  3492.                     {
  3493.                         if (poly1x > ptx)
  3494.                         {
  3495.                             double d = (double)(poly0x - ptx) * (poly1y - pty) -
  3496.                               (double)(poly1x - ptx) * (poly0y - pty);
  3497.                             if (d == 0) return -1;
  3498.                             if ((d > 0) == (poly1y > poly0y)) result = 1 - result;
  3499.                         }
  3500.                     }
  3501.                 }
  3502.                 poly0x = poly1x; poly0y = poly1y;
  3503.             } while (startOp != op);
  3504.             return result;
  3505.         }
  3506.  
  3507.         private static bool Poly2ContainsPoly1(OutPt outPt1, OutPt outPt2)
  3508.         {
  3509.             OutPt op = outPt1;
  3510.             do
  3511.             {
  3512.                 int res = PointInPolygon(op.Pt, outPt2);
  3513.                 if (res >= 0) return res > 0;
  3514.                 op = op.Next;
  3515.             }
  3516.             while (op != outPt1);
  3517.             return true;
  3518.         }
  3519.  
  3520.         private void FixupFirstLefts1(OutRec OldOutRec, OutRec NewOutRec)
  3521.         {
  3522.             foreach (OutRec outRec in m_PolyOuts)
  3523.             {
  3524.                 OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft);
  3525.                 if (outRec.Pts != null && firstLeft == OldOutRec)
  3526.                 {
  3527.                     if (Poly2ContainsPoly1(outRec.Pts, NewOutRec.Pts))
  3528.                         outRec.FirstLeft = NewOutRec;
  3529.                 }
  3530.             }
  3531.         }
  3532.  
  3533.         private void FixupFirstLefts2(OutRec innerOutRec, OutRec outerOutRec)
  3534.         {
  3535.             OutRec orfl = outerOutRec.FirstLeft;
  3536.             foreach (OutRec outRec in m_PolyOuts)
  3537.             {
  3538.                 if (outRec.Pts == null || outRec == outerOutRec || outRec == innerOutRec)
  3539.                     continue;
  3540.                 OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft);
  3541.                 if (firstLeft != orfl && firstLeft != innerOutRec && firstLeft != outerOutRec)
  3542.                     continue;
  3543.                 if (Poly2ContainsPoly1(outRec.Pts, innerOutRec.Pts))
  3544.                     outRec.FirstLeft = innerOutRec;
  3545.                 else if (Poly2ContainsPoly1(outRec.Pts, outerOutRec.Pts))
  3546.                     outRec.FirstLeft = outerOutRec;
  3547.                 else if (outRec.FirstLeft == innerOutRec || outRec.FirstLeft == outerOutRec)
  3548.                     outRec.FirstLeft = orfl;
  3549.             }
  3550.         }
  3551.  
  3552.         private void FixupFirstLefts3(OutRec OldOutRec, OutRec NewOutRec)
  3553.         {
  3554.             foreach (OutRec outRec in m_PolyOuts)
  3555.             {
  3556.                 OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft);
  3557.                 if (outRec.Pts != null && firstLeft == OldOutRec)
  3558.                     outRec.FirstLeft = NewOutRec;
  3559.             }
  3560.         }
  3561.  
  3562.         private static OutRec ParseFirstLeft(OutRec FirstLeft)
  3563.         {
  3564.             while (FirstLeft != null && FirstLeft.Pts == null)
  3565.                 FirstLeft = FirstLeft.FirstLeft;
  3566.             return FirstLeft;
  3567.         }
  3568.  
  3569.         private void JoinCommonEdges()
  3570.         {
  3571.             for (int i = 0; i < m_Joins.Count; i++)
  3572.             {
  3573.                 Join join = m_Joins[i];
  3574.  
  3575.                 OutRec outRec1 = GetOutRec(join.OutPt1.Idx);
  3576.                 OutRec outRec2 = GetOutRec(join.OutPt2.Idx);
  3577.  
  3578.                 if (outRec1.Pts == null || outRec2.Pts == null) continue;
  3579.                 if (outRec1.IsOpen || outRec2.IsOpen) continue;
  3580.  
  3581.                 OutRec holeStateRec;
  3582.                 if (outRec1 == outRec2) holeStateRec = outRec1;
  3583.                 else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2;
  3584.                 else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1;
  3585.                 else holeStateRec = GetLowermostRec(outRec1, outRec2);
  3586.  
  3587.                 if (!JoinPoints(join, outRec1, outRec2)) continue;
  3588.  
  3589.                 if (outRec1 == outRec2)
  3590.                 {
  3591.                     outRec1.Pts = join.OutPt1;
  3592.                     outRec1.BottomPt = null;
  3593.                     outRec2 = CreateOutRec();
  3594.                     outRec2.Pts = join.OutPt2;
  3595.  
  3596.                     UpdateOutPtIdxs(outRec2);
  3597.  
  3598.                     if (Poly2ContainsPoly1(outRec2.Pts, outRec1.Pts))
  3599.                     {
  3600.                         outRec2.IsHole = !outRec1.IsHole;
  3601.                         outRec2.FirstLeft = outRec1;
  3602.  
  3603.                         if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
  3604.  
  3605.                         if ((outRec2.IsHole ^ ReverseSolution) == (Area(outRec2) > 0))
  3606.                             ReversePolyPtLinks(outRec2.Pts);
  3607.  
  3608.                     }
  3609.                     else if (Poly2ContainsPoly1(outRec1.Pts, outRec2.Pts))
  3610.                     {
  3611.                         outRec2.IsHole = outRec1.IsHole;
  3612.                         outRec1.IsHole = !outRec2.IsHole;
  3613.                         outRec2.FirstLeft = outRec1.FirstLeft;
  3614.                         outRec1.FirstLeft = outRec2;
  3615.  
  3616.                         if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
  3617.  
  3618.                         if ((outRec1.IsHole ^ ReverseSolution) == (Area(outRec1) > 0))
  3619.                             ReversePolyPtLinks(outRec1.Pts);
  3620.                     }
  3621.                     else
  3622.                     {
  3623.                         outRec2.IsHole = outRec1.IsHole;
  3624.                         outRec2.FirstLeft = outRec1.FirstLeft;
  3625.  
  3626.                         if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2);
  3627.                     }
  3628.  
  3629.                 }
  3630.                 else
  3631.                 {
  3632.  
  3633.                     outRec2.Pts = null;
  3634.                     outRec2.BottomPt = null;
  3635.                     outRec2.Idx = outRec1.Idx;
  3636.  
  3637.                     outRec1.IsHole = holeStateRec.IsHole;
  3638.                     if (holeStateRec == outRec2)
  3639.                         outRec1.FirstLeft = outRec2.FirstLeft;
  3640.                     outRec2.FirstLeft = outRec1;
  3641.  
  3642.                     if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1);
  3643.                 }
  3644.             }
  3645.         }
  3646.  
  3647.         private void UpdateOutPtIdxs(OutRec outrec)
  3648.         {
  3649.             OutPt op = outrec.Pts;
  3650.             do
  3651.             {
  3652.                 op.Idx = outrec.Idx;
  3653.                 op = op.Prev;
  3654.             }
  3655.             while (op != outrec.Pts);
  3656.         }
  3657.  
  3658.         private void DoSimplePolygons()
  3659.         {
  3660.             int i = 0;
  3661.             while (i < m_PolyOuts.Count)
  3662.             {
  3663.                 OutRec outrec = m_PolyOuts[i++];
  3664.                 OutPt op = outrec.Pts;
  3665.                 if (op == null || outrec.IsOpen) continue;
  3666.                 do
  3667.                 {
  3668.                     OutPt op2 = op.Next;
  3669.                     while (op2 != outrec.Pts)
  3670.                     {
  3671.                         if ((op.Pt == op2.Pt) && op2.Next != op && op2.Prev != op)
  3672.                         {
  3673.                             OutPt op3 = op.Prev;
  3674.                             OutPt op4 = op2.Prev;
  3675.                             op.Prev = op4;
  3676.                             op4.Next = op;
  3677.                             op2.Prev = op3;
  3678.                             op3.Next = op2;
  3679.  
  3680.                             outrec.Pts = op;
  3681.                             OutRec outrec2 = CreateOutRec();
  3682.                             outrec2.Pts = op2;
  3683.                             UpdateOutPtIdxs(outrec2);
  3684.                             if (Poly2ContainsPoly1(outrec2.Pts, outrec.Pts))
  3685.                             {
  3686.                                 outrec2.IsHole = !outrec.IsHole;
  3687.                                 outrec2.FirstLeft = outrec;
  3688.                                 if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
  3689.                             }
  3690.                             else
  3691.                               if (Poly2ContainsPoly1(outrec.Pts, outrec2.Pts))
  3692.                             {
  3693.                                 outrec2.IsHole = outrec.IsHole;
  3694.                                 outrec.IsHole = !outrec2.IsHole;
  3695.                                 outrec2.FirstLeft = outrec.FirstLeft;
  3696.                                 outrec.FirstLeft = outrec2;
  3697.                                 if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
  3698.                             }
  3699.                             else
  3700.                             {
  3701.                                 outrec2.IsHole = outrec.IsHole;
  3702.                                 outrec2.FirstLeft = outrec.FirstLeft;
  3703.                                 if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
  3704.                             }
  3705.                             op2 = op;
  3706.                         }
  3707.                         op2 = op2.Next;
  3708.                     }
  3709.                     op = op.Next;
  3710.                 }
  3711.                 while (op != outrec.Pts);
  3712.             }
  3713.         }
  3714.  
  3715.         public static double Area(Path poly)
  3716.         {
  3717.             int cnt = (int)poly.Count;
  3718.             if (cnt < 3) return 0;
  3719.             double a = 0;
  3720.             for (int i = 0, j = cnt - 1; i < cnt; ++i)
  3721.             {
  3722.                 a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y);
  3723.                 j = i;
  3724.             }
  3725.             return -a * 0.5;
  3726.         }
  3727.  
  3728.         internal double Area(OutRec outRec)
  3729.         {
  3730.             return Area(outRec.Pts);
  3731.         }
  3732.  
  3733.         internal double Area(OutPt op)
  3734.         {
  3735.             OutPt opFirst = op;
  3736.             if (op == null) return 0;
  3737.             double a = 0;
  3738.             do
  3739.             {
  3740.                 a = a + (double)(op.Prev.Pt.X + op.Pt.X) * (double)(op.Prev.Pt.Y - op.Pt.Y);
  3741.                 op = op.Next;
  3742.             } while (op != opFirst);
  3743.             return a * 0.5;
  3744.         }
  3745.  
  3746.  
  3747.         public static Paths SimplifyPolygon(Path poly,
  3748.               PolyFillType fillType = PolyFillType.pftEvenOdd)
  3749.         {
  3750.             Paths result = new Paths();
  3751.             Clipper c = new Clipper();
  3752.             c.StrictlySimple = true;
  3753.             c.AddPath(poly, PolyType.ptSubject, true);
  3754.             c.Execute(ClipType.ctUnion, result, fillType, fillType);
  3755.             return result;
  3756.         }
  3757.  
  3758.         public static Paths SimplifyPolygons(Paths polys,
  3759.             PolyFillType fillType = PolyFillType.pftEvenOdd)
  3760.         {
  3761.             Paths result = new Paths();
  3762.             Clipper c = new Clipper();
  3763.             c.StrictlySimple = true;
  3764.             c.AddPaths(polys, PolyType.ptSubject, true);
  3765.             c.Execute(ClipType.ctUnion, result, fillType, fillType);
  3766.             return result;
  3767.         }
  3768.  
  3769.         private static double DistanceSqrd(IntPoint pt1, IntPoint pt2)
  3770.         {
  3771.             double dx = ((double)pt1.X - pt2.X);
  3772.             double dy = ((double)pt1.Y - pt2.Y);
  3773.             return (dx * dx + dy * dy);
  3774.         }
  3775.  
  3776.         private static double DistanceFromLineSqrd(IntPoint pt, IntPoint ln1, IntPoint ln2)
  3777.         {
  3778.             double A = ln1.Y - ln2.Y;
  3779.             double B = ln2.X - ln1.X;
  3780.             double C = A * ln1.X + B * ln1.Y;
  3781.             C = A * pt.X + B * pt.Y - C;
  3782.             return (C * C) / (A * A + B * B);
  3783.         }
  3784.  
  3785.         private static bool SlopesNearCollinear(IntPoint pt1,
  3786.             IntPoint pt2, IntPoint pt3, double distSqrd)
  3787.         {
  3788.             if (Math.Abs(pt1.X - pt2.X) > Math.Abs(pt1.Y - pt2.Y))
  3789.             {
  3790.                 if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
  3791.                     return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
  3792.                 else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
  3793.                     return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
  3794.                 else
  3795.                     return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
  3796.             }
  3797.             else
  3798.             {
  3799.                 if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
  3800.                     return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
  3801.                 else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
  3802.                     return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
  3803.                 else
  3804.                     return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
  3805.             }
  3806.         }
  3807.  
  3808.         private static bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
  3809.         {
  3810.             double dx = (double)pt1.X - pt2.X;
  3811.             double dy = (double)pt1.Y - pt2.Y;
  3812.             return ((dx * dx) + (dy * dy) <= distSqrd);
  3813.         }
  3814.  
  3815.         private static OutPt ExcludeOp(OutPt op)
  3816.         {
  3817.             OutPt result = op.Prev;
  3818.             result.Next = op.Next;
  3819.             op.Next.Prev = result;
  3820.             result.Idx = 0;
  3821.             return result;
  3822.         }
  3823.  
  3824.         public static Path CleanPolygon(Path path, double distance = 1.415)
  3825.         {
  3826.  
  3827.             int cnt = path.Count;
  3828.  
  3829.             if (cnt == 0) return new Path();
  3830.  
  3831.             OutPt[] outPts = new OutPt[cnt];
  3832.             for (int i = 0; i < cnt; ++i) outPts[i] = new OutPt();
  3833.  
  3834.             for (int i = 0; i < cnt; ++i)
  3835.             {
  3836.                 outPts[i].Pt = path[i];
  3837.                 outPts[i].Next = outPts[(i + 1) % cnt];
  3838.                 outPts[i].Next.Prev = outPts[i];
  3839.                 outPts[i].Idx = 0;
  3840.             }
  3841.  
  3842.             double distSqrd = distance * distance;
  3843.             OutPt op = outPts[0];
  3844.             while (op.Idx == 0 && op.Next != op.Prev)
  3845.             {
  3846.                 if (PointsAreClose(op.Pt, op.Prev.Pt, distSqrd))
  3847.                 {
  3848.                     op = ExcludeOp(op);
  3849.                     cnt--;
  3850.                 }
  3851.                 else if (PointsAreClose(op.Prev.Pt, op.Next.Pt, distSqrd))
  3852.                 {
  3853.                     ExcludeOp(op.Next);
  3854.                     op = ExcludeOp(op);
  3855.                     cnt -= 2;
  3856.                 }
  3857.                 else if (SlopesNearCollinear(op.Prev.Pt, op.Pt, op.Next.Pt, distSqrd))
  3858.                 {
  3859.                     op = ExcludeOp(op);
  3860.                     cnt--;
  3861.                 }
  3862.                 else
  3863.                 {
  3864.                     op.Idx = 1;
  3865.                     op = op.Next;
  3866.                 }
  3867.             }
  3868.  
  3869.             if (cnt < 3) cnt = 0;
  3870.             Path result = new Path(cnt);
  3871.             for (int i = 0; i < cnt; ++i)
  3872.             {
  3873.                 result.Add(op.Pt);
  3874.                 op = op.Next;
  3875.             }
  3876.             outPts = null;
  3877.             return result;
  3878.         }
  3879.  
  3880.         public static Paths CleanPolygons(Paths polys,
  3881.             double distance = 1.415)
  3882.         {
  3883.             Paths result = new Paths(polys.Count);
  3884.             for (int i = 0; i < polys.Count; i++)
  3885.                 result.Add(CleanPolygon(polys[i], distance));
  3886.             return result;
  3887.         }
  3888.  
  3889.         internal static Paths Minkowski(Path pattern, Path path, bool IsSum, bool IsClosed)
  3890.         {
  3891.             int delta = (IsClosed ? 1 : 0);
  3892.             int polyCnt = pattern.Count;
  3893.             int pathCnt = path.Count;
  3894.             Paths result = new Paths(pathCnt);
  3895.             if (IsSum)
  3896.                 for (int i = 0; i < pathCnt; i++)
  3897.                 {
  3898.                     Path p = new Path(polyCnt);
  3899.                     foreach (IntPoint ip in pattern)
  3900.                         p.Add(new IntPoint(path[i].X + ip.X, path[i].Y + ip.Y));
  3901.                     result.Add(p);
  3902.                 }
  3903.             else
  3904.                 for (int i = 0; i < pathCnt; i++)
  3905.                 {
  3906.                     Path p = new Path(polyCnt);
  3907.                     foreach (IntPoint ip in pattern)
  3908.                         p.Add(new IntPoint(path[i].X - ip.X, path[i].Y - ip.Y));
  3909.                     result.Add(p);
  3910.                 }
  3911.  
  3912.             Paths quads = new Paths((pathCnt + delta) * (polyCnt + 1));
  3913.             for (int i = 0; i < pathCnt - 1 + delta; i++)
  3914.                 for (int j = 0; j < polyCnt; j++)
  3915.                 {
  3916.                     Path quad = new Path(4);
  3917.                     quad.Add(result[i % pathCnt][j % polyCnt]);
  3918.                     quad.Add(result[(i + 1) % pathCnt][j % polyCnt]);
  3919.                     quad.Add(result[(i + 1) % pathCnt][(j + 1) % polyCnt]);
  3920.                     quad.Add(result[i % pathCnt][(j + 1) % polyCnt]);
  3921.                     if (!Orientation(quad)) quad.Reverse();
  3922.                     quads.Add(quad);
  3923.                 }
  3924.             return quads;
  3925.         }
  3926.  
  3927.         public static Paths MinkowskiSum(Path pattern, Path path, bool pathIsClosed)
  3928.         {
  3929.             Paths paths = Minkowski(pattern, path, true, pathIsClosed);
  3930.             Clipper c = new Clipper();
  3931.             c.AddPaths(paths, PolyType.ptSubject, true);
  3932.             c.Execute(ClipType.ctUnion, paths, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
  3933.             return paths;
  3934.         }
  3935.  
  3936.         private static Path TranslatePath(Path path, IntPoint delta)
  3937.         {
  3938.             Path outPath = new Path(path.Count);
  3939.             for (int i = 0; i < path.Count; i++)
  3940.                 outPath.Add(new IntPoint(path[i].X + delta.X, path[i].Y + delta.Y));
  3941.             return outPath;
  3942.         }
  3943.  
  3944.         public static Paths MinkowskiSum(Path pattern, Paths paths, bool pathIsClosed)
  3945.         {
  3946.             Paths solution = new Paths();
  3947.             Clipper c = new Clipper();
  3948.             for (int i = 0; i < paths.Count; ++i)
  3949.             {
  3950.                 Paths tmp = Minkowski(pattern, paths[i], true, pathIsClosed);
  3951.                 c.AddPaths(tmp, PolyType.ptSubject, true);
  3952.                 if (pathIsClosed)
  3953.                 {
  3954.                     Path path = TranslatePath(paths[i], pattern[0]);
  3955.                     c.AddPath(path, PolyType.ptClip, true);
  3956.                 }
  3957.             }
  3958.             c.Execute(ClipType.ctUnion, solution,
  3959.               PolyFillType.pftNonZero, PolyFillType.pftNonZero);
  3960.             return solution;
  3961.         }
  3962.  
  3963.         public static Paths MinkowskiDiff(Path poly1, Path poly2)
  3964.         {
  3965.             Paths paths = Minkowski(poly1, poly2, false, true);
  3966.             Clipper c = new Clipper();
  3967.             c.AddPaths(paths, PolyType.ptSubject, true);
  3968.             c.Execute(ClipType.ctUnion, paths, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
  3969.             return paths;
  3970.         }
  3971.  
  3972.         internal enum NodeType { ntAny, ntOpen, ntClosed };
  3973.  
  3974.         public static Paths PolyTreeToPaths(PolyTree polytree)
  3975.         {
  3976.  
  3977.             Paths result = new Paths();
  3978.             result.Capacity = polytree.Total;
  3979.             AddPolyNodeToPaths(polytree, NodeType.ntAny, result);
  3980.             return result;
  3981.         }
  3982.  
  3983.         internal static void AddPolyNodeToPaths(PolyNode polynode, NodeType nt, Paths paths)
  3984.         {
  3985.             bool match = true;
  3986.             switch (nt)
  3987.             {
  3988.                 case NodeType.ntOpen: return;
  3989.                 case NodeType.ntClosed: match = !polynode.IsOpen; break;
  3990.                 default: break;
  3991.             }
  3992.  
  3993.             if (polynode.m_polygon.Count > 0 && match)
  3994.                 paths.Add(polynode.m_polygon);
  3995.             foreach (PolyNode pn in polynode.Childs)
  3996.                 AddPolyNodeToPaths(pn, nt, paths);
  3997.         }
  3998.  
  3999.         public static Paths OpenPathsFromPolyTree(PolyTree polytree)
  4000.         {
  4001.             Paths result = new Paths();
  4002.             result.Capacity = polytree.ChildCount;
  4003.             for (int i = 0; i < polytree.ChildCount; i++)
  4004.                 if (polytree.Childs[i].IsOpen)
  4005.                     result.Add(polytree.Childs[i].m_polygon);
  4006.             return result;
  4007.         }
  4008.  
  4009.         public static Paths ClosedPathsFromPolyTree(PolyTree polytree)
  4010.         {
  4011.             Paths result = new Paths();
  4012.             result.Capacity = polytree.Total;
  4013.             AddPolyNodeToPaths(polytree, NodeType.ntClosed, result);
  4014.             return result;
  4015.         }
  4016.  
  4017.     }
  4018.     public class ClipperOffset
  4019.     {
  4020.         private Paths m_destPolys;
  4021.         private Path m_srcPoly;
  4022.         private Path m_destPoly;
  4023.         private List<DoublePoint> m_normals = new List<DoublePoint>();
  4024.         private double m_delta, m_sinA, m_sin, m_cos;
  4025.         private double m_miterLim, m_StepsPerRad;
  4026.  
  4027.         private IntPoint m_lowest;
  4028.         private PolyNode m_polyNodes = new PolyNode();
  4029.  
  4030.         public double ArcTolerance { get; set; }
  4031.         public double MiterLimit { get; set; }
  4032.  
  4033.         private const double two_pi = Math.PI * 2;
  4034.         private const double def_arc_tolerance = 0.25;
  4035.  
  4036.         public ClipperOffset(
  4037.           double miterLimit = 2.0, double arcTolerance = def_arc_tolerance)
  4038.         {
  4039.             MiterLimit = miterLimit;
  4040.             ArcTolerance = arcTolerance;
  4041.             m_lowest.X = -1;
  4042.         }
  4043.  
  4044.         public void Clear()
  4045.         {
  4046.             m_polyNodes.Childs.Clear();
  4047.             m_lowest.X = -1;
  4048.         }
  4049.  
  4050.         internal static cInt Round(double value)
  4051.         {
  4052.             return value < 0 ? (cInt)(value - 0.5) : (cInt)(value + 0.5);
  4053.         }
  4054.  
  4055.         public void AddPath(Path path, JoinType joinType, EndType endType)
  4056.         {
  4057.             int highI = path.Count - 1;
  4058.             if (highI < 0) return;
  4059.             PolyNode newNode = new PolyNode();
  4060.             newNode.m_jointype = joinType;
  4061.             newNode.m_endtype = endType;
  4062.  
  4063.             if (endType == EndType.etClosedLine || endType == EndType.etClosedPolygon)
  4064.                 while (highI > 0 && path[0] == path[highI]) highI--;
  4065.             newNode.m_polygon.Capacity = highI + 1;
  4066.             newNode.m_polygon.Add(path[0]);
  4067.             int j = 0, k = 0;
  4068.             for (int i = 1; i <= highI; i++)
  4069.                 if (newNode.m_polygon[j] != path[i])
  4070.                 {
  4071.                     j++;
  4072.                     newNode.m_polygon.Add(path[i]);
  4073.                     if (path[i].Y > newNode.m_polygon[k].Y ||
  4074.                       (path[i].Y == newNode.m_polygon[k].Y &&
  4075.                       path[i].X < newNode.m_polygon[k].X)) k = j;
  4076.                 }
  4077.             if (endType == EndType.etClosedPolygon && j < 2) return;
  4078.  
  4079.             m_polyNodes.AddChild(newNode);
  4080.  
  4081.             if (endType != EndType.etClosedPolygon) return;
  4082.             if (m_lowest.X < 0)
  4083.                 m_lowest = new IntPoint(m_polyNodes.ChildCount - 1, k);
  4084.             else
  4085.             {
  4086.                 IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X].m_polygon[(int)m_lowest.Y];
  4087.                 if (newNode.m_polygon[k].Y > ip.Y ||
  4088.                   (newNode.m_polygon[k].Y == ip.Y &&
  4089.                   newNode.m_polygon[k].X < ip.X))
  4090.                     m_lowest = new IntPoint(m_polyNodes.ChildCount - 1, k);
  4091.             }
  4092.         }
  4093.  
  4094.         public void AddPaths(Paths paths, JoinType joinType, EndType endType)
  4095.         {
  4096.             foreach (Path p in paths)
  4097.                 AddPath(p, joinType, endType);
  4098.         }
  4099.  
  4100.         private void FixOrientations()
  4101.         {
  4102.             if (m_lowest.X >= 0 &&
  4103. !Clipper.Orientation(m_polyNodes.Childs[(int)m_lowest.X].m_polygon))
  4104.             {
  4105.                 for (int i = 0; i < m_polyNodes.ChildCount; i++)
  4106.                 {
  4107.                     PolyNode node = m_polyNodes.Childs[i];
  4108.                     if (node.m_endtype == EndType.etClosedPolygon ||
  4109.                       (node.m_endtype == EndType.etClosedLine &&
  4110.                       Clipper.Orientation(node.m_polygon)))
  4111.                         node.m_polygon.Reverse();
  4112.                 }
  4113.             }
  4114.             else
  4115.             {
  4116.                 for (int i = 0; i < m_polyNodes.ChildCount; i++)
  4117.                 {
  4118.                     PolyNode node = m_polyNodes.Childs[i];
  4119.                     if (node.m_endtype == EndType.etClosedLine &&
  4120.                       !Clipper.Orientation(node.m_polygon))
  4121.                         node.m_polygon.Reverse();
  4122.                 }
  4123.             }
  4124.         }
  4125.  
  4126.         internal static DoublePoint GetUnitNormal(IntPoint pt1, IntPoint pt2)
  4127.         {
  4128.             double dx = (pt2.X - pt1.X);
  4129.             double dy = (pt2.Y - pt1.Y);
  4130.             if ((dx == 0) && (dy == 0)) return new DoublePoint();
  4131.  
  4132.             double f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy);
  4133.             dx *= f;
  4134.             dy *= f;
  4135.  
  4136.             return new DoublePoint(dy, -dx);
  4137.         }
  4138.  
  4139.         private void DoOffset(double delta)
  4140.         {
  4141.             m_destPolys = new Paths();
  4142.             m_delta = delta;
  4143.  
  4144.             if (ClipperBase.near_zero(delta))
  4145.             {
  4146.                 m_destPolys.Capacity = m_polyNodes.ChildCount;
  4147.                 for (int i = 0; i < m_polyNodes.ChildCount; i++)
  4148.                 {
  4149.                     PolyNode node = m_polyNodes.Childs[i];
  4150.                     if (node.m_endtype == EndType.etClosedPolygon)
  4151.                         m_destPolys.Add(node.m_polygon);
  4152.                 }
  4153.                 return;
  4154.             }
  4155.  
  4156.             if (MiterLimit > 2) m_miterLim = 2 / (MiterLimit * MiterLimit);
  4157.             else m_miterLim = 0.5;
  4158.  
  4159.             double y;
  4160.             if (ArcTolerance <= 0.0)
  4161.                 y = def_arc_tolerance;
  4162.             else if (ArcTolerance > Math.Abs(delta) * def_arc_tolerance)
  4163.                 y = Math.Abs(delta) * def_arc_tolerance;
  4164.             else
  4165.                 y = ArcTolerance;
  4166.             double steps = Math.PI / Math.Acos(1 - y / Math.Abs(delta));
  4167.             m_sin = Math.Sin(two_pi / steps);
  4168.             m_cos = Math.Cos(two_pi / steps);
  4169.             m_StepsPerRad = steps / two_pi;
  4170.             if (delta < 0.0) m_sin = -m_sin;
  4171.  
  4172.             m_destPolys.Capacity = m_polyNodes.ChildCount * 2;
  4173.             for (int i = 0; i < m_polyNodes.ChildCount; i++)
  4174.             {
  4175.                 PolyNode node = m_polyNodes.Childs[i];
  4176.                 m_srcPoly = node.m_polygon;
  4177.  
  4178.                 int len = m_srcPoly.Count;
  4179.  
  4180.                 if (len == 0 || (delta <= 0 && (len < 3 ||
  4181.                   node.m_endtype != EndType.etClosedPolygon)))
  4182.                     continue;
  4183.  
  4184.                 m_destPoly = new Path();
  4185.  
  4186.                 if (len == 1)
  4187.                 {
  4188.                     if (node.m_jointype == JoinType.jtRound)
  4189.                     {
  4190.                         double X = 1.0, Y = 0.0;
  4191.                         for (int j = 1; j <= steps; j++)
  4192.                         {
  4193.                             m_destPoly.Add(new IntPoint(
  4194.                               Round(m_srcPoly[0].X + X * delta),
  4195.                               Round(m_srcPoly[0].Y + Y * delta)));
  4196.                             double X2 = X;
  4197.                             X = X * m_cos - m_sin * Y;
  4198.                             Y = X2 * m_sin + Y * m_cos;
  4199.                         }
  4200.                     }
  4201.                     else
  4202.                     {
  4203.                         double X = -1.0, Y = -1.0;
  4204.                         for (int j = 0; j < 4; ++j)
  4205.                         {
  4206.                             m_destPoly.Add(new IntPoint(
  4207.                               Round(m_srcPoly[0].X + X * delta),
  4208.                               Round(m_srcPoly[0].Y + Y * delta)));
  4209.                             if (X < 0) X = 1;
  4210.                             else if (Y < 0) Y = 1;
  4211.                             else X = -1;
  4212.                         }
  4213.                     }
  4214.                     m_destPolys.Add(m_destPoly);
  4215.                     continue;
  4216.                 }
  4217.  
  4218.                 m_normals.Clear();
  4219.                 m_normals.Capacity = len;
  4220.                 for (int j = 0; j < len - 1; j++)
  4221.                     m_normals.Add(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1]));
  4222.                 if (node.m_endtype == EndType.etClosedLine ||
  4223.                   node.m_endtype == EndType.etClosedPolygon)
  4224.                     m_normals.Add(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0]));
  4225.                 else
  4226.                     m_normals.Add(new DoublePoint(m_normals[len - 2]));
  4227.  
  4228.                 if (node.m_endtype == EndType.etClosedPolygon)
  4229.                 {
  4230.                     int k = len - 1;
  4231.                     for (int j = 0; j < len; j++)
  4232.                         OffsetPoint(j, ref k, node.m_jointype);
  4233.                     m_destPolys.Add(m_destPoly);
  4234.                 }
  4235.                 else if (node.m_endtype == EndType.etClosedLine)
  4236.                 {
  4237.                     int k = len - 1;
  4238.                     for (int j = 0; j < len; j++)
  4239.                         OffsetPoint(j, ref k, node.m_jointype);
  4240.                     m_destPolys.Add(m_destPoly);
  4241.                     m_destPoly = new Path();
  4242.                     DoublePoint n = m_normals[len - 1];
  4243.                     for (int j = len - 1; j > 0; j--)
  4244.                         m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
  4245.                     m_normals[0] = new DoublePoint(-n.X, -n.Y);
  4246.                     k = 0;
  4247.                     for (int j = len - 1; j >= 0; j--)
  4248.                         OffsetPoint(j, ref k, node.m_jointype);
  4249.                     m_destPolys.Add(m_destPoly);
  4250.                 }
  4251.                 else
  4252.                 {
  4253.                     int k = 0;
  4254.                     for (int j = 1; j < len - 1; ++j)
  4255.                         OffsetPoint(j, ref k, node.m_jointype);
  4256.  
  4257.                     IntPoint pt1;
  4258.                     if (node.m_endtype == EndType.etOpenButt)
  4259.                     {
  4260.                         int j = len - 1;
  4261.                         pt1 = new IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X *
  4262.                           delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
  4263.                         m_destPoly.Add(pt1);
  4264.                         pt1 = new IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X *
  4265.                           delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
  4266.                         m_destPoly.Add(pt1);
  4267.                     }
  4268.                     else
  4269.                     {
  4270.                         int j = len - 1;
  4271.                         k = len - 2;
  4272.                         m_sinA = 0;
  4273.                         m_normals[j] = new DoublePoint(-m_normals[j].X, -m_normals[j].Y);
  4274.                         if (node.m_endtype == EndType.etOpenSquare)
  4275.                             DoSquare(j, k);
  4276.                         else
  4277.                             DoRound(j, k);
  4278.                     }
  4279.  
  4280.                     for (int j = len - 1; j > 0; j--)
  4281.                         m_normals[j] = new DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
  4282.  
  4283.                     m_normals[0] = new DoublePoint(-m_normals[1].X, -m_normals[1].Y);
  4284.  
  4285.                     k = len - 1;
  4286.                     for (int j = k - 1; j > 0; --j)
  4287.                         OffsetPoint(j, ref k, node.m_jointype);
  4288.  
  4289.                     if (node.m_endtype == EndType.etOpenButt)
  4290.                     {
  4291.                         pt1 = new IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta),
  4292.                           (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
  4293.                         m_destPoly.Add(pt1);
  4294.                         pt1 = new IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta),
  4295.                           (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
  4296.                         m_destPoly.Add(pt1);
  4297.                     }
  4298.                     else
  4299.                     {
  4300.                         k = 1;
  4301.                         m_sinA = 0;
  4302.                         if (node.m_endtype == EndType.etOpenSquare)
  4303.                             DoSquare(0, 1);
  4304.                         else
  4305.                             DoRound(0, 1);
  4306.                     }
  4307.                     m_destPolys.Add(m_destPoly);
  4308.                 }
  4309.             }
  4310.         }
  4311.  
  4312.         public void Execute(ref Paths solution, double delta)
  4313.         {
  4314.             solution.Clear();
  4315.             FixOrientations();
  4316.             DoOffset(delta);
  4317.             Clipper clpr = new Clipper();
  4318.             clpr.AddPaths(m_destPolys, PolyType.ptSubject, true);
  4319.             if (delta > 0)
  4320.             {
  4321.                 clpr.Execute(ClipType.ctUnion, solution,
  4322.                   PolyFillType.pftPositive, PolyFillType.pftPositive);
  4323.             }
  4324.             else
  4325.             {
  4326.                 IntRect r = ClipperBase.GetBounds(m_destPolys);
  4327.                 Path outer = new Path(4);
  4328.  
  4329.                 outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
  4330.                 outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
  4331.                 outer.Add(new IntPoint(r.right + 10, r.top - 10));
  4332.                 outer.Add(new IntPoint(r.left - 10, r.top - 10));
  4333.  
  4334.                 clpr.AddPath(outer, PolyType.ptSubject, true);
  4335.                 clpr.ReverseSolution = true;
  4336.                 clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
  4337.                 if (solution.Count > 0) solution.RemoveAt(0);
  4338.             }
  4339.         }
  4340.  
  4341.         public void Execute(ref PolyTree solution, double delta)
  4342.         {
  4343.             solution.Clear();
  4344.             FixOrientations();
  4345.             DoOffset(delta);
  4346.  
  4347.             Clipper clpr = new Clipper();
  4348.             clpr.AddPaths(m_destPolys, PolyType.ptSubject, true);
  4349.             if (delta > 0)
  4350.             {
  4351.                 clpr.Execute(ClipType.ctUnion, solution,
  4352.                   PolyFillType.pftPositive, PolyFillType.pftPositive);
  4353.             }
  4354.             else
  4355.             {
  4356.                 IntRect r = ClipperBase.GetBounds(m_destPolys);
  4357.                 Path outer = new Path(4);
  4358.  
  4359.                 outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
  4360.                 outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
  4361.                 outer.Add(new IntPoint(r.right + 10, r.top - 10));
  4362.                 outer.Add(new IntPoint(r.left - 10, r.top - 10));
  4363.  
  4364.                 clpr.AddPath(outer, PolyType.ptSubject, true);
  4365.                 clpr.ReverseSolution = true;
  4366.                 clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
  4367.                 if (solution.ChildCount == 1 && solution.Childs[0].ChildCount > 0)
  4368.                 {
  4369.                     PolyNode outerNode = solution.Childs[0];
  4370.                     solution.Childs.Capacity = outerNode.ChildCount;
  4371.                     solution.Childs[0] = outerNode.Childs[0];
  4372.                     solution.Childs[0].m_Parent = solution;
  4373.                     for (int i = 1; i < outerNode.ChildCount; i++)
  4374.                         solution.AddChild(outerNode.Childs[i]);
  4375.                 }
  4376.                 else
  4377.                     solution.Clear();
  4378.             }
  4379.         }
  4380.  
  4381.         void OffsetPoint(int j, ref int k, JoinType jointype)
  4382.         {
  4383.             m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
  4384.  
  4385.             if (Math.Abs(m_sinA * m_delta) < 1.0)
  4386.             {
  4387.                 double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y);
  4388.                 if (cosA > 0)
  4389.                 {
  4390.                     m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
  4391.                       Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
  4392.                     return;
  4393.                 }
  4394.             }
  4395.             else if (m_sinA > 1.0) m_sinA = 1.0;
  4396.             else if (m_sinA < -1.0) m_sinA = -1.0;
  4397.  
  4398.             if (m_sinA * m_delta < 0)
  4399.             {
  4400.                 m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
  4401.                   Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
  4402.                 m_destPoly.Add(m_srcPoly[j]);
  4403.                 m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
  4404.                   Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
  4405.             }
  4406.             else
  4407.                 switch (jointype)
  4408.                 {
  4409.                     case JoinType.jtMiter:
  4410.                         {
  4411.                             double r = 1 + (m_normals[j].X * m_normals[k].X +
  4412.                               m_normals[j].Y * m_normals[k].Y);
  4413.                             if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k);
  4414.                             break;
  4415.                         }
  4416.                     case JoinType.jtSquare: DoSquare(j, k); break;
  4417.                     case JoinType.jtRound: DoRound(j, k); break;
  4418.                 }
  4419.             k = j;
  4420.         }
  4421.  
  4422.         internal void DoSquare(int j, int k)
  4423.         {
  4424.             double dx = Math.Tan(Math.Atan2(m_sinA,
  4425.                 m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4);
  4426.             m_destPoly.Add(new IntPoint(
  4427.                 Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)),
  4428.                 Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx))));
  4429.             m_destPoly.Add(new IntPoint(
  4430.                 Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)),
  4431.                 Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx))));
  4432.         }
  4433.  
  4434.         internal void DoMiter(int j, int k, double r)
  4435.         {
  4436.             double q = m_delta / r;
  4437.             m_destPoly.Add(new IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q),
  4438.                 Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q)));
  4439.         }
  4440.  
  4441.         internal void DoRound(int j, int k)
  4442.         {
  4443.             double a = Math.Atan2(m_sinA,
  4444.             m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
  4445.             int steps = Math.Max((int)Round(m_StepsPerRad * Math.Abs(a)), 1);
  4446.  
  4447.             double X = m_normals[k].X, Y = m_normals[k].Y, X2;
  4448.             for (int i = 0; i < steps; ++i)
  4449.             {
  4450.                 m_destPoly.Add(new IntPoint(
  4451.                     Round(m_srcPoly[j].X + X * m_delta),
  4452.                     Round(m_srcPoly[j].Y + Y * m_delta)));
  4453.                 X2 = X;
  4454.                 X = X * m_cos - m_sin * Y;
  4455.                 Y = X2 * m_sin + Y * m_cos;
  4456.             }
  4457.             m_destPoly.Add(new IntPoint(
  4458.             Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
  4459.             Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
  4460.         }
  4461.     }
  4462.  
  4463.     public class CyrusBeck
  4464.     {
  4465.         public static IEnumerable<PointF[]> Calculate(PointF[] subjectPoly, PointF[] clipPoly, bool inside)
  4466.         {
  4467.             var clipper = new Clipper();
  4468.             var result = new List<List<IntPoint>>();
  4469.             var subject = new List<List<IntPoint>>
  4470.             {
  4471.                 subjectPoly.Select(x => new IntPoint((int)x.X, (int)x.Y)).ToList()
  4472.             };
  4473.  
  4474.             var clip = new List<List<IntPoint>>
  4475.             {
  4476.                 clipPoly.Select(x => new IntPoint((int)x.X, (int)x.Y)).ToList()
  4477.             };
  4478.  
  4479.             clipper.AddPaths(subject, PolyType.ptSubject, true);
  4480.             clipper.AddPaths(clip, PolyType.ptClip, true);
  4481.  
  4482.             var type = inside ? ClipType.ctIntersection : ClipType.ctDifference;
  4483.  
  4484.             clipper.Execute(type, result, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);
  4485.  
  4486.             foreach (var res in result)
  4487.             {
  4488.                 yield return res.Select(x => new PointF((int)x.X, (int)x.Y)).ToArray();
  4489.             }
  4490.         }
  4491.     }
  4492.  
  4493.     class ClipperException : Exception
  4494.     {
  4495.         public ClipperException(string description) : base(description) { }
  4496.     }
  4497.  
  4498. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement