Downgrade Clipper to 5.1.5
This commit is contained in:
parent
0933a2cf6b
commit
b6005327d6
@ -21,9 +21,9 @@ my $build = Module::Build::WithXSpp->new(
|
||||
Module::Build 0.38
|
||||
Module::Build::WithXSpp 0.13
|
||||
)},
|
||||
|
||||
# _GLIBCXX_USE_C99 : to get the long long type for g++
|
||||
# HAS_BOOL : stops Perl/lib/CORE/handy.h from doing "# define bool char" for MSVC
|
||||
extra_compiler_flags => [qw(-DHAS_BOOL)],
|
||||
extra_compiler_flags => [qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL)],
|
||||
|
||||
# Provides extra C typemaps that are auto-merged
|
||||
extra_typemap_modules => {
|
||||
|
@ -144,7 +144,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
|
||||
|
||||
void
|
||||
offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta1,
|
||||
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
|
||||
{
|
||||
// read input
|
||||
ClipperLib::Polygons* input = new ClipperLib::Polygons();
|
||||
@ -168,7 +168,7 @@ offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float de
|
||||
|
||||
void
|
||||
offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1,
|
||||
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
|
||||
{
|
||||
// perform offset
|
||||
ClipperLib::Polygons* output = new ClipperLib::Polygons();
|
||||
@ -181,7 +181,7 @@ offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1
|
||||
|
||||
void
|
||||
offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1,
|
||||
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
|
||||
{
|
||||
// perform offset
|
||||
ClipperLib::Polygons* output = new ClipperLib::Polygons();
|
||||
@ -193,8 +193,8 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||
Slic3r::Polygons &clip, T &retval, bool safety_offset)
|
||||
void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
|
||||
Slic3r::Polygons &clip, T &retval, const bool safety_offset)
|
||||
{
|
||||
// read input
|
||||
ClipperLib::Polygons* input_subject = new ClipperLib::Polygons();
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 5.1.6 *
|
||||
* Date : 23 May 2013 *
|
||||
* Version : 5.1.5 *
|
||||
* Date : 4 May 2013 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2013 *
|
||||
* *
|
||||
@ -59,8 +59,6 @@ enum Direction { dRightToLeft, dLeftToRight };
|
||||
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
|
||||
#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
|
||||
|
||||
const char coords_range_error[] = "Coordinate exceeds range bounds.";
|
||||
|
||||
inline long64 Abs(long64 val)
|
||||
{
|
||||
return val < 0 ? -val : val;
|
||||
@ -356,7 +354,7 @@ bool FullRangeNeeded(const Polygon &pts)
|
||||
for (Polygon::size_type i = 0; i < pts.size(); ++i)
|
||||
{
|
||||
if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange)
|
||||
throw coords_range_error;
|
||||
throw "Coordinate exceeds range bounds.";
|
||||
else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
|
||||
result = true;
|
||||
}
|
||||
@ -456,17 +454,17 @@ bool PointOnLineSegment(const IntPoint pt,
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool PointOnPolygon(const IntPoint pt, OutPt *pp, bool UseFullInt64Range)
|
||||
bool PointOnPolygon(const IntPoint pt,
|
||||
OutPt *pp, bool UseFullInt64Range)
|
||||
{
|
||||
OutPt *pp2 = pp;
|
||||
while (true)
|
||||
for (;;)
|
||||
{
|
||||
if (PointOnLineSegment(pt, pp2->pt, pp2->next->pt, UseFullInt64Range))
|
||||
return true;
|
||||
pp2 = pp2->next;
|
||||
if (pp2 == pp) break;
|
||||
if (pp2 == pp) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -503,7 +501,7 @@ bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
|
||||
bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
|
||||
{
|
||||
if (UseFullInt64Range)
|
||||
return Int128Mul(e1.deltaY, e2.deltaX) == Int128Mul(e1.deltaX, e2.deltaY);
|
||||
@ -669,7 +667,8 @@ void DisposeOutPts(OutPt*& pp)
|
||||
void InitEdge(TEdge *e, TEdge *eNext,
|
||||
TEdge *ePrev, const IntPoint &pt, PolyType polyType)
|
||||
{
|
||||
std::memset(e, 0, sizeof(TEdge));
|
||||
std::memset( e, 0, sizeof( TEdge ));
|
||||
|
||||
e->next = eNext;
|
||||
e->prev = ePrev;
|
||||
e->xcurr = pt.X;
|
||||
@ -861,39 +860,27 @@ ClipperBase::~ClipperBase() //destructor
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void RangeTest(const IntPoint& pt, long64& maxrange)
|
||||
{
|
||||
if (Abs(pt.X) > maxrange)
|
||||
{
|
||||
if (Abs(pt.X) > hiRange)
|
||||
throw coords_range_error;
|
||||
else maxrange = hiRange;
|
||||
}
|
||||
if (Abs(pt.Y) > maxrange)
|
||||
{
|
||||
if (Abs(pt.Y) > hiRange)
|
||||
throw coords_range_error;
|
||||
else maxrange = hiRange;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ClipperBase::AddPolygon(const Polygon &pg, PolyType polyType)
|
||||
bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
|
||||
{
|
||||
int len = (int)pg.size();
|
||||
if (len < 3) return false;
|
||||
|
||||
long64 maxVal;
|
||||
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
|
||||
RangeTest(pg[0], maxVal);
|
||||
|
||||
Polygon p(len);
|
||||
p[0] = pg[0];
|
||||
int j = 0;
|
||||
|
||||
long64 maxVal;
|
||||
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
RangeTest(pg[i], maxVal);
|
||||
if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
|
||||
{
|
||||
if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange)
|
||||
throw "Coordinate exceeds range bounds";
|
||||
maxVal = hiRange;
|
||||
m_UseFullRange = true;
|
||||
}
|
||||
|
||||
if (i == 0 || PointsEqual(p[j], pg[i])) continue;
|
||||
else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
|
||||
@ -1203,6 +1190,7 @@ void Clipper::Reset()
|
||||
while (lm)
|
||||
{
|
||||
InsertScanbeam(lm->Y);
|
||||
InsertScanbeam(lm->leftBound->ytop);
|
||||
lm = lm->next;
|
||||
}
|
||||
}
|
||||
@ -1272,7 +1260,7 @@ bool Clipper::ExecuteInternal()
|
||||
if (!succeeded) break;
|
||||
ProcessEdgesAtTopOfScanbeam(topY);
|
||||
botY = topY;
|
||||
} while(m_Scanbeam || m_CurrentLM);
|
||||
} while( m_Scanbeam );
|
||||
}
|
||||
catch(...) {
|
||||
succeeded = false;
|
||||
@ -1470,7 +1458,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
||||
default:
|
||||
return (edge.windCnt2 < 0);
|
||||
}
|
||||
break;
|
||||
case ctUnion:
|
||||
switch(pft2)
|
||||
{
|
||||
@ -1482,7 +1469,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
||||
default:
|
||||
return (edge.windCnt2 >= 0);
|
||||
}
|
||||
break;
|
||||
case ctDifference:
|
||||
if (edge.polyType == ptSubject)
|
||||
switch(pft2)
|
||||
@ -1506,7 +1492,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
||||
default:
|
||||
return (edge.windCnt2 < 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -2070,12 +2055,12 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
||||
{
|
||||
OutRec *outRec = CreateOutRec();
|
||||
e->outIdx = outRec->idx;
|
||||
OutPt* newOp = new OutPt;
|
||||
outRec->pts = newOp;
|
||||
newOp->pt = pt;
|
||||
newOp->idx = outRec->idx;
|
||||
newOp->next = newOp;
|
||||
newOp->prev = newOp;
|
||||
OutPt* op = new OutPt;
|
||||
outRec->pts = op;
|
||||
op->pt = pt;
|
||||
op->idx = outRec->idx;
|
||||
op->next = op;
|
||||
op->prev = op;
|
||||
SetHoleState(e, outRec);
|
||||
} else
|
||||
{
|
||||
@ -2084,14 +2069,14 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
||||
if ((ToFront && PointsEqual(pt, op->pt)) ||
|
||||
(!ToFront && PointsEqual(pt, op->prev->pt))) return;
|
||||
|
||||
OutPt* newOp = new OutPt;
|
||||
newOp->pt = pt;
|
||||
newOp->idx = outRec->idx;
|
||||
newOp->next = op;
|
||||
newOp->prev = op->prev;
|
||||
newOp->prev->next = newOp;
|
||||
op->prev = newOp;
|
||||
if (ToFront) outRec->pts = newOp;
|
||||
OutPt* op2 = new OutPt;
|
||||
op2->pt = pt;
|
||||
op2->idx = outRec->idx;
|
||||
op2->next = op;
|
||||
op2->prev = op->prev;
|
||||
op2->prev->next = op2;
|
||||
op->prev = op2;
|
||||
if (ToFront) outRec->pts = op2;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@ -2413,8 +2398,8 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
|
||||
}
|
||||
|
||||
//bubblesort ...
|
||||
bool isModified;
|
||||
do
|
||||
bool isModified = true;
|
||||
while( isModified && m_SortedEdges )
|
||||
{
|
||||
isModified = false;
|
||||
e = m_SortedEdges;
|
||||
@ -2431,7 +2416,7 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
|
||||
pt.Y = botY;
|
||||
pt.X = TopX(*e, pt.Y);
|
||||
}
|
||||
InsertIntersectNode( e, eNext, pt );
|
||||
AddIntersectNode( e, eNext, pt );
|
||||
SwapPositionsInSEL(e, eNext);
|
||||
isModified = true;
|
||||
}
|
||||
@ -2441,12 +2426,11 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
|
||||
if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
|
||||
else break;
|
||||
}
|
||||
while ( isModified );
|
||||
m_SortedEdges = 0; //important
|
||||
m_SortedEdges = 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
||||
void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
||||
{
|
||||
IntersectNode* newNode = new IntersectNode;
|
||||
newNode->edge1 = e1;
|
||||
@ -2463,7 +2447,7 @@ void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
||||
{
|
||||
IntersectNode* iNode = m_IntersectNodes;
|
||||
while(iNode->next && newNode->pt.Y <= iNode->next->pt.Y)
|
||||
iNode = iNode->next;
|
||||
iNode = iNode->next;
|
||||
newNode->next = iNode->next;
|
||||
iNode->next = newNode;
|
||||
}
|
||||
@ -2766,7 +2750,7 @@ bool Clipper::FixupIntersectionOrder()
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
|
||||
bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
|
||||
{
|
||||
if (e2.xcurr == e1.xcurr)
|
||||
{
|
||||
@ -3172,151 +3156,134 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class OffsetBuilder
|
||||
class PolyOffsetBuilder
|
||||
{
|
||||
private:
|
||||
const Polygons& m_p;
|
||||
Polygons m_p;
|
||||
Polygon* m_curr_poly;
|
||||
std::vector<DoublePoint> normals;
|
||||
double m_delta, m_rmin, m_r;
|
||||
double m_delta, m_RMin, m_R;
|
||||
size_t m_i, m_j, m_k;
|
||||
static const int buffLength = 128;
|
||||
JoinType m_jointype;
|
||||
|
||||
public:
|
||||
|
||||
OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
||||
bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit): m_p(in_polys)
|
||||
PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
||||
double delta, JoinType jointype, double limit, bool autoFix)
|
||||
{
|
||||
//precondition: &out_polys != &in_polys
|
||||
//nb precondition - out_polys != ptsin_polys
|
||||
if (NEAR_ZERO(delta))
|
||||
{
|
||||
out_polys = in_polys;
|
||||
return;
|
||||
}
|
||||
|
||||
if (NEAR_ZERO(delta)) {out_polys = in_polys; return;}
|
||||
m_rmin = 0.5;
|
||||
m_delta = delta;
|
||||
if (jointype == jtMiter)
|
||||
this->m_p = in_polys;
|
||||
this->m_delta = delta;
|
||||
this->m_jointype = jointype;
|
||||
|
||||
//ChecksInput - fixes polygon orientation if necessary and removes
|
||||
//duplicate vertices. Can be set false when you're sure that polygon
|
||||
//orientation is correct and that there are no duplicate vertices.
|
||||
if (autoFix)
|
||||
{
|
||||
if (limit > 2) m_rmin = 2.0 / (limit * limit);
|
||||
limit = 0.25; //just in case endtype == etRound
|
||||
size_t Len = m_p.size(), botI = 0;
|
||||
while (botI < Len && m_p[botI].empty()) botI++;
|
||||
if (botI == Len) return;
|
||||
|
||||
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
|
||||
//This point (on m_p[botI]) must be on an outer polygon ring and if
|
||||
//its orientation is false (counterclockwise) then assume all polygons
|
||||
//need reversing ...
|
||||
IntPoint botPt = m_p[botI][0];
|
||||
for (size_t i = botI; i < Len; ++i)
|
||||
{
|
||||
if (m_p[i].size() < 3) continue;
|
||||
if (UpdateBotPt(m_p[i][0], botPt)) botI = i;
|
||||
Polygon::iterator it = m_p[i].begin() +1;
|
||||
while (it != m_p[i].end())
|
||||
{
|
||||
if (PointsEqual(*it, *(it -1)))
|
||||
it = m_p[i].erase(it);
|
||||
else
|
||||
{
|
||||
if (UpdateBotPt(*it, botPt)) botI = i;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Orientation(m_p[botI]))
|
||||
ReversePolygons(m_p);
|
||||
}
|
||||
else
|
||||
|
||||
switch (jointype)
|
||||
{
|
||||
if (limit <= 0) limit = 0.25;
|
||||
else if (limit > std::fabs(delta)) limit = std::fabs(delta);
|
||||
case jtRound:
|
||||
if (limit <= 0) limit = 0.25;
|
||||
else if (limit > std::fabs(delta)) limit = std::fabs(delta);
|
||||
break;
|
||||
case jtMiter:
|
||||
if (limit < 2) limit = 2;
|
||||
break;
|
||||
default: //unused
|
||||
limit = 1;
|
||||
}
|
||||
m_RMin = 2.0/(limit*limit);
|
||||
|
||||
double deltaSq = delta*delta;
|
||||
out_polys.clear();
|
||||
out_polys.resize(m_p.size());
|
||||
for (m_i = 0; m_i < m_p.size(); m_i++)
|
||||
{
|
||||
m_curr_poly = &out_polys[m_i];
|
||||
size_t len = m_p[m_i].size();
|
||||
if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X &&
|
||||
m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--;
|
||||
|
||||
//when 'shrinking' polygons - to minimize artefacts
|
||||
//strip those polygons that have an area < pi * delta^2 ...
|
||||
double a1 = Area(m_p[m_i]);
|
||||
if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; }
|
||||
else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area
|
||||
|
||||
if (len == 0 || (len < 3 && delta <= 0))
|
||||
continue;
|
||||
continue;
|
||||
else if (len == 1)
|
||||
{
|
||||
out_polys[m_i] = BuildArc(m_p[m_i][0], 0, 2*pi, delta, limit);
|
||||
Polygon arc;
|
||||
arc = BuildArc(m_p[m_i][len-1], 0, 2 * pi, delta, limit);
|
||||
out_polys[m_i] = arc;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool forceClose = PointsEqual(m_p[m_i][0], m_p[m_i][len -1]);
|
||||
if (forceClose) len--;
|
||||
|
||||
//build normals ...
|
||||
normals.clear();
|
||||
normals.resize(len);
|
||||
normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]);
|
||||
for (m_j = 0; m_j < len -1; ++m_j)
|
||||
normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j +1]);
|
||||
if (isPolygon || forceClose)
|
||||
normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]);
|
||||
else //is open polyline
|
||||
normals[len-1] = normals[len-2];
|
||||
normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j+1]);
|
||||
|
||||
m_curr_poly = &out_polys[m_i];
|
||||
m_curr_poly->reserve(len);
|
||||
|
||||
if (isPolygon || forceClose)
|
||||
m_k = len -1;
|
||||
for (m_j = 0; m_j < len; ++m_j)
|
||||
{
|
||||
m_k = len -1;
|
||||
for (m_j = 0; m_j < len; ++m_j)
|
||||
OffsetPoint(jointype, limit);
|
||||
|
||||
if (!isPolygon)
|
||||
switch (jointype)
|
||||
{
|
||||
size_t j = out_polys.size();
|
||||
out_polys.resize(j+1);
|
||||
m_curr_poly = &out_polys[j];
|
||||
m_curr_poly->reserve(len);
|
||||
m_delta = -m_delta;
|
||||
|
||||
m_k = len -1;
|
||||
for (m_j = 0; m_j < len; ++m_j)
|
||||
OffsetPoint(jointype, limit);
|
||||
m_delta = -m_delta;
|
||||
ReversePolygon(*m_curr_poly);
|
||||
}
|
||||
}
|
||||
else //is open polyline
|
||||
{
|
||||
//offset the polyline going forward ...
|
||||
m_k = 0;
|
||||
for (m_j = 1; m_j < len -1; ++m_j)
|
||||
OffsetPoint(jointype, limit);
|
||||
|
||||
//handle the end (butt, round or square) ...
|
||||
IntPoint pt1;
|
||||
if (endtype == etButt)
|
||||
{
|
||||
m_j = len - 1;
|
||||
pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
pt1 = IntPoint(Round(m_p[m_i][m_j].X - normals[m_j].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y - normals[m_j].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_j = len - 1;
|
||||
m_k = len - 2;
|
||||
normals[m_j].X = -normals[m_j].X;
|
||||
normals[m_j].Y = -normals[m_j].Y;
|
||||
if (endtype == etSquare) DoSquare();
|
||||
else DoRound(limit);
|
||||
}
|
||||
|
||||
//re-build Normals ...
|
||||
for (int j = len - 1; j > 0; --j)
|
||||
{
|
||||
normals[j].X = -normals[j - 1].X;
|
||||
normals[j].Y = -normals[j - 1].Y;
|
||||
}
|
||||
normals[0].X = -normals[1].X;
|
||||
normals[0].Y = -normals[1].Y;
|
||||
|
||||
//offset the polyline going backward ...
|
||||
m_k = len -1;
|
||||
for (m_j = m_k - 1; m_j > 0; --m_j)
|
||||
OffsetPoint(jointype, limit);
|
||||
|
||||
//finally handle the start (butt, round or square) ...
|
||||
if (endtype == etButt)
|
||||
{
|
||||
pt1 = IntPoint(Round(m_p[m_i][0].X - normals[0].X * m_delta),
|
||||
Round(m_p[m_i][0].Y - normals[0].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
pt1 = IntPoint(Round(m_p[m_i][0].X + normals[0].X * m_delta),
|
||||
Round(m_p[m_i][0].Y + normals[0].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
} else
|
||||
{
|
||||
m_k = 1;
|
||||
if (endtype == etSquare) DoSquare();
|
||||
else DoRound(limit);
|
||||
case jtMiter:
|
||||
{
|
||||
m_R = 1 + (normals[m_j].X*normals[m_k].X +
|
||||
normals[m_j].Y*normals[m_k].Y);
|
||||
if (m_R >= m_RMin) DoMiter(); else DoSquare(limit);
|
||||
break;
|
||||
}
|
||||
case jtSquare: DoSquare(1.0); break;
|
||||
case jtRound: DoRound(limit); break;
|
||||
}
|
||||
m_k = m_j;
|
||||
}
|
||||
}
|
||||
|
||||
//and clean up untidy corners using Clipper ...
|
||||
//finally, clean up untidy corners using Clipper ...
|
||||
Clipper clpr;
|
||||
clpr.AddPolygons(out_polys, ptSubject);
|
||||
if (delta > 0)
|
||||
@ -3334,10 +3301,12 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
||||
outer[3] = IntPoint(r.left - 10, r.top - 10);
|
||||
|
||||
clpr.AddPolygon(outer, ptSubject);
|
||||
clpr.ReverseSolution(true);
|
||||
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
|
||||
{
|
||||
out_polys.erase(out_polys.begin());
|
||||
else
|
||||
ReversePolygons(out_polys);
|
||||
|
||||
} else
|
||||
out_polys.clear();
|
||||
}
|
||||
}
|
||||
@ -3345,24 +3314,6 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
||||
|
||||
private:
|
||||
|
||||
void OffsetPoint(JoinType jointype, double limit)
|
||||
{
|
||||
switch (jointype)
|
||||
{
|
||||
case jtMiter:
|
||||
{
|
||||
m_r = 1 + (normals[m_j].X*normals[m_k].X +
|
||||
normals[m_j].Y*normals[m_k].Y);
|
||||
if (m_r >= m_rmin) DoMiter(); else DoSquare();
|
||||
break;
|
||||
}
|
||||
case jtSquare: DoSquare(); break;
|
||||
case jtRound: DoRound(limit); break;
|
||||
}
|
||||
m_k = m_j;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void AddPoint(const IntPoint& pt)
|
||||
{
|
||||
if (m_curr_poly->size() == m_curr_poly->capacity())
|
||||
@ -3371,22 +3322,24 @@ void AddPoint(const IntPoint& pt)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void DoSquare()
|
||||
void DoSquare(double mul)
|
||||
{
|
||||
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
|
||||
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
|
||||
{
|
||||
double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
|
||||
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
|
||||
a1 = std::fabs(a2 - a1);
|
||||
if (a1 > pi) a1 = pi * 2 - a1;
|
||||
double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta);
|
||||
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), (long64)(pt1.Y + normals[m_k].X * dx));
|
||||
double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta * mul);
|
||||
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
|
||||
(long64)(pt1.Y + normals[m_k].X * dx));
|
||||
AddPoint(pt1);
|
||||
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), (long64)(pt2.Y -normals[m_j].X * dx));
|
||||
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
|
||||
(long64)(pt2.Y -normals[m_j].X * dx));
|
||||
AddPoint(pt2);
|
||||
}
|
||||
else
|
||||
@ -3402,16 +3355,17 @@ void DoMiter()
|
||||
{
|
||||
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
|
||||
{
|
||||
double q = m_delta / m_r;
|
||||
AddPoint(IntPoint(Round(m_p[m_i][m_j].X + (normals[m_k].X + normals[m_j].X) * q),
|
||||
Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
|
||||
double q = m_delta / m_R;
|
||||
AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X +
|
||||
(normals[m_k].X + normals[m_j].X) * q),
|
||||
(long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X *
|
||||
m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X *
|
||||
m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
AddPoint(m_p[m_i][m_j]);
|
||||
AddPoint(pt2);
|
||||
@ -3421,10 +3375,10 @@ void DoMiter()
|
||||
|
||||
void DoRound(double limit)
|
||||
{
|
||||
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
|
||||
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
AddPoint(pt1);
|
||||
//round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg).
|
||||
if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0)
|
||||
@ -3446,11 +3400,6 @@ void DoRound(double limit)
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
}; //end PolyOffsetBuilder
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
|
||||
{
|
||||
if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
|
||||
@ -3462,93 +3411,20 @@ bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
}; //end PolyOffsetBuilder
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype, double limit, bool autoFix)
|
||||
{
|
||||
if (!autoFix && &in_polys != &out_polys)
|
||||
if (&out_polys == &in_polys)
|
||||
{
|
||||
OffsetBuilder(in_polys, out_polys, true, delta, jointype, etClosed, limit);
|
||||
return;
|
||||
Polygons poly2(in_polys);
|
||||
PolyOffsetBuilder(poly2, out_polys, delta, jointype, limit, autoFix);
|
||||
}
|
||||
|
||||
Polygons inPolys = Polygons(in_polys);
|
||||
out_polys.clear();
|
||||
|
||||
//ChecksInput - fixes polygon orientation if necessary and removes
|
||||
//duplicate vertices. Can be set false when you're sure that polygon
|
||||
//orientation is correct and that there are no duplicate vertices.
|
||||
if (autoFix)
|
||||
{
|
||||
size_t polyCount = inPolys.size(), botPoly = 0;
|
||||
while (botPoly < polyCount && inPolys[botPoly].empty()) botPoly++;
|
||||
if (botPoly == polyCount) return;
|
||||
|
||||
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
|
||||
//This point (on m_p[botPoly]) must be on an outer polygon ring and if
|
||||
//its orientation is false (counterclockwise) then assume all polygons
|
||||
//need reversing ...
|
||||
IntPoint botPt = inPolys[botPoly][0];
|
||||
for (size_t i = botPoly; i < polyCount; ++i)
|
||||
{
|
||||
if (inPolys[i].size() < 3) { inPolys[i].clear(); continue; }
|
||||
if (UpdateBotPt(inPolys[i][0], botPt)) botPoly = i;
|
||||
Polygon::iterator it = inPolys[i].begin() +1;
|
||||
while (it != inPolys[i].end())
|
||||
{
|
||||
if (PointsEqual(*it, *(it -1)))
|
||||
it = inPolys[i].erase(it);
|
||||
else
|
||||
{
|
||||
if (UpdateBotPt(*it, botPt)) botPoly = i;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Orientation(inPolys[botPoly]))
|
||||
ReversePolygons(inPolys);
|
||||
}
|
||||
OffsetBuilder(inPolys, out_polys, true, delta, jointype, etClosed, limit);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines,
|
||||
double delta, JoinType jointype, EndType endtype,
|
||||
double limit, bool autoFix)
|
||||
{
|
||||
if (!autoFix && endtype != etClosed && &in_lines != &out_lines)
|
||||
{
|
||||
OffsetBuilder(in_lines, out_lines, false, delta, jointype, endtype, limit);
|
||||
return;
|
||||
}
|
||||
|
||||
Polygons inLines = Polygons(in_lines);
|
||||
if (autoFix)
|
||||
for (size_t i = 0; i < inLines.size(); ++i)
|
||||
{
|
||||
if (inLines[i].size() < 2) { inLines[i].clear(); continue; }
|
||||
Polygon::iterator it = inLines[i].begin() +1;
|
||||
while (it != inLines[i].end())
|
||||
{
|
||||
if (PointsEqual(*it, *(it -1)))
|
||||
it = inLines[i].erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (endtype == etClosed)
|
||||
{
|
||||
size_t sz = inLines.size();
|
||||
inLines.resize(sz * 2);
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
inLines[sz+i] = inLines[i];
|
||||
ReversePolygon(inLines[sz+i]);
|
||||
}
|
||||
OffsetBuilder(inLines, out_lines, true, delta, jointype, endtype, limit);
|
||||
}
|
||||
else
|
||||
OffsetBuilder(inLines, out_lines, false, delta, jointype, endtype, limit);
|
||||
else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, limit, autoFix);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -3616,7 +3492,7 @@ bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
|
||||
void CleanPolygon(Polygon& in_poly, Polygon& out_poly, double distance)
|
||||
{
|
||||
//distance = proximity in units/pixels below which vertices
|
||||
//will be stripped. Default ~= sqrt(2).
|
||||
@ -3625,17 +3501,15 @@ void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
|
||||
while (highI > 0 && PointsAreClose(in_poly[highI], in_poly[0], distSqrd)) highI--;
|
||||
if (highI < 2) { out_poly.clear(); return; }
|
||||
|
||||
if (&in_poly != &out_poly)
|
||||
out_poly.resize(highI + 1);
|
||||
|
||||
out_poly.resize(highI + 1);
|
||||
IntPoint pt = in_poly[highI];
|
||||
int i = 0, k = 0;
|
||||
for (;;)
|
||||
{
|
||||
while (i < highI && PointsAreClose(pt, in_poly[i+1], distSqrd)) i+=2;
|
||||
while (i <= highI && PointsAreClose(pt, in_poly[i+1], distSqrd)) i+=2;
|
||||
int i2 = i;
|
||||
while (i < highI && (PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) ||
|
||||
SlopesNearColinear(pt, in_poly[i], in_poly[i+1], distSqrd))) i++;
|
||||
while (i <= highI && PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) ||
|
||||
SlopesNearColinear(pt, in_poly[i], in_poly[+1], distSqrd)) i++;
|
||||
if (i >= highI) break;
|
||||
else if (i != i2) continue;
|
||||
pt = in_poly[i++];
|
||||
@ -3648,14 +3522,14 @@ void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance)
|
||||
void CleanPolygons(Polygons& in_polys, Polygons& out_polys, double distance)
|
||||
{
|
||||
for (Polygons::size_type i = 0; i < in_polys.size(); ++i)
|
||||
CleanPolygon(in_polys[i], out_polys[i], distance);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void AddPolyNodeToPolygons(const PolyNode& polynode, Polygons& polygons)
|
||||
void AddPolyNodeToPolygons(PolyNode& polynode, Polygons& polygons)
|
||||
{
|
||||
if (!polynode.Contour.empty())
|
||||
polygons.push_back(polynode.Contour);
|
||||
@ -3664,7 +3538,7 @@ void AddPolyNodeToPolygons(const PolyNode& polynode, Polygons& polygons)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons)
|
||||
void PolyTreeToPolygons(PolyTree& polytree, Polygons& polygons)
|
||||
{
|
||||
polygons.resize(0);
|
||||
polygons.reserve(polytree.Total());
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 5.1.6 *
|
||||
* Date : 23 May 2013 *
|
||||
* Version : 5.1.5 *
|
||||
* Date : 4 May 2013 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2013 *
|
||||
* *
|
||||
@ -101,7 +101,6 @@ private:
|
||||
};
|
||||
|
||||
enum JoinType { jtSquare, jtRound, jtMiter };
|
||||
enum EndType { etClosed, etButt, etSquare, etRound};
|
||||
|
||||
bool Orientation(const Polygon &poly);
|
||||
double Area(const Polygon &poly);
|
||||
@ -109,17 +108,14 @@ double Area(const Polygon &poly);
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true);
|
||||
|
||||
void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines,
|
||||
double delta, JoinType jointype = jtSquare, EndType endtype = etSquare, double limit = 0, bool autoFix = true);
|
||||
|
||||
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
|
||||
|
||||
void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance = 1.415);
|
||||
void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance = 1.415);
|
||||
void CleanPolygon(Polygon& in_poly, Polygon& out_poly, double distance = 1.415);
|
||||
void CleanPolygons(Polygons& in_polys, Polygons& out_polys, double distance = 1.415);
|
||||
|
||||
void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons);
|
||||
void PolyTreeToPolygons(PolyTree& polytree, Polygons& polygons);
|
||||
|
||||
void ReversePolygon(Polygon& p);
|
||||
void ReversePolygons(Polygons& p);
|
||||
@ -127,8 +123,6 @@ void ReversePolygons(Polygons& p);
|
||||
//used internally ...
|
||||
enum EdgeSide { esLeft = 1, esRight = 2};
|
||||
enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
|
||||
//inline IntersectProtects operator|(IntersectProtects a, IntersectProtects b)
|
||||
//{return static_cast<IntersectProtects>(static_cast<int>(a) | static_cast<int>(b));}
|
||||
|
||||
struct TEdge {
|
||||
long64 xbot;
|
||||
@ -304,7 +298,7 @@ private:
|
||||
void DisposeAllPolyPts();
|
||||
void DisposeOutRec(PolyOutList::size_type index);
|
||||
bool ProcessIntersections(const long64 botY, const long64 topY);
|
||||
void InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
void BuildIntersectList(const long64 botY, const long64 topY);
|
||||
void ProcessIntersectList();
|
||||
void ProcessEdgesAtTopOfScanbeam(const long64 topY);
|
||||
|
@ -62,7 +62,7 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
|
||||
[15000000, 15000000],
|
||||
[15000000, 5000000],
|
||||
]);
|
||||
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon2 ], +49900, -49900);
|
||||
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon2 ], -1, +1);
|
||||
is_deeply $result->[0]->pp, $expolygon2->pp, 'offset2_ex';
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user