Commits

Lars Brubaker committed b3bac66

Adding the cilpper library to agg-sharp
Put an error range onto the check for pathstorage unit test
started work on vertexsourceadapter using iterators.
The font tests pass now
Made flood fill run as an exe
made some code work with fixed spelling of checkboxviewstates

Comments (0)

Files changed (14)

AggTests/AggDrawingTests.cs

             stringPrintere.TypeFaceStyle.FlatenCurves = true;
             CheckTestAgainstControl(stringPrintere, "ShapeStringeFlattened");
 
-            return;
             TypeFacePrinter stringPrinterAe = new TypeFacePrinter("Ae");
             stringPrinterAe.TypeFaceStyle.FlatenCurves = false;
             CheckTestAgainstControl(stringPrinterAe, "ShapeStringAeNotFlattened");
             stringPrinterAe.TypeFaceStyle.FlatenCurves = true;
             CheckTestAgainstControl(stringPrinterAe, "ShapeStringAeFlattened");
 
-            return;
             TypeFacePrinter stringPrinterTest = new TypeFacePrinter("Test");
             stringPrinterTest.TypeFaceStyle.FlatenCurves = false;
             CheckTestAgainstControl(stringPrinterTest, "ShapeStringTestNotFlattened");
             testImage.NewGraphics2D().Render(rectOutline, RGBA_Bytes.White);
 
             CheckTestAgainstControl(testImage, "DrawStroked");
-            //CheckTestAgainstControl(rectOutline, "ShapeStroked");
+            CheckTestAgainstControl(rectOutline, "ShapeStroked");
         }
     }
 }

agg/VertexSource/PathStorage.cs

             ShapePath.FlagsAndCommand otherFlagsAndCommand = test.vertex(out testX, out testY);
 
             int index = 1;
