tidy up clipper related code

This commit is contained in:
Eliot Jones
2020-04-05 17:09:44 +01:00
parent 60595e1341
commit 2998b1b2eb
20 changed files with 3074 additions and 2157 deletions

View File

@@ -4,23 +4,27 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UglyToad.PdfPig.Content;
using UglyToad.PdfPig.Graphics;
using UglyToad.PdfPig.Graphics.Colors;
using UglyToad.PdfPig.Graphics.Core;
using Content;
using Graphics;
using Graphics.Colors;
using Graphics.Core;
/// <inheritdoc />
/// <summary>
///
/// Exports a page as an SVG.
/// </summary>
public class SvgTextExporter : ITextExporter
{
static readonly int rounding = 4;
private const int Rounding = 4;
private static readonly Dictionary<string, string> Fonts = new Dictionary<string, string>()
{
{ "ArialMT", "Arial Rounded MT Bold" }
};
/// <summary>
///
/// Get the page contents as an SVG.
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public string Get(Page page)
{
var builder = new StringBuilder($"<svg width='{page.Width}' height='{page.Height}'><g transform=\"scale(1, 1) translate(0, 0)\">");
@@ -48,24 +52,19 @@
builder.Append("</g></svg>");
return builder.ToString();
}
static readonly Dictionary<string, string> _fonts = new Dictionary<string, string>()
{
{ "ArialMT", "Arial Rounded MT Bold" }
};
private static string LetterToSvg(Letter l, double height)
{
string fontFamily = GetFontFamily(l.FontName, out string style, out string weight);
string rotation = "";
if (l.GlyphRectangle.Rotation != 0)
{
rotation = $" transform='rotate({Math.Round(-l.GlyphRectangle.Rotation, rounding)} {Math.Round(l.GlyphRectangle.BottomLeft.X, rounding)},{Math.Round(height - l.GlyphRectangle.TopLeft.Y, rounding)})'";
rotation = $" transform='rotate({Math.Round(-l.GlyphRectangle.Rotation, Rounding)} {Math.Round(l.GlyphRectangle.BottomLeft.X, Rounding)},{Math.Round(height - l.GlyphRectangle.TopLeft.Y, Rounding)})'";
}
string fontSize = l.FontSize != 1 ? $"font-size='{l.FontSize.ToString("0")}'" : $"style='font-size:{Math.Round(l.GlyphRectangle.Height, 2)}px'";
string fontSize = l.FontSize != 1 ? $"font-size='{l.FontSize:0}'" : $"style='font-size:{Math.Round(l.GlyphRectangle.Height, 2)}px'";
return $"<text x='{Math.Round(l.StartBaseLine.X, rounding)}' y='{Math.Round(height - l.StartBaseLine.Y, rounding)}'{rotation} font-family='{fontFamily}' font-style='{style}' font-weight='{weight}' {fontSize} fill='{ColorToSvg(l.Color)}'>{l.Value}</text>";
return $"<text x='{Math.Round(l.StartBaseLine.X, Rounding)}' y='{Math.Round(height - l.StartBaseLine.Y, Rounding)}'{rotation} font-family='{fontFamily}' font-style='{style}' font-weight='{weight}' {fontSize} fill='{ColorToSvg(l.Color)}'>{l.Value}</text>";
}
private static string GetFontFamily(string fontName, out string style, out string weight)
@@ -79,7 +78,7 @@
if (fontName.Length > 7 && fontName[6] == '+')
{
var split = fontName.Split('+');
if (split[0].All(c => char.IsUpper(c)))
if (split[0].All(char.IsUpper))
{
fontName = split[1];
}
@@ -118,7 +117,7 @@
}
}
if (_fonts.ContainsKey(fontName)) fontName = _fonts[fontName];
if (Fonts.ContainsKey(fontName)) fontName = Fonts[fontName];
return fontName;
}

View File

@@ -4,4 +4,6 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CMYK/@EntryIndexedValue">CMYK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ICC/@EntryIndexedValue">ICC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XY/@EntryIndexedValue">XY</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XY/@EntryIndexedValue">XY</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String></wpf:ResourceDictionary>

View File

