Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
ClipperLib::ClipperOffset Class Reference

#include <src/clipper/clipper.hpp>

+ Collaboration diagram for ClipperLib::ClipperOffset:

Public Member Functions

 ClipperOffset (double miterLimit=2.0, double roundPrecision=0.25, double shortestEdgeLength=0.)
 
 ~ClipperOffset ()
 
void AddPath (const Path &path, JoinType joinType, EndType endType)
 
template<typename PathsProvider >
void AddPaths (PathsProvider &&paths, JoinType joinType, EndType endType)
 
void Execute (Paths &solution, double delta)
 
void Execute (PolyTree &solution, double delta)
 
void Clear ()
 

Public Attributes

double MiterLimit
 
double ArcTolerance
 
double ShortestEdgeLength
 

Private Member Functions

void FixOrientations ()
 
void DoOffset (double delta)
 
void OffsetPoint (int j, int &k, JoinType jointype)
 
void DoSquare (int j, int k)
 
void DoMiter (int j, int k, double r)
 
void DoRound (int j, int k)
 

Private Attributes

Paths m_destPolys
 
Path m_srcPoly
 
Path m_destPoly
 
std::vector< DoublePoint, Allocator< DoublePoint > > m_normals
 
double m_delta
 
double m_sinA
 
double m_sin
 
double m_cos
 
double m_miterLim
 
double m_StepsPerRad
 
IntPoint m_lowest
 
PolyNode m_polyNodes
 

Detailed Description

Constructor & Destructor Documentation

◆ ClipperOffset()

ClipperLib::ClipperOffset::ClipperOffset ( double  miterLimit = 2.0,
double  roundPrecision = 0.25,
double  shortestEdgeLength = 0. 
)
inline
542 :
543 MiterLimit(miterLimit), ArcTolerance(roundPrecision), ShortestEdgeLength(shortestEdgeLength), m_lowest(-1, 0) {}
IntPoint m_lowest
Definition clipper.hpp:567
double MiterLimit
Definition clipper.hpp:554
double ArcTolerance
Definition clipper.hpp:555
double ShortestEdgeLength
Definition clipper.hpp:556

◆ ~ClipperOffset()

ClipperLib::ClipperOffset::~ClipperOffset ( )
inline
544{ Clear(); }
void Clear()
Definition clipper.cpp:3319

Member Function Documentation

◆ AddPath()

void ClipperLib::ClipperOffset::AddPath ( const Path path,
JoinType  joinType,
EndType  endType 
)
3329{
3330 int highI = (int)path.size() - 1;
3331 if (highI < 0) return;
3332 PolyNode* newNode = new PolyNode();
3333 newNode->m_jointype = joinType;
3334 newNode->m_endtype = endType;
3335
3336 //strip duplicate points from path and also get index to the lowest point ...
3337 bool has_shortest_edge_length = ShortestEdgeLength > 0.;
3338 double shortest_edge_length2 = has_shortest_edge_length ? ShortestEdgeLength * ShortestEdgeLength : 0.;
3339 if (endType == etClosedLine || endType == etClosedPolygon)
3340 for (; highI > 0; -- highI) {
3341 bool same = false;
3342 if (has_shortest_edge_length) {
3343 double dx = double(path[highI].x() - path[0].x());
3344 double dy = double(path[highI].y() - path[0].y());
3345 same = dx*dx + dy*dy < shortest_edge_length2;
3346 } else
3347 same = path[0] == path[highI];
3348 if (! same)
3349 break;
3350 }
3351 newNode->Contour.reserve(highI + 1);
3352 newNode->Contour.emplace_back(path[0]);
3353 int j = 0, k = 0;
3354 for (int i = 1; i <= highI; i++) {
3355 bool same = false;
3356 if (has_shortest_edge_length) {
3357 double dx = double(path[i].x() - newNode->Contour[j].x());
3358 double dy = double(path[i].y() - newNode->Contour[j].y());
3359 same = dx*dx + dy*dy < shortest_edge_length2;
3360 } else
3361 same = newNode->Contour[j] == path[i];
3362 if (same)
3363 continue;
3364 j++;
3365 newNode->Contour.emplace_back(path[i]);
3366 if (path[i].y() > newNode->Contour[k].y() ||
3367 (path[i].y() == newNode->Contour[k].y() &&
3368 path[i].x() < newNode->Contour[k].x())) k = j;
3369 }
3370 if (endType == etClosedPolygon && j < 2)
3371 {
3372 delete newNode;
3373 return;
3374 }
3375 m_polyNodes.AddChild(*newNode);
3376
3377 //if this path's lowest pt is lower than all the others then update m_lowest
3378 if (endType != etClosedPolygon) return;
3379 if (m_lowest.x() < 0)
3381 else
3382 {
3383 IntPoint ip = m_polyNodes.Childs[(int)m_lowest.x()]->Contour[(int)m_lowest.y()];
3384 if (newNode->Contour[k].y() > ip.y() ||
3385 (newNode->Contour[k].y() == ip.y() &&
3386 newNode->Contour[k].x() < ip.x()))
3388 }
3389}
PolyNode m_polyNodes
Definition clipper.hpp:568
int ChildCount() const
Definition clipper.hpp:156
PolyNodes Childs
Definition clipper.hpp:150
void AddChild(PolyNode &child)
Definition clipper.cpp:112
Eigen::Matrix< cInt, 2, 1, Eigen::DontAlign > IntPoint
Definition clipper.hpp:111
IntPoint IntPoint2d(cInt x, cInt y)
Definition clipper.cpp:78
@ etClosedLine
Definition clipper.hpp:139
@ etClosedPolygon
Definition clipper.hpp:139
const Scalar & y
Definition MathFunctions.h:552
TCoord< P > x(const P &p)
Definition geometry_traits.hpp:297

