Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass Z values from the input to the solution when using Offset #411

Merged
merged 3 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CPP/Clipper2Lib/include/clipper2/clipper.offset.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define CLIPPER_OFFSET_H_

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

namespace Clipper2Lib {

Expand Down Expand Up @@ -55,6 +56,10 @@ class ClipperOffset {
bool preserve_collinear_ = false;
bool reverse_solution_ = false;

#if USINGZ
ZCallback64 zCallback64_ = nullptr;
#endif

void DoSquare(Group& group, const Path64& path, size_t j, size_t k);
void DoMiter(Group& group, const Path64& path, size_t j, size_t k, double cos_a);
void DoRound(Group& group, const Path64& path, size_t j, size_t k, double angle);
Expand Down Expand Up @@ -96,6 +101,10 @@ class ClipperOffset {

bool ReverseSolution() const { return reverse_solution_; }
void ReverseSolution(bool reverse_solution) {reverse_solution_ = reverse_solution;}

#if USINGZ
void SetZCallback(ZCallback64 cb) { zCallback64_ = cb; }
#endif
};

}
Expand Down
65 changes: 65 additions & 0 deletions CPP/Clipper2Lib/src/clipper.offset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,20 @@ inline bool IsClosedPath(EndType et)

inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta)
{
#if 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);
#endif
}

inline PointD GetPerpendicD(const Point64& pt, const PointD& norm, double delta)
{
#if 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);
#endif
}

inline void NegatePath(PathD& path)
Expand All @@ -112,6 +120,9 @@ inline void NegatePath(PathD& path)
{
pt.x = -pt.x;
pt.y = -pt.y;
#if USINGZ
pt.z = pt.z;
#endif
}
}

Expand Down Expand Up @@ -158,12 +169,20 @@ void ClipperOffset::BuildNormals(const Path64& path)

inline PointD TranslatePoint(const PointD& pt, double dx, double dy)
{
#if USINGZ
return PointD(pt.x + dx, pt.y + dy, pt.z);
#else
return PointD(pt.x + dx, pt.y + dy);
#endif
}

inline PointD ReflectPoint(const PointD& pt, const PointD& pivot)
{
#if 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));
#endif
}

PointD IntersectPoint(const PointD& pt1a, const PointD& pt1b,
Expand Down Expand Up @@ -217,6 +236,9 @@ 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
pt.z = ptQ.z;
#endif
//get the second intersect point through reflecion
group.path.push_back(Point64(ReflectPoint(pt, ptQ)));
group.path.push_back(Point64(pt));
Expand All @@ -225,6 +247,9 @@ 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
pt.z = ptQ.z;
#endif
group.path.push_back(Point64(pt));
//get the second intersect point through reflecion
group.path.push_back(Point64(ReflectPoint(pt, ptQ)));
Expand All @@ -234,17 +259,28 @@ 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
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,
path[j].z));
#else
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));
#endif
}

void ClipperOffset::DoRound(Group& group, const Path64& path, size_t j, size_t k, double angle)
{
Point64 pt = path[j];
PointD offsetVec = PointD(norms[k].x * group_delta_, norms[k].y * group_delta_);
if (j == k) offsetVec.Negate();
#if 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>(
Expand All @@ -255,7 +291,11 @@ void ClipperOffset::DoRound(Group& group, const Path64& path, size_t j, size_t k
{
offsetVec = PointD(offsetVec.x * step_cos - step_sin * offsetVec.y,
offsetVec.x * step_sin + offsetVec.y * step_cos);
#if 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
}
}
group.path.push_back(GetPerpendic(path[j], norms[j], group_delta_));
Expand Down Expand Up @@ -335,9 +375,16 @@ void ClipperOffset::OffsetOpenPath(Group& group, Path64& path)
switch (end_type_)
{
case EndType::Butt:
#if USINGZ
group.path.push_back(Point64(
path[0].x - norms[0].x * group_delta_,
path[0].y - norms[0].y * group_delta_,
path[0].z));
#else
group.path.push_back(Point64(
path[0].x - norms[0].x * group_delta_,
path[0].y - norms[0].y * group_delta_));
#endif
group.path.push_back(GetPerpendic(path[0], norms[0], group_delta_));
break;
case EndType::Round:
Expand All @@ -363,9 +410,16 @@ void ClipperOffset::OffsetOpenPath(Group& group, Path64& path)
switch (end_type_)
{
case EndType::Butt:
#if USINGZ
group.path.push_back(Point64(
path[highI].x - norms[highI].x * group_delta_,
path[highI].y - norms[highI].y * group_delta_,
path[highI].z));
#else
group.path.push_back(Point64(
path[highI].x - norms[highI].x * group_delta_,
path[highI].y - norms[highI].y * group_delta_));
#endif
group.path.push_back(GetPerpendic(path[highI], norms[highI], group_delta_));
break;
case EndType::Round:
Expand Down Expand Up @@ -451,12 +505,18 @@ void ClipperOffset::DoGroupOffset(Group& group)
{
double radius = abs_group_delta_;
group.path = Ellipse(path[0], radius, radius);
#if USINGZ
for (auto& p : group.path) p.z = path[0].z;
#endif
}
else
{
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
for (auto& p : group.path) p.z = path[0].z;
#endif
}
group.paths_out.push_back(group.path);
}
Expand Down Expand Up @@ -516,6 +576,11 @@ Paths64 ClipperOffset::Execute(double delta)
c.PreserveCollinear = false;
//the solution should retain the orientation of the input
c.ReverseSolution = reverse_solution_ != groups_[0].is_reversed;
#if USINGZ
if (zCallback64_) {
c.SetZCallback(zCallback64_);
}
#endif
c.AddSubject(solution);
if (groups_[0].is_reversed)
c.Execute(ClipType::Union, FillRule::Negative, solution);
Expand Down
12 changes: 10 additions & 2 deletions CSharp/Clipper2Lib/Clipper.Offset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,9 @@ public Group(Paths64 paths, JoinType joinType, EndType endType = EndType.Polygon
public double MiterLimit { get; set; }
public bool PreserveCollinear { get; set; }
public bool ReverseSolution { get; set; }

#if USINGZ
public ClipperBase.ZCallback64? ZCallback { get; set; }
#endif

public ClipperOffset(double miterLimit = 2.0,
double arcTolerance = 0.0, bool
preserveCollinear = false, bool reverseSolution = false)
Expand Down Expand Up @@ -325,6 +323,9 @@ private void DoSquare(Group group, Path64 path, int j, int k)
{
PointD pt4 = GetPerpendicD(path[j], _normals[k]);
PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
#if USINGZ
pt.z = ptQ.z;
#endif
group.outPath.Add(new Point64(pt));
//get the second intersect point through reflecion
group.outPath.Add(new Point64(ReflectPoint(pt, ptQ)));
Expand Down Expand Up @@ -492,9 +493,16 @@ private void OffsetOpenPath(Group group, Path64 path)
switch (_endType)
{
case EndType.Butt:
#if USINGZ
group.outPath.Add(new Point64(
path[highI].X - _normals[highI].x * _group_delta,
path[highI].Y - _normals[highI].y * _group_delta,
path[highI].Z));
#else
group.outPath.Add(new Point64(
path[highI].X - _normals[highI].x * _group_delta,
path[highI].Y - _normals[highI].y * _group_delta));
#endif
group.outPath.Add(GetPerpendic(path[highI], _normals[highI]));
break;
case EndType.Round:
Expand Down
Loading