Skip to content

Commit

Permalink
Caution: Fixed SimplifyPaths function in C# with confusing parameters
Browse files Browse the repository at this point in the history
Caution: Fixed SimplifyPaths function in Delphi with reversed boolean parameter.
Minor code tidy to SimplifyPaths function.
Reminder: Offsetting open path 'delta' behaviour also changed (ie doubled) recently.
  • Loading branch information
AngusJohnson committed Nov 18, 2023
1 parent 7a481e8 commit 60cd293
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 147 deletions.
29 changes: 15 additions & 14 deletions CPP/Clipper2Lib/include/clipper2/clipper.export.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,35 @@ _______________________________
_______________________________
CPolytree64 and CPolytreeD:
These are also simple arrays consisting of CPolyPath structures.
However, since the very first CPolyPath is the tree container, it has no
path and its structure will be very slightly different from the remaining
These are also simple arrays consisting of CPolyPath structures that
represent individual paths in a tree structure. However, the very first
CPolyPath is just the tree container so it won't have a path. And because
of that, its structure will be very slightly different from the remaining
CPolyPath. This difference will be discussed below.
CPolyPath64 and CPolyPathD:
These are simple arrays consisting path coordinates followed by any number of
child CPolyPath (representing the paths they own). Preceding these are a pair
of values: the length of its path (N); and the number of child CPolyPath (C).
These are simple arrays consisting of a series of path coordinates followed
by any number of child (ie nested) CPolyPath. Preceeding these are two values
indicating the length of the path (N) and the number of child CPolyPath (C).
____________________________________________________________
|counter|coord1|coord2|...|coordN| child1|child2|...|childC|
|N , C |x1, y1|x2, y2|...|xN, yN| |
____________________________________________________________
As mentioned above, the very first CPolyPath structure is just a container
(both directly and indirectly) for every other CPolyPath in the tree. So
where this first CPolyPath has no path, instead of a path length, its first
value contains the total length of the CPolytree array (A).
that owns (both directly and indirectly) every other CPolyPath in the tree.
Since this first CPolyPath has no path, instead of a path length, its first
value will contain the total length of the CPolytree array.
All the exported structures (CPaths64, CPathsD, CPolyTree64 & CPolyTreeD)
are arrays of type int64_t or double. And the first value in these arrays
will always contain the length of that array.
These array structures will be allocated in heap memory, so eventually this
memory will need to be released. But because the applications dynamically
linking to these functions may use a different memory manager, the only
really safe way to free up this memory is to use the exported
DisposeArray64 and DisposeArrayD functions below.
These array structures are allocated in heap memory which will eventually
need to be released. But since applications dynamically linking to these
functions may use different memory managers, the only really safe way to
free up this memory is to use the exported DisposeArray64 and
DisposeArrayD functions below.
*/