-            if (controlFlagsAndCommand == otherFlagsAndCommand && controlX == testX && controlY == testY)
+            if (controlFlagsAndCommand == otherFlagsAndCommand && controlX == testX && agg_basics.is_equal_eps(controlY, testY, .000000001))
             {
                 while (controlFlagsAndCommand != ShapePath.FlagsAndCommand.CommandStop)
                 {

agg/VertexSource/VertexSourceAdapter.cs

 using System;
 using System.Collections.Generic;
 
+using MatterHackers.VectorMath;
+
 namespace MatterHackers.Agg.VertexSource
 {
     //------------------------------------------------------------null_markers
 
         public IEnumerable<VertexData> VertexIterator()
         {
-            throw new NotImplementedException();
+            markers.remove_all();
+            generator.RemoveAll();
+
+            foreach(VertexData vertexData in VertexSource.VertexIterator())
+            {
+                generator.AddVertex(vertexData.position.x, vertexData.position.y, ShapePath.FlagsAndCommand.CommandMoveTo);
+                markers.AddVertex(vertexData.position.x, vertexData.position.y, ShapePath.FlagsAndCommand.CommandMoveTo);
+            }
         }
 
         public void rewind(int path_id)

clipper_library/License.txt

+The Clipper Library (including Delphi, C++ & C# source code, other accompanying
+code, examples and documentation), hereafter called "the Software", has been 
+released under the following license, terms and conditions:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+http://www.boost.org/LICENSE_1_0.txt
+
+Permission is hereby granted, free of charge, to any person or organization 
+obtaining a copy of the Software covered by this license to use, reproduce, 
+display, distribute, execute, and transmit the Software, and to prepare 
+derivative works of the Software, and to permit third-parties to whom the 
+Software is furnished to do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including the 
+above license grant, this restriction and the following disclaimer, must be 
+included in all copies of the Software, in whole or in part, and all derivative 
+works of the Software, unless such copies or derivative works are solely in the 
+form of machine-executable object code generated by a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL 
+THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY 
+DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
+THE SOFTWARE.

clipper_library/Properties/AssemblyInfo.cs

+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("clipper_library")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("clipper_library")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("51a6bdca-bc4e-4b2c-ae69-36e2497204f2")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

clipper_library/README

+============================================================
+Clipper Change Log
+============================================================
+
+v5.1.6 (23 May 2014)
+* BugFix: CleanPolygon function was buggy.
+* Changed: The behaviour of the 'miter' JoinType has been 
+  changed so that when squaring occurs, it's no longer 
+  extended up to the miter limit but is squared off at 
+  exactly 'delta' units. (This improves the look of mitering 
+  with larger limits at acute angles.) 
+* Added: New OffsetPolyLines function
+* Update: Minor code refactoring and optimisations
+
+v5.1.5 (5 May 2014)
+* Added: ForceSimple property to Clipper class
+* Update: Improved documentation  
+
+v5.1.4 (24 March 2013)
+* Update: CleanPolygon function enhanced.
+* Update: Documentation improved.  
+
+v5.1.3 (14 March 2013)
+* Bugfix: Minor bugfixes.
+* Update: Documentation significantly improved.  
+
+v5.1.2 (26 February 2013)
+* Bugfix: PolyNode class was missing a constructor. 
+* Update: The MiterLimit parameter in the OffsetPolygons 
+  function has been renamed Limit and can now also be used to 
+  limit the number of vertices used to construct arcs when 
+  JoinType is set to jtRound.
+
+v5.1.0 (17 February 2013)
+* Update: ExPolygons has been replaced with the PolyTree & 
+  PolyNode classes to more fully represent the parent-child 
+  relationships of the polygons returned by Clipper. 
+* Added: New CleanPolygon and CleanPolygons functions. 
+* Bugfix: Another orientation bug fixed.
+
+v5.0.2 - 30 December 2012
+* Bugfix: Significant fixes in and tidy of the internal 
+  Int128 class (which is used only when polygon coordinate 
+  values are greater than �0x3FFFFFFF (~1.07e9)). 
+* Update: The Area algorithm has been updated and is faster. 
+* Update: Documentation updates. The newish but undocumented 
+  'CheckInputs' parameter of the OffsetPolygons function has been 
+  renamed 'AutoFix' and documented too. The comments on rounding 
+  have also been improved (ie clearer and expanded).
+
+v4.10.0 - 25 December 2012
+* Bugfix: Orientation bugs should now be resolved (finally!).
+* Bugfix: Bug in Int128 class
+
+v4.9.8 - 2 December 2012
+* Bugfix: Further fixes to rare Orientation bug.
+
+v4.9.7 - 29 November 2012
+* Bugfix: Bug that very rarely returned the wrong polygon 
+  orientation.
+* Bugfix: Obscure bug affecting OffsetPolygons when using 
+  jtRound for the JoinType parameter and when polygons also
+  contain very large coordinate values (> +/-100000000000).
+
+v4.9.6 - 9 November 2012
+* Bugfix: Another obscure bug related to joining polygons.
+
+v4.9.4 - 2 November 2012
+* Bugfix: Bugs in Int128 class occasionally causing 
+  wrong orientations.
+* Bugfix: Further fixes related to joining polygons.
+
+v4.9.0 - 9 October 2012
+* Bugfix: Obscure bug related to joining polygons.
+
+v4.8.9 - 25 September 2012
+* Bugfix: Obscure bug related to precision of intersections.
+          
+v4.8.8 - 30 August 2012
+* Bugfix: Fixed bug in OffsetPolygons function introduced in 
+  version 4.8.5.
+
+v4.8.7 - 24 August 2012
+* Bugfix: ReversePolygon function in C++ translation was broken.
+* Bugfix: Two obscure bugs affecting orientation fixed too.
+
+v4.8.6 - 11 August 2012
+* Bugfix: Potential for memory overflow errors when using 
+  ExPolygons structure.
+* Bugfix: The polygon coordinate range has been reduced to 
+  +/- 0x3FFFFFFFFFFFFFFF (4.6e18).
+* Update: ReversePolygons function was misnamed ReversePoints in C++.
+* Update: SimplifyPolygon function now takes a PolyFillType parameter.
+          
+v4.8.5 - 15 July 2012
+* Bugfix: Potential for memory overflow errors in OffsetPolygons().
+
+v4.8.4 - 1 June 2012
+* Bugfix: Another obscure bug affecting ExPolygons structure.
+
+v4.8.3 - 27 May 2012
+* Bugfix: Obscure bug causing incorrect removal of a vertex.
+
+v4.8.2 - 21 May 2012
+* Bugfix: Obscure bug could cause an exception when using 
+  ExPolygon structure.
+
+v4.8.1 - 12 May 2012
+* Update: Cody tidy and minor bug fixes.
+
+v4.8.0 - 30 April 2012
+* Bugfix: Occasional errors in orientation fixed. 
+* Update: Added notes on rounding to the documentation. 
+
+v4.7.6 - 11 April 2012
+* Fixed a bug in Orientation function (affecting C# translations only).
+* Minor documentation update.
+
+v4.7.5 - 28 March 2012
+* Bugfix: Fixed a recently introduced bug that occasionally caused an 
+  unhandled exception in C++ and C# translations. 
+
+v4.7.4 - 15 March 2012
+* Bugfix: Another minor bugfix.
+
+v4.7.2 - 4 March 2012
+* Bugfix: Fixed bug introduced in ver 4.7 which sometimes caused 
+  an exception if ExPolygon structure was passed to Clipper's 
+  Execute method. 
+
+v4.7.1 - 3 March 2012
+* Bugfix: Rare crash when JoinCommonEdges joined polygons that 
+  'cancelled' each other. 
+* Bugfix: Clipper's internal Orientation method occasionally 
+  returned wrong result. 
+* Update: Improved C# code (thanks to numerous excellent suggestions 
+  from David Piepgrass) 
+
+v4.7 - 10 February 2012
+* Improved the joining of output polygons sharing a common edge.
+
+v4.6.6 - 3 February 2012
+* Bugfix: Another obscure bug occasionally causing incorrect 
+  polygon orientation. 
+
+v4.6.5 - 17 January 2012
+* Bugfix: Obscure bug occasionally causing incorrect hole 
+  assignment in ExPolygon structure. 
+
+v4.6.4 - 8 November 2011
+* Added: SimplifyPolygon and SimplifyPolygons functions.
+
+v4.6.3 - 11 November 2011
+* Bugfix: Fixed another minor mitering bug in OffsetPolygons.
+
+v4.6.2 - 10 November 2011
+* Bugfix: Fixed a rare bug in the orientation of polygons 
+  returned by Clipper's Execute() method.
+* Bugfix: Previous update introduced a mitering bug in the
+  OffsetPolygons function.
+
+v4.6 - 29 October 2011
+* Added: Support for Positive and Negative polygon fill 
+  types (in addition to the EvenOdd and NonZero fill types).
+* Bugfix: The OffsetPolygons function was generating the 
+  occasional artefact when 'shrinking' polygons.
+
+v4.5.5 - 8 October 2011
+* Bugfix: Fixed an obscure bug in Clipper's JoinCommonEdges 
+  method. 
+* Update: Replaced IsClockwise function with Orientation 
+  function. The orientation issues affecting OffsetPolygons 
+  should now be finally resolved.
+* Change: The Area function once again returns a signed value.
+ 
+v4.5.1 - 28 September 2011
+* Deleted: The UseFullCoordinateRange property has been 
+  deleted since integer range is now managed implicitly. 
+* BugFix: Minor bug in OffsetPolygon mitering. 
+* Change: C# JoinType enum moved from Clipper class to 
+  ClipperLib namespace. 
+* Change: The Area function now returns the absolute area 
+  (irrespective of orientation). 
+* Change: The IsClockwise function now requires a second 
+  parameter - YAxisPositiveUpward - to accommodate displays 
+  with Y-axis oriented in either direction
+
+v4.4.4 - 10 September 2011
+* Change: Deleted jtButt from JoinType (used by the 
+  OffsetPolygons function). 
+* BugFix: Fixed another minor bug in OffsetPolygons function. 
+* Update: Further improvements to the help file
+
+v4.4.3 - 29 August 2011
+* BugFix: fixed a minor rounding issue in OffsetPolygons 
+  function (affected C++ & C# translations). 
+* BugFix: fixed a minor bug in OffsetPolygons' function 
+  declaration (affected C++ translation only). 
+* Change: 'clipper' namespace changed to 'ClipperLib' 
+  namespace in both C++ and C# code to remove the ambiguity 
+  between the Clipper class and the namespace. (This also 
+  required numerous updates to the accompanying demos.)
+
+v4.4.2 - 26 August 2011
+* BugFix: minor bugfixes in Clipper. 
+* Update: the OffsetPolygons function has been significantly 
+  improved by offering 4 different join styles. 
+
+v4.4.0 - 6 August 2011
+* BugFix: A number of minor bugs have been fixed that mostly 
+  affected the new ExPolygons structure. 
+
+v4.3.0 - 17 June 2011
+* New: ExPolygons structure that explicitly associates 'hole' 
+  polygons with their 'outer' container polygons.
+* New: Execute method overloaded so the solution parameter 
+  can now be either Polygons or ExPolygons.  
+* BugFix: Fixed a rare bug in solution polygons orientation. 
+
+v4.2.8 - 21 May 2011
+* Update: JoinCommonEdges() improved once more. 
+* BugFix: Several minor bugs fixed. 
+
+v4.2.6 - 1 May 2011
+* Bugfix: minor bug in SlopesEqual function.
+* Update: Merging of output polygons sharing common edges 
+  has been significantly inproved
+
+v4.2.4 - 26 April 2011
+  Input polygon coordinates can now contain the full range of 
+  signed 64bit integers (ie +/-9,223,372,036,854,775,807). This 
+  means that floating point values can be converted to and from 
+  Clipper's 64bit integer coordinates structure (IntPoint) and  
+  still retain a precision of up to 18 decimal places. However, 
+  since the large-integer math that supports this expanded range 
+  imposes a small cost on performance (~15%), a new property 
+  UseFullCoordinateRange has been added to the Clipper class to 
+  allow users the choice of whether or not to use this expanded 
+  coordinate range. If this property is disabled, coordinate values 
+  are restricted to +/-1,500,000,000.
+
+v4.2 - 12 April 2011
+  JoinCommonEdges() code significantly improved plus other minor 
+  improvements.
+
+v4.1.2 - 9 April 2011
+* Update: Minor code tidy. 
+* Bugfix: Possible endless loop in JoinCommonEdges() in clipper.pas.
+
+v4.1.1 - 8 April 2011
+* Update: All polygon coordinates are now stored as 64bit integers
+  (though they're still restricted to range -1.5e9 to +1.5e9 pending 
+  the inclusion of code supporting 64bit math).
+* Change: AddPolygon and AddPolygons methods now return boolean 
+  values. 
+* Bugfix: Bug in JoinCommonEdges() caused potential endless loop. 
+* Bugfix: Bug in IsClockwise(). (C++ code only)
+
+v4.0 - 5 April 2011
+* Clipper 4 is a major rewrite of earlier versions. The biggest 
+  change is that floating point values are no longer used, 
+  except for the storing of edge slope values. The main benefit 
+  of this is the issue of numerical robustness has been 
+  addressed. Due to other major code improvements Clipper v4 
+  is approximately 40% faster than Clipper v3. 
+* The AddPolyPolygon method has been renamed to AddPolygons. 
+* The IgnoreOrientation property has been removed. 
+* The clipper_misc library has been merged back into the 
+  main clipper library.
+  
+v3.1.0 - 17 February 2011
+* Bugfix: Obscure bug in TClipperBase.SetDx method that caused 
+  problems with very small edges ( edges <1/1000th pixel in size).
+  
+v3.0.3 - 9 February 2011
+* Bugfix: Significant bug, but only in C# code.
+* Update: Minor refactoring.
+
+v3.0 - 31 January 2011
+* Update: Major rewrite of the portion of code that calculates 
+  the output polygons' orientation.
+* Update: Help file significantly improved.
+* Change: Renamed ForceOrientation property to IgnoreOrientation. 
+  If the orientation of output polygons is not important, or can 
+  be managed separately, clipping routines can be sped up by about 
+  60% by setting IgnoreOrientation to true. Defaults to false.
+* Change: The OffsetPolygon and Area functions have been moved to 
+  the new unit - clipper_misc. 
+
+2.99 - 15 January 2011
+* Bugfix: Obscure bug in AddPolygon method could cause an endless loop. 
+
+2.8 - 20 November 2010
+* Updated: Output polygons which previously shared a common 
+  edge are now merged. 
+* Changed: The orientation of outer polygons is now clockwise 
+  when the display's Y axis is positive downwards (as is 
+  typical for most Windows applications). Inner polygons 
+  (holes) have the opposite orientation.
+* Added: Support module for Cairo Graphics Library (with demo). 
+* Updated: C# and C++ demos.
+
+2.522 - 15 October 2010
+* Added C# translation (thanks to Olivier Lejeune) and 
+  a link to Ruby bindings (thanks to Mike Owens).
+
+2.0 - 30 July 2010
+* Clipper now clips using both the Even-Odd (alternate) and 
+  Non-Zero (winding) polygon filling rules. (Previously Clipper 
+  assumed the Even-Odd rule for polygon filling.)
+  
+1.4c - 16 June 2010
+* Added C++ support for AGG graphics library 
+  
+1.2s - 2 June 2010
+* Added C++ translation of clipper.pas
+
+1.0 - 9 May 2010

clipper_library/clipper.cs

+/*******************************************************************************
+*                                                                              *
+* Author    :  Angus Johnson                                                   *
+* Version   :  5.1.6                                                           *
+* Date      :  23 May 2013                                                     *
+* Website   :  http://www.angusj.com                                           *
+* Copyright :  Angus Johnson 2010-2013                                         *
+*                                                                              *
+* License:                                                                     *
+* Use, modification & distribution is subject to Boost Software License Ver 1. *
+* http://www.boost.org/LICENSE_1_0.txt                                         *
+*                                                                              *
+* Attributions:                                                                *
+* The code in this library is an extension of Bala Vatti's clipping algorithm: *
+* "A generic solution to polygon clipping"                                     *
+* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
+* http://portal.acm.org/citation.cfm?id=129906                                 *
+*                                                                              *
+* Computer graphics and geometric modeling: implementation and algorithms      *
+* By Max K. Agoston                                                            *
+* Springer; 1 edition (January 4, 2005)                                        *
+* http://books.google.com/books?q=vatti+clipping+agoston                       *
+*                                                                              *
+* See also:                                                                    *
+* "Polygon Offsetting by Computing Winding Numbers"                            *
+* Paper no. DETC2005-85513 pp. 565-575                                         *
+* ASME 2005 International Design Engineering Technical Conferences             *
+* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
+* September 24-28, 2005 , Long Beach, California, USA                          *
+* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
+*                                                                              *
+*******************************************************************************/
+
+/*******************************************************************************
+*                                                                              *
+* This is a translation of the Delphi Clipper library and the naming style     *
+* used has retained a Delphi flavour.                                          *
+*                                                                              *
+*******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+//using System.Text; //for Int128.AsString() & StringBuilder
+//using System.IO; //streamReader & StreamWriter
+
+namespace ClipperLib
+{
+   
+    using Polygon = List<IntPoint>;
+    using Polygons = List<List<IntPoint>>;
+
+    //------------------------------------------------------------------------------
+    // PolyTree & PolyNode classes
+    //------------------------------------------------------------------------------
+
+    public class PolyTree : PolyNode
+    {
+        internal List<PolyNode> m_AllPolys = new List<PolyNode>();
+
+        ~PolyTree()
+        {
+            Clear();
+        }
+        
+        public void Clear() 
+        {
+            for (int i = 0; i < m_AllPolys.Count; i++)
+                m_AllPolys[i] = null;
+            m_AllPolys.Clear(); 
+            m_Childs.Clear(); 
+        }
+        
+        public PolyNode GetFirst()
+        {
+            if (m_Childs.Count > 0)
+                return m_Childs[0];
+            else
+                return null;
+        }
+
+        public int Total
+        {
+            get { return m_AllPolys.Count; }
+        }
+
+    }
+        
+    public class PolyNode 
+    {
+        internal PolyNode m_Parent;
+        internal Polygon m_polygon = new Polygon();
+        internal int m_Index;
+        internal List<PolyNode> m_Childs = new List<PolyNode>();
+
+        private bool IsHoleNode()
+        {
+            bool result = true;
+            PolyNode node = m_Parent;
+            while (node != null)
+            {
+                result = !result;
+                node = node.m_Parent;
+            }
+            return result;
+        }
+
+        public int ChildCount
+        {
+            get { return m_Childs.Count; }
+        }
+
+        public Polygon Contour
+        {
+            get { return m_polygon; }
+        }
+
+        internal void AddChild(PolyNode Child)
+        {
+            int cnt = m_Childs.Count;
+            m_Childs.Add(Child);
+            Child.m_Parent = this;
+            Child.m_Index = cnt;
+        }
+
+        public PolyNode GetNext()
+        {
+            if (m_Childs.Count > 0) 
+                return m_Childs[0]; 
+            else
+                return GetNextSiblingUp();        
+        }
+  
+        internal PolyNode GetNextSiblingUp()
+        {
+            if (m_Parent == null)
+                return null;
+            else if (m_Index == m_Parent.m_Childs.Count - 1)
+                return m_Parent.GetNextSiblingUp();
+            else
+                return m_Parent.m_Childs[m_Index + 1];
+        }
+
+        public List<PolyNode> Childs
+        {
+            get { return m_Childs; }
+        }
+
+        public PolyNode Parent
+        {
+            get { return m_Parent; }
+        }
+
+        public bool IsHole
+        {
+            get { return IsHoleNode(); }
+        }
+    }
+        
+
+    //------------------------------------------------------------------------------
+    // Int128 struct (enables safe math on signed 64bit integers)
+    // eg Int128 val1((Int64)9223372036854775807); //ie 2^63 -1
+    //    Int128 val2((Int64)9223372036854775807);
+    //    Int128 val3 = val1 * val2;
+    //    val3.ToString => "85070591730234615847396907784232501249" (8.5e+37)
+    //------------------------------------------------------------------------------
+
+    internal struct Int128
+    {
+        private Int64 hi;
+        private UInt64 lo;
+
+        public Int128(Int64 _lo)
+        {
+            lo = (UInt64)_lo;
+            if (_lo < 0) hi = -1; 
+            else hi = 0;
+        }
+
+        public Int128(Int64 _hi, UInt64 _lo)
+        {
+            lo = _lo;
+            hi = _hi;
+        }
+ 
+        public Int128(Int128 val)
+        {
+            hi = val.hi;
+            lo = val.lo;
+        }
+
+        public bool IsNegative()
+        {
+            return hi < 0;
+        }
+
+        public static bool operator ==(Int128 val1, Int128 val2)
+        {
+            if ((object)val1 == (object)val2) return true;
+            else if ((object)val1 == null || (object)val2 == null) return false;
+            return (val1.hi == val2.hi && val1.lo == val2.lo);
+        }
+
+        public static bool operator!= (Int128 val1, Int128 val2) 
+        { 
+            return !(val1 == val2); 
+        }
+
+        public override bool Equals(System.Object obj)
+        {
+            if (obj == null || !(obj is Int128))
+	            return false;
+            Int128 i128 = (Int128)obj;
+            return (i128.hi == hi && i128.lo == lo);
+        }
+
+        public override int GetHashCode()
+        {
+            return hi.GetHashCode() ^ lo.GetHashCode();
+        }
+
+        public static bool operator> (Int128 val1, Int128 val2) 
+        {
+            if (val1.hi != val2.hi)
+                return val1.hi > val2.hi;
+            else
+                return val1.lo > val2.lo;
+        }
+
+        public static bool operator< (Int128 val1, Int128 val2) 
+        {
+            if (val1.hi != val2.hi)
+                return val1.hi < val2.hi;
+            else
+                return val1.lo < val2.lo;
+        }
+
+        public static Int128 operator+ (Int128 lhs, Int128 rhs) 
+        {
+            lhs.hi += rhs.hi;
+            lhs.lo += rhs.lo;
+            if (lhs.lo < rhs.lo) lhs.hi++;
+            return lhs;
+        }
+
+        public static Int128 operator- (Int128 lhs, Int128 rhs) 
+        {
+            return lhs + -rhs;
+        }
+
+		public static Int128 operator -(Int128 val)
+		{
+            if (val.lo == 0) 
+                return new Int128(-val.hi, 0);
+            else 
+                return new Int128(~val.hi, ~val.lo +1);
+		}
+
+        //nb: Constructing two new Int128 objects every time we want to multiply longs  
+        //is slow. So, although calling the Int128Mul method doesn't look as clean, the 
+        //code runs significantly faster than if we'd used the * operator.
+        
+        public static Int128 Int128Mul(Int64 lhs, Int64 rhs)
+        {
+            bool negate = (lhs < 0) != (rhs < 0);
+            if (lhs < 0) lhs = -lhs;
+            if (rhs < 0) rhs = -rhs;
+            UInt64 int1Hi = (UInt64)lhs >> 32;
+            UInt64 int1Lo = (UInt64)lhs & 0xFFFFFFFF;
+            UInt64 int2Hi = (UInt64)rhs >> 32;
+            UInt64 int2Lo = (UInt64)rhs & 0xFFFFFFFF;
+
+            //nb: see comments in clipper.pas
+            UInt64 a = int1Hi * int2Hi;
+            UInt64 b = int1Lo * int2Lo;
+            UInt64 c = int1Hi * int2Lo + int1Lo * int2Hi;
+
+            UInt64 lo; 
+            Int64 hi;
+            hi = (Int64)(a + (c >> 32));
+
+            unchecked { lo = (c << 32) + b; }
+            if (lo < b) hi++;
+            Int128 result = new Int128(hi, lo);
+            return negate ? -result : result;            
+        }
+
+        public static Int128 operator /(Int128 lhs, Int128 rhs)
+        {
+            if (rhs.lo == 0 && rhs.hi == 0)
+                throw new ClipperException("Int128: divide by zero");
+
+            bool negate = (rhs.hi < 0) != (lhs.hi < 0);
+            if (lhs.hi < 0) lhs = -lhs;
+            if (rhs.hi < 0) rhs = -rhs;
+
+            if (rhs < lhs)
+            {
+                Int128 result = new Int128(0);
+                Int128 cntr = new Int128(1);
+                while (rhs.hi >= 0 && !(rhs > lhs))
+                {
+                    rhs.hi <<= 1;
+                    if ((Int64)rhs.lo < 0) rhs.hi++;
+                    rhs.lo <<= 1;
+
+                    cntr.hi <<= 1;
+                    if ((Int64)cntr.lo < 0) cntr.hi++;
+                    cntr.lo <<= 1;
+                }
+                rhs.lo >>= 1;
+                if ((rhs.hi & 1) == 1)
+                    rhs.lo |= 0x8000000000000000;
+                rhs.hi = (Int64)((UInt64)rhs.hi >> 1);
+
+                cntr.lo >>= 1;
+                if ((cntr.hi & 1) == 1)
+                    cntr.lo |= 0x8000000000000000;
+                cntr.hi >>= 1;
+
+                while (cntr.hi != 0 || cntr.lo != 0)
+                {
+                    if (!(lhs < rhs))
+                    {
+                        lhs -= rhs;
+                        result.hi |= cntr.hi;
+                        result.lo |= cntr.lo;
+                    }
+                    rhs.lo >>= 1;
+                    if ((rhs.hi & 1) == 1)
+                        rhs.lo |= 0x8000000000000000; 
+                    rhs.hi >>= 1;
+
+                    cntr.lo >>= 1;
+                    if ((cntr.hi & 1) == 1)
+                        cntr.lo |= 0x8000000000000000;
+                    cntr.hi >>= 1;
+                }
+                return negate ? -result : result;
+            }
+            else if (rhs == lhs)
+                return new Int128(1);
+            else
+                return new Int128(0);
+        }
+
+        public double ToDouble()
+        {
+            const double shift64 = 18446744073709551616.0; //2^64
+            if (hi < 0)
+            {
+                if (lo == 0)
+                    return (double)hi * shift64;
+                else
+                    return -(double)(~lo + ~hi * shift64);
+            }
+            else
+                return (double)(lo + hi * shift64);
+        }
+
+    };
+
+    //------------------------------------------------------------------------------
+    //------------------------------------------------------------------------------
+   
+    public struct IntPoint
+    {
+        public Int64 X;
+        public Int64 Y;
+        
+        public IntPoint(Int64 X, Int64 Y)
+        {
+            this.X = X; this.Y = Y;
+        }
+        
+        public IntPoint(IntPoint pt)
+        {
+            this.X = pt.X; this.Y = pt.Y;
+        }
+    }
+
+    public struct IntRect
+    {
+        public Int64 left;
+        public Int64 top;
+        public Int64 right;
+        public Int64 bottom;
+
+        public IntRect(Int64 l, Int64 t, Int64 r, Int64 b)
+        {
+            this.left = l; this.top = t;
+            this.right = r; this.bottom = b;
+        }
+    }
+
+    public enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
+    public enum PolyType { ptSubject, ptClip };
+    //By far the most widely used winding rules for polygon filling are
+    //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
+    //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
+    //see http://glprogramming.com/red/chapter11.html
+    public enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
+    public enum JoinType { jtSquare, jtRound, jtMiter };
+    public enum EndType { etClosed, etButt, etSquare, etRound};
+
+
+    [Flags]
+    internal enum EdgeSide { esLeft = 1, esRight = 2 };
+    [Flags]
+    internal enum Protects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
+    internal enum Direction { dRightToLeft, dLeftToRight };
+    
+    internal class TEdge {
+        public Int64 xbot;
+        public Int64 ybot;
+        public Int64 xcurr;
+        public Int64 ycurr;
+        public Int64 xtop;
+        public Int64 ytop;
+        public double dx;
+        public Int64 deltaX;
+        public Int64 deltaY;
+        public PolyType polyType;
+        public EdgeSide side;
+        public int windDelta; //1 or -1 depending on winding direction
+        public int windCnt;
+        public int windCnt2; //winding count of the opposite polytype
+        public int outIdx;
+        public TEdge next;
+        public TEdge prev;
+        public TEdge nextInLML;
+        public TEdge nextInAEL;
+        public TEdge prevInAEL;
+        public TEdge nextInSEL;
+        public TEdge prevInSEL;
+    };
+
+    internal class IntersectNode
+    {
+        public TEdge edge1;
+        public TEdge edge2;
+        public IntPoint pt;
+        public IntersectNode next;
+    };
+
+    internal class LocalMinima
+    {
+        public Int64 Y;
+        public TEdge leftBound;
+        public TEdge rightBound;
+        public LocalMinima next;
+    };
+
+    internal class Scanbeam
+    {
+        public Int64 Y;
+        public Scanbeam next;
+    };
+
+    internal class OutRec
+    {
+        public int idx;
+        public bool isHole;
+        public OutRec FirstLeft; //see comments in clipper.pas
+        public OutPt pts;
+        public OutPt bottomPt;
+        public PolyNode polyNode;
+    };
+
+    internal class OutPt
+    {
+        public int idx;
+        public IntPoint pt;
+        public OutPt next;
+        public OutPt prev;
+    };
+
+    internal class JoinRec
+    {
+        public IntPoint pt1a;
+        public IntPoint pt1b;
+        public int poly1Idx;
+        public IntPoint pt2a;
+        public IntPoint pt2b;
+        public int poly2Idx;
+    };
+
+    internal class HorzJoinRec
+    {
+        public TEdge edge;
+        public int savedIdx;
+    };
+
+    public class ClipperBase
+    {
+        protected const double horizontal = -3.4E+38;
+        internal const Int64 loRange = 0x3FFFFFFF;          
+        internal const Int64 hiRange = 0x3FFFFFFFFFFFFFFFL; 
+
+        internal LocalMinima m_MinimaList;
+        internal LocalMinima m_CurrentLM;
+        internal List<List<TEdge>> m_edges = new List<List<TEdge>>();
+        internal bool m_UseFullRange;
+
+        //------------------------------------------------------------------------------
+
+        protected static bool PointsEqual(IntPoint pt1, IntPoint pt2)
+        {
+          return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
+        }
+        //------------------------------------------------------------------------------
+
+        internal bool PointIsVertex(IntPoint pt, OutPt pp)
+        {
+          OutPt pp2 = pp;
+          do
+          {
+            if (PointsEqual(pp2.pt, pt)) return true;
+            pp2 = pp2.next;
+          }
+          while (pp2 != pp);
+          return false;
+        }
+        //------------------------------------------------------------------------------
+
+        internal bool PointOnLineSegment(IntPoint pt, 
+            IntPoint linePt1, IntPoint linePt2, bool UseFullInt64Range)
+        {
+          if (UseFullInt64Range)
+            return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
+              ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
+              (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
+              ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
+              ((Int128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) ==
+              Int128.Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y)))));
+          else
+            return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) ||
+              ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) ||
+              (((pt.X > linePt1.X) == (pt.X < linePt2.X)) &&
+              ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) &&
+              ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) ==
+                (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y)));
+        }
+        //------------------------------------------------------------------------------
+
+        internal bool PointOnPolygon(IntPoint pt, OutPt pp, bool UseFullInt64Range)
+        {
+          OutPt pp2 = pp;
+          while (true)
+          {
+            if (PointOnLineSegment(pt, pp2.pt, pp2.next.pt, UseFullInt64Range))
+              return true;
+            pp2 = pp2.next;
+            if (pp2 == pp) break;
+          }
+          return false;
+        }
+        //------------------------------------------------------------------------------
+
+        internal bool PointInPolygon(IntPoint pt, OutPt pp, bool UseFulllongRange)
+        {
+          OutPt pp2 = pp;
+          bool result = false;
+          if (UseFulllongRange)
+          {
+              do
+              {
+                  if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) ||
+                      ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) &&
+                      new Int128(pt.X - pp2.pt.X) < 
+                      Int128.Int128Mul(pp2.prev.pt.X - pp2.pt.X,  pt.Y - pp2.pt.Y) / 
+                      new Int128(pp2.prev.pt.Y - pp2.pt.Y))
+                        result = !result;
+                  pp2 = pp2.next;
+              }
+              while (pp2 != pp);
+          }
+          else
+          {
+              do
+              {
+                  if ((((pp2.pt.Y <= pt.Y) && (pt.Y < pp2.prev.pt.Y)) ||
+                    ((pp2.prev.pt.Y <= pt.Y) && (pt.Y < pp2.pt.Y))) &&
+                    (pt.X - pp2.pt.X < (pp2.prev.pt.X - pp2.pt.X) * (pt.Y - pp2.pt.Y) /
+                    (pp2.prev.pt.Y - pp2.pt.Y))) result = !result;
+                  pp2 = pp2.next;
+              }
+              while (pp2 != pp);
+          }
+          return result;
+        }
+        //------------------------------------------------------------------------------
+
+        internal static bool SlopesEqual(TEdge e1, TEdge e2, bool UseFullRange)
+        {
+            if (UseFullRange)
+              return Int128.Int128Mul(e1.deltaY, e2.deltaX) ==
+                  Int128.Int128Mul(e1.deltaX, e2.deltaY);
+            else return (Int64)(e1.deltaY) * (e2.deltaX) ==
+              (Int64)(e1.deltaX) * (e2.deltaY);
+        }
+        //------------------------------------------------------------------------------
+
+        protected static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
+            IntPoint pt3, bool UseFullRange)
+        {
+            if (UseFullRange)
+                return Int128.Int128Mul(pt1.Y - pt2.Y, pt2.X - pt3.X) ==
+                  Int128.Int128Mul(pt1.X - pt2.X, pt2.Y - pt3.Y);
+            else return
+              (Int64)(pt1.Y - pt2.Y) * (pt2.X - pt3.X) - (Int64)(pt1.X - pt2.X) * (pt2.Y - pt3.Y) == 0;
+        }
+        //------------------------------------------------------------------------------
+
+        protected static bool SlopesEqual(IntPoint pt1, IntPoint pt2,
+            IntPoint pt3, IntPoint pt4, bool UseFullRange)
+        {
+            if (UseFullRange)
+                return Int128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
+                  Int128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
+            else return
+              (Int64)(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (Int64)(pt1.X - pt2.X) * (pt3.Y - pt4.Y) == 0;
+        }
+        //------------------------------------------------------------------------------
+
+        internal ClipperBase() //constructor (nb: no external instantiation)
+        {
+            m_MinimaList = null;
+            m_CurrentLM = null;
+            m_UseFullRange = false;
+        }
+        //------------------------------------------------------------------------------
+
+        //destructor - commented out since I gather this impedes the GC 
+        //~ClipperBase() 
+        //{
+        //    Clear();
+        //}
+        //------------------------------------------------------------------------------
+
+        public virtual void Clear()
+        {
+            DisposeLocalMinimaList();
+            for (int i = 0; i < m_edges.Count; ++i)
+            {
+                for (int j = 0; j < m_edges[i].Count; ++j) m_edges[i][j] = null;
+                m_edges[i].Clear();
+            }
+            m_edges.Clear();
+            m_UseFullRange = false;
+        }
+        //------------------------------------------------------------------------------
+
+        private void DisposeLocalMinimaList()
+        {
+            while( m_MinimaList != null )
+            {
+                LocalMinima tmpLm = m_MinimaList.next;
+                m_MinimaList = null;
+                m_MinimaList = tmpLm;
+            }
+            m_CurrentLM = null;
+        }
+        //------------------------------------------------------------------------------
+
+        public bool AddPolygons(Polygons ppg, PolyType polyType)
+        {
+            bool result = false;
+            for (int i = 0; i < ppg.Count; ++i)
+                if (AddPolygon(ppg[i], polyType)) result = true;
+            return result;
+        }
+        //------------------------------------------------------------------------------
+
+        void RangeTest(IntPoint pt, ref Int64 maxrange)
+        {
+          if (pt.X > maxrange)
+          {
+            if (pt.X > hiRange)
+                throw new ClipperException("Coordinate exceeds range bounds");
+            else maxrange = hiRange;
+          }
+          if (pt.Y > maxrange)
+          {
+            if (pt.Y > hiRange)
+                throw new ClipperException("Coordinate exceeds range bounds");
+            else maxrange = hiRange;
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        public bool AddPolygon(Polygon pg, PolyType polyType)
+        {
+            int len = pg.Count;
+            if (len < 3) return false;
+            Int64 maxVal;
+            if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
+            RangeTest(pg[0], ref maxVal);
+
+            Polygon p = new Polygon(len);
+            p.Add(new IntPoint(pg[0].X, pg[0].Y));
+            int j = 0;
+            for (int i = 1; i < len; ++i)
+            {
+                RangeTest(pg[i], ref maxVal);
+                if (PointsEqual(p[j], pg[i])) continue;
+                else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], maxVal == hiRange))
+                {
+                    if (PointsEqual(p[j-1], pg[i])) j--;
+                } else j++;
+                if (j < p.Count)
+                    p[j] = pg[i]; else
+                    p.Add(new IntPoint(pg[i].X, pg[i].Y));
+            }
+            if (j < 2) return false;
+            m_UseFullRange = maxVal == hiRange;
+
+            len = j+1;
+            while (len > 2)
+            {
+                //nb: test for point equality before testing slopes ...
+                if (PointsEqual(p[j], p[0])) j--;
+                else if (PointsEqual(p[0], p[1]) || SlopesEqual(p[j], p[0], p[1], m_UseFullRange))
+                    p[0] = p[j--];
+                else if (SlopesEqual(p[j - 1], p[j], p[0], m_UseFullRange)) j--;
+                else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange))
+                {
+                    for (int i = 2; i <= j; ++i) p[i - 1] = p[i];
+                    j--;
+                }
+                else break;
+                len--;
+            }
+            if (len < 3) return false;
+
+            //create a new edge array ...
+            List<TEdge> edges = new List<TEdge>(len);
+            for (int i = 0; i < len; i++) edges.Add(new TEdge());
+            m_edges.Add(edges);
+
+            //convert vertices to a double-linked-list of edges and initialize ...
+            edges[0].xcurr = p[0].X;
+            edges[0].ycurr = p[0].Y;
+            InitEdge(edges[len-1], edges[0], edges[len-2], p[len-1], polyType);
+            for (int i = len-2; i > 0; --i)
+            InitEdge(edges[i], edges[i+1], edges[i-1], p[i], polyType);
+            InitEdge(edges[0], edges[1], edges[len-1], p[0], polyType);
+
+            //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates
+            //increase downward so the 'highest' edge will have the smallest ytop) ...
+            TEdge e = edges[0];
+            TEdge eHighest = e;
+            do
+            {
+            e.xcurr = e.xbot;
+            e.ycurr = e.ybot;
+            if (e.ytop < eHighest.ytop) eHighest = e;
+            e = e.next;
+            }
+            while ( e != edges[0]);
+
+            //make sure eHighest is positioned so the following loop works safely ...
+            if (eHighest.windDelta > 0) eHighest = eHighest.next;
+            if (eHighest.dx == horizontal) eHighest = eHighest.next;
+
+            //finally insert each local minima ...
+            e = eHighest;
+            do {
+            e = AddBoundsToLML(e);
+            }
+            while( e != eHighest );
+            return true;
+        }
+        //------------------------------------------------------------------------------
+
+        private void InitEdge(TEdge e, TEdge eNext,
+          TEdge ePrev, IntPoint pt, PolyType polyType)
+        {
+          e.next = eNext;
+          e.prev = ePrev;
+          e.xcurr = pt.X;
+          e.ycurr = pt.Y;
+          if (e.ycurr >= e.next.ycurr)
+          {
+            e.xbot = e.xcurr;
+            e.ybot = e.ycurr;
+            e.xtop = e.next.xcurr;
+            e.ytop = e.next.ycurr;
+            e.windDelta = 1;
+          } else
+          {
+            e.xtop = e.xcurr;
+            e.ytop = e.ycurr;
+            e.xbot = e.next.xcurr;
+            e.ybot = e.next.ycurr;
+            e.windDelta = -1;
+          }
+          SetDx(e);
+          e.polyType = polyType;
+          e.outIdx = -1;
+        }
+        //------------------------------------------------------------------------------
+
+        private void SetDx(TEdge e)
+        {
+          e.deltaX = (e.xtop - e.xbot);
+          e.deltaY = (e.ytop - e.ybot);
+          if (e.deltaY == 0) e.dx = horizontal;
+          else e.dx = (double)(e.deltaX) / (e.deltaY);
+        }
+        //---------------------------------------------------------------------------
+
+        TEdge AddBoundsToLML(TEdge e)
+        {
+          //Starting at the top of one bound we progress to the bottom where there's
+          //a local minima. We then go to the top of the next bound. These two bounds
+          //form the left and right (or right and left) bounds of the local minima.
+          e.nextInLML = null;
+          e = e.next;
+          for (;;)
+          {
+            if ( e.dx == horizontal )
+            {
+              //nb: proceed through horizontals when approaching from their right,
+              //    but break on horizontal minima if approaching from their left.
+              //    This ensures 'local minima' are always on the left of horizontals.
+              if (e.next.ytop < e.ytop && e.next.xbot > e.prev.xbot) break;
+              if (e.xtop != e.prev.xbot) SwapX(e);
+              e.nextInLML = e.prev;
+            }
+            else if (e.ycurr == e.prev.ycurr) break;
+            else e.nextInLML = e.prev;
+            e = e.next;
+          }
+
+          //e and e.prev are now at a local minima ...
+          LocalMinima newLm = new LocalMinima();
+          newLm.next = null;
+          newLm.Y = e.prev.ybot;
+
+          if ( e.dx == horizontal ) //horizontal edges never start a left bound
+          {
+            if (e.xbot != e.prev.xbot) SwapX(e);
+            newLm.leftBound = e.prev;
+            newLm.rightBound = e;
+          } else if (e.dx < e.prev.dx)
+          {
+            newLm.leftBound = e.prev;
+            newLm.rightBound = e;
+          } else
+          {
+            newLm.leftBound = e;
+            newLm.rightBound = e.prev;
+          }
+          newLm.leftBound.side = EdgeSide.esLeft;
+          newLm.rightBound.side = EdgeSide.esRight;
+          InsertLocalMinima( newLm );
+
+          for (;;)
+          {
+            if ( e.next.ytop == e.ytop && e.next.dx != horizontal ) break;
+            e.nextInLML = e.next;
+            e = e.next;
+            if ( e.dx == horizontal && e.xbot != e.prev.xtop) SwapX(e);
+          }
+          return e.next;
+        }
+        //------------------------------------------------------------------------------
+
+        private void InsertLocalMinima(LocalMinima newLm)
+        {
+          if( m_MinimaList == null )
+          {
+            m_MinimaList = newLm;
+          }
+          else if( newLm.Y >= m_MinimaList.Y )
+          {
+            newLm.next = m_MinimaList;
+            m_MinimaList = newLm;
+          } else
+          {
+            LocalMinima tmpLm = m_MinimaList;
+            while( tmpLm.next != null  && ( newLm.Y < tmpLm.next.Y ) )
+              tmpLm = tmpLm.next;
+            newLm.next = tmpLm.next;
+            tmpLm.next = newLm;
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        protected void PopLocalMinima()
+        {
+            if (m_CurrentLM == null) return;
+            m_CurrentLM = m_CurrentLM.next;
+        }
+        //------------------------------------------------------------------------------
+
+        private void SwapX(TEdge e)
+        {
+          //swap horizontal edges' top and bottom x's so they follow the natural
+          //progression of the bounds - ie so their xbots will align with the
+          //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
+          e.xcurr = e.xtop;
+          e.xtop = e.xbot;
+          e.xbot = e.xcurr;
+        }
+        //------------------------------------------------------------------------------
+
+        protected virtual void Reset()
+        {
+            m_CurrentLM = m_MinimaList;
+
+            //reset all edges ...
+            LocalMinima lm = m_MinimaList;
+            while (lm != null)
+            {
+                TEdge e = lm.leftBound;
+                while (e != null)
+                {
+                    e.xcurr = e.xbot;
+                    e.ycurr = e.ybot;
+                    e.side = EdgeSide.esLeft;
+                    e.outIdx = -1;
+                    e = e.nextInLML;
+                }
+                e = lm.rightBound;
+                while (e != null)
+                {
+                    e.xcurr = e.xbot;
+                    e.ycurr = e.ybot;
+                    e.side = EdgeSide.esRight;
+                    e.outIdx = -1;
+                    e = e.nextInLML;
+                }
+                lm = lm.next;
+            }
+            return;
+        }
+        //------------------------------------------------------------------------------
+
+        public IntRect GetBounds()
+        {
+            IntRect result = new IntRect();
+            LocalMinima lm = m_MinimaList;
+            if (lm == null) return result;
+            result.left = lm.leftBound.xbot;
+            result.top = lm.leftBound.ybot;
+            result.right = lm.leftBound.xbot;
+            result.bottom = lm.leftBound.ybot;
+            while (lm != null)
+            {
+                if (lm.leftBound.ybot > result.bottom)
+                    result.bottom = lm.leftBound.ybot;
+                TEdge e = lm.leftBound;
+                for (; ; )
+                {
+                    TEdge bottomE = e;
+                    while (e.nextInLML != null)
+                    {
+                        if (e.xbot < result.left) result.left = e.xbot;
+                        if (e.xbot > result.right) result.right = e.xbot;
+                        e = e.nextInLML;
+                    }
+                    if (e.xbot < result.left) result.left = e.xbot;
+                    if (e.xbot > result.right) result.right = e.xbot;
+                    if (e.xtop < result.left) result.left = e.xtop;
+                    if (e.xtop > result.right) result.right = e.xtop;
+                    if (e.ytop < result.top) result.top = e.ytop;
+
+                    if (bottomE == lm.leftBound) e = lm.rightBound;
+                    else break;
+                }
+                lm = lm.next;
+            }
+            return result;
+        }
+
+    } //ClipperBase
+
+    public class Clipper : ClipperBase
+    {
+        private List<OutRec> m_PolyOuts;
+        private ClipType m_ClipType;
+        private Scanbeam m_Scanbeam;
+        private TEdge m_ActiveEdges;
+        private TEdge m_SortedEdges;
+        private IntersectNode m_IntersectNodes;
+        private bool m_ExecuteLocked;
+        private PolyFillType m_ClipFillType;
+        private PolyFillType m_SubjFillType;
+        private List<JoinRec> m_Joins;
+        private List<HorzJoinRec> m_HorizJoins;
+        private bool m_ReverseOutput;
+        private bool m_ForceSimple;
+        private bool m_UsingPolyTree;
+
+        public Clipper()
+        {
+            m_Scanbeam = null;
+            m_ActiveEdges = null;
+            m_SortedEdges = null;
+            m_IntersectNodes = null;
+            m_ExecuteLocked = false;
+            m_UsingPolyTree = false;
+            m_PolyOuts = new List<OutRec>();
+            m_Joins = new List<JoinRec>();
+            m_HorizJoins = new List<HorzJoinRec>();
+            m_ReverseOutput = false;
+            m_ForceSimple = false;
+        }
+        //------------------------------------------------------------------------------
+
+        //destructor - commented out since I gather this impedes the GC 
+        //~Clipper() //destructor
+        //{
+        //    Clear();
+        //    DisposeScanbeamList();
+        //}
+        //------------------------------------------------------------------------------
+
+        public override void Clear()
+        {
+            if (m_edges.Count == 0) return; //avoids problems with ClipperBase destructor
+            DisposeAllPolyPts();
+            base.Clear();
+        }
+        //------------------------------------------------------------------------------
+
+        void DisposeScanbeamList()
+        {
+          while ( m_Scanbeam != null ) {
+          Scanbeam sb2 = m_Scanbeam.next;
+          m_Scanbeam = null;
+          m_Scanbeam = sb2;
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        protected override void Reset() 
+        {
+          base.Reset();
+          m_Scanbeam = null;
+          m_ActiveEdges = null;
+          m_SortedEdges = null;
+          DisposeAllPolyPts();
+          LocalMinima lm = m_MinimaList;
+          while (lm != null)
+          {
+            InsertScanbeam(lm.Y);
+            lm = lm.next;
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        public bool ReverseSolution
+        {
+            get { return m_ReverseOutput; }
+            set { m_ReverseOutput = value; }
+        }
+        //------------------------------------------------------------------------------
+
+        public bool ForceSimple
+        {
+            get { return m_ForceSimple; }
+            set { m_ForceSimple = value; }
+        }
+        //------------------------------------------------------------------------------
+       
+        private void InsertScanbeam(Int64 Y)
+        {
+          if( m_Scanbeam == null )
+          {
+            m_Scanbeam = new Scanbeam();
+            m_Scanbeam.next = null;
+            m_Scanbeam.Y = Y;
+          }
+          else if(  Y > m_Scanbeam.Y )
+          {
+            Scanbeam newSb = new Scanbeam();
+            newSb.Y = Y;
+            newSb.next = m_Scanbeam;
+            m_Scanbeam = newSb;
+          } else
+          {
+            Scanbeam sb2 = m_Scanbeam;
+            while( sb2.next != null  && ( Y <= sb2.next.Y ) ) sb2 = sb2.next;
+            if(  Y == sb2.Y ) return; //ie ignores duplicates
+            Scanbeam newSb = new Scanbeam();
+            newSb.Y = Y;
+            newSb.next = sb2.next;
+            sb2.next = newSb;
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        public bool Execute(ClipType clipType, Polygons solution,
+            PolyFillType subjFillType, PolyFillType clipFillType)
+        {
+            if (m_ExecuteLocked) return false;
+            m_ExecuteLocked = true;
+            solution.Clear();
+            m_SubjFillType = subjFillType;
+            m_ClipFillType = clipFillType;
+            m_ClipType = clipType;
+            m_UsingPolyTree = false;
+            bool succeeded = ExecuteInternal();
+            //build the return polygons ...
+            if (succeeded) BuildResult(solution);
+            m_ExecuteLocked = false;
+            return succeeded;
+        }
+        //------------------------------------------------------------------------------
+
+        public bool Execute(ClipType clipType, PolyTree polytree,
+            PolyFillType subjFillType, PolyFillType clipFillType)
+        {
+            if (m_ExecuteLocked) return false;
+            m_ExecuteLocked = true;
+            m_SubjFillType = subjFillType;
+            m_ClipFillType = clipFillType;
+            m_ClipType = clipType;
+            m_UsingPolyTree = true;
+            bool succeeded = ExecuteInternal();
+            //build the return polygons ...
+            if (succeeded) BuildResult2(polytree);
+            m_ExecuteLocked = false;
+            return succeeded;
+        }
+        //------------------------------------------------------------------------------
+
+        public bool Execute(ClipType clipType, Polygons solution)
+        {
+            return Execute(clipType, solution,
+                PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);
+        }
+        //------------------------------------------------------------------------------
+
+        public bool Execute(ClipType clipType, PolyTree polytree)
+        {
+            return Execute(clipType, polytree,
+                PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);
+        }
+        //------------------------------------------------------------------------------
+
+        internal void FixHoleLinkage(OutRec outRec)
+        {
+            //skip if an outermost polygon or
+            //already already points to the correct FirstLeft ...
+            if (outRec.FirstLeft == null ||                
+                  (outRec.isHole != outRec.FirstLeft.isHole &&
+                  outRec.FirstLeft.pts != null)) return;
+
+            OutRec orfl = outRec.FirstLeft;
+            while (orfl != null && ((orfl.isHole == outRec.isHole) || orfl.pts == null))
+                orfl = orfl.FirstLeft;
+            outRec.FirstLeft = orfl;
+        }
+        //------------------------------------------------------------------------------
+
+        private bool ExecuteInternal()
+        {
+            bool succeeded;
+            try
+            {
+                Reset();
+                if (m_CurrentLM == null) return true;
+                Int64 botY = PopScanbeam();
+                do
+                {
+                    InsertLocalMinimaIntoAEL(botY);
+                    m_HorizJoins.Clear();
+                    ProcessHorizontals();
+                    Int64 topY = PopScanbeam();
+                    succeeded = ProcessIntersections(botY, topY);
+                    if (!succeeded) break;
+                    ProcessEdgesAtTopOfScanbeam(topY);
+                    botY = topY;
+                } while (m_Scanbeam != null || m_CurrentLM != null);
+            }
+            catch { succeeded = false; }
+
+            if (succeeded)
+            { 
+                //tidy up output polygons and fix orientations where necessary ...
+                for (int i = 0; i < m_PolyOuts.Count; i++)
+                {
+                  OutRec outRec = m_PolyOuts[i];
+                  if (outRec.pts == null) continue;
+                  FixupOutPolygon(outRec);
+                  if (outRec.pts == null) continue;
+                  if ((outRec.isHole ^ m_ReverseOutput) == (Area(outRec, m_UseFullRange) > 0))
+                      ReversePolyPtLinks(outRec.pts);
+                }
+                JoinCommonEdges();
+                if (m_ForceSimple) DoSimplePolygons();
+            }
+            m_Joins.Clear();
+            m_HorizJoins.Clear();
+            return succeeded;
+        }
+        //------------------------------------------------------------------------------
+
+        private Int64 PopScanbeam()
+        {
+          Int64 Y = m_Scanbeam.Y;
+          Scanbeam sb2 = m_Scanbeam;
+          m_Scanbeam = m_Scanbeam.next;
+          sb2 = null;
+          return Y;
+        }
+        //------------------------------------------------------------------------------
+
+        private void DisposeAllPolyPts(){
+          for (int i = 0; i < m_PolyOuts.Count; ++i) DisposeOutRec(i);
+          m_PolyOuts.Clear();
+        }
+        //------------------------------------------------------------------------------
+
+        void DisposeOutRec(int index)
+        {
+          OutRec outRec = m_PolyOuts[index];
+          if (outRec.pts != null) DisposeOutPts(outRec.pts);
+          outRec = null;
+          m_PolyOuts[index] = null;
+        }
+        //------------------------------------------------------------------------------
+
+        private void DisposeOutPts(OutPt pp)
+        {
+            if (pp == null) return;
+            OutPt tmpPp = null;
+            pp.prev.next = null;
+            while (pp != null)
+            {
+                tmpPp = pp;
+                pp = pp.next;
+                tmpPp = null;
+            }
+        }
+        //------------------------------------------------------------------------------
+
+        private void AddJoin(TEdge e1, TEdge e2, int e1OutIdx, int e2OutIdx)
+        {
+            JoinRec jr = new JoinRec();
+            if (e1OutIdx >= 0)
+                jr.poly1Idx = e1OutIdx; else
+            jr.poly1Idx = e1.outIdx;
+            jr.pt1a = new IntPoint(e1.xcurr, e1.ycurr);
+            jr.pt1b = new IntPoint(e1.xtop, e1.ytop);
+            if (e2OutIdx >= 0)
+                jr.poly2Idx = e2OutIdx; else
+                jr.poly2Idx = e2.outIdx;
+            jr.pt2a = new IntPoint(e2.xcurr, e2.ycurr);
+            jr.pt2b = new IntPoint(e2.xtop, e2.ytop);
+            m_Joins.Add(jr);
+        }
+        //------------------------------------------------------------------------------
+
+        private void AddHorzJoin(TEdge e, int idx)
+        {
+            HorzJoinRec hj = new HorzJoinRec();
+            hj.edge = e;
+            hj.savedIdx = idx;
+            m_HorizJoins.Add(hj);
+        }
+        //------------------------------------------------------------------------------
+
+        private void InsertLocalMinimaIntoAEL(Int64 botY)
+        {
+          while(  m_CurrentLM != null  && ( m_CurrentLM.Y == botY ) )
+          {
+            TEdge lb = m_CurrentLM.leftBound;
+            TEdge rb = m_CurrentLM.rightBound;
+
+            InsertEdgeIntoAEL( lb );
+            InsertScanbeam( lb.ytop );
+            InsertEdgeIntoAEL( rb );
+
+            if (IsEvenOddFillType(lb))
+            {
+                lb.windDelta = 1;
+                rb.windDelta = 1;
+            }
+            else
+            {
+                rb.windDelta = -lb.windDelta;
+            }
+            SetWindingCount(lb);
+            rb.windCnt = lb.windCnt;
+            rb.windCnt2 = lb.windCnt2;
+
+            if(  rb.dx == horizontal )
+            {
+              //nb: only rightbounds can have a horizontal bottom edge
+              AddEdgeToSEL( rb );
+              InsertScanbeam( rb.nextInLML.ytop );
+            }
+            else
+              InsertScanbeam( rb.ytop );
+
+            if( IsContributing(lb) )
+                AddLocalMinPoly(lb, rb, new IntPoint(lb.xcurr, m_CurrentLM.Y));
+
+            //if any output polygons share an edge, they'll need joining later ...
+            if (rb.outIdx >= 0 && rb.dx == horizontal)
+            {
+                for (int i = 0; i < m_HorizJoins.Count; i++)
+                {
+                    IntPoint pt = new IntPoint(), pt2 = new IntPoint(); //used as dummy params.
+                    HorzJoinRec hj = m_HorizJoins[i];
+                    //if horizontals rb and hj.edge overlap, flag for joining later ...
+                    if (GetOverlapSegment(new IntPoint(hj.edge.xbot, hj.edge.ybot),
+                        new IntPoint(hj.edge.xtop, hj.edge.ytop),
+                        new IntPoint(rb.xbot, rb.ybot),
+                        new IntPoint(rb.xtop, rb.ytop), 
+                        ref pt, ref pt2))
+                        AddJoin(hj.edge, rb, hj.savedIdx, -1);
+                }
+            }
+
+
+            if( lb.nextInAEL != rb )
+            {
+                if (rb.outIdx >= 0 && rb.prevInAEL.outIdx >= 0 && 
+                    SlopesEqual(rb.prevInAEL, rb, m_UseFullRange))
+                    AddJoin(rb, rb.prevInAEL, -1, -1);
+
+              TEdge e = lb.nextInAEL;
+              IntPoint pt = new IntPoint(lb.xcurr, lb.ycurr);
+              while( e != rb )
+              {
+                if(e == null) 
+                    throw new ClipperException("InsertLocalMinimaIntoAEL: missing rightbound!");
+                //nb: For calculating winding counts etc, IntersectEdges() assumes
+                //that param1 will be to the right of param2 ABOVE the intersection ...
+                IntersectEdges( rb , e , pt , Protects.ipNone); //order important here
+                e = e.nextInAEL;
+              }
+            }
+            PopLocalMinima();
+          }
+        }
+        //------------------------------------------------------------------------------
+
+        private void InsertEdgeIntoAEL(TEdge edge)
+        {
+          edge.prevInAEL = null;
+          edge.nextInAEL = null;
+          if (m_ActiveEdges == null)
+          {
+            m_ActiveEdges = edge;
+          }
+          else if( E2InsertsBeforeE1(m_ActiveEdges, edge) )
+          {
+            edge.nextInAEL = m_ActiveEdges;
+            m_ActiveEdges.prevInAEL = edge;
+            m_ActiveEdges = edge;
+          } else
+          {
+            TEdge e = m_ActiveEdges;
+            while (e.nextInAEL != null && !E2InsertsBeforeE1(e.nextInAEL, edge))
+              e = e.nextInAEL;
+            edge.nextInAEL = e.nextInAEL;
+            if (e.nextInAEL != null) e.nextInAEL.prevInAEL = edge;
+            edge.prevInAEL = e;
+            e.nextInAEL = edge;
+          }
+        }
+        //----------------------------------------------------------------------
+
+        private bool E2InsertsBeforeE1(TEdge e1, TEdge e2)
+        {
+            if (e2.xcurr == e1.xcurr)
+            {
+                if (e2.ytop > e1.ytop)
+                    return e2.xtop < TopX(e1, e2.ytop);
+                else return e1.xtop > TopX(e2, e1.ytop);
+            }
+            else return e2.xcurr < e1.xcurr;
+        }
+        //------------------------------------------------------------------------------
+
+        private bool IsEvenOddFillType(TEdge edge) 
+        {
+          if (edge.polyType == PolyType.ptSubject)
+              return m_SubjFillType == PolyFillType.pftEvenOdd; 
+          else
+              return m_ClipFillType == PolyFillType.pftEvenOdd;
+        }
+        //------------------------------------------------------------------------------
+
+        private bool IsEvenOddAltFillType(TEdge edge) 
+        {
+          if (edge.polyType == PolyType.ptSubject)
+              return m_ClipFillType == PolyFillType.pftEvenOdd; 
+          else
+              return m_SubjFillType == PolyFillType.pftEvenOdd;
+        }
+        //------------------------------------------------------------------------------
+
+        private bool IsContributing(TEdge edge)
+        {
+            PolyFillType pft, pft2;
+            if (edge.polyType == PolyType.ptSubject)
+            {
+                pft = m_SubjFillType;
+                pft2 = m_ClipFillType;
+            }
+            else
+            {
+                pft = m_ClipFillType;
+                pft2 = m_SubjFillType;
+            }
+
+            switch (pft)
+            {
+                case PolyFillType.pftEvenOdd:
+                case PolyFillType.pftNonZero:
+                    if (Math.Abs(edge.windCnt) != 1) return false;
+                    break;
+                case PolyFillType.pftPositive:
+                    if (edge.windCnt != 1) return false;
+                    break;
+                default: //PolyFillType.pftNegative
+                    if (edge.windCnt != -1) return false; 
+                    break;
+            }
+
+            switch (m_ClipType)
+            {
+                case ClipType.ctIntersection:
+                    switch (pft2)
+                    {
+                        case PolyFillType.pftEvenOdd:
+                        case PolyFillType.pftNonZero:
+                            return (edge.windCnt2 != 0);
+                        case PolyFillType.pftPositive:
+                            return (edge.windCnt2 > 0);
+                        default:
+                            return (edge.windCnt2 < 0);
+                    }
+                case ClipType.ctUnion:
+                    switch (pft2)
+                    {
+                        case PolyFillType.pftEvenOdd:
+                        case PolyFillType.pftNonZero:
+                            return (edge.windCnt2 == 0);
+                        case PolyFillType.pftPositive:
+                            return (edge.windCnt2 <= 0);
+                        default:
+                            return (edge.windCnt2 >= 0);
+                    }
+                case ClipType.ctDifference:
+                    if (edge.polyType == PolyType.ptSubject)
+                        switch (pft2)
+                        {
+                            case PolyFillType.pftEvenOdd:
+                            case PolyFillType.pftNonZero:
+                                return (edge.windCnt2 == 0);
+                            case PolyFillType.pftPositive:
+                                return (edge.windCnt2 <= 0);
+                            default:
+                                return (edge.windCnt2 >= 0);
+                        }
+                    else
+                        switch (pft2)
+                        {
+                            case PolyFillType.pftEvenOdd:
+                            case PolyFillType.pftNonZero:
+                                return (edge.windCnt2 != 0);
+                            case PolyFillType.pftPositive:
+                                return (edge.windCnt2 > 0);
+                            default:
+                                return (edge.windCnt2 < 0);
+                        }
+            }
+            return true;
+        }
+        //------------------------------------------------------------------------------
+
+        private void SetWindingCount(TEdge edge)
+        {
+            TEdge e = edge.prevInAEL;
+            //find the edge of the same polytype that immediately preceeds 'edge' in AEL
+            while (e != null && e.polyType != edge.polyType)
+                e = e.prevInAEL;
+            if (e == null)
+            {
+                edge.windCnt = edge.windDelta;
+                edge.windCnt2 = 0;
+                e = m_ActiveEdges; //ie get ready to calc windCnt2
+            }
+            else if (IsEvenOddFillType(edge))
+            {
+                //even-odd filling ...
+                edge.windCnt = 1;
+                edge.windCnt2 = e.windCnt2;
+                e = e.nextInAEL; //ie get ready to calc windCnt2
+            }
+            else
+            {
+                //nonZero filling ...
+                if (e.windCnt * e.windDelta < 0)
+                {
+                    if (Math.Abs(e.windCnt) > 1)
+                    {
+                        if (e.windDelta * edge.windDelta < 0)
+                            edge.windCnt = e.windCnt;
+                        else
+                            edge.windCnt = e.windCnt + edge.windDelta;
+                    }
+                    else
+                        edge.windCnt = e.windCnt + e.windDelta + edge.windDelta;
+                }
+                else
+                {
+                    if (Math.Abs(e.windCnt) > 1 && e.windDelta * edge.windDelta < 0)
+                        edge.windCnt = e.windCnt;
+                    else if (e.windCnt + edge.windDelta == 0)
+                        edge.windCnt = e.windCnt;
+                    else
+                        edge.windCnt = e.windCnt + edge.windDelta;
+                }
+                edge.windCnt2 = e.windCnt2;
+                e = e.nextInAEL; //ie get ready to calc windCnt2
+            }
+
+            //update windCnt2 ...
+            if (IsEvenOddAltFillType(edge))
+            {
+                //even-odd filling ...
+                while (e != edge)
+                {
+                    edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
+                    e = e.nextInAEL;
+                }
+            }
+            else
+            {
+                //nonZero filling ...
+                while (e != edge)
+                {
+                    edge.windCnt2 += e.windDelta;
+                    e = e.nextInAEL;
+                }
+            }
+        }
+        //------------------------------------------------------------------------------
+
+        private void AddEdgeToSEL(TEdge edge)
+        {
+            //SEL pointers in PEdge are reused to build a list of horizontal edges.
+            //However, we don't need to worry about order with horizontal edge processing.
+            if (m_SortedEdges == null)
+            {
+                m_SortedEdges = edge;
+                edge.prevInSEL = null;
+                edge.nextInSEL = null;
+            }
+            else
+            {
+                edge.nextInSEL = m_SortedEdges;
+                edge.prevInSEL = null;
+                m_SortedEdges.prevInSEL = edge;
+                m_SortedEdges = edge;
+            }
+        }
+        //------------------------------------------------------------------------------
+
+        private void CopyAELToSEL()
+        {
+            TEdge e = m_ActiveEdges;
+            m_SortedEdges = e;
+            while (e != null)
+            {
+                e.prevInSEL = e.prevInAEL;
+                e.nextInSEL = e.nextInAEL;
+                e = e.nextInAEL;
+            }
+        }
+        //------------------------------------------------------------------------------
+
+        private void SwapPositionsInAEL(TEdge edge1, TEdge edge2)
+        {
+            if (edge1.nextInAEL == edge2)
+            {
+                TEdge next = edge2.nextInAEL;
+                if (next != null)
+                    next.prevInAEL = edge1;
+                TEdge prev = edge1.prevInAEL;
+                if (prev != null)
+                    prev.nextInAEL = edge2;
+                edge2.prevInAEL = prev;
+                edge2.nextInAEL = edge1;
+                edge1.prevInAEL = edge2;
+                edge1.nextInAEL = next;
+            }
+            else if (edge2.nextInAEL == edge1)
+            {
+                TEdge next = edge1.nextInAEL;
+                if (next != null)
+                    next.prevInAEL = edge2;
+                TEdge prev = edge2.prevInAEL;
+                if (prev != null)
+                    prev.nextInAEL = edge1;
+                edge1.prevInAEL = prev;
+                edge1.nextInAEL = edge2;
+                edge2.prevInAEL = edge1;
+                edge2.nextInAEL = next;
+            }
+            else
+            {
+                TEdge next = edge1.nextInAEL;
+                TEdge prev = edge1.prevInAEL;
+                edge1.nextInAEL = edge2.nextInAEL;
+                if (edge1.nextInAEL != null)
+                    edge1.nextInAEL.prevInAEL = edge1;
+                edge1.prevInAEL = edge2.prevInAEL;
+                if (edge1.prevInAEL != null)
+                    edge1.prevInAEL.nextInAEL = edge1;
+                edge2.nextInAEL = next;
+                if (edge2.nextInAEL != null)
+                    edge2.nextInAEL.prevInAEL = edge2;
+                edge2.prevInAEL = prev;
+                if (edge2.prevInAEL != null)
+                    edge2.prevInAEL.nextInAEL = edge2;
+            }
+
+            if (edge1.prevInAEL == null)
+                m_ActiveEdges = edge1;
+            else if (edge2.prevInAEL == null)
+                m_ActiveEdges = edge2;
+        }
+        //------------------------------------------------------------------------------
+
+        private void SwapPositionsInSEL(TEdge edge1, TEdge edge2)
+        {
+            if (edge1.nextInSEL == null && edge1.prevInSEL == null)
+                return;
+            if (edge2.nextInSEL == null && edge2.prevInSEL == null)
+                return;
+
+            if (edge1.nextInSEL == edge2)
+            {
+                TEdge next = edge2.nextInSEL;
+                if (next != null)
+                    next.prevInSEL = edge1;
+                TEdge prev = edge1.prevInSEL;
+                if (prev != null)
+                    prev.nextInSEL = edge2;
+                edge2.prevInSEL = prev;
+                edge2.nextInSEL = edge1;
+                edge1.prevInSEL = edge2;
+                edge1.nextInSEL = next;
+            }
+            else if (edge2.nextInSEL == edge1)
+            {
+                TEdge next = edge1.nextInSEL;
+                if (next != null)
+                    next.prevInSEL = edge2;
+                TEdge prev = edge2.prevInSEL;
+                if (prev != null)
+                    prev.nextInSEL = edge1;
+                edge1.prevInSEL = prev;
+                edge1.nextInSEL = edge2;
+                edge2.prevInSEL = edge1;
+                edge2.nextInSEL = next;
+            }
+            else
+            {
+                TEdge next = edge1.nextInSEL;
+                TEdge prev = edge1.prevInSEL;
+                edge1.nextInSEL = edge2.nextInSEL;
+                if (edge1.nextInSEL != null)
+                    edge1.nextInSEL.prevInSEL = edge1;
+                edge1.prevInSEL = edge2.prevInSEL;
+                if (edge1.prevInSEL != null)
+                    edge1.prevInSEL.nextInSEL = edge1;
+                edge2.nextInSEL = next;
+                if (edge2.nextInSEL != null)
+                    edge2.nextInSEL.prevInSEL = edge2;
+                edge2.prevInSEL = prev;
+                if (edge2.prevInSEL != null)
+                    edge2.prevInSEL.nextInSEL = edge2;
+            }
+
+            if (edge1.prevInSEL == null)
+                m_SortedEdges = edge1;
+            else if (edge2.prevInSEL == null)
+                m_SortedE