Skip to content

Commit

Permalink
Proposed clean-ups (#894)
Browse files Browse the repository at this point in the history
This is a partial set of clean-ups. There could be others, but they may be controversial (e.g. adopting LINQ in some areas, which may or may not hurt performance). I've also tried to be mindful of target framework versions and also some edge cases (e.g. hashing) where seemingly redundant chunks of code, if removed or changed for another option, may blow things up.

See what you think.
  • Loading branch information
philstopford authored Sep 30, 2024
1 parent 20bd694 commit 80ef1fd
Show file tree
Hide file tree
Showing 13 changed files with 421 additions and 426 deletions.
6 changes: 3 additions & 3 deletions CSharp/Clipper2Lib.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public void GlobalSetup()
{
Random rand = new ();

_subj = new ();
_clip = new ();
_solution = new ();
_subj = new Paths64();
_clip = new Paths64();
_solution = new Paths64();

_subj.Add(MakeRandomPath(DisplayWidth, DisplayHeight, EdgeCount, rand));
_clip.Add(MakeRandomPath(DisplayWidth, DisplayHeight, EdgeCount, rand));
Expand Down
2 changes: 1 addition & 1 deletion CSharp/Clipper2Lib.Benchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Clipper2Lib.Benchmark
{
public class Program
public static class Program
{
public static void Main()
{
Expand Down
62 changes: 29 additions & 33 deletions CSharp/Clipper2Lib.Examples/ConsoleDemo/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace ClipperDemo1
{
public class Application
public static class Application
{
public static void Main()
{
Expand All @@ -32,7 +32,7 @@ public static Paths64 Polytree_Union(Paths64 subjects, FillRule fillrule)
{
// of course this function is inefficient,
// but it's purpose is simply to test polytrees.
PolyTree64 polytree = new PolyTree64();
PolyTree64 polytree = new();
Clipper.BooleanOp(ClipType.Union, subjects, null, polytree, fillrule);
return Clipper.PolyTreeToPaths64(polytree);
}
Expand All @@ -41,7 +41,7 @@ public static void SquaresTest(bool test_polytree = false)
{
const int size = 10;
const int w = 800, h = 600;
FillRule fillrule = FillRule.NonZero;
const FillRule fillrule = FillRule.NonZero;

Path64 shape = Clipper.MakePath(new int[] { 0, 0, size, 0, size, size, 0, size });
Paths64 subjects = new(), solution;
Expand All @@ -61,10 +61,10 @@ public static void SquaresTest(bool test_polytree = false)
else
solution = Clipper.Union(subjects, fillrule);

SvgWriter svg = new SvgWriter();
SvgWriter svg = new();
SvgUtils.AddSubject(svg, subjects);
SvgUtils.AddSolution(svg, solution, false);
string filename = @"..\..\..\squares.svg";
const string filename = @"..\..\..\squares.svg";
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
ClipperFileIO.OpenFileWithDefaultApp(filename);
}
Expand All @@ -73,7 +73,7 @@ public static void TrianglesTest(bool test_polytree = false)
{
const int size = 10;
const int w = 800, h = 600;
FillRule fillrule = FillRule.NonZero;
const FillRule fillrule = FillRule.NonZero;

Path64 tri1 = Clipper.MakePath(new int[] { 0,0, size * 2,0, size,size * 2 });
Path64 tri2 = Clipper.MakePath(new int[] { size * 2, 0, size, size * 2, size*3, size*2 });
Expand All @@ -98,10 +98,10 @@ public static void TrianglesTest(bool test_polytree = false)
else
solution = Clipper.Union(subjects, fillrule);

SvgWriter svg = new SvgWriter();
SvgWriter svg = new();
SvgUtils.AddSubject(svg, subjects);
SvgUtils.AddSolution(svg, solution, false);
string filename = @"..\..\..\triangles.svg";
const string filename = @"..\..\..\triangles.svg";
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
ClipperFileIO.OpenFileWithDefaultApp(filename);
}
Expand All @@ -110,7 +110,7 @@ public static void DiamondsTest(bool test_polytree = false)
{
const int size = 10;
const int w = 800, h = 600;
FillRule fillrule = FillRule.NonZero;
const FillRule fillrule = FillRule.NonZero;

Path64 shape = Clipper.MakePath(new int[] { size, 0, size * 2, size, size, size * 2, 0, size });
Paths64 subjects = new(), solution;
Expand All @@ -133,36 +133,34 @@ public static void DiamondsTest(bool test_polytree = false)
else
solution = Clipper.Union(subjects, fillrule);

SvgWriter svg = new SvgWriter();
SvgWriter svg = new();
SvgUtils.AddSubject(svg, subjects);
SvgUtils.AddSolution(svg, solution, false);
string filename = @"..\..\..\diamonds.svg";
const string filename = @"..\..\..\diamonds.svg";
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
ClipperFileIO.OpenFileWithDefaultApp(filename);
}

public static void LoopThruTestPolygons(int start = 0, int end = 0)
{
Paths64 subject = new Paths64();
Paths64 subject_open = new Paths64();
Paths64 clip = new Paths64();
Paths64 solution = new Paths64();
Paths64 solution_open = new Paths64();
ClipType ct;
FillRule fr;
Paths64 subject = new();
Paths64 subject_open = new();
Paths64 clip = new();
Paths64 solution = new();
Paths64 solution_open = new();
bool do_all = (start == 0 && end == 0);
if (do_all) { start = 1; end = 0xFFFF; }
else if (end == 0) end = start;

if (do_all)
Console.WriteLine("\nCount and area differences (expected vs measured):\n");
int test_number = start;
int test_number = start;
for (; test_number <= end; ++test_number)
{
if (!ClipperFileIO.LoadTestNum(@"..\..\..\..\..\..\Tests\Polygons.txt",
test_number, subject, subject_open, clip,
out ct, out fr, out long area, out int cnt, out _)) break;
Clipper64 c64 = new Clipper64();
test_number, subject, subject_open, clip,
out ClipType ct, out FillRule fr, out long area, out int cnt, out _)) break;
Clipper64 c64 = new();
c64.AddSubject(subject);
c64.AddOpenSubject(subject_open);
c64.AddClip(clip);
Expand All @@ -179,15 +177,15 @@ public static void LoopThruTestPolygons(int start = 0, int end = 0)
double area_diff = area <= 0 ? 0 : Math.Abs(measuredArea / area -1.0);

if (count_diff > 0.05)
Console.WriteLine(string.Format("{0}: count {1} vs {2}", test_number, cnt, measuredCnt));
Console.WriteLine($"{test_number}: count {cnt} vs {measuredCnt}");
if (area_diff > 0.1)
Console.WriteLine(string.Format("{0}: area {1} vs {2}", test_number, area, measuredArea));
Console.WriteLine($"{test_number}: area {area} vs {measuredArea}");

// don't display when looping through every test
continue;
}

SvgWriter svg = new SvgWriter();
SvgWriter svg = new();
SvgUtils.AddSubject(svg, subject);
SvgUtils.AddClip(svg, clip);
if (fr == FillRule.Negative)
Expand All @@ -199,11 +197,9 @@ public static void LoopThruTestPolygons(int start = 0, int end = 0)
ClipperFileIO.OpenFileWithDefaultApp(filename);
}

if (do_all)
{
Console.WriteLine(string.Format("\ntest ended at polygon {0}.\n", test_number));
Console.ReadKey();
}
if (!do_all) return;
Console.WriteLine($"\ntest ended at polygon {test_number}.\n");
Console.ReadKey();
}

public static Paths64 LoadPathsFromResource(string resourceName)
Expand Down Expand Up @@ -231,7 +227,7 @@ public static Paths64 LoadPathsFromResource(string resourceName)

public static void ClipTestPolys()
{
FillRule fillrule = FillRule.NonZero;
const FillRule fillrule = FillRule.NonZero;
Paths64 subject = LoadPathsFromResource("ConsoleDemo.subj.bin");
Paths64 clip = LoadPathsFromResource("ConsoleDemo.clip.bin");
Paths64 solution = Clipper.Intersect(subject, clip, fillrule);
Expand All @@ -240,8 +236,8 @@ public static void ClipTestPolys()
SvgUtils.AddSubject(svg, subject);
SvgUtils.AddClip(svg, clip);
SvgUtils.AddSolution(svg, solution, false);
SvgUtils.SaveToFile(svg, "..\\..\\..\\clipperD.svg", fillrule, 800, 600, 20);
ClipperFileIO.OpenFileWithDefaultApp("..\\..\\..\\clipperD.svg");
SvgUtils.SaveToFile(svg, @"..\..\..\clipperD.svg", fillrule, 800, 600, 20);
ClipperFileIO.OpenFileWithDefaultApp(@"..\..\..\clipperD.svg");
}


Expand Down
16 changes: 7 additions & 9 deletions CSharp/Clipper2Lib.Examples/InflateDemo/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/

using System;
using System.IO;
using System.Reflection;
using Clipper2Lib;

namespace ClipperDemo1
{

public class Application
public static class Application
{

public static void Main()
Expand All @@ -30,7 +29,7 @@ public static void DoSimpleShapes()
ClipperOffset co = new();

//triangle offset - with large miter
Paths64 p0 = new() { Clipper.MakePath(new int[] { 30,150, 60,350, 0,350 }) };
Paths64 p0 = new() { Clipper.MakePath(new [] { 30,150, 60,350, 0,350 }) };
Paths64 p = new();
for (int i = 0; i < 5; ++i)
{
Expand All @@ -44,7 +43,7 @@ public static void DoSimpleShapes()
//rectangle offset - both squared and rounded
//nb: using the ClipperOffest class directly here to control
//different join types within the same offset operation
p.Add(Clipper.MakePath(new int[] { 100,0, 340,0, 340,200, 100,200, 100, 0 }));
p.Add(Clipper.MakePath(new [] { 100,0, 340,0, 340,200, 100,200, 100, 0 }));
SvgUtils.AddOpenSubject(svg, p);
co.AddPaths(p, JoinType.Bevel, EndType.Joined);

Expand All @@ -57,7 +56,7 @@ public static void DoSimpleShapes()

co.Execute(10, p);

string filename = "../../../inflate.svg";
const string filename = "../../../inflate.svg";
SvgUtils.AddSolution(svg, p, false);
SvgUtils.AddCaption(svg, "Beveled join", 100, -27);
SvgUtils.AddCaption(svg, "Squared join", 160, 23);
Expand All @@ -81,7 +80,7 @@ public static void DoRabbit()
solution.AddRange(pd);
}

string filename = "../../../rabbit.svg";
const string filename = "../../../rabbit.svg";
SvgWriter svg = new ();
SvgUtils.AddSolution(svg, solution, false);
SvgUtils.SaveToFile(svg, filename, FillRule.EvenOdd, 450, 720, 10);
Expand Down Expand Up @@ -118,10 +117,9 @@ public static void DoVariableOffset()
ClipperOffset co = new();
co.AddPaths(p, JoinType.Square, EndType.Butt);
co.Execute(
delegate (Path64 path, PathD path_norms, int currPt, int prevPt)
{ return currPt* currPt + 10; } , solution);
(path, path_norms, currPt, prevPt) => currPt * currPt + 10, solution);

string filename = "../../../variable_offset.svg";
const string filename = "../../../variable_offset.svg";
SvgWriter svg = new();
SvgUtils.AddOpenSubject(svg, p);
SvgUtils.AddSolution(svg, solution, true);
Expand Down
65 changes: 26 additions & 39 deletions CSharp/Clipper2Lib/Clipper.Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -537,13 +537,13 @@ public enum ClipType
Union,
Difference,
Xor
};
}

public enum PathType
{
Subject,
Clip
};
}

// By far the most widely used filling rules for polygons are EvenOdd
// and NonZero, sometimes called Alternate and Winding respectively.
Expand All @@ -554,15 +554,15 @@ public enum FillRule
NonZero,
Positive,
Negative
};
}

// PointInPolygon
internal enum PipResult
{
Inside,
Outside,
OnEdge
};
}