References ClipperLib::PolyNode::AddChild(), ClipperLib::PolyNode::ChildCount(), ClipperLib::PolyNode::Childs, ClipperLib::PolyNode::Contour, ClipperLib::etClosedLine, ClipperLib::etClosedPolygon, ClipperLib::IntPoint2d(), ClipperLib::PolyNode::m_endtype, ClipperLib::PolyNode::m_jointype, m_lowest, m_polyNodes, and ShortestEdgeLength.

Referenced by Slic3r::Algorithm::expolygons_to_zpaths_expanded_opened(), Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::offset_expolygon_inner(), Slic3r::raw_offset(), Slic3r::FFFSupport::tree_supports_generate_paths(), Slic3r::Algorithm::wavefront_initial(), and Slic3r::Algorithm::wavefront_step().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ AddPaths()

template<typename PathsProvider >
void ClipperLib::ClipperOffset::AddPaths ( PathsProvider &&  paths,
JoinType  joinType,
EndType  endType 
)
inline
547 {
548 for (const Path &path : paths)
549 AddPath(path, joinType, endType);
550 }
void AddPath(const Path &path, JoinType joinType, EndType endType)
Definition clipper.cpp:3328
std::vector< IntPoint, Allocator< IntPoint > > Path
Definition clipper.hpp:121

◆ Clear()

void ClipperLib::ClipperOffset::Clear ( )
3320{
3321 for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3322 delete m_polyNodes.Childs[i];
3323 m_polyNodes.Childs.clear();
3324 m_lowest.x() = -1;
3325}

References ClipperLib::PolyNode::ChildCount(), ClipperLib::PolyNode::Childs, m_lowest, and m_polyNodes.

Referenced by Slic3r::Algorithm::expolygons_to_zpaths_expanded_opened(), Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::raw_offset(), Slic3r::Algorithm::wavefront_initial(), and Slic3r::Algorithm::wavefront_step().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DoMiter()

void ClipperLib::ClipperOffset::DoMiter ( int  j,
int  k,
double  r 
)
private
3708{
3709 double q = m_delta / r;
3710 m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + (m_normals[k].x() + m_normals[j].x()) * q),
3711 Round(m_srcPoly[j].y() + (m_normals[k].y() + m_normals[j].y()) * q)));
3712}
double m_delta
Definition clipper.hpp:563
std::vector< DoublePoint, Allocator< DoublePoint > > m_normals
Definition clipper.hpp:562
Path m_srcPoly
Definition clipper.hpp:560
Path m_destPoly
Definition clipper.hpp:561
cInt Round(double val)
Definition clipper.cpp:87

References ClipperLib::IntPoint2d(), m_delta, m_destPoly, m_normals, m_srcPoly, and ClipperLib::Round().

Referenced by OffsetPoint().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DoOffset()

void ClipperLib::ClipperOffset::DoOffset ( double  delta)
private
3481{
3482 m_destPolys.clear();
3483 m_delta = delta;
3484
3485 //if Zero offset, just copy any CLOSED polygons to m_p and return ...
3486 if (NEAR_ZERO(delta))
3487 {
3489 for (int i = 0; i < m_polyNodes.ChildCount(); i++)
3490 {
3491 PolyNode& node = *m_polyNodes.Childs[i];
3492 if (node.m_endtype == etClosedPolygon)
3493 m_destPolys.emplace_back(node.Contour);
3494 }
3495 return;
3496 }
3497
3498 //see offset_triginometry3.svg in the documentation folder ...
3499 m_miterLim = (MiterLimit > 2) ?
3500 2. / (MiterLimit * MiterLimit) :
3501 0.5;
3502
3503 double y;
3504 if (ArcTolerance <= 0.0) y = def_arc_tolerance;
3505 else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance)
3506 y = std::fabs(delta) * def_arc_tolerance;
3507 else y = ArcTolerance;
3508 //see offset_triginometry2.svg in the documentation folder ...
3509 double steps = pi / std::acos(1 - y / std::fabs(delta));
3510 if (steps > std::fabs(delta) * pi)
3511 steps = std::fabs(delta) * pi; //ie excessive precision check
3512 m_sin = std::sin(two_pi / steps);
3513 m_cos = std::cos(two_pi / steps);
3514 m_StepsPerRad = steps / two_pi;
3515 if (delta < 0.0) m_sin = -m_sin;
3516
3517 m_destPolys.reserve(m_polyNodes.ChildCount() * 2);
3518 for (int i = 0; i < m_polyNodes.ChildCount(); i++)
3519 {
3520 PolyNode& node = *m_polyNodes.Childs[i];
3521 m_srcPoly = node.Contour;
3522
3523 int len = (int)m_srcPoly.size();
3524 if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon)))
3525 continue;
3526
3527 m_destPoly.clear();
3528 if (len == 1)
3529 {
3530 if (node.m_jointype == jtRound)
3531 {
3532 double X = 1.0, Y = 0.0;
3533 for (cInt j = 1; j <= steps; j++)
3534 {
3535 m_destPoly.emplace_back(IntPoint2d(
3536 Round(m_srcPoly[0].x() + X * delta),
3537 Round(m_srcPoly[0].y() + Y * delta)));
3538 double X2 = X;
3539 X = X * m_cos - m_sin * Y;
3540 Y = X2 * m_sin + Y * m_cos;
3541 }
3542 }
3543 else
3544 {
3545 double X = -1.0, Y = -1.0;
3546 for (int j = 0; j < 4; ++j)
3547 {
3548 m_destPoly.emplace_back(IntPoint2d(
3549 Round(m_srcPoly[0].x() + X * delta),
3550 Round(m_srcPoly[0].y() + Y * delta)));
3551 if (X < 0) X = 1;
3552 else if (Y < 0) Y = 1;
3553 else X = -1;
3554 }
3555 }
3556 m_destPolys.emplace_back(m_destPoly);
3557 continue;
3558 }
3559 //build m_normals ...
3560 m_normals.clear();
3561 m_normals.reserve(len);
3562 for (int j = 0; j < len - 1; ++j)
3563 m_normals.emplace_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1]));
3564 if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon)
3565 m_normals.emplace_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0]));
3566 else
3567 m_normals.emplace_back(DoublePoint(m_normals[len - 2]));
3568
3569 if (node.m_endtype == etClosedPolygon)
3570 {
3571 int k = len - 1;
3572 for (int j = 0; j < len; ++j)
3573 OffsetPoint(j, k, node.m_jointype);
3574 m_destPolys.emplace_back(m_destPoly);
3575 }
3576 else if (node.m_endtype == etClosedLine)
3577 {
3578 int k = len - 1;
3579 for (int j = 0; j < len; ++j)
3580 OffsetPoint(j, k, node.m_jointype);
3581 m_destPolys.emplace_back(m_destPoly);
3582 m_destPoly.clear();
3583 //re-build m_normals ...
3584 DoublePoint n = m_normals[len -1];
3585 for (int j = len - 1; j > 0; j--)
3586 m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y());
3587 m_normals[0] = DoublePoint(-n.x(), -n.y());
3588 k = 0;
3589 for (int j = len - 1; j >= 0; j--)
3590 OffsetPoint(j, k, node.m_jointype);
3591 m_destPolys.emplace_back(m_destPoly);
3592 }
3593 else
3594 {
3595 int k = 0;
3596 for (int j = 1; j < len - 1; ++j)
3597 OffsetPoint(j, k, node.m_jointype);
3598
3599 IntPoint pt1;
3600 if (node.m_endtype == etOpenButt)
3601 {
3602 int j = len - 1;
3603 pt1 = IntPoint2d(Round(m_srcPoly[j].x() + m_normals[j].x() * delta), Round(m_srcPoly[j].y() + m_normals[j].y() * delta));
3604 m_destPoly.emplace_back(pt1);
3605 pt1 = IntPoint2d(Round(m_srcPoly[j].x() - m_normals[j].x() * delta), Round(m_srcPoly[j].y() - m_normals[j].y() * delta));
3606 m_destPoly.emplace_back(pt1);
3607 }
3608 else
3609 {
3610 int j = len - 1;
3611 k = len - 2;
3612 m_sinA = 0;
3613 m_normals[j] = DoublePoint(-m_normals[j].x(), -m_normals[j].y());
3614 if (node.m_endtype == etOpenSquare)
3615 DoSquare(j, k);
3616 else
3617 DoRound(j, k);
3618 }
3619
3620 //re-build m_normals ...
3621 for (int j = len - 1; j > 0; j--)
3622 m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y());
3623 m_normals[0] = DoublePoint(-m_normals[1].x(), -m_normals[1].y());
3624
3625 k = len - 1;
3626 for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype);
3627
3628 if (node.m_endtype == etOpenButt)
3629 {
3630 pt1 = IntPoint2d(Round(m_srcPoly[0].x() - m_normals[0].x() * delta), Round(m_srcPoly[0].y() - m_normals[0].y() * delta));
3631 m_destPoly.emplace_back(pt1);
3632 pt1 = IntPoint2d(Round(m_srcPoly[0].x() + m_normals[0].x() * delta), Round(m_srcPoly[0].y() + m_normals[0].y() * delta));
3633 m_destPoly.emplace_back(pt1);
3634 }
3635 else
3636 {
3637 k = 1;
3638 m_sinA = 0;
3639 if (node.m_endtype == etOpenSquare)
3640 DoSquare(0, 1);
3641 else
3642 DoRound(0, 1);
3643 }
3644 m_destPolys.emplace_back(m_destPoly);
3645 }
3646 }
3647}
Paths m_destPolys
Definition clipper.hpp:559
void DoSquare(int j, int k)
Definition clipper.cpp:3694
double m_miterLim
Definition clipper.hpp:564
double m_sinA
Definition clipper.hpp:563
void DoRound(int j, int k)
Definition clipper.cpp:3715
void OffsetPoint(int j, int &k, JoinType jointype)
Definition clipper.cpp:3650
double m_StepsPerRad
Definition clipper.hpp:564
double m_sin
Definition clipper.hpp:563
double m_cos
Definition clipper.hpp:563
#define NEAR_ZERO(val)
Definition clipper.cpp:74
static double const pi
Definition clipper.cpp:63
DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
Definition clipper.cpp:3302
@ jtRound
Definition clipper.hpp:138
static double const def_arc_tolerance
Definition clipper.cpp:65
@ etOpenButt
Definition clipper.hpp:139
@ etOpenSquare
Definition clipper.hpp:139
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > DoublePoint
Definition clipper.hpp:114
int32_t cInt
Definition clipper.hpp:91
static double const two_pi
Definition clipper.cpp:64
@ Y
Definition libslic3r.h:99
@ X
Definition libslic3r.h:98

References ArcTolerance, ClipperLib::PolyNode::ChildCount(), ClipperLib::PolyNode::Childs, ClipperLib::PolyNode::Contour, ClipperLib::def_arc_tolerance, DoRound(), DoSquare(), ClipperLib::etClosedLine, ClipperLib::etClosedPolygon, ClipperLib::etOpenButt, ClipperLib::etOpenSquare, ClipperLib::GetUnitNormal(), ClipperLib::IntPoint2d(), ClipperLib::jtRound, m_cos, m_delta, m_destPoly, m_destPolys, ClipperLib::PolyNode::m_endtype, ClipperLib::PolyNode::m_jointype, m_miterLim, m_normals, m_polyNodes, m_sin, m_sinA, m_srcPoly, m_StepsPerRad, MiterLimit, NEAR_ZERO, OffsetPoint(), ClipperLib::pi, ClipperLib::Round(), and ClipperLib::two_pi.

Referenced by Execute(), and Execute().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DoRound()

void ClipperLib::ClipperOffset::DoRound ( int  j,
int  k 
)
private
3716{
3717 double a = std::atan2(m_sinA,
3718 m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y());
3719 auto steps = std::max<int>(Round(m_StepsPerRad * std::fabs(a)), 1);
3720
3721 double X = m_normals[k].x(), Y = m_normals[k].y(), X2;
3722 for (int i = 0; i < steps; ++i)
3723 {
3724 m_destPoly.emplace_back(IntPoint2d(
3725 Round(m_srcPoly[j].x() + X * m_delta),
3726 Round(m_srcPoly[j].y() + Y * m_delta)));
3727 X2 = X;
3728 X = X * m_cos - m_sin * Y;
3729 Y = X2 * m_sin + Y * m_cos;
3730 }
3731 m_destPoly.emplace_back(IntPoint2d(
3732 Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta),
3733 Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta)));
3734}

References ClipperLib::IntPoint2d(), m_cos, m_delta, m_destPoly, m_normals, m_sin, m_sinA, m_srcPoly, m_StepsPerRad, and ClipperLib::Round().

Referenced by DoOffset(), and OffsetPoint().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ DoSquare()

void ClipperLib::ClipperOffset::DoSquare ( int  j,
int  k 
)
private
3695{
3696 double dx = std::tan(std::atan2(m_sinA,
3697 m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y()) / 4);
3698 m_destPoly.emplace_back(IntPoint2d(
3699 Round(m_srcPoly[j].x() + m_delta * (m_normals[k].x() - m_normals[k].y() * dx)),
3700 Round(m_srcPoly[j].y() + m_delta * (m_normals[k].y() + m_normals[k].x() * dx))));
3701 m_destPoly.emplace_back(IntPoint2d(
3702 Round(m_srcPoly[j].x() + m_delta * (m_normals[j].x() + m_normals[j].y() * dx)),
3703 Round(m_srcPoly[j].y() + m_delta * (m_normals[j].y() - m_normals[j].x() * dx))));
3704}

References ClipperLib::IntPoint2d(), m_delta, m_destPoly, m_normals, m_sinA, m_srcPoly, and ClipperLib::Round().

Referenced by DoOffset(), and OffsetPoint().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Execute() [1/2]

void ClipperLib::ClipperOffset::Execute ( Paths solution,
double  delta 
)
3419{
3420 solution.clear();
3422 DoOffset(delta);
3423
3424 //now clean up 'corners' ...
3425 Clipper clpr;
3426 clpr.AddPaths(m_destPolys, ptSubject, true);
3427 if (delta > 0)
3428 {
3429 clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
3430 }
3431 else
3432 {
3433 IntRect r = clpr.GetBounds();
3434 Path outer(4);
3435 outer[0] = IntPoint2d(r.left - 10, r.bottom + 10);
3436 outer[1] = IntPoint2d(r.right + 10, r.bottom + 10);
3437 outer[2] = IntPoint2d(r.right + 10, r.top - 10);
3438 outer[3] = IntPoint2d(r.left - 10, r.top - 10);
3439
3440 clpr.AddPath(outer, ptSubject, true);
3441 clpr.ReverseSolution(true);
3442 clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
3443 if (! solution.empty())
3444 solution.erase(solution.begin());
3445 }
3446}
void DoOffset(double delta)
Definition clipper.cpp:3480
void FixOrientations()
Definition clipper.cpp:3392
@ ctUnion
Definition clipper.hpp:75
@ ptSubject
Definition clipper.hpp:76
@ pftNegative
Definition clipper.hpp:81
@ pftPositive
Definition clipper.hpp:81

References ClipperLib::ClipperBase::AddPath(), ClipperLib::ClipperBase::AddPaths(), ClipperLib::IntRect::bottom, ClipperLib::ctUnion, DoOffset(), ClipperLib::Clipper::Execute(), FixOrientations(), ClipperLib::ClipperBase::GetBounds(), ClipperLib::IntPoint2d(), ClipperLib::IntRect::left, m_destPolys, ClipperLib::pftNegative, ClipperLib::pftPositive, ClipperLib::ptSubject, ClipperLib::Clipper::ReverseSolution(), ClipperLib::IntRect::right, and ClipperLib::IntRect::top.

Referenced by Slic3r::Algorithm::expolygons_to_zpaths_expanded_opened(), Slic3r::expolygons_to_zpaths_shrunk(), Slic3r::offset_expolygon_inner(), Slic3r::raw_offset(), Slic3r::FFFSupport::tree_supports_generate_paths(), Slic3r::Algorithm::wavefront_initial(), and Slic3r::Algorithm::wavefront_step().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Execute() [2/2]

void ClipperLib::ClipperOffset::Execute ( PolyTree solution,
double  delta 
)
3450{
3451 solution.Clear();
3453 DoOffset(delta);
3454
3455 //now clean up 'corners' ...
3456 Clipper clpr;
3457 clpr.AddPaths(m_destPolys, ptSubject, true);
3458 if (delta > 0)
3459 {
3460 clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
3461 }
3462 else
3463 {
3464 IntRect r = clpr.GetBounds();
3465 Path outer(4);
3466 outer[0] = IntPoint2d(r.left - 10, r.bottom + 10);
3467 outer[1] = IntPoint2d(r.right + 10, r.bottom + 10);
3468 outer[2] = IntPoint2d(r.right + 10, r.top - 10);
3469 outer[3] = IntPoint2d(r.left - 10, r.top - 10);
3470
3471 clpr.AddPath(outer, ptSubject, true);
3472 clpr.ReverseSolution(true);
3473 clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
3474 //remove the outer PolyNode rectangle ...
3475 solution.RemoveOutermostPolygon();
3476 }
3477}

References ClipperLib::ClipperBase::AddPath(), ClipperLib::ClipperBase::AddPaths(), ClipperLib::IntRect::bottom, ClipperLib::PolyTree::Clear(), ClipperLib::ctUnion, DoOffset(), ClipperLib::Clipper::Execute(), FixOrientations(), ClipperLib::ClipperBase::GetBounds(), ClipperLib::IntPoint2d(), ClipperLib::IntRect::left, m_destPolys, ClipperLib::pftNegative, ClipperLib::pftPositive, ClipperLib::ptSubject, ClipperLib::PolyTree::RemoveOutermostPolygon(), ClipperLib::Clipper::ReverseSolution(), ClipperLib::IntRect::right, and ClipperLib::IntRect::top.

+ Here is the call graph for this function:

◆ FixOrientations()

void ClipperLib::ClipperOffset::FixOrientations ( )
private
3393{
3394 //fixup orientations of all closed paths if the orientation of the
3395 //closed path with the lowermost vertex is wrong ...
3396 if (m_lowest.x() >= 0 &&
3397 !Orientation(m_polyNodes.Childs[(int)m_lowest.x()]->Contour))
3398 {
3399 for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3400 {
3401 PolyNode& node = *m_polyNodes.Childs[i];
3402 if (node.m_endtype == etClosedPolygon ||
3403 (node.m_endtype == etClosedLine && Orientation(node.Contour)))
3404 ReversePath(node.Contour);
3405 }
3406 } else
3407 {
3408 for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3409 {
3410 PolyNode& node = *m_polyNodes.Childs[i];
3411 if (node.m_endtype == etClosedLine && !Orientation(node.Contour))
3412 ReversePath(node.Contour);
3413 }
3414 }
3415}
void ReversePath(Path &p)
Definition clipper.cpp:3811
Orientation
Definition geometry_traits.hpp:131

