Skip to content

Commit

Permalink
Fixed a Clipper.Offset bug (#456)
Browse files Browse the repository at this point in the history
Minor issue with #IFDEF in clipper.offset (C++) (#454)
  • Loading branch information
AngusJohnson committed Mar 22, 2023
1 parent e9eea4c commit 037d47c
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 107 deletions.
79 changes: 27 additions & 52 deletions CPP/Clipper2Lib/include/clipper2/clipper.core.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 21 February 2023 *
* Date : 22 March 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : Core Clipper Library structures and functions *
Expand Down Expand Up @@ -337,69 +337,44 @@ namespace Clipper2Lib

static const Rect64 MaxInvalidRect64 = Rect64(
INT64_MAX, INT64_MAX, INT64_MIN, INT64_MIN);

static const RectD MaxInvalidRectD = RectD(
MAX_DBL, MAX_DBL, -MAX_DBL, -MAX_DBL);

inline Rect64 GetBounds(const Path64& path)
{
Rect64 rec = MaxInvalidRect64;
for (const Point64& pt : path)
{
if (pt.x < rec.left) rec.left = pt.x;
if (pt.x > rec.right) rec.right = pt.x;
if (pt.y < rec.top) rec.top = pt.y;
if (pt.y > rec.bottom) rec.bottom = pt.y;
}
if (rec.left == INT64_MAX) return Rect64();
return rec;
}

inline Rect64 GetBounds(const Paths64& paths)
{
Rect64 rec = MaxInvalidRect64;
for (const Path64& path : paths)
for (const Point64& pt : path)
{
if (pt.x < rec.left) rec.left = pt.x;
if (pt.x > rec.right) rec.right = pt.x;
if (pt.y < rec.top) rec.top = pt.y;
if (pt.y > rec.bottom) rec.bottom = pt.y;
}
if (rec.left == INT64_MAX) return Rect64();
return rec;
}

inline RectD GetBounds(const PathD& path)
template <typename T>
Rect<T> GetBounds(const Path<T>& path)
{
RectD rec = MaxInvalidRectD;
for (const PointD& pt : path)
auto xmin = std::numeric_limits<T>::max();
auto ymin = std::numeric_limits<T>::max();
auto xmax = std::numeric_limits<T>::lowest();
auto ymax = std::numeric_limits<T>::lowest();
for (const auto& p : path)
{
if (pt.x < rec.left) rec.left = pt.x;
if (pt.x > rec.right) rec.right = pt.x;
if (pt.y < rec.top) rec.top = pt.y;
if (pt.y > rec.bottom) rec.bottom = pt.y;
if (p.x < xmin) xmin = p.x;
if (p.x > xmax) xmax = p.x;
if (p.y < ymin) ymin = p.y;
if (p.y > ymax) ymax = p.y;
}
if (rec.left == MAX_DBL) return RectD();
return rec;
return Rect<T>(xmin, ymin, xmax, ymax);
}

inline RectD GetBounds(const PathsD& paths)
{
RectD rec = MaxInvalidRectD;
for (const PathD& path : paths)
for (const PointD& pt : path)
template <typename T>
Rect<T> GetBounds(const Paths<T>& paths)
{
auto xmin = std::numeric_limits<T>::max();
auto ymin = std::numeric_limits<T>::max();
auto xmax = std::numeric_limits<T>::lowest();
auto ymax = std::numeric_limits<T>::lowest();
for (const Path<T>& path : paths)
for (const Point<T>& p : path)
{
if (pt.x < rec.left) rec.left = pt.x;
if (pt.x > rec.right) rec.right = pt.x;
if (pt.y < rec.top) rec.top = pt.y;
if (pt.y > rec.bottom) rec.bottom = pt.y;
if (p.x < xmin) xmin = p.x;
if (p.x > xmax) xmax = p.x;
if (p.y < ymin) ymin = p.y;
if (p.y > ymax) ymax = p.y;
}
if (rec.left == MAX_DBL) return RectD();
return rec;
return Rect<T>(xmin, ymin, xmax, ymax);
}


template <typename T>
std::ostream& operator << (std::ostream& outstream, const Path<T>& path)
{
Expand Down
6 changes: 3 additions & 3 deletions CPP/Clipper2Lib/include/clipper2/clipper.offset.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 19 March 2023 *
* Date : 22 March 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : Path Offset (Inflate/Shrink) *
Expand Down Expand Up @@ -59,7 +59,7 @@ class ClipperOffset {
bool preserve_collinear_ = false;
bool reverse_solution_ = false;

#if USINGZ
#ifdef USINGZ
ZCallback64 zCallback64_ = nullptr;
#endif

Expand Down Expand Up @@ -105,7 +105,7 @@ class ClipperOffset {
bool ReverseSolution() const { return reverse_solution_; }
void ReverseSolution(bool reverse_solution) {reverse_solution_ = reverse_solution;}

#if USINGZ
#ifdef USINGZ
void SetZCallback(ZCallback64 cb) { zCallback64_ = cb; }
#endif
};
Expand Down
38 changes: 19 additions & 19 deletions CPP/Clipper2Lib/src/clipper.offset.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 19 March 2023 *
* Date : 22 March 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : Path Offset (Inflate/Shrink) *
Expand Down Expand Up @@ -98,7 +98,7 @@ inline bool IsClosedPath(EndType et)

inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta)
{
#if USINGZ
#ifdef USINGZ
return Point64(pt.x + norm.x * delta, pt.y + norm.y * delta, pt.z);
#else
return Point64(pt.x + norm.x * delta, pt.y + norm.y * delta);
Expand All @@ -107,7 +107,7 @@ inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta)

inline PointD GetPerpendicD(const Point64& pt, const PointD& norm, double delta)
{
#if USINGZ
#ifdef USINGZ
return PointD(pt.x + norm.x * delta, pt.y + norm.y * delta, pt.z);
#else
return PointD(pt.x + norm.x * delta, pt.y + norm.y * delta);
Expand All @@ -120,7 +120,7 @@ inline void NegatePath(PathD& path)
{
pt.x = -pt.x;
pt.y = -pt.y;
#if USINGZ
#ifdef USINGZ
pt.z = pt.z;
#endif
}
Expand Down Expand Up @@ -156,7 +156,7 @@ void ClipperOffset::BuildNormals(const Path64& path)

inline PointD TranslatePoint(const PointD& pt, double dx, double dy)
{
#if USINGZ
#ifdef USINGZ
return PointD(pt.x + dx, pt.y + dy, pt.z);
#else
return PointD(pt.x + dx, pt.y + dy);
Expand All @@ -165,7 +165,7 @@ inline PointD TranslatePoint(const PointD& pt, double dx, double dy)

inline PointD ReflectPoint(const PointD& pt, const PointD& pivot)
{
#if USINGZ
#ifdef USINGZ
return PointD(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y), pt.z);
#else
return PointD(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y));
Expand Down Expand Up @@ -223,7 +223,7 @@ void ClipperOffset::DoSquare(Group& group, const Path64& path, size_t j, size_t
{
PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_);
PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
#if USINGZ
#ifdef USINGZ
pt.z = ptQ.z;
#endif
//get the second intersect point through reflecion
Expand All @@ -234,7 +234,7 @@ void ClipperOffset::DoSquare(Group& group, const Path64& path, size_t j, size_t
{
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
#if USINGZ
#ifdef USINGZ
pt.z = ptQ.z;
#endif
group.path.push_back(Point64(pt));
Expand All @@ -246,7 +246,7 @@ void ClipperOffset::DoSquare(Group& group, const Path64& path, size_t j, size_t
void ClipperOffset::DoMiter(Group& group, const Path64& path, size_t j, size_t k, double cos_a)
{
double q = group_delta_ / (cos_a + 1);
#if USINGZ
#ifdef USINGZ
group.path.push_back(Point64(
path[j].x + (norms[k].x + norms[j].x) * q,
path[j].y + (norms[k].y + norms[j].y) * q,
Expand All @@ -264,20 +264,19 @@ void ClipperOffset::DoRound(Group& group, const Path64& path, size_t j, size_t k
PointD offsetVec = PointD(norms[k].x * group_delta_, norms[k].y * group_delta_);

if (j == k) offsetVec.Negate();
#if USINGZ
#ifdef USINGZ
group.path.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z));
#else
group.path.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y));
#endif
if (angle > -PI + 0.01) // avoid 180deg concave
{
int steps = std::max(2, static_cast<int>(
std::ceil(steps_per_rad_ * std::abs(angle)))); // #448
int steps = static_cast<int>(std::ceil(steps_per_rad_ * std::abs(angle))); // #448, #456
for (int i = 1; i < steps; ++i) // ie 1 less than steps
{
offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y,
offsetVec.x * step_sin_ + offsetVec.y * step_cos_);
#if USINGZ
#ifdef USINGZ
group.path.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z));
#else
group.path.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y));
Expand Down Expand Up @@ -364,7 +363,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, Path64& path)
switch (end_type_)
{
case EndType::Butt:
#if USINGZ
#ifdef USINGZ
group.path.push_back(Point64(
path[0].x - norms[0].x * group_delta_,
path[0].y - norms[0].y * group_delta_,
Expand Down Expand Up @@ -399,7 +398,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, Path64& path)
switch (end_type_)
{
case EndType::Butt:
#if USINGZ
#ifdef USINGZ
group.path.push_back(Point64(
path[highI].x - norms[highI].x * group_delta_,
path[highI].y - norms[highI].y * group_delta_,
Expand Down Expand Up @@ -499,7 +498,7 @@ void ClipperOffset::DoGroupOffset(Group& group)
{
double radius = abs_group_delta_;
group.path = Ellipse(path[0], radius, radius);
#if USINGZ
#ifdef USINGZ
for (auto& p : group.path) p.z = path[0].z;
#endif
}
Expand All @@ -508,7 +507,7 @@ void ClipperOffset::DoGroupOffset(Group& group)
int d = (int)std::ceil(abs_group_delta_);
r = Rect64(path[0].x - d, path[0].y - d, path[0].x + d, path[0].y + d);
group.path = r.AsPath();
#if USINGZ
#ifdef USINGZ
for (auto& p : group.path) p.z = path[0].z;
#endif
}
Expand Down Expand Up @@ -573,12 +572,13 @@ void ClipperOffset::Execute(double delta, Paths64& paths)
ExecuteInternal(delta);
if (!solution.size()) return;

paths = solution;
//clean up self-intersections ...
Clipper64 c;
c.PreserveCollinear = false;
//the solution should retain the orientation of the input
c.ReverseSolution = reverse_solution_ != groups_[0].is_reversed;
#if USINGZ
#ifdef USINGZ
if (zCallback64_) {
c.SetZCallback(zCallback64_);
}
Expand All @@ -603,7 +603,7 @@ void ClipperOffset::Execute(double delta, PolyTree64& polytree)
c.PreserveCollinear = false;
//the solution should retain the orientation of the input
c.ReverseSolution = reverse_solution_ != groups_[0].is_reversed;
#if USINGZ
#ifdef USINGZ
if (zCallback64_) {
c.SetZCallback(zCallback64_);
}
Expand Down
Loading

0 comments on commit 037d47c

Please sign in to comment.