public static class InternalClipper
{
Expand Down Expand Up @@ -612,8 +612,7 @@ internal static bool IsAlmostZero(double value)
internal static int TriSign(long x) // returns 0, 1 or -1
{
if (x < 0) return -1;
else if (x > 1) return 1;
else return 0;
return x > 1 ? 1 : 0;
}

public struct MultiplyUInt64Result
Expand Down Expand Up @@ -725,24 +724,19 @@ public static bool GetSegmentIntersectPt(Point64 ln1a,
internal static bool SegsIntersect(Point64 seg1a,
Point64 seg1b, Point64 seg2a, Point64 seg2b, bool inclusive = false)
{
if (inclusive)
{
double res1 = CrossProduct(seg1a, seg2a, seg2b);
double res2 = CrossProduct(seg1b, seg2a, seg2b);
if (res1 * res2 > 0) return false;
double res3 = CrossProduct(seg2a, seg1a, seg1b);
double res4 = CrossProduct(seg2b, seg1a, seg1b);
if (res3 * res4 > 0) return false;
// ensure NOT collinear
return (res1 != 0 || res2 != 0 || res3 != 0 || res4 != 0);
}
else
{
return (CrossProduct(seg1a, seg2a, seg2b) *
CrossProduct(seg1b, seg2a, seg2b) < 0) &&
(CrossProduct(seg2a, seg1a, seg1b) *
CrossProduct(seg2b, seg1a, seg1b) < 0);
}
if (!inclusive)
return (CrossProduct(seg1a, seg2a, seg2b) *
CrossProduct(seg1b, seg2a, seg2b) < 0) &&
(CrossProduct(seg2a, seg1a, seg1b) *
CrossProduct(seg2b, seg1a, seg1b) < 0);
double res1 = CrossProduct(seg1a, seg2a, seg2b);
double res2 = CrossProduct(seg1b, seg2a, seg2b);
if (res1 * res2 > 0) return false;
double res3 = CrossProduct(seg2a, seg1a, seg1b);
double res4 = CrossProduct(seg2b, seg1a, seg1b);
if (res3 * res4 > 0) return false;
// ensure NOT collinear
return (res1 != 0 || res2 != 0 || res3 != 0 || res4 != 0);
}
public static Point64 GetClosestPtOnSegment(Point64 offPt,
Point64 seg1, Point64 seg2)
Expand Down Expand Up @@ -783,14 +777,14 @@ public static PointInPolygonResult PointInPolygon(Point64 pt, Path64 polygon)
if (isAbove)
{
while (i < end && polygon[i].Y < pt.Y) i++;
if (i == end) continue;
}
else
{
while (i < end && polygon[i].Y > pt.Y) i++;
if (i == end) continue;
}

if (i == end) continue;

Point64 curr = polygon[i], prev;
if (i > 0) prev = polygon[i - 1];
else prev = polygon[len - 1];
Expand Down Expand Up @@ -823,20 +817,13 @@ public static PointInPolygonResult PointInPolygon(Point64 pt, Path64 polygon)
i++;
}

if (isAbove != startingAbove)
{
if (i == len) i = 0;
if (i == 0)
d = CrossProduct(polygon[len - 1], polygon[0], pt);
else
d = CrossProduct(polygon[i - 1], polygon[i], pt);
if (d == 0) return PointInPolygonResult.IsOn;
if ((d < 0) == isAbove) val = 1 - val;
}
if (isAbove == startingAbove) return val == 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
if (i == len) i = 0;
d = i == 0 ? CrossProduct(polygon[len - 1], polygon[0], pt) : CrossProduct(polygon[i - 1], polygon[i], pt);
if (d == 0) return PointInPolygonResult.IsOn;
if ((d < 0) == isAbove) val = 1 - val;

if (val == 0)
return PointInPolygonResult.IsOutside;
return PointInPolygonResult.IsInside;
return val == 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
}

} // InternalClipper
Expand Down
Loading

0 comments on commit 80ef1fd

Please sign in to comment.