@@ -0,0 +1,896 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
//use_lines: Enables open path clipping. Adds a very minor cost to performance.
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System.Collections.Generic;
internal class ClipperBase
{
internal const double Horizontal = -3.4E+38;
internal const int Skip = -2;
internal const int Unassigned = -1;
internal const double Tolerance = 1.0E-20;
internal static bool NearZero(double val) { return (val > -Tolerance) && (val < Tolerance); }
public const long loRange = 0x3FFFFFFF;
public const long hiRange = 0x3FFFFFFFFFFFFFFFL;
internal ClipperLocalMinima m_MinimaList;
internal ClipperLocalMinima m_CurrentLM;
internal List<List<ClipperTEdge>> m_edges = new List<List<ClipperTEdge>>();
internal ClipperScanbeam m_Scanbeam;
internal List<ClipperOutRec> m_PolyOuts;
internal ClipperTEdge m_ActiveEdges;
internal bool m_UseFullRange;
internal bool m_HasOpenPaths;
//------------------------------------------------------------------------------
public bool PreserveCollinear
{
get;
set;
}
//------------------------------------------------------------------------------
public void Swap(ref long val1, ref long val2)
{
long tmp = val1;
val1 = val2;
val2 = tmp;
}
//------------------------------------------------------------------------------
internal static bool IsHorizontal(ClipperTEdge e)
{
return e.Delta.Y == 0;
}
//------------------------------------------------------------------------------
internal bool PointIsVertex(ClipperIntPoint pt, ClipperOutPt pp)
{
ClipperOutPt pp2 = pp;
do
{
if (pp2.Pt == pt) return true;
pp2 = pp2.Next;
}
while (pp2 != pp);
return false;
}
//------------------------------------------------------------------------------
internal bool PointOnLineSegment(ClipperIntPoint pt,
ClipperIntPoint linePt1, ClipperIntPoint linePt2, bool UseFullRange)
{
if (UseFullRange)
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)) &&
((ClipperInt128.Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) ==
ClipperInt128.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(ClipperIntPoint pt, ClipperOutPt pp, bool UseFullRange)
{
ClipperOutPt pp2 = pp;
while (true)
{
if (PointOnLineSegment(pt, pp2.Pt, pp2.Next.Pt, UseFullRange))
return true;
pp2 = pp2.Next;
if (pp2 == pp) break;
}
return false;
}
//------------------------------------------------------------------------------
internal static bool SlopesEqual(ClipperTEdge e1, ClipperTEdge e2, bool UseFullRange)
{
if (UseFullRange)
return ClipperInt128.Int128Mul(e1.Delta.Y, e2.Delta.X) ==
ClipperInt128.Int128Mul(e1.Delta.X, e2.Delta.Y);
else return (long)(e1.Delta.Y) * (e2.Delta.X) ==
(long)(e1.Delta.X) * (e2.Delta.Y);
}
//------------------------------------------------------------------------------
internal static bool SlopesEqual(ClipperIntPoint pt1, ClipperIntPoint pt2,
ClipperIntPoint pt3, bool UseFullRange)
{
if (UseFullRange)
return ClipperInt128.Int128Mul(pt1.Y - pt2.Y, pt2.X - pt3.X) ==
ClipperInt128.Int128Mul(pt1.X - pt2.X, pt2.Y - pt3.Y);
else return
(pt1.Y - pt2.Y) * (pt2.X - pt3.X) - (pt1.X - pt2.X) * (pt2.Y - pt3.Y) == 0;
}
//------------------------------------------------------------------------------
internal static bool SlopesEqual(ClipperIntPoint pt1, ClipperIntPoint pt2,
ClipperIntPoint pt3, ClipperIntPoint pt4, bool UseFullRange)
{
if (UseFullRange)
return ClipperInt128.Int128Mul(pt1.Y - pt2.Y, pt3.X - pt4.X) ==
ClipperInt128.Int128Mul(pt1.X - pt2.X, pt3.Y - pt4.Y);
else return
(pt1.Y - pt2.Y) * (pt3.X - pt4.X) - (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;
m_HasOpenPaths = false;
}
//------------------------------------------------------------------------------
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;
m_HasOpenPaths = false;
}
//------------------------------------------------------------------------------
private void DisposeLocalMinimaList()
{
while (m_MinimaList != null)
{
ClipperLocalMinima tmpLm = m_MinimaList.Next;
m_MinimaList = null;
m_MinimaList = tmpLm;
}
m_CurrentLM = null;
}
//------------------------------------------------------------------------------
void RangeTest(ClipperIntPoint Pt, ref bool useFullRange)
{
if (useFullRange)
{
if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
throw new ClipperException("Coordinate outside allowed range");
}
else if (Pt.X > loRange || Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
{
useFullRange = true;
RangeTest(Pt, ref useFullRange);
}
}
//------------------------------------------------------------------------------
private void InitEdge(ClipperTEdge e, ClipperTEdge eNext,
ClipperTEdge ePrev, ClipperIntPoint pt)
{
e.Next = eNext;
e.Prev = ePrev;
e.Curr = pt;
e.OutIdx = Unassigned;
}
//------------------------------------------------------------------------------
private void InitEdge2(ClipperTEdge e, ClipperPolyType polyType)
{
if (e.Curr.Y >= e.Next.Curr.Y)
{
e.Bot = e.Curr;
e.Top = e.Next.Curr;
}
else
{
e.Top = e.Curr;
e.Bot = e.Next.Curr;
}
SetDx(e);
e.PolyTyp = polyType;
}
//------------------------------------------------------------------------------
private ClipperTEdge FindNextLocMin(ClipperTEdge E)
{
ClipperTEdge E2;
for (; ; )
{
while (E.Bot != E.Prev.Bot || E.Curr == E.Top) E = E.Next;
if (E.Dx != Horizontal && E.Prev.Dx != Horizontal) break;
while (E.Prev.Dx == Horizontal) E = E.Prev;
E2 = E;
while (E.Dx == Horizontal) E = E.Next;
if (E.Top.Y == E.Prev.Bot.Y) continue; //ie just an intermediate horz.
if (E2.Prev.Bot.X < E.Bot.X) E = E2;
break;
}
return E;
}
//------------------------------------------------------------------------------
private ClipperTEdge ProcessBound(ClipperTEdge E, bool LeftBoundIsForward)
{
ClipperTEdge EStart, Result = E;
ClipperTEdge Horz;
if (Result.OutIdx == Skip)
{
//check if there are edges beyond the skip edge in the bound and if so
//create another LocMin and calling ProcessBound once more ...
E = Result;
if (LeftBoundIsForward)
{
while (E.Top.Y == E.Next.Bot.Y) E = E.Next;
while (E != Result && E.Dx == Horizontal) E = E.Prev;
}
else
{
while (E.Top.Y == E.Prev.Bot.Y) E = E.Prev;
while (E != Result && E.Dx == Horizontal) E = E.Next;
}
if (E == Result)
{
if (LeftBoundIsForward) Result = E.Next;
else Result = E.Prev;
}
else
{
//there are more edges in the bound beyond result starting with E
if (LeftBoundIsForward)
E = Result.Next;
else
E = Result.Prev;
ClipperLocalMinima locMin = new ClipperLocalMinima
{
Next = null,
Y = E.Bot.Y,
LeftBound = null,
RightBound = E
};
E.WindDelta = 0;
Result = ProcessBound(E, LeftBoundIsForward);
InsertLocalMinima(locMin);
}
return Result;
}
if (E.Dx == Horizontal)
{
//We need to be careful with open paths because this may not be a
//true local minima (ie E may be following a skip edge).
//Also, consecutive horz. edges may start heading left before going right.
if (LeftBoundIsForward) EStart = E.Prev;
else EStart = E.Next;
if (EStart.Dx == Horizontal) //ie an adjoining horizontal skip edge
{
if (EStart.Bot.X != E.Bot.X && EStart.Top.X != E.Bot.X)
ReverseHorizontal(E);
}
else if (EStart.Bot.X != E.Bot.X)
ReverseHorizontal(E);
}
EStart = E;
if (LeftBoundIsForward)
{
while (Result.Top.Y == Result.Next.Bot.Y && Result.Next.OutIdx != Skip)
Result = Result.Next;
if (Result.Dx == Horizontal && Result.Next.OutIdx != Skip)
{
//nb: at the top of a bound, horizontals are added to the bound
//only when the preceding edge attaches to the horizontal's left vertex
//unless a Skip edge is encountered when that becomes the top divide
Horz = Result;
while (Horz.Prev.Dx == Horizontal) Horz = Horz.Prev;
if (Horz.Prev.Top.X > Result.Next.Top.X) Result = Horz.Prev;
}
while (E != Result)
{
E.NextInLML = E.Next;
if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
ReverseHorizontal(E);
E = E.Next;
}
if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Prev.Top.X)
ReverseHorizontal(E);
Result = Result.Next; //move to the edge just beyond current bound
}
else
{
while (Result.Top.Y == Result.Prev.Bot.Y && Result.Prev.OutIdx != Skip)
Result = Result.Prev;
if (Result.Dx == Horizontal && Result.Prev.OutIdx != Skip)
{
Horz = Result;
while (Horz.Next.Dx == Horizontal) Horz = Horz.Next;
if (Horz.Next.Top.X == Result.Prev.Top.X ||
Horz.Next.Top.X > Result.Prev.Top.X) Result = Horz.Next;
}
while (E != Result)
{
E.NextInLML = E.Prev;
if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
ReverseHorizontal(E);
E = E.Prev;
}
if (E.Dx == Horizontal && E != EStart && E.Bot.X != E.Next.Top.X)
ReverseHorizontal(E);
Result = Result.Prev; //move to the edge just beyond current bound
}
return Result;
}
//------------------------------------------------------------------------------
public bool AddPath(List<ClipperIntPoint> pg, ClipperPolyType polyType, bool Closed)
{
if (!Closed && polyType == ClipperPolyType.Clip)
throw new ClipperException("AddPath: Open paths must be subject.");
int highI = (int)pg.Count - 1;
if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI;
while (highI > 0 && (pg[highI] == pg[highI - 1])) --highI;
if ((Closed && highI < 2) || (!Closed && highI < 1)) return false;
//create a new edge array ...
List<ClipperTEdge> edges = new List<ClipperTEdge>(highI + 1);
for (int i = 0; i <= highI; i++) edges.Add(new ClipperTEdge());
bool IsFlat = true;
//1. Basic (first) edge initialization ...
edges[1].Curr = pg[1];
RangeTest(pg[0], ref m_UseFullRange);
RangeTest(pg[highI], ref m_UseFullRange);
InitEdge(edges[0], edges[1], edges[highI], pg[0]);
InitEdge(edges[highI], edges[0], edges[highI - 1], pg[highI]);
for (int i = highI - 1; i >= 1; --i)
{
RangeTest(pg[i], ref m_UseFullRange);
InitEdge(edges[i], edges[i + 1], edges[i - 1], pg[i]);
}
ClipperTEdge eStart = edges[0];
//2. Remove duplicate vertices, and (when closed) collinear edges ...
ClipperTEdge E = eStart, eLoopStop = eStart;
for (; ; )
{
//nb: allows matching start and end points when not Closed ...
if (E.Curr == E.Next.Curr && (Closed || E.Next != eStart))
{
if (E == E.Next) break;
if (E == eStart) eStart = E.Next;
E = RemoveEdge(E);
eLoopStop = E;
continue;
}
if (E.Prev == E.Next)
break; //only two vertices
else if (Closed &&
SlopesEqual(E.Prev.Curr, E.Curr, E.Next.Curr, m_UseFullRange) &&
(!PreserveCollinear ||
!Pt2IsBetweenPt1AndPt3(E.Prev.Curr, E.Curr, E.Next.Curr)))
{
//Collinear edges are allowed for open paths but in closed paths
//the default is to merge adjacent collinear edges into a single edge.
//However, if the PreserveCollinear property is enabled, only overlapping
//collinear edges (ie spikes) will be removed from closed paths.
if (E == eStart) eStart = E.Next;
E = RemoveEdge(E);
E = E.Prev;
eLoopStop = E;
continue;
}
E = E.Next;
if ((E == eLoopStop) || (!Closed && E.Next == eStart)) break;
}
if ((!Closed && (E == E.Next)) || (Closed && (E.Prev == E.Next)))
return false;
if (!Closed)
{
m_HasOpenPaths = true;
eStart.Prev.OutIdx = Skip;
}
//3. Do second stage of edge initialization ...
E = eStart;
do
{
InitEdge2(E, polyType);
E = E.Next;
if (IsFlat && E.Curr.Y != eStart.Curr.Y) IsFlat = false;
}
while (E != eStart);
//4. Finally, add edge bounds to LocalMinima list ...
//Totally flat paths must be handled differently when adding them
//to LocalMinima list to avoid endless loops etc ...
if (IsFlat)
{
if (Closed) return false;
E.Prev.OutIdx = Skip;
ClipperLocalMinima locMin = new ClipperLocalMinima
{
Next = null,
Y = E.Bot.Y,
LeftBound = null,
RightBound = E
};
locMin.RightBound.Side = ClipperEdgeSide.Right;
locMin.RightBound.WindDelta = 0;
for (; ; )
{
if (E.Bot.X != E.Prev.Top.X) ReverseHorizontal(E);
if (E.Next.OutIdx == Skip) break;
E.NextInLML = E.Next;
E = E.Next;
}
InsertLocalMinima(locMin);
m_edges.Add(edges);
return true;
}
m_edges.Add(edges);
bool leftBoundIsForward;
ClipperTEdge EMin = null;
//workaround to avoid an endless loop in the while loop below when
//open paths have matching start and end points ...
if (E.Prev.Bot == E.Prev.Top) E = E.Next;
for (; ; )
{
E = FindNextLocMin(E);
if (E == EMin) break;
else if (EMin == null) EMin = E;
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
ClipperLocalMinima locMin = new ClipperLocalMinima
{
Next = null,
Y = E.Bot.Y
};
if (E.Dx < E.Prev.Dx)
{
locMin.LeftBound = E.Prev;
locMin.RightBound = E;
leftBoundIsForward = false; //Q.nextInLML = Q.prev
}
else
{
locMin.LeftBound = E;
locMin.RightBound = E.Prev;
leftBoundIsForward = true; //Q.nextInLML = Q.next
}
locMin.LeftBound.Side = ClipperEdgeSide.Left;
locMin.RightBound.Side = ClipperEdgeSide.Right;
if (!Closed) locMin.LeftBound.WindDelta = 0;
else if (locMin.LeftBound.Next == locMin.RightBound)
locMin.LeftBound.WindDelta = -1;
else locMin.LeftBound.WindDelta = 1;
locMin.RightBound.WindDelta = -locMin.LeftBound.WindDelta;
E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
if (E.OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
ClipperTEdge E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
if (E2.OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
if (locMin.LeftBound.OutIdx == Skip)
locMin.LeftBound = null;
else if (locMin.RightBound.OutIdx == Skip)
locMin.RightBound = null;
InsertLocalMinima(locMin);
if (!leftBoundIsForward) E = E2;
}
return true;
}
//------------------------------------------------------------------------------
public bool AddPaths(List<List<ClipperIntPoint>> ppg, ClipperPolyType polyType, bool closed)
{
bool result = false;
for (int i = 0; i < ppg.Count; ++i)
if (AddPath(ppg[i], polyType, closed)) result = true;
return result;
}
//------------------------------------------------------------------------------
internal bool Pt2IsBetweenPt1AndPt3(ClipperIntPoint pt1, ClipperIntPoint pt2, ClipperIntPoint pt3)
{
if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) return false;
else if (pt1.X != pt3.X) return (pt2.X > pt1.X) == (pt2.X < pt3.X);
else return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
}
//------------------------------------------------------------------------------
ClipperTEdge RemoveEdge(ClipperTEdge e)
{
//removes e from double_linked_list (but without removing from memory)
e.Prev.Next = e.Next;
e.Next.Prev = e.Prev;
ClipperTEdge result = e.Next;
e.Prev = null; //flag as removed (see ClipperBase.Clear)
return result;
}
//------------------------------------------------------------------------------
private void SetDx(ClipperTEdge e)
{
e.Delta.X = (e.Top.X - e.Bot.X);
e.Delta.Y = (e.Top.Y - e.Bot.Y);
if (e.Delta.Y == 0) e.Dx = Horizontal;
else e.Dx = (double)(e.Delta.X) / (e.Delta.Y);
}
//---------------------------------------------------------------------------
private void InsertLocalMinima(ClipperLocalMinima newLm)
{
if (m_MinimaList == null)
{
m_MinimaList = newLm;
}
else if (newLm.Y >= m_MinimaList.Y)
{
newLm.Next = m_MinimaList;
m_MinimaList = newLm;
}
else
{
ClipperLocalMinima tmpLm = m_MinimaList;
while (tmpLm.Next != null && (newLm.Y < tmpLm.Next.Y))
tmpLm = tmpLm.Next;
newLm.Next = tmpLm.Next;
tmpLm.Next = newLm;
}
}
//------------------------------------------------------------------------------
internal bool PopLocalMinima(long Y, out ClipperLocalMinima current)
{
current = m_CurrentLM;
if (m_CurrentLM != null && m_CurrentLM.Y == Y)
{
m_CurrentLM = m_CurrentLM.Next;
return true;
}
return false;
}
//------------------------------------------------------------------------------
private void ReverseHorizontal(ClipperTEdge 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.]
Swap(ref e.Top.X, ref e.Bot.X);
}
//------------------------------------------------------------------------------
internal virtual void Reset()
{
m_CurrentLM = m_MinimaList;
if (m_CurrentLM == null) return; //ie nothing to process
//reset all edges ...
m_Scanbeam = null;
ClipperLocalMinima lm = m_MinimaList;
while (lm != null)
{
InsertScanbeam(lm.Y);
ClipperTEdge e = lm.LeftBound;
if (e != null)
{
e.Curr = e.Bot;
e.OutIdx = Unassigned;
}
e = lm.RightBound;
if (e != null)
{
e.Curr = e.Bot;
e.OutIdx = Unassigned;
}
lm = lm.Next;
}
m_ActiveEdges = null;
}
//------------------------------------------------------------------------------
public static ClipperIntRect GetBounds(List<List<ClipperIntPoint>> paths)
{
int i = 0, cnt = paths.Count;
while (i < cnt && paths[i].Count == 0) i++;
if (i == cnt) return new ClipperIntRect(0, 0, 0, 0);
ClipperIntRect result = new ClipperIntRect
{
Left = paths[i][0].X
};
result.Right = result.Left;
result.Top = paths[i][0].Y;
result.Bottom = result.Top;
for (; i < cnt; i++)
for (int j = 0; j < paths[i].Count; j++)
{
if (paths[i][j].X < result.Left) result.Left = paths[i][j].X;
else if (paths[i][j].X > result.Right) result.Right = paths[i][j].X;
if (paths[i][j].Y < result.Top) result.Top = paths[i][j].Y;
else if (paths[i][j].Y > result.Bottom) result.Bottom = paths[i][j].Y;
}
return result;
}
//------------------------------------------------------------------------------
internal void InsertScanbeam(long Y)
{
//single-linked list: sorted descending, ignoring dups.
if (m_Scanbeam == null)
{
m_Scanbeam = new ClipperScanbeam
{
Next = null,
Y = Y
};
}
else if (Y > m_Scanbeam.Y)
{
ClipperScanbeam newSb = new ClipperScanbeam
{
Y = Y,
Next = m_Scanbeam
};
m_Scanbeam = newSb;
}
else
{
ClipperScanbeam sb2 = m_Scanbeam;
while (sb2.Next != null && (Y <= sb2.Next.Y)) sb2 = sb2.Next;
if (Y == sb2.Y) return; //ie ignores duplicates
ClipperScanbeam newSb = new ClipperScanbeam
{
Y = Y,
Next = sb2.Next
};
sb2.Next = newSb;
}
}
//------------------------------------------------------------------------------
internal bool PopScanbeam(out long Y)
{
if (m_Scanbeam == null)
{
Y = 0;
return false;
}
Y = m_Scanbeam.Y;
m_Scanbeam = m_Scanbeam.Next;
return true;
}
//------------------------------------------------------------------------------
internal bool LocalMinimaPending()
{
return (m_CurrentLM != null);
}
//------------------------------------------------------------------------------
internal ClipperOutRec CreateOutRec()
{
ClipperOutRec result = new ClipperOutRec
{
Idx = Unassigned,
IsHole = false,
IsOpen = false,
FirstLeft = null,
Pts = null,
BottomPt = null,
PolyNode = null
};
m_PolyOuts.Add(result);
result.Idx = m_PolyOuts.Count - 1;
return result;
}
//------------------------------------------------------------------------------
internal void DisposeOutRec(int index)
{
ClipperOutRec outRec = m_PolyOuts[index];
outRec.Pts = null;
outRec = null;
m_PolyOuts[index] = null;
}
//------------------------------------------------------------------------------
internal void UpdateEdgeIntoAEL(ref ClipperTEdge e)
{
if (e.NextInLML == null)
throw new ClipperException("UpdateEdgeIntoAEL: invalid call");
ClipperTEdge AelPrev = e.PrevInAEL;
ClipperTEdge AelNext = e.NextInAEL;
e.NextInLML.OutIdx = e.OutIdx;
if (AelPrev != null)
AelPrev.NextInAEL = e.NextInLML;
else m_ActiveEdges = e.NextInLML;
if (AelNext != null)
AelNext.PrevInAEL = e.NextInLML;
e.NextInLML.Side = e.Side;
e.NextInLML.WindDelta = e.WindDelta;
e.NextInLML.WindCnt = e.WindCnt;
e.NextInLML.WindCnt2 = e.WindCnt2;
e = e.NextInLML;
e.Curr = e.Bot;
e.PrevInAEL = AelPrev;
e.NextInAEL = AelNext;
if (!IsHorizontal(e)) InsertScanbeam(e.Top.Y);
}
//------------------------------------------------------------------------------
internal void SwapPositionsInAEL(ClipperTEdge edge1, ClipperTEdge edge2)
{
//check that one or other edge hasn't already been removed from AEL ...
if (edge1.NextInAEL == edge1.PrevInAEL ||
edge2.NextInAEL == edge2.PrevInAEL) return;
if (edge1.NextInAEL == edge2)
{
ClipperTEdge next = edge2.NextInAEL;
if (next != null)
next.PrevInAEL = edge1;
ClipperTEdge 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)
{
ClipperTEdge next = edge1.NextInAEL;
if (next != null)
next.PrevInAEL = edge2;
ClipperTEdge prev = edge2.PrevInAEL;
if (prev != null)
prev.NextInAEL = edge1;
edge1.PrevInAEL = prev;
edge1.NextInAEL = edge2;
edge2.PrevInAEL = edge1;
edge2.NextInAEL = next;
}
else
{
ClipperTEdge next = edge1.NextInAEL;
ClipperTEdge 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;
}
//------------------------------------------------------------------------------
internal void DeleteFromAEL(ClipperTEdge e)
{
ClipperTEdge AelPrev = e.PrevInAEL;
ClipperTEdge AelNext = e.NextInAEL;
if (AelPrev == null && AelNext == null && (e != m_ActiveEdges))
return; //already deleted
if (AelPrev != null)
AelPrev.NextInAEL = AelNext;
else m_ActiveEdges = AelNext;
if (AelNext != null)
AelNext.PrevInAEL = AelPrev;
e.NextInAEL = null;
e.PrevInAEL = null;
}
//------------------------------------------------------------------------------
} //end ClipperBase
//------------------------------------------------------------------------------
} //end ClipperLib namespace

