Downgrade Clipper to 5.1.5
This commit is contained in:
parent
0933a2cf6b
commit
b6005327d6
5 changed files with 189 additions and 321 deletions
|
@ -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 => {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue