Skip to content

Commit

Permalink
Fixed a bug clipping open paths
Browse files Browse the repository at this point in the history
Reverted to using aliases in c# code (#26)
  • Loading branch information
AngusJohnson committed May 4, 2022
1 parent 69cc57f commit 04c591e
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 114 deletions.
2 changes: 1 addition & 1 deletion CPP/Clipper2Lib/clipper.core.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ inline double Area(const Path64& path)
for (path_iter = path.cbegin(); path_iter != path.cend();
path_iter_last = path_iter, ++path_iter)
{
a += static_cast<double>(path_iter_last->y - path_iter->y) *
a += static_cast<double>(path_iter_last->y - path_iter->y) *
(path_iter_last->x + path_iter->x);
}
#ifdef REVERSE_ORIENTATION
Expand Down
52 changes: 29 additions & 23 deletions CPP/Clipper2Lib/clipper.engine.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*******************************************************************************
* Author : Angus Johnson *
* Version : 10.0 (beta) - aka Clipper2 *
* Date : 3 May 2022 *
* Date : 4 May 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : This is the main polygon clipping module *
Expand Down Expand Up @@ -304,16 +304,29 @@ namespace Clipper2Lib {
}
//---------------------------------------------------------------------------

inline Vertex& NextVertex(const Active& e)
inline Vertex* NextVertex(const Active& e)
{
#ifdef REVERSE_ORIENTATION
if (e.wind_dx > 0)
#else
if (e.wind_dx < 0)
#endif
return *e.vertex_top->next;
return e.vertex_top->next;
else
return *e.vertex_top->prev;
return e.vertex_top->prev;
}
//------------------------------------------------------------------------------

inline Vertex* PrevPrevVertex(const Active& ae)
{
#ifdef REVERSE_ORIENTATION
if (ae.wind_dx > 0)
#else
if (ae.wind_dx < 0)
#endif
return ae.vertex_top->prev->prev;
else
return ae.vertex_top->next->next;
}
//------------------------------------------------------------------------------