View File

@@ -0,0 +1,127 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal enum ClipperClipType : byte
{
Intersection = 0,
Union = 1,
Difference = 2,
Xor = 3
}
internal enum ClipperDirection : byte
{
RightToLeft = 0,
LeftToRight = 1
}
internal enum ClipperEdgeSide : byte
{
Left = 0,
Right = 1
}
internal enum ClipperEndType : byte
{
ClosedPolygon = 0,
ClosedLine = 1,
OpenButt = 2,
OpenSquare = 3,
OpenRound = 4
}
internal enum ClipperJoinType : byte
{
Square = 0,
Round = 1,
Miter = 2
}
/// <summary>
/// By far the most widely used winding rules for polygon filling are
/// EvenOdd and 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
/// </summary>
internal enum ClipperPolyFillType : byte
{
EvenOdd = 0,
NonZero = 1,
}
internal enum ClipperPolyType : byte
{
Subject = 0,
Clip = 1
}
}

View File

@@ -0,0 +1,82 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System;
internal class ClipperException : Exception
{
public ClipperException(string description) : base(description)
{
}
}
}

View File

@@ -0,0 +1,223 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
//------------------------------------------------------------------------------
// Int128 struct (enables safe math on signed 64bit integers)
// eg Int128 val1((long)9223372036854775807); //ie 2^63 -1
// Int128 val2((long)9223372036854775807);
// Int128 val3 = val1 * val2;
// val3.ToString => "85070591730234615847396907784232501249" (8.5e+37)
//------------------------------------------------------------------------------
internal struct ClipperInt128
{
private long hi;
private ulong lo;
public ClipperInt128(long _lo)
{
lo = (ulong)_lo;
if (_lo < 0) hi = -1;
else hi = 0;
}
public ClipperInt128(long _hi, ulong _lo)
{
lo = _lo;
hi = _hi;
}
public ClipperInt128(ClipperInt128 val)
{
hi = val.hi;
lo = val.lo;
}
public bool IsNegative()
{
return hi < 0;
}
public static bool operator ==(ClipperInt128 val1, ClipperInt128 val2)
{
if ((object) val1 == (object) val2)
{
return true;
}
return (val1.hi == val2.hi && val1.lo == val2.lo);
}
public static bool operator !=(ClipperInt128 val1, ClipperInt128 val2)
{
return !(val1 == val2);
}
public override bool Equals(object obj)
{
if (!(obj is ClipperInt128 i128))
{
return false;
}
return (i128.hi == hi && i128.lo == lo);
}
public override int GetHashCode()
{
return hi.GetHashCode() ^ lo.GetHashCode();
}
public static bool operator >(ClipperInt128 val1, ClipperInt128 val2)
{
if (val1.hi != val2.hi)
return val1.hi > val2.hi;
else
return val1.lo > val2.lo;
}
public static bool operator <(ClipperInt128 val1, ClipperInt128 val2)
{
if (val1.hi != val2.hi)
return val1.hi < val2.hi;
else
return val1.lo < val2.lo;
}
public static ClipperInt128 operator +(ClipperInt128 lhs, ClipperInt128 rhs)
{
lhs.hi += rhs.hi;
lhs.lo += rhs.lo;
if (lhs.lo < rhs.lo) lhs.hi++;
return lhs;
}
public static ClipperInt128 operator -(ClipperInt128 lhs, ClipperInt128 rhs)
{
return lhs + -rhs;
}
public static ClipperInt128 operator -(ClipperInt128 val)
{
if (val.lo == 0)
return new ClipperInt128(-val.hi, 0);
else
return new ClipperInt128(~val.hi, ~val.lo + 1);
}
public static explicit operator double(ClipperInt128 val)
{
const double shift64 = 18446744073709551616.0; //2^64
if (val.hi < 0)
{
if (val.lo == 0)
{
return (double)val.hi * shift64;
}
return -(double)(~val.lo + ~val.hi * shift64);
}
return (double)(val.lo + val.hi * shift64);
}
//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 ClipperInt128 Int128Mul(long lhs, long rhs)
{
bool negate = (lhs < 0) != (rhs < 0);
if (lhs < 0) lhs = -lhs;
if (rhs < 0) rhs = -rhs;
ulong int1Hi = (ulong)lhs >> 32;
ulong int1Lo = (ulong)lhs & 0xFFFFFFFF;
ulong int2Hi = (ulong)rhs >> 32;
ulong int2Lo = (ulong)rhs & 0xFFFFFFFF;
//nb: see comments in clipper.pas
ulong a = int1Hi * int2Hi;
ulong b = int1Lo * int2Lo;
ulong c = int1Hi * int2Lo + int1Lo * int2Hi;
ulong lo;
long hi;
hi = (long)(a + (c >> 32));
unchecked { lo = (c << 32) + b; }
if (lo < b) hi++;
ClipperInt128 result = new ClipperInt128(hi, lo);
return negate ? -result : result;
}
}
}

