Downgrade Clipper to 5.1.5

This commit is contained in:
Alessandro Ranellucci 2013-08-26 15:57:54 +02:00
parent 0933a2cf6b
commit b6005327d6
5 changed files with 189 additions and 321 deletions

View file

@ -21,9 +21,9 @@ my $build = Module::Build::WithXSpp->new(
Module::Build 0.38 Module::Build 0.38
Module::Build::WithXSpp 0.13 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 # 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 # Provides extra C typemaps that are auto-merged
extra_typemap_modules => { extra_typemap_modules => {

View file

@ -144,7 +144,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
void void
offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta1, 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 // read input
ClipperLib::Polygons* input = new ClipperLib::Polygons(); ClipperLib::Polygons* input = new ClipperLib::Polygons();
@ -168,7 +168,7 @@ offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float de
void void
offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1, 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 // perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons(); ClipperLib::Polygons* output = new ClipperLib::Polygons();
@ -181,7 +181,7 @@ offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1
void void
offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1, 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 // perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons(); ClipperLib::Polygons* output = new ClipperLib::Polygons();
@ -193,8 +193,8 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d
} }
template <class T> template <class T>
void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject, void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
Slic3r::Polygons &clip, T &retval, bool safety_offset) Slic3r::Polygons &clip, T &retval, const bool safety_offset)
{ {
// read input // read input
ClipperLib::Polygons* input_subject = new ClipperLib::Polygons(); ClipperLib::Polygons* input_subject = new ClipperLib::Polygons();

View file

@ -1,8 +1,8 @@
/******************************************************************************* /*******************************************************************************
* * * *
* Author : Angus Johnson * * Author : Angus Johnson *
* Version : 5.1.6 * * Version : 5.1.5 *
* Date : 23 May 2013 * * Date : 4 May 2013 *
* Website : http://www.angusj.com * * Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 * * Copyright : Angus Johnson 2010-2013 *
* * * *
@ -59,8 +59,6 @@ enum Direction { dRightToLeft, dLeftToRight };
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b)) #define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
const char coords_range_error[] = "Coordinate exceeds range bounds.";
inline long64 Abs(long64 val) inline long64 Abs(long64 val)
{ {
return val < 0 ? -val : 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) for (Polygon::size_type i = 0; i < pts.size(); ++i)
{ {
if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange) 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) else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
result = true; 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; OutPt *pp2 = pp;
while (true) for (;;)
{ {
if (PointOnLineSegment(pt, pp2->pt, pp2->next->pt, UseFullInt64Range)) if (PointOnLineSegment(pt, pp2->pt, pp2->next->pt, UseFullInt64Range))
return true; return true;
pp2 = pp2->next; 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) if (UseFullInt64Range)
return Int128Mul(e1.deltaY, e2.deltaX) == Int128Mul(e1.deltaX, e2.deltaY); 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, void InitEdge(TEdge *e, TEdge *eNext,
TEdge *ePrev, const IntPoint &pt, PolyType polyType) TEdge *ePrev, const IntPoint &pt, PolyType polyType)
{ {
std::memset(e, 0, sizeof(TEdge)); std::memset( e, 0, sizeof( TEdge ));
e->next = eNext; e->next = eNext;
e->prev = ePrev; e->prev = ePrev;
e->xcurr = pt.X; e->xcurr = pt.X;
@ -861,39 +860,27 @@ ClipperBase::~ClipperBase() //destructor
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void RangeTest(const IntPoint& pt, long64& maxrange) bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
{
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)
{ {
int len = (int)pg.size(); int len = (int)pg.size();
if (len < 3) return false; if (len < 3) return false;
long64 maxVal;
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
RangeTest(pg[0], maxVal);
Polygon p(len); Polygon p(len);
p[0] = pg[0]; p[0] = pg[0];
int j = 0; int j = 0;
long64 maxVal;
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
for (int i = 0; i < len; ++i) 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; if (i == 0 || PointsEqual(p[j], pg[i])) continue;
else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange)) else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
@ -1203,6 +1190,7 @@ void Clipper::Reset()
while (lm) while (lm)
{ {
InsertScanbeam(lm->Y); InsertScanbeam(lm->Y);
InsertScanbeam(lm->leftBound->ytop);
lm = lm->next; lm = lm->next;
} }
} }
@ -1272,7 +1260,7 @@ bool Clipper::ExecuteInternal()
if (!succeeded) break; if (!succeeded) break;
ProcessEdgesAtTopOfScanbeam(topY); ProcessEdgesAtTopOfScanbeam(topY);
botY = topY; botY = topY;
} while(m_Scanbeam || m_CurrentLM); } while( m_Scanbeam );
} }
catch(...) { catch(...) {
succeeded = false; succeeded = false;
@ -1470,7 +1458,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default: default:
return (edge.windCnt2 < 0); return (edge.windCnt2 < 0);
} }
break;
case ctUnion: case ctUnion:
switch(pft2) switch(pft2)
{ {
@ -1482,7 +1469,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default: default:
return (edge.windCnt2 >= 0); return (edge.windCnt2 >= 0);
} }
break;
case ctDifference: case ctDifference:
if (edge.polyType == ptSubject) if (edge.polyType == ptSubject)
switch(pft2) switch(pft2)
@ -1506,7 +1492,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default: default:
return (edge.windCnt2 < 0); return (edge.windCnt2 < 0);
} }
break;
default: default:
return true; return true;
} }
@ -2070,12 +2055,12 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
{ {
OutRec *outRec = CreateOutRec(); OutRec *outRec = CreateOutRec();
e->outIdx = outRec->idx; e->outIdx = outRec->idx;
OutPt* newOp = new OutPt; OutPt* op = new OutPt;
outRec->pts = newOp; outRec->pts = op;
newOp->pt = pt; op->pt = pt;
newOp->idx = outRec->idx; op->idx = outRec->idx;
newOp->next = newOp; op->next = op;
newOp->prev = newOp; op->prev = op;
SetHoleState(e, outRec); SetHoleState(e, outRec);
} else } else
{ {
@ -2084,14 +2069,14 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
if ((ToFront && PointsEqual(pt, op->pt)) || if ((ToFront && PointsEqual(pt, op->pt)) ||
(!ToFront && PointsEqual(pt, op->prev->pt))) return; (!ToFront && PointsEqual(pt, op->prev->pt))) return;
OutPt* newOp = new OutPt; OutPt* op2 = new OutPt;
newOp->pt = pt; op2->pt = pt;
newOp->idx = outRec->idx; op2->idx = outRec->idx;
newOp->next = op; op2->next = op;
newOp->prev = op->prev; op2->prev = op->prev;
newOp->prev->next = newOp; op2->prev->next = op2;
op->prev = newOp; op->prev = op2;
if (ToFront) outRec->pts = newOp; if (ToFront) outRec->pts = op2;
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -2413,8 +2398,8 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
} }
//bubblesort ... //bubblesort ...
bool isModified; bool isModified = true;
do while( isModified && m_SortedEdges )
{ {
isModified = false; isModified = false;
e = m_SortedEdges; e = m_SortedEdges;
@ -2431,7 +2416,7 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
pt.Y = botY; pt.Y = botY;
pt.X = TopX(*e, pt.Y); pt.X = TopX(*e, pt.Y);
} }
InsertIntersectNode( e, eNext, pt ); AddIntersectNode( e, eNext, pt );
SwapPositionsInSEL(e, eNext); SwapPositionsInSEL(e, eNext);
isModified = true; isModified = true;
} }
@ -2441,12 +2426,11 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0; if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
else break; else break;
} }
while ( isModified ); m_SortedEdges = 0;
m_SortedEdges = 0; //important
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt) void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
{ {
IntersectNode* newNode = new IntersectNode; IntersectNode* newNode = new IntersectNode;
newNode->edge1 = e1; newNode->edge1 = e1;
@ -2463,7 +2447,7 @@ void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
{ {
IntersectNode* iNode = m_IntersectNodes; IntersectNode* iNode = m_IntersectNodes;
while(iNode->next && newNode->pt.Y <= iNode->next->pt.Y) while(iNode->next && newNode->pt.Y <= iNode->next->pt.Y)
iNode = iNode->next; iNode = iNode->next;
newNode->next = iNode->next; newNode->next = iNode->next;
iNode->next = newNode; 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) if (e2.xcurr == e1.xcurr)
{ {
@ -3172,151 +3156,134 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class OffsetBuilder class PolyOffsetBuilder
{ {
private: private:
const Polygons& m_p; Polygons m_p;
Polygon* m_curr_poly; Polygon* m_curr_poly;
std::vector<DoublePoint> normals; 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; size_t m_i, m_j, m_k;
static const int buffLength = 128; static const int buffLength = 128;
JoinType m_jointype;
public: public:
OffsetBuilder(const Polygons& in_polys, Polygons& out_polys, PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit): m_p(in_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;} this->m_p = in_polys;
m_rmin = 0.5; this->m_delta = delta;
m_delta = delta; this->m_jointype = jointype;
if (jointype == jtMiter)
//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); size_t Len = m_p.size(), botI = 0;
limit = 0.25; //just in case endtype == etRound 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; case jtRound:
else if (limit > std::fabs(delta)) limit = std::fabs(delta); 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; double deltaSq = delta*delta;
out_polys.clear(); out_polys.clear();
out_polys.resize(m_p.size()); out_polys.resize(m_p.size());
for (m_i = 0; m_i < m_p.size(); m_i++) 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(); 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)) if (len == 0 || (len < 3 && delta <= 0))
continue; continue;
else if (len == 1) 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; continue;
} }
bool forceClose = PointsEqual(m_p[m_i][0], m_p[m_i][len -1]);
if (forceClose) len--;
//build normals ... //build normals ...
normals.clear(); normals.clear();
normals.resize(len); 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) 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]); 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];
m_curr_poly = &out_polys[m_i]; m_k = len -1;
m_curr_poly->reserve(len); for (m_j = 0; m_j < len; ++m_j)
if (isPolygon || forceClose)
{ {
m_k = len -1; switch (jointype)
for (m_j = 0; m_j < len; ++m_j)
OffsetPoint(jointype, limit);
if (!isPolygon)
{ {
size_t j = out_polys.size(); case jtMiter:
out_polys.resize(j+1); {
m_curr_poly = &out_polys[j]; m_R = 1 + (normals[m_j].X*normals[m_k].X +
m_curr_poly->reserve(len); normals[m_j].Y*normals[m_k].Y);
m_delta = -m_delta; if (m_R >= m_RMin) DoMiter(); else DoSquare(limit);
break;
m_k = len -1; }
for (m_j = 0; m_j < len; ++m_j) case jtSquare: DoSquare(1.0); break;
OffsetPoint(jointype, limit); case jtRound: DoRound(limit); break;
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);
} }
m_k = m_j;
} }
} }
//and clean up untidy corners using Clipper ... //finally, clean up untidy corners using Clipper ...
Clipper clpr; Clipper clpr;
clpr.AddPolygons(out_polys, ptSubject); clpr.AddPolygons(out_polys, ptSubject);
if (delta > 0) if (delta > 0)
@ -3334,10 +3301,12 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
outer[3] = IntPoint(r.left - 10, r.top - 10); outer[3] = IntPoint(r.left - 10, r.top - 10);
clpr.AddPolygon(outer, ptSubject); clpr.AddPolygon(outer, ptSubject);
clpr.ReverseSolution(true);
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative)) if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
{
out_polys.erase(out_polys.begin()); out_polys.erase(out_polys.begin());
else ReversePolygons(out_polys);
} else
out_polys.clear(); out_polys.clear();
} }
} }
@ -3345,24 +3314,6 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
private: 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) void AddPoint(const IntPoint& pt)
{ {
if (m_curr_poly->size() == m_curr_poly->capacity()) 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), IntPoint pt1 = IntPoint((long64)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)); (long64)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), IntPoint pt2 = IntPoint((long64)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)); (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) 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 a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X); double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
a1 = std::fabs(a2 - a1); a1 = std::fabs(a2 - a1);
if (a1 > pi) a1 = pi * 2 - a1; if (a1 > pi) a1 = pi * 2 - a1;
double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta); 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)); pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
(long64)(pt1.Y + normals[m_k].X * dx));
AddPoint(pt1); 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); AddPoint(pt2);
} }
else 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) 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; 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), AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X +
Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q))); (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 else
{ {
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X *
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); m_delta), (long64)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), IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X *
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
AddPoint(pt1); AddPoint(pt1);
AddPoint(m_p[m_i][m_j]); AddPoint(m_p[m_i][m_j]);
AddPoint(pt2); AddPoint(pt2);
@ -3421,10 +3375,10 @@ void DoMiter()
void DoRound(double limit) void DoRound(double limit)
{ {
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), IntPoint pt1 = IntPoint((long64)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)); (long64)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), IntPoint pt2 = IntPoint((long64)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)); (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
AddPoint(pt1); AddPoint(pt1);
//round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg). //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) 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) bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
{ {
if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X)) 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, void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype, double limit, bool autoFix) 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); Polygons poly2(in_polys);
return; PolyOffsetBuilder(poly2, out_polys, delta, jointype, limit, autoFix);
} }
else PolyOffsetBuilder(in_polys, 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);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -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 //distance = proximity in units/pixels below which vertices
//will be stripped. Default ~= sqrt(2). //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--; while (highI > 0 && PointsAreClose(in_poly[highI], in_poly[0], distSqrd)) highI--;
if (highI < 2) { out_poly.clear(); return; } 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]; IntPoint pt = in_poly[highI];
int i = 0, k = 0; int i = 0, k = 0;
for (;;) 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; int i2 = i;
while (i < highI && (PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) || while (i <= highI && PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) ||
SlopesNearColinear(pt, in_poly[i], in_poly[i+1], distSqrd))) i++; SlopesNearColinear(pt, in_poly[i], in_poly[+1], distSqrd)) i++;
if (i >= highI) break; if (i >= highI) break;
else if (i != i2) continue; else if (i != i2) continue;
pt = in_poly[i++]; 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) for (Polygons::size_type i = 0; i < in_polys.size(); ++i)
CleanPolygon(in_polys[i], out_polys[i], distance); 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()) if (!polynode.Contour.empty())
polygons.push_back(polynode.Contour); 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.resize(0);
polygons.reserve(polytree.Total()); polygons.reserve(polytree.Total());

View file

@ -1,8 +1,8 @@
/******************************************************************************* /*******************************************************************************
* * * *
* Author : Angus Johnson * * Author : Angus Johnson *
* Version : 5.1.6 * * Version : 5.1.5 *
* Date : 23 May 2013 * * Date : 4 May 2013 *
* Website : http://www.angusj.com * * Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 * * Copyright : Angus Johnson 2010-2013 *
* * * *
@ -101,7 +101,6 @@ private:
}; };
enum JoinType { jtSquare, jtRound, jtMiter }; enum JoinType { jtSquare, jtRound, jtMiter };
enum EndType { etClosed, etButt, etSquare, etRound};
bool Orientation(const Polygon &poly); bool Orientation(const Polygon &poly);
double Area(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, void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true); 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 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(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Polygons &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 CleanPolygon(Polygon& in_poly, Polygon& out_poly, double distance = 1.415);
void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, 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 ReversePolygon(Polygon& p);
void ReversePolygons(Polygons& p); void ReversePolygons(Polygons& p);
@ -127,8 +123,6 @@ void ReversePolygons(Polygons& p);
//used internally ... //used internally ...
enum EdgeSide { esLeft = 1, esRight = 2}; enum EdgeSide { esLeft = 1, esRight = 2};
enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 }; 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 { struct TEdge {
long64 xbot; long64 xbot;
@ -304,7 +298,7 @@ private:
void DisposeAllPolyPts(); void DisposeAllPolyPts();
void DisposeOutRec(PolyOutList::size_type index); void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const long64 botY, const long64 topY); 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 BuildIntersectList(const long64 botY, const long64 topY);
void ProcessIntersectList(); void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const long64 topY); void ProcessEdgesAtTopOfScanbeam(const long64 topY);

View file

@ -62,7 +62,7 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
[15000000, 15000000], [15000000, 15000000],
[15000000, 5000000], [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'; is_deeply $result->[0]->pp, $expolygon2->pp, 'offset2_ex';
} }