Dent in perimeters around a hole Clipper Offset has been extended to remove tiny edges before the offset. This is important as the tiny edges pose difficulty for normal calculation, leading to various adverse effects like kinks and dents in the offsetted contour.
This commit is contained in:
parent
70fcedb113
commit
bd9ee88e2f
@ -595,7 +595,8 @@ void InitEdge2(TEdge& e, PolyType Pt)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEdge* RemoveEdge(TEdge* e)
|
||||
// Called from ClipperBase::AddPathInternal() to remove collinear and duplicate points.
|
||||
inline TEdge* RemoveEdge(TEdge* e)
|
||||
{
|
||||
//removes e from double_linked_list (but without removing from memory)
|
||||
e->Prev->Next = e->Next;
|
||||
@ -3486,14 +3487,6 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
|
||||
// ClipperOffset class
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance)
|
||||
{
|
||||
this->MiterLimit = miterLimit;
|
||||
this->ArcTolerance = arcTolerance;
|
||||
m_lowest.X = -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ClipperOffset::Clear()
|
||||
{
|
||||
for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
|
||||
@ -3512,20 +3505,39 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
|
||||
newNode->m_endtype = endType;
|
||||
|
||||
//strip duplicate points from path and also get index to the lowest point ...
|
||||
bool has_shortest_edge_length = ShortestEdgeLength > 0.;
|
||||
double shortest_edge_length2 = has_shortest_edge_length ? ShortestEdgeLength * ShortestEdgeLength : 0.;
|
||||
if (endType == etClosedLine || endType == etClosedPolygon)
|
||||
while (highI > 0 && path[0] == path[highI]) highI--;
|
||||
for (; highI > 0; -- highI) {
|
||||
bool same = false;
|
||||
if (has_shortest_edge_length) {
|
||||
double dx = double(path[highI].X - path[0].X);
|
||||
double dy = double(path[highI].Y - path[0].Y);
|
||||
same = dx*dx + dy*dy < shortest_edge_length2;
|
||||
} else
|
||||
same = path[0] == path[highI];
|
||||
if (! same)
|
||||
break;
|
||||
}
|
||||
newNode->Contour.reserve(highI + 1);
|
||||
newNode->Contour.push_back(path[0]);
|
||||
int j = 0, k = 0;
|
||||
for (int i = 1; i <= highI; i++)
|
||||
if (newNode->Contour[j] != path[i])
|
||||
{
|
||||
j++;
|
||||
newNode->Contour.push_back(path[i]);
|
||||
if (path[i].Y > newNode->Contour[k].Y ||
|
||||
(path[i].Y == newNode->Contour[k].Y &&
|
||||
path[i].X < newNode->Contour[k].X)) k = j;
|
||||
}
|
||||
for (int i = 1; i <= highI; i++) {
|
||||
bool same = false;
|
||||
if (has_shortest_edge_length) {
|
||||
double dx = double(path[i].X - newNode->Contour[j].X);
|
||||
double dy = double(path[i].Y - newNode->Contour[j].Y);
|
||||
same = dx*dx + dy*dy < shortest_edge_length2;
|
||||
} else
|
||||
same = newNode->Contour[j] == path[i];
|
||||
if (same)
|
||||
continue;
|
||||
j++;
|
||||
newNode->Contour.push_back(path[i]);
|
||||
if (path[i].Y > newNode->Contour[k].Y ||
|
||||
(path[i].Y == newNode->Contour[k].Y &&
|
||||
path[i].X < newNode->Contour[k].X)) k = j;
|
||||
}
|
||||
if (endType == etClosedPolygon && j < 2)
|
||||
{
|
||||
delete newNode;
|
||||
@ -3550,8 +3562,8 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
|
||||
|
||||
void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType)
|
||||
{
|
||||
for (Paths::size_type i = 0; i < paths.size(); ++i)
|
||||
AddPath(paths[i], joinType, endType);
|
||||
for (const Path &path : paths)
|
||||
AddPath(path, joinType, endType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -448,7 +448,8 @@ private:
|
||||
class ClipperOffset
|
||||
{
|
||||
public:
|
||||
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
|
||||
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25, double shortestEdgeLength = 0.) :
|
||||
MiterLimit(miterLimit), ArcTolerance(roundPrecision), ShortestEdgeLength(shortestEdgeLength), m_lowest(-1, 0) {}
|
||||
~ClipperOffset() { Clear(); }
|
||||
void AddPath(const Path& path, JoinType joinType, EndType endType);
|
||||
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
|
||||
@ -457,6 +458,7 @@ public:
|
||||
void Clear();
|
||||
double MiterLimit;
|
||||
double ArcTolerance;
|
||||
double ShortestEdgeLength;
|
||||
private:
|
||||
Paths m_destPolys;
|
||||
Path m_srcPoly;
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
#define CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR (0.005f)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
#ifdef CLIPPER_UTILS_DEBUG
|
||||
@ -210,9 +212,11 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
|
||||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPaths(input, joinType, endType);
|
||||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta * float(CLIPPER_OFFSET_SCALE));
|
||||
co.Execute(retval, delta_scaled);
|
||||
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
@ -244,6 +248,7 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
co.Execute(contours, delta_scaled);
|
||||
}
|
||||
@ -260,6 +265,7 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
@ -308,6 +314,7 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
co.Execute(contours, delta_scaled);
|
||||
}
|
||||
@ -331,6 +338,7 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
@ -408,17 +416,20 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
||||
} else {
|
||||
co.MiterLimit = miterLimit;
|
||||
}
|
||||
float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE);
|
||||
float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE);
|
||||
co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR);
|
||||
|
||||
// perform first offset
|
||||
ClipperLib::Paths output1;
|
||||
co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
|
||||
co.Execute(output1, delta1 * float(CLIPPER_OFFSET_SCALE));
|
||||
co.Execute(output1, delta_scaled1);
|
||||
|
||||
// perform second offset
|
||||
co.Clear();
|
||||
co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta2 * float(CLIPPER_OFFSET_SCALE));
|
||||
co.Execute(retval, delta_scaled2);
|
||||
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
|
@ -38,6 +38,7 @@ class Point
|
||||
return Point(scale_(x), scale_(y));
|
||||
};
|
||||
bool operator==(const Point& rhs) const { return this->x == rhs.x && this->y == rhs.y; }
|
||||
bool operator!=(const Point& rhs) const { return ! (*this == rhs); }
|
||||
std::string wkt() const;
|
||||
std::string dump_perl() const;
|
||||
void scale(double factor);
|
||||
|
Loading…
Reference in New Issue
Block a user