Expand Down Expand Up @@ -708,7 +721,7 @@ namespace Clipper2Lib {

void ClipperBase::AddPaths(const Paths64& paths, PathType polytype, bool is_open)
{
has_open_paths_ = is_open;
if (is_open) has_open_paths_ = true;
minima_list_sorted_ = false;

Paths64::size_type paths_cnt = paths.size();
Expand Down Expand Up @@ -1032,13 +1045,6 @@ namespace Clipper2Lib {
}
//------------------------------------------------------------------------------

inline Vertex* PrevPrevVertex(const Active& ae)
{
if (ae.wind_dx < 0) return ae.vertex_top->prev->prev;
else return ae.vertex_top->next->next;
}
//------------------------------------------------------------------------------

bool IsValidAelOrder(const Active &a1, const Active &a2)
{
//a2 is always the new edge being inserted
Expand All @@ -1057,10 +1063,10 @@ namespace Clipper2Lib {
//the direction they're about to turn
if (IsOpen(a1) && !IsMaxima(a1) && (a1.bot.y <= a2.bot.y) &&
!IsSamePolyType(a1, a2) && (a1.top.y > a2.top.y))
return CrossProduct(a1.bot, a1.top, NextVertex(a1).pt) <= 0;
return CrossProduct(a1.bot, a1.top, NextVertex(a1)->pt) <= 0;
else if (IsOpen(a2) && !IsMaxima(a2) && (a2.bot.y <= a1.bot.y) &&
!IsSamePolyType(a1, a2) && (a2.top.y > a1.top.y))
return CrossProduct(a2.bot, a2.top, NextVertex(a2).pt) >= 0;
return CrossProduct(a2.bot, a2.top, NextVertex(a2)->pt) >= 0;

int64_t a2botY = a2.bot.y;
bool a1IsNewEdge = !IsOpen(a1) &&
Expand Down Expand Up @@ -1713,7 +1719,7 @@ namespace Clipper2Lib {

inline void ClipperBase::UpdateEdgeIntoAEL(Active *e) {
e->bot = e->top;
e->vertex_top = &NextVertex(*e);
e->vertex_top = NextVertex(*e);
e->top = e->vertex_top->pt;
e->curr_x = e->bot.x;
SetDx(*e);
Expand Down Expand Up @@ -2224,16 +2230,16 @@ namespace Clipper2Lib {
bool TrimHorz(Active& horzEdge, bool preserveCollinear)
{
bool result = false;
Point64 pt = NextVertex(horzEdge).pt;
Point64 pt = NextVertex(horzEdge)->pt;
//trim 180 deg. spikes in closed paths
while ((pt.y == horzEdge.top.y) && (!preserveCollinear ||
((pt.x < horzEdge.top.x) == (horzEdge.bot.x < horzEdge.top.x))))
{
horzEdge.vertex_top = &NextVertex(horzEdge);
horzEdge.vertex_top = NextVertex(horzEdge);
horzEdge.top = pt;
result = true;
if (IsMaxima(horzEdge)) break;
pt = NextVertex(horzEdge).pt;
pt = NextVertex(horzEdge)->pt;
}

if (result) SetDx(horzEdge); // +/-infinity
Expand Down Expand Up @@ -2315,7 +2321,7 @@ namespace Clipper2Lib {
{
//for edges at horzEdge's end, only stop when horzEdge's
//outslope is greater than e's slope when heading right or when
pt = NextVertex(horz).pt;
pt = NextVertex(horz)->pt;
if ((is_left_to_right && TopX(*e, pt.y) >= pt.x) ||
(!is_left_to_right && TopX(*e, pt.y) <= pt.x)) break;
}
Expand Down Expand Up @@ -2364,7 +2370,7 @@ namespace Clipper2Lib {
}

//check if we've finished with (consecutive) horizontals ...
if (isMax || NextVertex(horz).pt.y != horz.top.y) break;
if (isMax || NextVertex(horz)->pt.y != horz.top.y) break;

//still more horizontals in bound to process ...
if (IsHotEdge(horz))
Expand Down Expand Up @@ -3212,13 +3218,13 @@ namespace Clipper2Lib {
Path64 path;
if (solutionOpen && outrec->state == OutRecState::Open)
{
if (BuildPath(*outrec->pts->next, true, path))
if (BuildPath(*outrec->pts, true, path))
solutionOpen->emplace_back(std::move(path));
path.resize(0);
}
else
{
if (BuildPath(*outrec->pts->next, false, path))
if (BuildPath(*outrec->pts, false, path))
solutionClosed.emplace_back(std::move(path));
path.resize(0);
}
Expand Down Expand Up @@ -3257,7 +3263,7 @@ namespace Clipper2Lib {

Path64 path;
bool is_open_path = IsOpen(*outrec);
if (!BuildPath(*outrec->pts->next, is_open_path, path)) continue;
if (!BuildPath(*outrec->pts, is_open_path, path)) continue;

if (is_open_path)
{
Expand Down
19 changes: 19 additions & 0 deletions CPP/Clipper2Lib/clipper.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,25 @@ namespace Clipper2Lib {
return BooleanOp(ClipType::Xor, fillrule, subjects, clips);
}

inline Path64 ScalePath(const Path64 path, double scale)
{
Path64 result;
result.reserve(path.size());
for (const Point64 pt : path)
result.push_back(pt * scale);
return result;
}

inline Paths64 ScalePaths(const Paths64 paths, double scale)
{
Paths64 result;
result.reserve(paths.size());
for (const Path64 path : paths)
result.push_back(ScalePath(path, scale));
return result;
}


namespace details {

static void AddPolyNodeToPaths(const PolyPath64& polytree, Paths64& paths)
Expand Down
10 changes: 5 additions & 5 deletions CPP/Clipper2Lib/clipper.minkowski.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
namespace Clipper2Lib
{

namespace internal
namespace detail
{
static Paths64 Minkowski(const Path64& pattern, const Path64& path, bool isSum, bool isClosed)
{
Expand Down Expand Up @@ -81,27 +81,27 @@ namespace Clipper2Lib

static Paths64 MinkowskiSum(const Path64& pattern, const Path64& path, bool isClosed)
{
return internal::Union(internal::Minkowski(pattern, path, true, isClosed), FillRule::NonZero);
return detail::Union(detail::Minkowski(pattern, path, true, isClosed), FillRule::NonZero);
}

static PathsD MinkowskiSum(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2)
{
double scale = pow(10, decimalPlaces);
Path64 pat64 = PathDToPath64(pattern, scale), path64 = PathDToPath64(path, scale);
Paths64 tmp = internal::Union(internal::Minkowski(pat64, path64, true, isClosed), FillRule::NonZero);
Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, true, isClosed), FillRule::NonZero);
return Paths64ToPathsD(tmp, 1 / scale);
}

static Paths64 MinkowskiDiff(const Path64& pattern, const Path64& path, bool isClosed)
{
return internal::Union(internal::Minkowski(pattern, path, false, isClosed), FillRule::NonZero);
return detail::Union(detail::Minkowski(pattern, path, false, isClosed), FillRule::NonZero);
}

static PathsD MinkowskiDiff(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2)
{
double scale = pow(10, decimalPlaces);
Path64 pat64 = PathDToPath64(pattern, scale), path64 = PathDToPath64(path, scale);
Paths64 tmp = internal::Union(internal::Minkowski(pat64, path64, false, isClosed), FillRule::NonZero);
Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, false, isClosed), FillRule::NonZero);
return Paths64ToPathsD(tmp, 1 / scale);
}

Expand Down
2 changes: 1 addition & 1 deletion CPP/Clipper2Lib/clipper.offset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

#include <cmath>

#include "clipper.h"
#include "clipper.core.h"
#include "clipper.engine.h"
#include "clipper.offset.h"

namespace Clipper2Lib {

Expand Down
4 changes: 4 additions & 0 deletions CSharp/Clipper2Lib.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;

namespace Clipper2Lib.Benchmark
{
using Path64 = List<Point64>;
using Paths64 = List<List<Point64>>;

public class FastConfig : ManualConfig
{
public FastConfig()
Expand Down
33 changes: 2 additions & 31 deletions CSharp/Clipper2Lib/Clipper.Core.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/*******************************************************************************
* Author : Angus Johnson *
* Version : 10.0 (release candidate 1) - also known as Clipper2 *
* Date : 1 May 2022 *
* Version : 10.0 (beta) - also known as Clipper2 *
* Date : 4 May 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : Core structures and functions for the Clipper Library *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/

using System;
using System.Collections.Generic;

namespace Clipper2Lib
{
Expand Down Expand Up @@ -250,34 +249,6 @@ public override string ToString()
public override int GetHashCode() { return 0; }
}

public class Path64 : List<Point64>
{
public Path64() { }
public Path64(Path64 other) : base(other) { }
public Path64(int capacity) : base(capacity) { }
}

public class Paths64 : List<Path64>
{
public Paths64() { }
public Paths64(Paths64 other) : base (other) { }
public Paths64(int capacity) : base(capacity) { }
}

public class PathD : List<PointD>
{
public PathD() { }
public PathD(PathD other) : base(other) { }
public PathD(int capacity) : base(capacity) { }
}

public class PathsD : List<PathD>
{
public PathsD() { }
public PathsD(PathsD other) : base(other) { }
public PathsD(int capacity) : base(capacity) { }
}

public struct Rect64
{
public long left;
Expand Down
35 changes: 24 additions & 11 deletions CSharp/Clipper2Lib/Clipper.Engine.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*******************************************************************************
* Author : Angus Johnson *
* Version : 10.0 (beta) - also known as Clipper2 *
* Date : 2 May 2022 *
* Date : 4 May 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : This is the main polygon clipping module *
Expand All @@ -17,7 +17,12 @@

namespace Clipper2Lib
{


using Path64 = List<Point64>;
using Paths64 = List<List<Point64>>;
using PathD = List<PointD>;
using PathsD = List<List<PointD>>;

//Vertex: a pre-clipping data structure. It is used to separate polygons
//into ascending and descending 'bounds' (or sides) that start at local
//minima and ascend to a local maxima, before descending again.
Expand Down Expand Up @@ -444,6 +449,19 @@ private static Vertex NextVertex(Active ae)
return ae.vertexTop!.prev!;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vertex PrevPrevVertex(Active ae)
{
#if REVERSE_ORIENTATION
if (ae.windDx > 0)
#else
if (ae.windDx < 0)
#endif
return ae.vertexTop!.prev!.prev!;
else
return ae.vertexTop!.next!.next!;
}

private static bool IsMaxima(Active ae)
{
return ((ae.vertexTop!.flags & VertexFlags.LocalMax) != VertexFlags.None);
Expand Down Expand Up @@ -1132,12 +1150,6 @@ private void SetWindCountForOpenPathEdge(Active ae)
}
}

private Vertex PrevPrevVertex(Active ae)
{
if (ae.windDx < 0) return ae.vertexTop!.prev!.prev!;
else return ae.vertexTop!.next!.next!;
}

private bool IsValidAelOrder(Active a1, Active a2)
{
//a2 is always the new edge being inserted
Expand Down Expand Up @@ -1500,6 +1512,7 @@ private void JoinOutrecPaths(Active ae1, Active ae2)
p2Start.next = p1End;
p1Start.next = p2End;
p2End.prev = p1Start;

if (!IsOpen(ae1))
{
ae1.outrec.backEdge = ae2.outrec.backEdge;
Expand Down Expand Up @@ -3304,12 +3317,12 @@ protected bool BuildPaths(Paths64 solutionClosed, Paths64 solutionOpen)
Path64 path = new Path64();
if (outrec.state == OutRecState.Open)
{
if (BuildPath(outrec.pts.next!, true, path))
if (BuildPath(outrec.pts!, true, path))
solutionOpen.Add(path);
}
else
{
if (BuildPath(outrec.pts.next!, false, path))
if (BuildPath(outrec.pts!, false, path))
solutionClosed.Add(path);
}
}
Expand Down Expand Up @@ -3348,7 +3361,7 @@ protected bool BuildTree(PolyPathBase polytree, Paths64 solutionOpen)
bool isOpenPath = outrec.state == OutRecState.Open;

Path64 path = new Path64();
if (!BuildPath(outrec.pts.next!, isOpenPath, path)) continue;
if (!BuildPath(outrec.pts!, isOpenPath, path)) continue;

if (isOpenPath)
{
Expand Down
Loading

0 comments on commit 04c591e

Please sign in to comment.