Expand Down
32 changes: 15 additions & 17 deletions CPP/Clipper2Lib/include/clipper2/clipper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 1 November 2023 *
* Date : 18 November 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This module provides a simple interface to the Clipper Library *
Expand Down Expand Up @@ -659,7 +659,7 @@ namespace Clipper2Lib {

std::vector<bool> flags(len);
std::vector<double> distSqr(len);
size_t prior = high, curr = 0, start, next, prior2, next2;
size_t prior = high, curr = 0, start, next, prior2;
if (isClosedPath)
{
distSqr[0] = PerpendicDistFromLineSqrd(path[0], path[high], path[1]);
Expand Down Expand Up @@ -689,27 +689,25 @@ namespace Clipper2Lib {
next = GetNext(curr, high, flags);
if (next == prior) break;

// flag for removal the smaller of adjacent 'distances'
if (distSqr[next] < distSqr[curr])
{
flags[next] = true;
next = GetNext(next, high, flags);
next2 = GetNext(next, high, flags);
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
if (next != high || isClosedPath)
distSqr[next] = PerpendicDistFromLineSqrd(path[next], path[curr], path[next2]);
prior2 = prior;
prior = curr;
curr = next;
next = GetNext(next, high, flags);
}
else
{
flags[curr] = true;
curr = next;
next = GetNext(next, high, flags);
prior2 = GetPrior(prior, high, flags);
if (curr != high || isClosedPath)
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
if (prior != 0 || isClosedPath)
distSqr[prior] = PerpendicDistFromLineSqrd(path[prior], path[prior2], path[curr]);
}

flags[curr] = true;
curr = next;
next = GetNext(next, high, flags);

if (isClosedPath || ((curr != high) && (curr != 0)))
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
if (isClosedPath || ((prior != 0) && (prior != high)))
distSqr[prior] = PerpendicDistFromLineSqrd(path[prior], path[prior2], path[curr]);
}
Path<T> result;
result.reserve(len);
Expand Down
17 changes: 8 additions & 9 deletions CPP/Examples/Inflate/Inflate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,41 @@ void DoRabbit();
void DoSimpleShapes();
void System(const std::string& filename);


int main(int argc, char* argv[])
{

DoSimpleShapes();
DoRabbit();

//std::getchar();
}

void DoSimpleShapes()
{
//open path offsets
Paths64 op1, op2;

FillRule fr2 = FillRule::EvenOdd;
SvgWriter svg2;

op1.push_back(MakePath({ 80,60, 20,20, 180,20, 180,70, 25,150, 20,180, 180,180 }));
op2 = InflatePaths(op1, 20, JoinType::Miter, EndType::Square, 3);
op2 = InflatePaths(op1, 15, JoinType::Miter, EndType::Square, 3);
SvgAddOpenSubject(svg2, op1, fr2, false);
SvgAddSolution(svg2, TransformPaths<double, int64_t>(op2), fr2, false);
SvgAddCaption(svg2, "Miter Joins; Square Ends", 20, 210);

op1 = TranslatePaths<int64_t>(op1, 210, 0);
op2 = InflatePaths(op1, 20, JoinType::Square, EndType::Square);
op2 = InflatePaths(op1, 15, JoinType::Square, EndType::Square);
SvgAddOpenSubject(svg2, op1, fr2, false);
SvgAddSolution(svg2, TransformPaths<double, int64_t>(op2), fr2, false);
SvgAddCaption(svg2, "Square Joins; Square Ends", 230, 210);

op1 = TranslatePaths<int64_t>(op1, 210, 0);
op2 = InflatePaths(op1, 20, JoinType::Bevel, EndType::Butt, 3);
op2 = InflatePaths(op1, 15, JoinType::Bevel, EndType::Butt, 3);
SvgAddOpenSubject(svg2, op1, fr2, false);
SvgAddSolution(svg2, TransformPaths<double, int64_t>(op2), fr2, false);
SvgAddCaption(svg2, "Bevel Joins; Butt Ends", 440, 210);

op1 = TranslatePaths<int64_t>(op1, 210, 0);
op2 = InflatePaths(op1, 20, JoinType::Round, EndType::Round);
op2 = InflatePaths(op1, 15, JoinType::Round, EndType::Round);
SvgAddOpenSubject(svg2, op1, fr2, false);
SvgAddSolution(svg2, TransformPaths<double, int64_t>(op2), fr2, false);
SvgAddCaption(svg2, "Round Joins; Round Ends", 650, 210);
Expand Down Expand Up @@ -78,7 +77,7 @@ void DoSimpleShapes()
p = TranslatePaths<int64_t>(p, 120, 100);
pp.insert(pp.end(), p.begin(), p.end());
co.AddPaths(p, JoinType::Round, EndType::Joined);
co.Execute(20, p);
co.Execute(10, p);
pp.insert(pp.end(), p.begin(), p.end());

FillRule fr3 = FillRule::EvenOdd;
Expand Down Expand Up @@ -111,7 +110,7 @@ void DoRabbit()

FillRule fr = FillRule::EvenOdd;
SvgWriter svg;
SvgAddSolution(svg, solution, fr, false);
SvgAddSolution(svg, solution, fr, false);
SvgSaveToFile(svg, "solution_off2.svg", 450, 720, 0);
System("solution_off2.svg");
}
Expand Down
35 changes: 16 additions & 19 deletions CSharp/Clipper2Lib.Examples/InflateDemo/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/

using System;
using System.IO;
using System.Reflection;
using Clipper2Lib;
Expand All @@ -25,43 +26,39 @@ public static void Main()

public static void DoSimpleShapes()
{
//triangle offset - with large miter
Paths64 p = new() { Clipper.MakePath(new int[] { 30, 150, 60, 350, 0, 350 }) };
Paths64 pp = new();
pp.AddRange(p);
SvgWriter svg = new();
ClipperOffset co = new();

//triangle offset - with large miter
Paths64 p0 = new() { Clipper.MakePath(new int[] { 30,150, 60,350, 0,350 }) };
Paths64 p = new();
for (int i = 0; i < 5; ++i)
{
//nb: the last parameter here (10) greatly increases miter limit
p = Clipper.InflatePaths(p, 5, JoinType.Miter, EndType.Polygon, 10);
pp.AddRange(p);
p0 = Clipper.InflatePaths(p0, 5, JoinType.Miter, EndType.Polygon, 10);
p.AddRange(p0);
}
SvgUtils.AddSolution(svg, p, false);
p.Clear();

//rectangle offset - both squared and rounded
p.Clear();
ClipperOffset co = new();

//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 }));
pp.AddRange(p);
p.Add(Clipper.MakePath(new int[] { 100,0, 340,0, 340,200, 100,200, 100, 0 }));
SvgUtils.AddOpenSubject(svg, p);
co.AddPaths(p, JoinType.Bevel, EndType.Joined);

p = Clipper.TranslatePaths(p, 60, 50);
pp.AddRange(p);
SvgUtils.AddOpenSubject(svg, p);
co.AddPaths(p, JoinType.Square, EndType.Joined);

p = Clipper.TranslatePaths(p, 60, 50);
pp.AddRange(p);
SvgUtils.AddOpenSubject(svg, p);
co.AddPaths(p, JoinType.Round, EndType.Joined);


co.Execute(20, p);
pp.AddRange(p);
co.Execute(10, p);

string filename = "../../../inflate.svg";
SvgWriter svg = new();
SvgUtils.AddSolution(svg, pp, false);
SvgUtils.AddSolution(svg, p, false);
SvgUtils.AddCaption(svg, "Beveled join", 100, -27);
SvgUtils.AddCaption(svg, "Squared join", 160, 23);
SvgUtils.AddCaption(svg, "Rounded join", 220, 73);
Expand Down
76 changes: 35 additions & 41 deletions CSharp/Clipper2Lib/Clipper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 1 October 2023 *
* Date : 18 October 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This module contains simple functions that will likely cover *
Expand Down Expand Up @@ -850,16 +850,16 @@ private static int GetPrior(int current, int high, ref bool[] flags)
return current;
}

public static Path64 SimplifyPath(Path64 path,
double epsilon, bool isClosedPath = false)
public static Path64 SimplifyPath(Path64 path,
double epsilon, bool isClosedPath = true)
{
int len = path.Count, high = len - 1;
double epsSqr = Sqr(epsilon);
if (len < 4) return path;

bool[] flags = new bool[len];
double[] dsq = new double[len];
int curr = 0, prev, start, next, prior2, next2;
int curr = 0, prev, start, next, prior2;

if (isClosedPath)
{
Expand Down Expand Up @@ -893,24 +893,21 @@ public static Path64 SimplifyPath(Path64 path,

if (dsq[next] < dsq[curr])
{
flags[next] = true;
next = GetNext(next, high, ref flags);
next2 = GetNext(next, high, ref flags);
dsq[curr] = PerpendicDistFromLineSqrd(path[curr], path[prev], path[next]);
if (next != high || isClosedPath)
dsq[next] = PerpendicDistFromLineSqrd(path[next], path[curr], path[next2]);
prior2 = prev;
prev = curr;
curr = next;
next = GetNext(next, high, ref flags);
}
else
{
flags[curr] = true;
curr = next;
next = GetNext(next, high, ref flags);
prior2 = GetPrior(prev, high, ref flags);

flags[curr] = true;
curr = next;
next = GetNext(next, high, ref flags);
if (isClosedPath || ((curr != high) && (curr != 0)))
dsq[curr] = PerpendicDistFromLineSqrd(path[curr], path[prev], path[next]);
if (prev != 0 || isClosedPath)
dsq[prev] = PerpendicDistFromLineSqrd(path[prev], path[prior2], path[curr]);
}
if (isClosedPath || ((prev != 0) && (prev != high)))
dsq[prev] = PerpendicDistFromLineSqrd(path[prev], path[prior2], path[curr]);
}
Path64 result = new Path64(len);
for (int i = 0; i < len; i++)
Expand All @@ -919,7 +916,7 @@ public static Path64 SimplifyPath(Path64 path,
}

public static Paths64 SimplifyPaths(Paths64 paths,
double epsilon, bool isClosedPaths = false)
double epsilon, bool isClosedPaths = true)
{
Paths64 result = new Paths64(paths.Count);
foreach (Path64 path in paths)
Expand All @@ -928,24 +925,24 @@ public static Paths64 SimplifyPaths(Paths64 paths,
}

public static PathD SimplifyPath(PathD path,
double epsilon, bool isOpenPath = false)
double epsilon, bool isClosedPath = true)
{
int len = path.Count, high = len - 1;
double epsSqr = Sqr(epsilon);
if (len < 4) return path;

bool[] flags = new bool[len];
double[] dsq = new double[len];
int curr = 0, prev, start, next, prior2, next2;
if (isOpenPath)
int curr = 0, prev, start, next, prior2;
if (isClosedPath)
{
dsq[0] = double.MaxValue;
dsq[high] = double.MaxValue;
dsq[0] = PerpendicDistFromLineSqrd(path[0], path[high], path[1]);
dsq[high] = PerpendicDistFromLineSqrd(path[high], path[0], path[high - 1]);
}
else
{
dsq[0] = PerpendicDistFromLineSqrd(path[0], path[high], path[1]);
dsq[high] = PerpendicDistFromLineSqrd(path[high], path[0], path[high - 1]);
dsq[0] = double.MaxValue;
dsq[high] = double.MaxValue;
}
for (int i = 1; i < high; ++i)
dsq[i] = PerpendicDistFromLineSqrd(path[i], path[i - 1], path[i + 1]);
Expand All @@ -968,24 +965,21 @@ public static PathD SimplifyPath(PathD path,

if (dsq[next] < dsq[curr])
{
flags[next] = true;
next = GetNext(next, high, ref flags);
next2 = GetNext(next, high, ref flags);
dsq[curr] = PerpendicDistFromLineSqrd(path[curr], path[prev], path[next]);
if (next != high || !isOpenPath)
dsq[next] = PerpendicDistFromLineSqrd(path[next], path[curr], path[next2]);
curr = next;
}
else
{
flags[curr] = true;
prior2 = prev;
prev = curr;
curr = next;
next = GetNext(next, high, ref flags);
}
else
prior2 = GetPrior(prev, high, ref flags);

flags[curr] = true;
curr = next;
next = GetNext(next, high, ref flags);
if (isClosedPath || ((curr != high) && (curr != 0)))
dsq[curr] = PerpendicDistFromLineSqrd(path[curr], path[prev], path[next]);
if (prev != 0 || !isOpenPath)
dsq[prev] = PerpendicDistFromLineSqrd(path[prev], path[prior2], path[curr]);
}
if (isClosedPath || ((prev != 0) && (prev != high)))
dsq[prev] = PerpendicDistFromLineSqrd(path[prev], path[prior2], path[curr]);
}
PathD result = new PathD(len);
for (int i = 0; i < len; i++)
Expand All @@ -994,11 +988,11 @@ public static PathD SimplifyPath(PathD path,
}

public static PathsD SimplifyPaths(PathsD paths,
double epsilon, bool isOpenPath = false)
double epsilon, bool isClosedPath = true)
{
PathsD result = new PathsD(paths.Count);
foreach (PathD path in paths)
result.Add(SimplifyPath(path, epsilon, isOpenPath));
result.Add(SimplifyPath(path, epsilon, isClosedPath));
return result;
}

Expand Down
Loading

0 comments on commit 60cd293

Please sign in to comment.