View File

@@ -0,0 +1,96 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal struct ClipperIntRect
{
public long Left;
public long Top;
public long Right;
public long Bottom;
public ClipperIntRect(long l, long t, long r, long b)
{
Left = l;
Top = t;
Right = r;
Bottom = b;
}
public ClipperIntRect(ClipperIntRect ir) : this(ir.Left, ir.Top, ir.Right, ir.Bottom)
{
}
}
}

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System.Collections.Generic;
internal class ClipperIntersectNode
{
internal ClipperTEdge Edge1;
internal ClipperTEdge Edge2;
internal ClipperIntPoint Pt;
}
internal class ClipperIntersectNodeSort : IComparer<ClipperIntersectNode>
{
public int Compare(ClipperIntersectNode node1, ClipperIntersectNode node2)
{
long i = node2.Pt.Y - node1.Pt.Y;
if (i > 0) return 1;
return i < 0 ? -1 : 0;
}
}
}

View File

@@ -0,0 +1,80 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperJoin
{
public ClipperOutPt OutPt1;
public ClipperOutPt OutPt2;
public ClipperIntPoint OffPt;
}
}

View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperLocalMinima
{
public long Y;
public ClipperTEdge LeftBound;
public ClipperTEdge RightBound;
public ClipperLocalMinima Next;
}
}