References ClipperLib::PolyNode::ChildCount(), ClipperLib::PolyNode::Childs, ClipperLib::PolyNode::Contour, ClipperLib::etClosedLine, ClipperLib::etClosedPolygon, ClipperLib::PolyNode::m_endtype, m_lowest, m_polyNodes, and ClipperLib::ReversePath().

Referenced by Execute(), and Execute().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ OffsetPoint()

void ClipperLib::ClipperOffset::OffsetPoint ( int  j,
int &  k,
JoinType  jointype 
)
private
3651{
3652 //cross product ...
3653 m_sinA = (m_normals[k].x() * m_normals[j].y() - m_normals[j].x() * m_normals[k].y());
3654 if (std::fabs(m_sinA * m_delta) < 1.0)
3655 {
3656 //dot product ...
3657 double cosA = (m_normals[k].x() * m_normals[j].x() + m_normals[j].y() * m_normals[k].y() );
3658 if (cosA > 0) // angle => 0 degrees
3659 {
3660 m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta),
3661 Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta)));
3662 return;
3663 }
3664 //else angle => 180 degrees
3665 }
3666 else if (m_sinA > 1.0) m_sinA = 1.0;
3667 else if (m_sinA < -1.0) m_sinA = -1.0;
3668
3669 if (m_sinA * m_delta < 0)
3670 {
3671 m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta),
3672 Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta)));
3673 m_destPoly.emplace_back(m_srcPoly[j]);
3674 m_destPoly.emplace_back(IntPoint2d(Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta),
3675 Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta)));
3676 }
3677 else
3678 switch (jointype)
3679 {
3680 case jtMiter:
3681 {
3682 double r = 1 + (m_normals[j].x() * m_normals[k].x() +
3683 m_normals[j].y() * m_normals[k].y());
3684 if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k);
3685 break;
3686 }
3687 case jtSquare: DoSquare(j, k); break;
3688 case jtRound: DoRound(j, k); break;
3689 }
3690 k = j;
3691}
void DoMiter(int j, int k, double r)
Definition clipper.cpp:3707
@ jtSquare
Definition clipper.hpp:138
@ jtMiter
Definition clipper.hpp:138

References DoMiter(), DoRound(), DoSquare(), ClipperLib::IntPoint2d(), ClipperLib::jtMiter, ClipperLib::jtRound, ClipperLib::jtSquare, m_delta, m_destPoly, m_miterLim, m_normals, m_sinA, m_srcPoly, and ClipperLib::Round().

Referenced by DoOffset().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ ArcTolerance

◆ m_cos

double ClipperLib::ClipperOffset::m_cos
private

Referenced by DoOffset(), and DoRound().

◆ m_delta

double ClipperLib::ClipperOffset::m_delta
private

◆ m_destPoly

Path ClipperLib::ClipperOffset::m_destPoly
private

◆ m_destPolys

Paths ClipperLib::ClipperOffset::m_destPolys
private

Referenced by DoOffset(), Execute(), and Execute().

◆ m_lowest

IntPoint ClipperLib::ClipperOffset::m_lowest
private

Referenced by AddPath(), Clear(), and FixOrientations().

◆ m_miterLim

double ClipperLib::ClipperOffset::m_miterLim
private

Referenced by DoOffset(), and OffsetPoint().

◆ m_normals

std::vector<DoublePoint, Allocator<DoublePoint> > ClipperLib::ClipperOffset::m_normals
private

◆ m_polyNodes

PolyNode ClipperLib::ClipperOffset::m_polyNodes
private

◆ m_sin

double ClipperLib::ClipperOffset::m_sin
private

Referenced by DoOffset(), and DoRound().

◆ m_sinA

double ClipperLib::ClipperOffset::m_sinA
private

◆ m_srcPoly

Path ClipperLib::ClipperOffset::m_srcPoly
private

◆ m_StepsPerRad

double ClipperLib::ClipperOffset::m_StepsPerRad
private

Referenced by DoOffset(), and DoRound().

◆ MiterLimit

◆ ShortestEdgeLength


The documentation for this class was generated from the following files: