feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -1,21 +1,15 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 27 April 2024 *
* Website : http://www.angusj.com *
* Date : 17 September 2024 *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2024 *
* Purpose : This is the main polygon clipping module *
* License : http://www.boost.org/LICENSE_1_0.txt *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
#include <cstdlib>
#include <cmath>
#include <stdexcept>
#include <vector>
#include <numeric>
#include <algorithm>
#include "clipper2/clipper.engine.h"
#include "clipper2/clipper.h"
#include <stdexcept>
// https://github.com/AngusJohnson/Clipper2/discussions/334
// #discussioncomment-4248602
@ -85,7 +79,7 @@ namespace Clipper2Lib {
inline bool IsOpenEnd(const Vertex& v)
{
return (v.flags & (VertexFlags::OpenStart | VertexFlags::OpenEnd)) !=
VertexFlags::None;
VertexFlags::Empty;
}
@ -220,7 +214,7 @@ namespace Clipper2Lib {
inline bool IsMaxima(const Vertex& v)
{
return ((v.flags & VertexFlags::LocalMax) != VertexFlags::None);
return ((v.flags & VertexFlags::LocalMax) != VertexFlags::Empty);
}
@ -235,12 +229,12 @@ namespace Clipper2Lib {
if (e.wind_dx > 0)
while ((result->next->pt.y == result->pt.y) &&
((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
VertexFlags::LocalMax)) == VertexFlags::Empty))
result = result->next;
else
while (result->prev->pt.y == result->pt.y &&
((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
VertexFlags::LocalMax)) == VertexFlags::Empty))
result = result->prev;
if (!IsMaxima(*result)) result = nullptr; // not a maxima
return result;
@ -478,7 +472,7 @@ namespace Clipper2Lib {
inline bool IsJoined(const Active& e)
{
return e.join_with != JoinWith::None;
return e.join_with != JoinWith::NoJoin;
}
inline void SetOwner(OutRec* outrec, OutRec* new_owner)
@ -517,7 +511,7 @@ namespace Clipper2Lib {
while (op2 != op && op2->pt.y > pt.y) op2 = op2->next;
if (op2 == op) break;
// must have touched or crossed the pt.Y horizonal
// must have touched or crossed the pt.Y horizontal
// and this must happen an even number of times
if (op2->pt.y == pt.y) // touching the horizontal
@ -564,7 +558,7 @@ namespace Clipper2Lib {
while (op2->next != op &&
((op2->pt.x == op2->next->pt.x && op2->pt.x == op2->prev->pt.x) ||
(op2->pt.y == op2->next->pt.y && op2->pt.y == op2->prev->pt.y))) op2 = op2->next;
result.push_back(op2->pt);
result.emplace_back(op2->pt);
OutPt* prevOp = op2;
op2 = op2->next;
while (op2 != op)
@ -572,7 +566,7 @@ namespace Clipper2Lib {
if ((op2->pt.x != op2->next->pt.x || op2->pt.x != prevOp->pt.x) &&
(op2->pt.y != op2->next->pt.y || op2->pt.y != prevOp->pt.y))
{
result.push_back(op2->pt);
result.emplace_back(op2->pt);
prevOp = op2;
}
op2 = op2->next;
@ -608,10 +602,10 @@ namespace Clipper2Lib {
Vertex& vert, PathType polytype, bool is_open)
{
//make sure the vertex is added only once ...
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return;
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return;
vert.flags = (vert.flags | VertexFlags::LocalMin);
list.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
list.emplace_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
}
void AddPaths_(const Paths64& paths, PathType polytype, bool is_open,
@ -643,7 +637,7 @@ namespace Clipper2Lib {
}
curr_v->prev = prev_v;
curr_v->pt = pt;
curr_v->flags = VertexFlags::None;
curr_v->flags = VertexFlags::Empty;
prev_v = curr_v++;
cnt++;
}
@ -725,10 +719,10 @@ namespace Clipper2Lib {
void ReuseableDataContainer64::AddLocMin(Vertex& vert, PathType polytype, bool is_open)
{
//make sure the vertex is added only once ...
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return;
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return;
vert.flags = (vert.flags | VertexFlags::LocalMin);
minima_list_.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
minima_list_.emplace_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
}
void ReuseableDataContainer64::AddPaths(const Paths64& paths,
@ -836,9 +830,7 @@ namespace Clipper2Lib {
void ClipperBase::AddPath(const Path64& path, PathType polytype, bool is_open)
{
Paths64 tmp;
tmp.push_back(path);
AddPaths(tmp, polytype, is_open);
AddPaths(Paths64(1, path), polytype, is_open);
}
void ClipperBase::AddPaths(const Paths64& paths, PathType polytype, bool is_open)
@ -857,7 +849,7 @@ namespace Clipper2Lib {
LocalMinimaList::const_iterator i;
for (i = reuseable_data.minima_list_.cbegin(); i != reuseable_data.minima_list_.cend(); ++i)
{
minima_list_.push_back(std::make_unique <LocalMinima>((*i)->vertex, (*i)->polytype, (*i)->is_open));
minima_list_.emplace_back(std::make_unique <LocalMinima>((*i)->vertex, (*i)->polytype, (*i)->is_open));
if ((*i)->is_open) has_open_paths_ = true;
}
}
@ -907,10 +899,10 @@ namespace Clipper2Lib {
void ClipperBase::AddLocMin(Vertex& vert, PathType polytype, bool is_open)
{
//make sure the vertex is added only once ...
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return;
if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::Empty) return;
vert.flags = (vert.flags | VertexFlags::LocalMin);
minima_list_.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
minima_list_.emplace_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
}
bool ClipperBase::IsContributingClosed(const Active& e) const
@ -928,11 +920,14 @@ namespace Clipper2Lib {
case FillRule::Negative:
if (e.wind_cnt != -1) return false;
break;
// Should never happen, but adding this to stop a compiler warning
default:
break;
}
switch (cliptype_)
{
case ClipType::None:
case ClipType::NoClip:
return false;
case ClipType::Intersection:
switch (fillrule_)
@ -978,6 +973,9 @@ namespace Clipper2Lib {
break;
case ClipType::Xor: return true; break;
// Should never happen, but adding this to stop a compiler warning
default:
break;
}
return false; // we should never get here
}
@ -1208,7 +1206,7 @@ namespace Clipper2Lib {
while (PopLocalMinima(bot_y, local_minima))
{
if ((local_minima->vertex->flags & VertexFlags::OpenStart) != VertexFlags::None)
if ((local_minima->vertex->flags & VertexFlags::OpenStart) != VertexFlags::Empty)
{
left_bound = nullptr;
}
@ -1224,7 +1222,7 @@ namespace Clipper2Lib {
SetDx(*left_bound);
}
if ((local_minima->vertex->flags & VertexFlags::OpenEnd) != VertexFlags::None)
if ((local_minima->vertex->flags & VertexFlags::OpenEnd) != VertexFlags::Empty)
{
right_bound = nullptr;
}
@ -1488,7 +1486,7 @@ namespace Clipper2Lib {
{
OutRec* result = new OutRec();
result->idx = outrec_list_.size();
outrec_list_.push_back(result);
outrec_list_.emplace_back(result);
result->pts = nullptr;
result->owner = nullptr;
result->polypath = nullptr;
@ -1631,12 +1629,12 @@ namespace Clipper2Lib {
if (Path1InsidePath2(prevOp, newOp))
{
newOr->splits = new OutRecList();
newOr->splits->push_back(outrec);
newOr->splits->emplace_back(outrec);
}
else
{
if (!outrec->splits) outrec->splits = new OutRecList();
outrec->splits->push_back(newOr);
outrec->splits->emplace_back(newOr);
}
}
}
@ -1955,7 +1953,7 @@ namespace Clipper2Lib {
else if (IsFront(e1) || (e1.outrec == e2.outrec))
{
//this 'else if' condition isn't strictly needed but
//it's sensible to split polygons that ony touch at
//it's sensible to split polygons that only touch at
//a common vertex (not at common edges).
#ifdef USINGZ
@ -2125,7 +2123,7 @@ namespace Clipper2Lib {
using_polytree_ = use_polytrees;
Reset();
int64_t y;
if (ct == ClipType::None || !PopScanline(y)) return true;
if (ct == ClipType::NoClip || !PopScanline(y)) return true;
while (succeeded_)
{
@ -2239,7 +2237,7 @@ namespace Clipper2Lib {
HorzJoin join = HorzJoin(
DuplicateOp(hs1->left_op, true),
DuplicateOp(hs2->left_op, false));
horz_join_list_.push_back(join);
horz_join_list_.emplace_back(join);
}
else
{
@ -2252,7 +2250,7 @@ namespace Clipper2Lib {
HorzJoin join = HorzJoin(
DuplicateOp(hs2->left_op, true),
DuplicateOp(hs1->left_op, false));
horz_join_list_.push_back(join);
horz_join_list_.emplace_back(join);
}
}
}
@ -2264,7 +2262,7 @@ namespace Clipper2Lib {
if (!toOr->splits) toOr->splits = new OutRecList();
OutRecList::iterator orIter = fromOr->splits->begin();
for (; orIter != fromOr->splits->end(); ++orIter)
toOr->splits->push_back(*orIter);
toOr->splits->emplace_back(*orIter);
fromOr->splits->clear();
}
@ -2317,7 +2315,7 @@ namespace Clipper2Lib {
or2->owner = or1->owner;
if (!or1->splits) or1->splits = new OutRecList();
or1->splits->push_back(or2);
or1->splits->emplace_back(or2);
}
else
or2->owner = or1;
@ -2376,7 +2374,7 @@ namespace Clipper2Lib {
else ip.x = TopX(e2, ip.y);
}
}
intersect_nodes_.push_back(IntersectNode(&e1, &e2, ip));
intersect_nodes_.emplace_back(&e1, &e2, ip);
}
bool ClipperBase::BuildIntersectList(const int64_t top_y)
@ -2497,7 +2495,7 @@ namespace Clipper2Lib {
void ClipperBase::AddTrialHorzJoin(OutPt* op)
{
if (op->outrec->is_open) return;
horz_seg_list_.push_back(HorzSegment(op));
horz_seg_list_.emplace_back(op);
}
bool ClipperBase::ResetHorzDirection(const Active& horz,
@ -2655,7 +2653,7 @@ namespace Clipper2Lib {
if (horz.outrec)
{
//nb: The outrec containining the op returned by IntersectEdges
//nb: The outrec containing the op returned by IntersectEdges
//above may no longer be associated with horzEdge.
AddTrialHorzJoin(GetLastOp(horz));
}
@ -2789,14 +2787,14 @@ namespace Clipper2Lib {
{
if (e.join_with == JoinWith::Right)
{
e.join_with = JoinWith::None;
e.next_in_ael->join_with = JoinWith::None;
e.join_with = JoinWith::NoJoin;
e.next_in_ael->join_with = JoinWith::NoJoin;
AddLocalMinPoly(e, *e.next_in_ael, pt, true);
}
else
{
e.join_with = JoinWith::None;
e.prev_in_ael->join_with = JoinWith::None;
e.join_with = JoinWith::NoJoin;
e.prev_in_ael->join_with = JoinWith::NoJoin;
AddLocalMinPoly(*e.prev_in_ael, e, pt, true);
}
}
@ -2899,14 +2897,14 @@ namespace Clipper2Lib {
lastPt = op->pt;
op2 = op->next;
}
path.push_back(lastPt);
path.emplace_back(lastPt);
while (op2 != op)
{
if (op2->pt != lastPt)
{
lastPt = op2->pt;
path.push_back(lastPt);
path.emplace_back(lastPt);
}
if (reverse)
op2 = op2->prev;
@ -3031,7 +3029,7 @@ namespace Clipper2Lib {
{
Path64 path;
if (BuildPath64(outrec->pts, reverse_solution_, true, path))
open_paths.push_back(path);
open_paths.emplace_back(std::move(path));
continue;
}
@ -3060,9 +3058,9 @@ namespace Clipper2Lib {
op2 = op->next;
}
#ifdef USINGZ
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z));
path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z);
#else
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale);
#endif
while (op2 != op)
@ -3071,9 +3069,9 @@ namespace Clipper2Lib {
{
lastPt = op2->pt;
#ifdef USINGZ
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z));
path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale, lastPt.z);
#else
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
path.emplace_back(lastPt.x * inv_scale, lastPt.y * inv_scale);
#endif
}
@ -3137,7 +3135,7 @@ namespace Clipper2Lib {
{
PathD path;
if (BuildPathD(outrec->pts, reverse_solution_, true, path, invScale_))
open_paths.push_back(path);
open_paths.emplace_back(std::move(path));
continue;
}

View file

@ -1,21 +1,34 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 17 April 2024 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2024 *
* Date : 22 January 2025 *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2025 *
* Purpose : Path Offset (Inflate/Shrink) *
* License : http://www.boost.org/LICENSE_1_0.txt *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
#include <cmath>
#include "clipper2/clipper.h"
#include "clipper2/clipper.offset.h"
namespace Clipper2Lib {
const double default_arc_tolerance = 0.25;
const double floating_point_tolerance = 1e-12;
// Clipper2 approximates arcs by using series of relatively short straight
//line segments. And logically, shorter line segments will produce better arc
// approximations. But very short segments can degrade performance, usually
// with little or no discernable improvement in curve quality. Very short
// segments can even detract from curve quality, due to the effects of integer
// rounding. Since there isn't an optimal number of line segments for any given
// arc radius (that perfectly balances curve approximation with performance),
// arc tolerance is user defined. Nevertheless, when the user doesn't define
// an arc tolerance (ie leaves alone the 0 default value), the calculated
// default arc tolerance (offset_radius / 500) generally produces good (smooth)
// arc approximations without producing excessively small segment lengths.
// See also: https://www.angusj.com/clipper2/Docs/Trigonometry.htm
const double arc_const = 0.002; // <-- 1/500
//------------------------------------------------------------------------------
// Miscellaneous methods
//------------------------------------------------------------------------------
@ -38,13 +51,22 @@ std::optional<size_t> GetLowestClosedPathIdx(const Paths64& paths)
return result;
}
PointD GetUnitNormal(const Point64& pt1, const Point64& pt2)
inline double Hypot(double x, double y)
{
// given that this is an internal function, and given the x and y parameters
// will always be coordinate values (or the difference between coordinate values),
// x and y should always be within INT64_MIN to INT64_MAX. Consequently,
// there should be no risk that the following computation will overflow
// see https://stackoverflow.com/a/32436148/359538
return std::sqrt(x * x + y * y);
}
static PointD GetUnitNormal(const Point64& pt1, const Point64& pt2)
{
double dx, dy, inverse_hypot;
if (pt1 == pt2) return PointD(0.0, 0.0);
dx = static_cast<double>(pt2.x - pt1.x);
dy = static_cast<double>(pt2.y - pt1.y);
inverse_hypot = 1.0 / hypot(dx, dy);
double dx = static_cast<double>(pt2.x - pt1.x);
double dy = static_cast<double>(pt2.y - pt1.y);
double inverse_hypot = 1.0 / Hypot(dx, dy);
dx *= inverse_hypot;
dy *= inverse_hypot;
return PointD(dy, -dx);
@ -55,12 +77,6 @@ inline bool AlmostZero(double value, double epsilon = 0.001)
return std::fabs(value) < epsilon;
}
inline double Hypot(double x, double y)
{
//see https://stackoverflow.com/a/32436148/359538
return std::sqrt(x * x + y * y);
}
inline PointD NormalizeVector(const PointD& vec)
{
double h = Hypot(vec.x, vec.y);
@ -79,7 +95,7 @@ inline bool IsClosedPath(EndType et)
return et == EndType::Polygon || et == EndType::Joined;
}
inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta)
static inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta)
{
#ifdef USINGZ
return Point64(pt.x + norm.x * delta, pt.y + norm.y * delta, pt.z);
@ -129,11 +145,11 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
// the lowermost path must be an outer path, so if its orientation is negative,
// then flag the whole group is 'reversed' (will negate delta etc.)
// as this is much more efficient than reversing every path.
is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
}
else
{
lowest_path_idx = std::nullopt;
lowest_path_idx = std::nullopt;
is_reversed = false;
}
}
@ -144,15 +160,13 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
void ClipperOffset::AddPath(const Path64& path, JoinType jt_, EndType et_)
{
Paths64 paths;
paths.push_back(path);
AddPaths(paths, jt_, et_);
groups_.emplace_back(Paths64(1, path), jt_, et_);
}
void ClipperOffset::AddPaths(const Paths64 &paths, JoinType jt_, EndType et_)
{
if (paths.size() == 0) return;
groups_.push_back(Group(paths, jt_, et_));
groups_.emplace_back(paths, jt_, et_);
}
void ClipperOffset::BuildNormals(const Path64& path)
@ -162,8 +176,8 @@ void ClipperOffset::BuildNormals(const Path64& path)
if (path.size() == 0) return;
Path64::const_iterator path_iter, path_stop_iter = --path.cend();
for (path_iter = path.cbegin(); path_iter != path_stop_iter; ++path_iter)
norms.push_back(GetUnitNormal(*path_iter,*(path_iter +1)));
norms.push_back(GetUnitNormal(*path_stop_iter, *(path.cbegin())));
norms.emplace_back(GetUnitNormal(*path_iter,*(path_iter +1)));
norms.emplace_back(GetUnitNormal(*path_stop_iter, *(path.cbegin())));
}
void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k)
@ -190,8 +204,8 @@ void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k)
pt2 = PointD(path[j].x + group_delta_ * norms[j].x, path[j].y + group_delta_ * norms[j].y);
#endif
}
path_out.push_back(Point64(pt1));
path_out.push_back(Point64(pt2));
path_out.emplace_back(pt1);
path_out.emplace_back(pt2);
}
void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
@ -220,17 +234,17 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
PointD pt = ptQ;
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
//get the second intersect point through reflecion
path_out.push_back(Point64(ReflectPoint(pt, ptQ)));
path_out.push_back(Point64(pt));
path_out.emplace_back(ReflectPoint(pt, ptQ));
path_out.emplace_back(pt);
}
else
{
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
PointD pt = ptQ;
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
path_out.push_back(Point64(pt));
path_out.emplace_back(pt);
//get the second intersect point through reflecion
path_out.push_back(Point64(ReflectPoint(pt, ptQ)));
path_out.emplace_back(ReflectPoint(pt, ptQ));
}
}
@ -238,14 +252,14 @@ void ClipperOffset::DoMiter(const Path64& path, size_t j, size_t k, double cos_a
{
double q = group_delta_ / (cos_a + 1);
#ifdef USINGZ
path_out.push_back(Point64(
path_out.emplace_back(
path[j].x + (norms[k].x + norms[j].x) * q,
path[j].y + (norms[k].y + norms[j].y) * q,
path[j].z));
path[j].z);
#else
path_out.push_back(Point64(
path_out.emplace_back(
path[j].x + (norms[k].x + norms[j].x) * q,
path[j].y + (norms[k].y + norms[j].y) * q));
path[j].y + (norms[k].y + norms[j].y) * q);
#endif
}
@ -256,8 +270,7 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle
// so we'll need to do the following calculations for *every* vertex.
double abs_delta = std::fabs(group_delta_);
double arcTol = (arc_tolerance_ > floating_point_tolerance ?
std::min(abs_delta, arc_tolerance_) :
std::log10(2 + abs_delta) * default_arc_tolerance);
std::min(abs_delta, arc_tolerance_) : abs_delta * arc_const);
double steps_per_360 = std::min(PI / std::acos(1 - arcTol / abs_delta), abs_delta * PI);
step_sin_ = std::sin(2 * PI / steps_per_360);
step_cos_ = std::cos(2 * PI / steps_per_360);
@ -270,9 +283,9 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle
if (j == k) offsetVec.Negate();
#ifdef USINGZ
path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z));
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z);
#else
path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y));
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y);
#endif
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
@ -280,12 +293,12 @@ void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle
offsetVec = PointD(offsetVec.x * step_cos_ - step_sin_ * offsetVec.y,
offsetVec.x * step_sin_ + offsetVec.y * step_cos_);
#ifdef USINGZ
path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z));
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y, pt.z);
#else
path_out.push_back(Point64(pt.x + offsetVec.x, pt.y + offsetVec.y));
path_out.emplace_back(pt.x + offsetVec.x, pt.y + offsetVec.y);
#endif
}
path_out.push_back(GetPerpendic(path[j], norms[j], group_delta_));
path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_));
}
void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size_t k)
@ -309,28 +322,25 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
}
if (std::fabs(group_delta_) <= floating_point_tolerance)
{
path_out.push_back(path[j]);
path_out.emplace_back(path[j]);
return;
}
if (cos_a > -0.999 && (sin_a * group_delta_ < 0)) // test for concavity first (#593)
{
// is concave (so insert 3 points that will create a negative region)
// is concave
// by far the simplest way to construct concave joins, especially those joining very
// short segments, is to insert 3 points that produce negative regions. These regions
// will be removed later by the finishing union operation. This is also the best way
// to ensure that path reversals (ie over-shrunk paths) are removed.
#ifdef USINGZ
path_out.push_back(Point64(GetPerpendic(path[j], norms[k], group_delta_), path[j].z));
path_out.emplace_back(GetPerpendic(path[j], norms[k], group_delta_), path[j].z);
path_out.emplace_back(path[j]); // (#405, #873, #916)
path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_), path[j].z);
#else
path_out.push_back(GetPerpendic(path[j], norms[k], group_delta_));
#endif
// this extra point is the only simple way to ensure that path reversals
// (ie over-shrunk paths) are fully cleaned out with the trailing union op.
// However it's probably safe to skip this whenever an angle is almost flat.
if (cos_a < 0.99) path_out.push_back(path[j]); // (#405)
#ifdef USINGZ
path_out.push_back(Point64(GetPerpendic(path[j], norms[j], group_delta_), path[j].z));
#else
path_out.push_back(GetPerpendic(path[j], norms[j], group_delta_));
path_out.emplace_back(GetPerpendic(path[j], norms[k], group_delta_));
path_out.emplace_back(path[j]); // (#405, #873, #916)
path_out.emplace_back(GetPerpendic(path[j], norms[j], group_delta_));
#endif
}
else if (cos_a > 0.999 && join_type_ != JoinType::Round)
@ -357,7 +367,7 @@ void ClipperOffset::OffsetPolygon(Group& group, const Path64& path)
path_out.clear();
for (Path64::size_type j = 0, k = path.size() - 1; j < path.size(); k = j, ++j)
OffsetPoint(group, path, j, k);
solution->push_back(path_out);
solution->emplace_back(path_out);
}
void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path)
@ -368,7 +378,7 @@ void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path)
//rebuild normals
std::reverse(norms.begin(), norms.end());
norms.push_back(norms[0]);
norms.emplace_back(norms[0]);
norms.erase(norms.begin());
NegatePath(norms);
@ -381,7 +391,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
if (deltaCallback64_) group_delta_ = deltaCallback64_(path, norms, 0, 0);
if (std::fabs(group_delta_) <= floating_point_tolerance)
path_out.push_back(path[0]);
path_out.emplace_back(path[0]);
else
{
switch (end_type_)
@ -413,7 +423,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
group_delta_ = deltaCallback64_(path, norms, highI, highI);
if (std::fabs(group_delta_) <= floating_point_tolerance)
path_out.push_back(path[highI]);
path_out.emplace_back(path[highI]);
else
{
switch (end_type_)
@ -432,7 +442,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
for (size_t j = highI -1, k = highI; j > 0; k = j, --j)
OffsetPoint(group, path, j, k);
solution->push_back(path_out);
solution->emplace_back(path_out);
}
void ClipperOffset::DoGroupOffset(Group& group)
@ -454,13 +464,12 @@ void ClipperOffset::DoGroupOffset(Group& group)
if (group.join_type == JoinType::Round || group.end_type == EndType::Round)
{
// calculate the number of steps required to approximate a circle
// (see http://www.angusj.com/clipper2/Docs/Trigonometry.htm)
// (see https://www.angusj.com/clipper2/Docs/Trigonometry.htm)
// arcTol - when arc_tolerance_ is undefined (0) then curve imprecision
// will be relative to the size of the offset (delta). Obviously very
//large offsets will almost always require much less precision.
double arcTol = (arc_tolerance_ > floating_point_tolerance ?
std::min(abs_delta, arc_tolerance_) :
std::log10(2 + abs_delta) * default_arc_tolerance);
double arcTol = (arc_tolerance_ > floating_point_tolerance) ?
std::min(abs_delta, arc_tolerance_) : abs_delta * arc_const;
double steps_per_360 = std::min(PI / std::acos(1 - arcTol / abs_delta), abs_delta * PI);
step_sin_ = std::sin(2 * PI / steps_per_360);
@ -507,7 +516,7 @@ void ClipperOffset::DoGroupOffset(Group& group)
#endif
}
solution->push_back(path_out);
solution->emplace_back(path_out);
continue;
} // end of offsetting a single point
@ -588,7 +597,7 @@ void ClipperOffset::ExecuteInternal(double delta)
if (!solution->size()) return;
bool paths_reversed = CheckReverseOrientation();
bool paths_reversed = CheckReverseOrientation();
//clean up self-intersections ...
Clipper64 c;
c.PreserveCollinear(false);
@ -617,10 +626,10 @@ void ClipperOffset::ExecuteInternal(double delta)
}
}
void ClipperOffset::Execute(double delta, Paths64& paths)
void ClipperOffset::Execute(double delta, Paths64& paths64)
{
paths.clear();
solution = &paths;
paths64.clear();
solution = &paths64;
solution_tree = nullptr;
ExecuteInternal(delta);
}

View file

@ -1,13 +1,12 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 5 July 2024 *
* Website : http://www.angusj.com *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2024 *
* Purpose : FAST rectangular clipping *
* License : http://www.boost.org/LICENSE_1_0.txt *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
#include <cmath>
#include "clipper2/clipper.h"
#include "clipper2/clipper.rectclip.h"
@ -282,7 +281,7 @@ namespace Clipper2Lib {
{
if (op->edge) return;
op->edge = &edge;
edge.push_back(op);
edge.emplace_back(op);
}
inline void UncoupleEdge(OutPt2* op)
@ -328,7 +327,7 @@ namespace Clipper2Lib {
result->pt = pt;
result->next = result;
result->prev = result;
results_.push_back(result);
results_.emplace_back(result);
}
else
{
@ -489,7 +488,7 @@ namespace Clipper2Lib {
{
bool isClockw = IsClockwise(prev, loc, prev_pt, path[i], rect_mp_);
do {
start_locs_.push_back(prev);
start_locs_.emplace_back(prev);
prev = GetAdjacentLocation(prev, isClockw);
} while (prev != loc);
crossing_loc = crossing_prev; // still not crossed
@ -514,7 +513,7 @@ namespace Clipper2Lib {
if (first_cross_ == Location::Inside)
{
first_cross_ = crossing_loc;
start_locs_.push_back(prev);
start_locs_.emplace_back(prev);
}
else if (prev != crossing_loc)
{
@ -536,7 +535,7 @@ namespace Clipper2Lib {
if (first_cross_ == Location::Inside)
{
first_cross_ = loc;
start_locs_.push_back(prev);
start_locs_.emplace_back(prev);
}
loc = crossing_loc;
@ -750,7 +749,7 @@ namespace Clipper2Lib {
if (!isRejoining)
{
size_t new_idx = results_.size();
results_.push_back(p1a);
results_.emplace_back(p1a);
SetNewOwner(p1a, new_idx);
}
@ -861,11 +860,11 @@ namespace Clipper2Lib {
if (!op2) return Path64();
Path64 result;
result.push_back(op->pt);
result.emplace_back(op->pt);
op2 = op->next;
while (op2 != op)
{
result.push_back(op2->pt);
result.emplace_back(op2->pt);
op2 = op2->next;
}
return result;
@ -885,7 +884,7 @@ namespace Clipper2Lib {
else if (rect_.Contains(path_bounds_))
{
// the path must be completely inside rect_
result.push_back(path);
result.emplace_back(path);
continue;
}
@ -898,7 +897,7 @@ namespace Clipper2Lib {
{
Path64 tmp = GetPath(op);
if (!tmp.empty())
result.emplace_back(tmp);
result.emplace_back(std::move(tmp));
}
//clean up after every loop
@ -930,7 +929,7 @@ namespace Clipper2Lib {
{
Path64 tmp = GetPath(op);
if (!tmp.empty())
result.emplace_back(tmp);
result.emplace_back(std::move(tmp));
}
results_.clear();
@ -1015,11 +1014,11 @@ namespace Clipper2Lib {
Path64 result;
if (!op || op == op->next) return result;
op = op->next; // starting at path beginning
result.push_back(op->pt);
result.emplace_back(op->pt);
OutPt2 *op2 = op->next;
while (op2 != op)
{
result.push_back(op2->pt);
result.emplace_back(op2->pt);
op2 = op2->next;
}
return result;