View File

@@ -0,0 +1,80 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperMaxima
{
public long X;
public ClipperMaxima Next;
public ClipperMaxima Previous;
}
}

View File

@@ -0,0 +1,189 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System;
using System.Collections.Generic;
internal class ClipperOffset
{
private const double DefArcTolerance = 0.25;
private ClipperIntPoint lowest;
private readonly ClipperPolyNode polyNodes = new ClipperPolyNode();
public double ArcTolerance { get; set; }
public double MiterLimit { get; set; }
public ClipperOffset(
double miterLimit = 2.0, double arcTolerance = DefArcTolerance)
{
MiterLimit = miterLimit;
ArcTolerance = arcTolerance;
lowest.X = -1;
}
public void Clear()
{
polyNodes.Children.Clear();
lowest.X = -1;
}
public void AddPath(List<ClipperIntPoint> path, ClipperJoinType joinType, ClipperEndType endType)
{
var highI = path.Count - 1;
if (highI < 0) return;
var newNode = new ClipperPolyNode
{
JoinType = joinType,
EndType = endType
};
//strip duplicate points from path and also get index to the lowest point ...
if (endType == ClipperEndType.ClosedLine || endType == ClipperEndType.ClosedPolygon)
{
while (highI > 0 && path[0] == path[highI])
{
highI--;
}
}
newNode.Polygon.Capacity = highI + 1;
newNode.Polygon.Add(path[0]);
int j = 0, k = 0;
for (var i = 1; i <= highI; i++)
if (newNode.Polygon[j] != path[i])
{
j++;
newNode.Polygon.Add(path[i]);
if (path[i].Y > newNode.Polygon[k].Y ||
(path[i].Y == newNode.Polygon[k].Y &&
path[i].X < newNode.Polygon[k].X)) k = j;
}
if (endType == ClipperEndType.ClosedPolygon && j < 2)
{
return;
}
polyNodes.AddChild(newNode);
//if this path's lowest pt is lower than all the others then update m_lowest
if (endType != ClipperEndType.ClosedPolygon)
{
return;
}
if (lowest.X < 0)
{
lowest = new ClipperIntPoint(polyNodes.ChildCount - 1, k);
}
else
{
var ip = polyNodes.Children[(int)lowest.X].Polygon[(int)lowest.Y];
if (newNode.Polygon[k].Y > ip.Y ||
(newNode.Polygon[k].Y == ip.Y &&
newNode.Polygon[k].X < ip.X))
{
lowest = new ClipperIntPoint(polyNodes.ChildCount - 1, k);
}
}
}
public void AddPaths(List<List<ClipperIntPoint>> paths, ClipperJoinType joinType, ClipperEndType endType)
{
foreach (var p in paths)
{
AddPath(p, joinType, endType);
}
}
public static long Round(double value) => value < 0 ? (long)(value - 0.5) : (long)(value + 0.5);
public static ClipperDoublePoint GetUnitNormal(ClipperIntPoint pt1, ClipperIntPoint pt2)
{
double dx = (pt2.X - pt1.X);
double dy = (pt2.Y - pt1.Y);
if ((dx == 0) && (dy == 0))
{
return new ClipperDoublePoint();
}
var f = 1 * 1.0 / Math.Sqrt(dx * dx + dy * dy);
dx *= f;
dy *= f;
return new ClipperDoublePoint(dy, -dx);
}
}
}

View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperOutPt
{
public int Index;
public ClipperIntPoint Pt;
public ClipperOutPt Next;
public ClipperOutPt Prev;
}
}

View File

@@ -0,0 +1,88 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
/// <summary>
/// OutRec: contains a path in the clipping solution. Edges in the AEL will
/// carry a pointer to an OutRec when they are part of the clipping solution.
/// </summary>
internal class ClipperOutRec
{
public int Idx;
public bool IsHole;
public bool IsOpen;
public ClipperOutRec FirstLeft; //see comments in clipper.pas
public ClipperOutPt Pts;
public ClipperOutPt BottomPt;
public ClipperPolyNode PolyNode;
}
}

View File

@@ -0,0 +1,141 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal struct ClipperDoublePoint
{
public double X;
public double Y;
public ClipperDoublePoint(double x, double y)
{
X = x;
Y = y;
}
public ClipperDoublePoint(ClipperDoublePoint dp) : this(dp.X, dp.Y)
{
}
public ClipperDoublePoint(ClipperIntPoint ip) : this(ip.X, ip.Y)
{
}
}
internal struct ClipperIntPoint
{
public long X;
public long Y;
public ClipperIntPoint(long x, long y)
{
X = x;
Y = y;
}
public ClipperIntPoint(double x, double y) : this((long)x, (long)y)
{
}
public ClipperIntPoint(ClipperIntPoint pt) : this(pt.X, pt.Y)
{
}
public static bool operator ==(ClipperIntPoint a, ClipperIntPoint b) => a.X == b.X && a.Y == b.Y;
public static bool operator !=(ClipperIntPoint a, ClipperIntPoint b) => a.X != b.X || a.Y != b.Y;
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is ClipperIntPoint a)
{
return (X == a.X) && (Y == a.Y);
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,179 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
using System.Collections.Generic;
internal class ClipperPolyTree : ClipperPolyNode
{
internal List<ClipperPolyNode> AllPolys = new List<ClipperPolyNode>();
public void Clear()
{
for (var i = 0; i < AllPolys.Count; i++)
{
AllPolys[i] = null;
}
AllPolys.Clear();
Children.Clear();
}
public ClipperPolyNode GetFirst()
{
if (Children.Count > 0)
{
return Children[0];
}
return null;
}
public int Total
{
get
{
int result = AllPolys.Count;
//with negative offsets, ignore the hidden outer polygon ...
if (result > 0 && Children[0] != AllPolys[0])
{
result--;
}
return result;
}
}
}
internal class ClipperPolyNode
{
public ClipperPolyNode Parent { get; set; }
internal List<ClipperIntPoint> Polygon = new List<ClipperIntPoint>();
internal int Index;
internal ClipperJoinType JoinType;
internal ClipperEndType EndType;
internal List<ClipperPolyNode> Children = new List<ClipperPolyNode>();
public bool IsHole => IsHoleNode();
public bool IsOpen { get; set; }
private bool IsHoleNode()
{
bool result = true;
ClipperPolyNode node = Parent;
while (node != null)
{
result = !result;
node = node.Parent;
}
return result;
}
public int ChildCount => Children.Count;
public List<ClipperIntPoint> Contour => Polygon;
internal void AddChild(ClipperPolyNode child)
{
int cnt = Children.Count;
Children.Add(child);
child.Parent = this;
child.Index = cnt;
}
public ClipperPolyNode GetNext()
{
if (Children.Count > 0)
{
return Children[0];
}
return GetNextSiblingUp();
}
internal ClipperPolyNode GetNextSiblingUp()
{
if (Parent == null)
{
return null;
}
if (Index == Parent.Children.Count - 1)
{
return Parent.GetNextSiblingUp();
}
return Parent.Children[Index + 1];
}
}
}

View File

@@ -0,0 +1,79 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperScanbeam
{
public long Y;
public ClipperScanbeam Next;
}
}

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* 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. *
* *
*******************************************************************************/
/*******************************************************************************
* Boost Software License - Version 1.0 - August 17th, 2003 *
* *
* Permission is hereby granted, free of charge, to any person or organization *
* obtaining a copy of the software and accompanying documentation covered by *
* this license (the "Software") 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. *
*******************************************************************************/
/*******************************************************************************
* *
* Code modified for PdfPig *
* *
*******************************************************************************/
namespace UglyToad.PdfPig.Geometry.ClipperLibrary
{
internal class ClipperTEdge
{
internal ClipperIntPoint Bot;
internal ClipperIntPoint Curr; //current (updated for every new scanbeam)
internal ClipperIntPoint Top;
internal ClipperIntPoint Delta;
internal double Dx;
internal ClipperPolyType PolyTyp;
internal ClipperEdgeSide Side; //side only refers to current side of solution poly
internal int WindDelta; //1 or -1 depending on winding direction
internal int WindCnt;
internal int WindCnt2; //winding count of the opposite polytype
internal int OutIdx;
internal ClipperTEdge Next;
internal ClipperTEdge Prev;
internal ClipperTEdge NextInLML;
internal ClipperTEdge NextInAEL;
internal ClipperTEdge PrevInAEL;
internal ClipperTEdge NextInSEL;
internal ClipperTEdge PrevInSEL;
}
}

View File

@@ -3,33 +3,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UglyToad.PdfPig.Core;
using UglyToad.PdfPig.Graphics;
using static UglyToad.PdfPig.Core.PdfSubpath;
using ClipperLibrary;
using Core;
using Graphics;
using static Core.PdfSubpath;
/// <summary>
///
/// Applies clipping from a clipping path to another path.
/// </summary>
internal static class Clipping
internal static class ClippingExtensions
{
const double factor = 10_000.0;
const int linesInCurve = 10; // number of lines to use when transforming bezier curve to polyline.
private const double Factor = 10_000.0;
/// <summary>
/// Number of lines to use when transforming bezier curve to polyline.
/// </summary>
private const int LinesInCurve = 10;
/// <summary>
/// Generates the result of applying a clipping path to another path.
/// </summary>
public static PdfPath Clip(this PdfPath clipping, PdfPath subject)
{
if (clipping == null)
{
throw new ArgumentNullException(nameof(clipping), "Clip(): the clipping path cannot be null.");
throw new ArgumentNullException(nameof(clipping), $"{nameof(Clip)}: the clipping path cannot be null.");
}
if (!clipping.IsClipping)
{
throw new ArgumentException("Clip(): the clipping path does not have the IsClipping flag set to true.", nameof(clipping));
throw new ArgumentException($"{nameof(Clip)}: the clipping path does not have the IsClipping flag set to true.", nameof(clipping));
}
if (subject == null)
{
throw new ArgumentNullException(nameof(subject), "Clip(): the subject path cannot be null.");
throw new ArgumentNullException(nameof(subject), $"{nameof(Clip)}: the subject path cannot be null.");
}
if (subject.Count == 0)
@@ -37,7 +45,7 @@
return subject;
}
Clipper clipper = new Clipper();
var clipper = new Clipper();
// Clipping path
foreach (var subPathClipping in clipping)
@@ -53,7 +61,7 @@
subPathClipping.CloseSubpath();
}
clipper.AddPath(subPathClipping.ToClipperPolygon().ToList(), PolyType.ptClip, true);
clipper.AddPath(subPathClipping.ToClipperPolygon().ToList(), ClipperPolyType.Clip, true);
}
// Subject path
@@ -72,36 +80,41 @@
subPathSubject.CloseSubpath();
}
clipper.AddPath(subPathSubject.ToClipperPolygon().ToList(), PolyType.ptSubject, subjectClose);
clipper.AddPath(subPathSubject.ToClipperPolygon().ToList(), ClipperPolyType.Subject, subjectClose);
}
var clippingFillType = clipping.FillingRule == FillingRule.NonZeroWinding ? PolyFillType.pftNonZero : PolyFillType.pftEvenOdd;
var subjectFillType = subject.FillingRule == FillingRule.NonZeroWinding ? PolyFillType.pftNonZero : PolyFillType.pftEvenOdd;
var clippingFillType = clipping.FillingRule == FillingRule.NonZeroWinding ? ClipperPolyFillType.NonZero : ClipperPolyFillType.EvenOdd;
var subjectFillType = subject.FillingRule == FillingRule.NonZeroWinding ? ClipperPolyFillType.NonZero : ClipperPolyFillType.EvenOdd;
if (!subjectClose)
{
PdfPath clippedPath = subject.CloneEmpty();
// Case where subject is not closed
var solutions = new PolyTree();
if (clipper.Execute(ClipType.ctIntersection, solutions, subjectFillType, clippingFillType))
var solutions = new ClipperPolyTree();
if (clipper.Execute(ClipperClipType.Intersection, solutions, subjectFillType, clippingFillType))
{
foreach (var solution in solutions.Childs)
foreach (var solution in solutions.Children)
{
if (solution.Contour.Count > 0)
{
PdfSubpath clippedSubpath = new PdfSubpath();
clippedSubpath.MoveTo(solution.Contour[0].X / factor, solution.Contour[0].Y / factor);
clippedSubpath.MoveTo(solution.Contour[0].X / Factor, solution.Contour[0].Y / Factor);
for (int i = 1; i < solution.Contour.Count; i++)
{
clippedSubpath.LineTo(solution.Contour[i].X / factor, solution.Contour[i].Y / factor);
clippedSubpath.LineTo(solution.Contour[i].X / Factor, solution.Contour[i].Y / Factor);
}
clippedPath.Add(clippedSubpath);
}
}
if (clippedPath.Count > 0) return clippedPath;
if (clippedPath.Count > 0)
{
return clippedPath;
}
}
return null;
}
else
@@ -109,34 +122,42 @@
PdfPath clippedPath = subject.CloneEmpty();
// Case where subject is closed
var solutions = new List<List<IntPoint>>();
if (clipper.Execute(ClipType.ctIntersection, solutions, subjectFillType, clippingFillType))
var solutions = new List<List<ClipperIntPoint>>();
if (!clipper.Execute(ClipperClipType.Intersection, solutions, subjectFillType, clippingFillType))
{
foreach (var solution in solutions)
{
if (solution.Count > 0)
{
PdfSubpath clippedSubpath = new PdfSubpath();
clippedSubpath.MoveTo(solution[0].X / factor, solution[0].Y / factor);
for (int i = 1; i < solution.Count; i++)
{
clippedSubpath.LineTo(solution[i].X / factor, solution[i].Y / factor);
}
clippedSubpath.CloseSubpath();
clippedPath.Add(clippedSubpath);
}
}
if (clippedPath.Count > 0) return clippedPath;
return null;
}
foreach (var solution in solutions)
{
if (solution.Count > 0)
{
PdfSubpath clippedSubpath = new PdfSubpath();
clippedSubpath.MoveTo(solution[0].X / Factor, solution[0].Y / Factor);
for (int i = 1; i < solution.Count; i++)
{
clippedSubpath.LineTo(solution[i].X / Factor, solution[i].Y / Factor);
}
clippedSubpath.CloseSubpath();
clippedPath.Add(clippedSubpath);
}
}
if (clippedPath.Count > 0)
{
return clippedPath;
}
return null;
}
}
/// <summary>
/// Converts a path to a set of points for the Clipper algorithm to use.
/// Allows duplicate points as they will be removed by Clipper.
/// </summary>
private static IEnumerable<IntPoint> ToClipperPolygon(this PdfSubpath pdfPath)
private static IEnumerable<ClipperIntPoint> ToClipperPolygon(this PdfSubpath pdfPath)
{
if (pdfPath.Commands.Count == 0)
{
@@ -145,38 +166,44 @@
if (pdfPath.Commands[0] is Move currentMove)
{
var previous = new IntPoint(currentMove.Location.X * factor, currentMove.Location.Y * factor);
var previous = new ClipperIntPoint(currentMove.Location.X * Factor, currentMove.Location.Y * Factor);
yield return previous;
if (pdfPath.Commands.Count == 1) yield break;
if (pdfPath.Commands.Count == 1)
{
yield break;
}
}
else
{
throw new ArgumentException("ToClipperPolygon(): First command is not a Move command. Type is '" + pdfPath.Commands[0].GetType().ToString() + "'.", nameof(pdfPath));
throw new ArgumentException($"ToClipperPolygon(): First command is not a Move command. Type is '{pdfPath.Commands[0].GetType()}'.", nameof(pdfPath));
}
for (int i = 1; i < pdfPath.Commands.Count; i++)
for (var i = 1; i < pdfPath.Commands.Count; i++)
{
var command = pdfPath.Commands[i];
if (command is Move move)
if (command is Move)
{
throw new ArgumentException("ToClipperPolygon():only one move allowed per subpath.", nameof(pdfPath));
}
else if (command is Line line)
if (command is Line line)
{
yield return new IntPoint(line.From.X * factor, line.From.Y * factor);
yield return new IntPoint(line.To.X * factor, line.To.Y * factor);
yield return new ClipperIntPoint(line.From.X * Factor, line.From.Y * Factor);
yield return new ClipperIntPoint(line.To.X * Factor, line.To.Y * Factor);
}
else if (command is BezierCurve curve)
{
foreach (var lineB in curve.ToLines(linesInCurve))
foreach (var lineB in curve.ToLines(LinesInCurve))
{
yield return new IntPoint(lineB.From.X * factor, lineB.From.Y * factor);
yield return new IntPoint(lineB.To.X * factor, lineB.To.Y * factor);
yield return new ClipperIntPoint(lineB.From.X * Factor, lineB.From.Y * Factor);
yield return new ClipperIntPoint(lineB.To.X * Factor, lineB.To.Y * Factor);
}
}
else if (command is Close)
{
yield return new IntPoint(currentMove.Location.X * factor, currentMove.Location.Y * factor);
yield return new ClipperIntPoint(currentMove.Location.X * Factor, currentMove.Location.Y * Factor);
}
}
}