Update Clipper to 6.0.0
This commit is contained in:
parent
d49052779f
commit
50c0081d25
@ -293,6 +293,7 @@ sub make_perimeters {
|
||||
my @p = map $_->medial_axis($pspacing), @thin_walls;
|
||||
my @paths = ();
|
||||
for my $p (@p) {
|
||||
next if $p->length <= $pspacing * 2;
|
||||
my %params = (
|
||||
role => EXTR_ROLE_EXTERNAL_PERIMETER,
|
||||
flow_spacing => $self->perimeter_flow->spacing,
|
||||
|
@ -31,7 +31,7 @@ sub point_on_left {
|
||||
|
||||
sub grow {
|
||||
my $self = shift;
|
||||
return Slic3r::Polyline->new(@$self[0,1,0])->grow(@_);
|
||||
return Slic3r::Polyline->new(@$self)->grow(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -35,20 +35,6 @@ sub simplify {
|
||||
return __PACKAGE__->new(@$simplified);
|
||||
}
|
||||
|
||||
sub grow {
|
||||
my $self = shift;
|
||||
my ($distance, $scale, $joinType, $miterLimit) = @_;
|
||||
$joinType //= JT_SQUARE; # we override this one
|
||||
$scale //= 100000; # we init these because we can't pass undef
|
||||
$miterLimit //= 3;
|
||||
|
||||
my @points = @$self;
|
||||
return @{Slic3r::Geometry::Clipper::offset(
|
||||
[ Slic3r::Polygon->new(@points, CORE::reverse @points[1..($#points-1)]) ],
|
||||
$distance, $scale, $joinType, $miterLimit,
|
||||
)};
|
||||
}
|
||||
|
||||
sub clip_with_polygon {
|
||||
my $self = shift;
|
||||
my ($polygon) = @_;
|
||||
|
@ -652,10 +652,10 @@ sub make_brim {
|
||||
if (@{ $object->support_layers }) {
|
||||
my $support_layer0 = $object->support_layers->[0];
|
||||
push @object_islands,
|
||||
(map $_->polyline->grow($grow_distance), @{$support_layer0->support_fills})
|
||||
(map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_fills})
|
||||
if $support_layer0->support_fills;
|
||||
push @object_islands,
|
||||
(map $_->polyline->grow($grow_distance), @{$support_layer0->support_interface_fills})
|
||||
(map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_interface_fills})
|
||||
if $support_layer0->support_interface_fills;
|
||||
}
|
||||
foreach my $copy (@{$object->copies}) {
|
||||
@ -666,7 +666,7 @@ sub make_brim {
|
||||
# if brim touches skirt, make it around skirt too
|
||||
# TODO: calculate actual skirt width (using each extruder's flow in multi-extruder setups)
|
||||
if ($Slic3r::Config->skirt_distance + (($Slic3r::Config->skirts - 1) * $flow->spacing) <= $Slic3r::Config->brim_width) {
|
||||
push @islands, map $_->split_at_first_point->polyline->grow($grow_distance), @{$self->skirt};
|
||||
push @islands, map @{$_->split_at_first_point->polyline->grow($grow_distance)}, @{$self->skirt};
|
||||
}
|
||||
|
||||
my @loops = ();
|
||||
|
@ -258,6 +258,10 @@ sub make_perimeters {
|
||||
|
||||
# only add the perimeter if there's an intersection with the collapsed area
|
||||
last CYCLE if !@{ intersection($diff, $hypothetical_perimeter) };
|
||||
use Slic3r::SVG;
|
||||
Slic3r::SVG::output("extra.svg",
|
||||
expolygons => union_ex(intersection($diff, $hypothetical_perimeter)),
|
||||
);exit;
|
||||
Slic3r::debugf " adding one more perimeter at layer %d\n", $layer_id;
|
||||
$slice->extra_perimeters($extra_perimeters);
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ sub generate_toolpaths {
|
||||
# solution should be found to achieve both goals
|
||||
$contact_infill = diff(
|
||||
$contact,
|
||||
[ map $_->grow($circle_radius*1.1), @loops ],
|
||||
[ map @{$_->grow($circle_radius*1.1)}, @loops ],
|
||||
);
|
||||
|
||||
# transform loops into ExtrusionPath objects
|
||||
|
@ -92,7 +92,7 @@ sub _plot {
|
||||
foreach my $path (@paths) {
|
||||
foreach my $line (@{$path->lines}) {
|
||||
my @intersections = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
||||
Slic3r::ExPolygon->new($line->grow(Slic3r::Geometry::scale $path->flow_spacing/2))->pp,
|
||||
Slic3r::ExPolygon->new(@{$line->grow(Slic3r::Geometry::scale $path->flow_spacing/2)})->pp,
|
||||
[ $self->line ],
|
||||
) };
|
||||
die "Intersection has more than two points!\n" if first { @$_ > 2 } @intersections;
|
||||
|
@ -35,16 +35,16 @@ use Slic3r::Geometry::Clipper qw(intersection_ex union_ex diff_ex);
|
||||
|
||||
is_deeply [ map $_->pp, @$intersection ], [[
|
||||
[
|
||||
[20, 12],
|
||||
[20, 18],
|
||||
[10, 18],
|
||||
[10, 12],
|
||||
[20, 12],
|
||||
],
|
||||
[
|
||||
[14, 14],
|
||||
[14, 16],
|
||||
[16, 16],
|
||||
[16, 14],
|
||||
[14, 14],
|
||||
],
|
||||
]], 'hole is preserved after intersection';
|
||||
}
|
||||
@ -58,11 +58,11 @@ use Slic3r::Geometry::Clipper qw(intersection_ex union_ex diff_ex);
|
||||
|
||||
my $union = union_ex([ $contour1, $contour2, $hole ]);
|
||||
|
||||
is_deeply [ map $_->pp, @$union ], [[ [ [40,0], [40,40], [0,40], [0,0] ] ]],
|
||||
is_deeply [ map $_->pp, @$union ], [[ [ [40,40], [0,40], [0,0], [40,0] ] ]],
|
||||
'union of two ccw and one cw is a contour with no holes';
|
||||
|
||||
my $diff = diff_ex([ $contour1, $contour2 ], [ $hole ]);
|
||||
is_deeply [ map $_->pp, @$diff ], [[ [ [40,0], [40,40], [0,40], [0,0] ], [ [15,15], [15,25], [25,25], [25,15] ] ]],
|
||||
is_deeply [ map $_->pp, @$diff ], [[ [ [40,40], [0,40], [0,0], [40,0] ], [ [15,25], [25,25], [25,15], [15,15] ] ]],
|
||||
'difference of a cw from two ccw is a contour with one hole';
|
||||
}
|
||||
|
||||
|
2
t/fill.t
2
t/fill.t
@ -68,7 +68,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
||||
);
|
||||
|
||||
# check whether any part was left uncovered
|
||||
my @grown_paths = map Slic3r::Polyline->new(@$_)->grow(scale $params->{flow_spacing}/2), @paths;
|
||||
my @grown_paths = map @{Slic3r::Polyline->new(@$_)->grow(scale $params->{flow_spacing}/2)}, @paths;
|
||||
my $uncovered = diff_ex([ @$expolygon ], [ @grown_paths ], 1);
|
||||
|
||||
# ignore very small dots
|
||||
|
@ -187,7 +187,7 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po
|
||||
|
||||
{
|
||||
my $line = Slic3r::Line->new([10,10], [20,10]);
|
||||
is +($line->grow(5))[0]->area, Slic3r::Polygon->new([5,5], [25,5], [25,15], [5,15])->area, 'grow line';
|
||||
is $line->grow(5)->[0]->area, Slic3r::Polygon->new([10,5], [20,5], [20,15], [10,15])->area, 'grow line';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
@ -67,7 +67,7 @@ ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Polygons &input, Slic3r::E
|
||||
}
|
||||
|
||||
void
|
||||
Slic3rPolygon_to_ClipperPolygon(const Slic3r::Polygon &input, ClipperLib::Polygon &output)
|
||||
Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Polygon &output)
|
||||
{
|
||||
output.clear();
|
||||
for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
|
||||
@ -75,11 +75,12 @@ Slic3rPolygon_to_ClipperPolygon(const Slic3r::Polygon &input, ClipperLib::Polygo
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
Slic3rPolygons_to_ClipperPolygons(const Slic3r::Polygons &input, ClipperLib::Polygons &output)
|
||||
Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Polygons &output)
|
||||
{
|
||||
output.clear();
|
||||
for (Slic3r::Polygons::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||
for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||
ClipperLib::Polygon p;
|
||||
Slic3rPolygon_to_ClipperPolygon(*it, p);
|
||||
output.push_back(p);
|
||||
@ -129,6 +130,38 @@ offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
|
||||
delete output;
|
||||
}
|
||||
|
||||
void
|
||||
offset(Slic3r::Polylines &polylines, ClipperLib::Polygons &retval, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
// read input
|
||||
ClipperLib::Polygons* input = new ClipperLib::Polygons();
|
||||
Slic3rPolygons_to_ClipperPolygons(polylines, *input);
|
||||
|
||||
// scale input
|
||||
scaleClipperPolygons(*input, scale);
|
||||
|
||||
// perform offset
|
||||
ClipperLib::OffsetPaths(*input, retval, (delta*scale), joinType, ClipperLib::etButt, miterLimit);
|
||||
delete input;
|
||||
|
||||
// unscale output
|
||||
scaleClipperPolygons(retval, 1/scale);
|
||||
}
|
||||
|
||||
void
|
||||
offset(Slic3r::Polylines &polylines, Slic3r::Polygons &retval, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
// perform offset
|
||||
ClipperLib::Polygons* output = new ClipperLib::Polygons();
|
||||
offset(polylines, *output, delta, scale, joinType, miterLimit);
|
||||
|
||||
// convert into ExPolygons
|
||||
ClipperPolygons_to_Slic3rPolygons(*output, retval);
|
||||
delete output;
|
||||
}
|
||||
|
||||
void
|
||||
offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
|
@ -21,20 +21,31 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPoly
|
||||
void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons);
|
||||
//-----------------------------------------------------------
|
||||
|
||||
void Slic3rPolygon_to_ClipperPolygon(const Slic3r::Polygon &input, ClipperLib::Polygon &output);
|
||||
void Slic3rPolygons_to_ClipperPolygons(const Slic3r::Polygons &input, ClipperLib::Polygons &output);
|
||||
void Slic3rPolygon_to_ClipperPolygon(const Slic3r::MultiPoint &input, ClipperLib::Polygon &output);
|
||||
template <class T>
|
||||
void Slic3rPolygons_to_ClipperPolygons(const T &input, ClipperLib::Polygons &output);
|
||||
void ClipperPolygon_to_Slic3rPolygon(const ClipperLib::Polygon &input, Slic3r::Polygon &output);
|
||||
void ClipperPolygons_to_Slic3rPolygons(const ClipperLib::Polygons &input, Slic3r::Polygons &output);
|
||||
void ClipperPolygons_to_Slic3rExPolygons(const ClipperLib::Polygons &input, Slic3r::ExPolygons &output);
|
||||
|
||||
void scaleClipperPolygons(ClipperLib::Polygons &polygons, const double scale);
|
||||
|
||||
// offset Polygons
|
||||
void offset(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta,
|
||||
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
void offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
|
||||
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
||||
// offset Polylines
|
||||
void offset(Slic3r::Polylines &polylines, ClipperLib::Polygons &retval, const float delta,
|
||||
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
|
||||
double miterLimit = 3);
|
||||
void offset(Slic3r::Polylines &polylines, Slic3r::Polygons &retval, const float delta,
|
||||
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
|
||||
double miterLimit = 3);
|
||||
|
||||
void offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta,
|
||||
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
4308
xs/src/clipper.cpp
4308
xs/src/clipper.cpp
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 5.1.5 *
|
||||
* Date : 4 May 2013 *
|
||||
* Version : 6.0.0 *
|
||||
* Date : 30 October 2013 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2013 *
|
||||
* *
|
||||
@ -34,11 +34,30 @@
|
||||
#ifndef clipper_hpp
|
||||
#define clipper_hpp
|
||||
|
||||
#define CLIPPER_VERSION "6.0.0"
|
||||
|
||||
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
|
||||
//improve performance but coordinate values are limited to the range +/- 46340
|
||||
//#define use_int32
|
||||
|
||||
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
|
||||
//#define use_xyz
|
||||
|
||||
//use_lines: Enables line clipping. Adds a very minor cost to performance.
|
||||
//#define use_lines
|
||||
|
||||
//When enabled, code developed with earlier versions of Clipper
|
||||
//(ie prior to ver 6) should compile without changes.
|
||||
//In a future update, this compatability code will be removed.
|
||||
#define use_deprecated
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <functional>
|
||||
|
||||
namespace ClipperLib {
|
||||
|
||||
@ -50,23 +69,63 @@ enum PolyType { ptSubject, ptClip };
|
||||
//see http://glprogramming.com/red/chapter11.html
|
||||
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||
|
||||
typedef signed long long long64;
|
||||
typedef unsigned long long ulong64;
|
||||
#ifdef use_int32
|
||||
typedef int cInt;
|
||||
typedef unsigned int cUInt;
|
||||
#else
|
||||
typedef signed long long cInt;
|
||||
typedef unsigned long long cUInt;
|
||||
#endif
|
||||
|
||||
struct IntPoint {
|
||||
public:
|
||||
long64 X;
|
||||
long64 Y;
|
||||
IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {};
|
||||
friend std::ostream& operator <<(std::ostream &s, IntPoint &p);
|
||||
cInt X;
|
||||
cInt Y;
|
||||
#ifdef use_xyz
|
||||
cInt Z;
|
||||
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
|
||||
#else
|
||||
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
|
||||
#endif
|
||||
|
||||
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
|
||||
{
|
||||
return a.X == b.X && a.Y == b.Y;
|
||||
}
|
||||
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
|
||||
{
|
||||
return a.X != b.X || a.Y != b.Y;
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
typedef std::vector< IntPoint > Polygon;
|
||||
typedef std::vector< Polygon > Polygons;
|
||||
typedef std::vector< IntPoint > Path;
|
||||
typedef std::vector< Path > Paths;
|
||||
|
||||
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
|
||||
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
|
||||
|
||||
std::ostream& operator <<(std::ostream &s, Polygon &p);
|
||||
std::ostream& operator <<(std::ostream &s, Polygons &p);
|
||||
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
|
||||
std::ostream& operator <<(std::ostream &s, const Path &p);
|
||||
std::ostream& operator <<(std::ostream &s, const Paths &p);
|
||||
|
||||
#ifdef use_deprecated
|
||||
typedef signed long long long64; //backward compatibility only
|
||||
typedef Path Polygon;
|
||||
typedef Paths Polygons;
|
||||
#endif
|
||||
|
||||
struct DoublePoint
|
||||
{
|
||||
double X;
|
||||
double Y;
|
||||
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
|
||||
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef use_xyz
|
||||
typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
|
||||
#endif
|
||||
|
||||
class PolyNode;
|
||||
typedef std::vector< PolyNode* > PolyNodes;
|
||||
@ -75,13 +134,15 @@ class PolyNode
|
||||
{
|
||||
public:
|
||||
PolyNode();
|
||||
Polygon Contour;
|
||||
Path Contour;
|
||||
PolyNodes Childs;
|
||||
PolyNode* Parent;
|
||||
PolyNode* GetNext() const;
|
||||
bool IsHole() const;
|
||||
bool IsOpen() const;
|
||||
int ChildCount() const;
|
||||
private:
|
||||
bool m_IsOpen;
|
||||
PolyNode* GetNextSiblingUp() const;
|
||||
unsigned Index; //node index in Parent.Childs
|
||||
void AddChild(PolyNode& child);
|
||||
@ -99,113 +160,63 @@ private:
|
||||
PolyNodes AllNodes;
|
||||
friend class Clipper; //to access AllNodes
|
||||
};
|
||||
|
||||
enum JoinType { jtSquare, jtRound, jtMiter };
|
||||
|
||||
bool Orientation(const Polygon &poly);
|
||||
double Area(const Polygon &poly);
|
||||
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
|
||||
enum JoinType {jtSquare, jtRound, jtMiter};
|
||||
enum EndType {etClosed, etButt, etSquare, etRound};
|
||||
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true);
|
||||
bool Orientation(const Path &poly);
|
||||
double Area(const Path &poly);
|
||||
|
||||
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);
|
||||
#ifdef use_deprecated
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true);
|
||||
void PolyTreeToPolygons(const PolyTree& polytree, Paths& paths);
|
||||
void ReversePolygon(Path& p);
|
||||
void ReversePolygons(Paths& p);
|
||||
#endif
|
||||
|
||||
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 OffsetPaths(const Paths &in_polys, Paths &out_polys,
|
||||
double delta, JoinType jointype, EndType endtype, double limit = 0);
|
||||
|
||||
void PolyTreeToPolygons(PolyTree& polytree, Polygons& polygons);
|
||||
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
|
||||
|
||||
void ReversePolygon(Polygon& p);
|
||||
void ReversePolygons(Polygons& p);
|
||||
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
|
||||
void CleanPolygon(Path& poly, double distance = 1.415);
|
||||
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
|
||||
void CleanPolygons(Paths& polys, double distance = 1.415);
|
||||
|
||||
//used internally ...
|
||||
void MinkowkiSum(const Path& poly, const Path& path, Paths& solution, bool isClosed);
|
||||
void MinkowkiDiff(const Path& poly, const Path& path, Paths& solution, bool isClosed);
|
||||
|
||||
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
|
||||
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
|
||||
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
|
||||
|
||||
void ReversePath(Path& p);
|
||||
void ReversePaths(Paths& p);
|
||||
|
||||
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
|
||||
|
||||
//enums that are used internally ...
|
||||
enum EdgeSide { esLeft = 1, esRight = 2};
|
||||
enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
|
||||
|
||||
struct TEdge {
|
||||
long64 xbot;
|
||||
long64 ybot;
|
||||
long64 xcurr;
|
||||
long64 ycurr;
|
||||
long64 xtop;
|
||||
long64 ytop;
|
||||
double dx;
|
||||
long64 deltaX;
|
||||
long64 deltaY;
|
||||
PolyType polyType;
|
||||
EdgeSide side;
|
||||
int windDelta; //1 or -1 depending on winding direction
|
||||
int windCnt;
|
||||
int windCnt2; //winding count of the opposite polytype
|
||||
int outIdx;
|
||||
TEdge *next;
|
||||
TEdge *prev;
|
||||
TEdge *nextInLML;
|
||||
TEdge *nextInAEL;
|
||||
TEdge *prevInAEL;
|
||||
TEdge *nextInSEL;
|
||||
TEdge *prevInSEL;
|
||||
};
|
||||
|
||||
struct IntersectNode {
|
||||
TEdge *edge1;
|
||||
TEdge *edge2;
|
||||
IntPoint pt;
|
||||
IntersectNode *next;
|
||||
};
|
||||
|
||||
struct LocalMinima {
|
||||
long64 Y;
|
||||
TEdge *leftBound;
|
||||
TEdge *rightBound;
|
||||
LocalMinima *next;
|
||||
};
|
||||
|
||||
struct Scanbeam {
|
||||
long64 Y;
|
||||
Scanbeam *next;
|
||||
};
|
||||
|
||||
struct OutPt; //forward declaration
|
||||
|
||||
struct OutRec {
|
||||
int idx;
|
||||
bool isHole;
|
||||
OutRec *FirstLeft; //see comments in clipper.pas
|
||||
PolyNode *polyNode;
|
||||
OutPt *pts;
|
||||
OutPt *bottomPt;
|
||||
};
|
||||
|
||||
struct OutPt {
|
||||
int idx;
|
||||
IntPoint pt;
|
||||
OutPt *next;
|
||||
OutPt *prev;
|
||||
};
|
||||
|
||||
struct JoinRec {
|
||||
IntPoint pt1a;
|
||||
IntPoint pt1b;
|
||||
int poly1Idx;
|
||||
IntPoint pt2a;
|
||||
IntPoint pt2b;
|
||||
int poly2Idx;
|
||||
};
|
||||
|
||||
struct HorzJoinRec {
|
||||
TEdge *edge;
|
||||
int savedIdx;
|
||||
};
|
||||
|
||||
struct IntRect { long64 left; long64 top; long64 right; long64 bottom; };
|
||||
//forward declarations (for stuff used internally) ...
|
||||
struct TEdge;
|
||||
struct IntersectNode;
|
||||
struct LocalMinima;
|
||||
struct Scanbeam;
|
||||
struct OutPt;
|
||||
struct OutRec;
|
||||
struct Join;
|
||||
|
||||
typedef std::vector < OutRec* > PolyOutList;
|
||||
typedef std::vector < TEdge* > EdgeList;
|
||||
typedef std::vector < JoinRec* > JoinList;
|
||||
typedef std::vector < HorzJoinRec* > HorzJoinList;
|
||||
typedef std::vector < Join* > JoinList;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//ClipperBase is the ancestor to the Clipper class. It should not be
|
||||
//instantiated directly. This class simply abstracts the conversion of sets of
|
||||
@ -215,29 +226,43 @@ class ClipperBase
|
||||
public:
|
||||
ClipperBase();
|
||||
virtual ~ClipperBase();
|
||||
bool AddPolygon(const Polygon &pg, PolyType polyType);
|
||||
bool AddPolygons( const Polygons &ppg, PolyType polyType);
|
||||
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
|
||||
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
|
||||
|
||||
#ifdef use_deprecated
|
||||
bool AddPolygon(const Path &pg, PolyType PolyTyp);
|
||||
bool AddPolygons(const Paths &ppg, PolyType PolyTyp);
|
||||
#endif
|
||||
|
||||
virtual void Clear();
|
||||
IntRect GetBounds();
|
||||
bool PreserveCollinear() {return m_PreserveCollinear;};
|
||||
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
|
||||
protected:
|
||||
void DisposeLocalMinimaList();
|
||||
TEdge* AddBoundsToLML(TEdge *e);
|
||||
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
|
||||
void PopLocalMinima();
|
||||
virtual void Reset();
|
||||
void InsertLocalMinima(LocalMinima *newLm);
|
||||
void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
|
||||
TEdge* DescendToMin(TEdge *&E);
|
||||
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
|
||||
LocalMinima *m_CurrentLM;
|
||||
LocalMinima *m_MinimaList;
|
||||
bool m_UseFullRange;
|
||||
EdgeList m_edges;
|
||||
bool m_PreserveCollinear;
|
||||
bool m_HasOpenPaths;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Clipper : public virtual ClipperBase
|
||||
{
|
||||
public:
|
||||
Clipper();
|
||||
Clipper(int initOptions = 0);
|
||||
~Clipper();
|
||||
bool Execute(ClipType clipType,
|
||||
Polygons &solution,
|
||||
Paths &solution,
|
||||
PolyFillType subjFillType = pftEvenOdd,
|
||||
PolyFillType clipFillType = pftEvenOdd);
|
||||
bool Execute(ClipType clipType,
|
||||
@ -247,17 +272,21 @@ public:
|
||||
void Clear();
|
||||
bool ReverseSolution() {return m_ReverseOutput;};
|
||||
void ReverseSolution(bool value) {m_ReverseOutput = value;};
|
||||
bool ForceSimple() {return m_ForceSimple;};
|
||||
void ForceSimple(bool value) {m_ForceSimple = value;};
|
||||
bool StrictlySimple() {return m_StrictSimple;};
|
||||
void StrictlySimple(bool value) {m_StrictSimple = value;};
|
||||
//set the callback function for z value filling on intersections (otherwise Z is 0)
|
||||
#ifdef use_xyz
|
||||
void ZFillFunction(TZFillCallback zFillFunc);
|
||||
#endif
|
||||
protected:
|
||||
void Reset();
|
||||
virtual bool ExecuteInternal();
|
||||
private:
|
||||
PolyOutList m_PolyOuts;
|
||||
JoinList m_Joins;
|
||||
HorzJoinList m_HorizJoins;
|
||||
JoinList m_GhostJoins;
|
||||
ClipType m_ClipType;
|
||||
Scanbeam *m_Scanbeam;
|
||||
std::set< cInt, std::greater<cInt> > m_Scanbeam;
|
||||
TEdge *m_ActiveEdges;
|
||||
TEdge *m_SortedEdges;
|
||||
IntersectNode *m_IntersectNodes;
|
||||
@ -266,15 +295,17 @@ private:
|
||||
PolyFillType m_SubjFillType;
|
||||
bool m_ReverseOutput;
|
||||
bool m_UsingPolyTree;
|
||||
bool m_ForceSimple;
|
||||
void DisposeScanbeamList();
|
||||
bool m_StrictSimple;
|
||||
#ifdef use_xyz
|
||||
TZFillCallback m_ZFill; //custom callback
|
||||
#endif
|
||||
void SetWindingCount(TEdge& edge);
|
||||
bool IsEvenOddFillType(const TEdge& edge) const;
|
||||
bool IsEvenOddAltFillType(const TEdge& edge) const;
|
||||
void InsertScanbeam(const long64 Y);
|
||||
long64 PopScanbeam();
|
||||
void InsertLocalMinimaIntoAEL(const long64 botY);
|
||||
void InsertEdgeIntoAEL(TEdge *edge);
|
||||
void InsertScanbeam(const cInt Y);
|
||||
cInt PopScanbeam();
|
||||
void InsertLocalMinimaIntoAEL(const cInt botY);
|
||||
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
|
||||
void AddEdgeToSEL(TEdge *edge);
|
||||
void CopyAELToSEL();
|
||||
void DeleteFromSEL(TEdge *e);
|
||||
@ -282,27 +313,28 @@ private:
|
||||
void UpdateEdgeIntoAEL(TEdge *&e);
|
||||
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
|
||||
bool IsContributing(const TEdge& edge) const;
|
||||
bool IsTopHorz(const long64 XPos);
|
||||
bool IsTopHorz(const cInt XPos);
|
||||
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
|
||||
void DoMaxima(TEdge *e, long64 topY);
|
||||
void ProcessHorizontals();
|
||||
void ProcessHorizontal(TEdge *horzEdge);
|
||||
void DoMaxima(TEdge *e);
|
||||
void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
|
||||
void ProcessHorizontals(bool IsTopOfScanbeam);
|
||||
void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
|
||||
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
OutRec* GetOutRec(int idx);
|
||||
void AppendPolygon(TEdge *e1, TEdge *e2);
|
||||
void IntersectEdges(TEdge *e1, TEdge *e2,
|
||||
const IntPoint &pt, const IntersectProtects protects);
|
||||
const IntPoint &pt, bool protect = false);
|
||||
OutRec* CreateOutRec();
|
||||
void AddOutPt(TEdge *e, const IntPoint &pt);
|
||||
void DisposeAllPolyPts();
|
||||
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
|
||||
void DisposeAllOutRecs();
|
||||
void DisposeOutRec(PolyOutList::size_type index);
|
||||
bool ProcessIntersections(const long64 botY, const long64 topY);
|
||||
void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
void BuildIntersectList(const long64 botY, const long64 topY);
|
||||
bool ProcessIntersections(const cInt botY, const cInt topY);
|
||||
void InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
void BuildIntersectList(const cInt botY, const cInt topY);
|
||||
void ProcessIntersectList();
|
||||
void ProcessEdgesAtTopOfScanbeam(const long64 topY);
|
||||
void BuildResult(Polygons& polys);
|
||||
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
|
||||
void BuildResult(Paths& polys);
|
||||
void BuildResult2(PolyTree& polytree);
|
||||
void SetHoleState(TEdge *e, OutRec *outrec);
|
||||
void DisposeIntersectNodes();
|
||||
@ -310,19 +342,19 @@ private:
|
||||
void FixupOutPolygon(OutRec &outrec);
|
||||
bool IsHole(TEdge *e);
|
||||
void FixHoleLinkage(OutRec &outrec);
|
||||
void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1);
|
||||
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
|
||||
void ClearJoins();
|
||||
void AddHorzJoin(TEdge *e, int idx);
|
||||
void ClearHorzJoins();
|
||||
bool JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2);
|
||||
void FixupJoinRecs(JoinRec *j, OutPt *pt, unsigned startIdx);
|
||||
void ClearGhostJoins();
|
||||
void AddGhostJoin(OutPt *op, const IntPoint offPt);
|
||||
bool JoinPoints(const Join *j, OutPt *&p1, OutPt *&p2);
|
||||
void JoinCommonEdges();
|
||||
void DoSimplePolygons();
|
||||
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||
#ifdef use_xyz
|
||||
void SetZ(IntPoint& pt, TEdge& e);
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class clipperException : public std::exception
|
||||
|
@ -23,59 +23,59 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
|
||||
{
|
||||
my $result = Slic3r::Geometry::Clipper::offset([ $square, $hole_in_square ], 5);
|
||||
is_deeply [ map $_->pp, @$result ], [ [
|
||||
[205, 95],
|
||||
[205, 205],
|
||||
[95, 205],
|
||||
[95, 95],
|
||||
[205, 95],
|
||||
], [
|
||||
[155, 145],
|
||||
[145, 145],
|
||||
[145, 155],
|
||||
[155, 155],
|
||||
[155, 145],
|
||||
] ], 'offset';
|
||||
}
|
||||
|
||||
{
|
||||
my $result = Slic3r::Geometry::Clipper::offset_ex([ @$expolygon ], 5);
|
||||
is_deeply $result->[0]->pp, [ [
|
||||
[205, 95],
|
||||
[205, 205],
|
||||
[95, 205],
|
||||
[95, 95],
|
||||
[205, 95],
|
||||
], [
|
||||
[145, 145],
|
||||
[145, 155],
|
||||
[155, 155],
|
||||
[155, 145],
|
||||
[145, 145],
|
||||
] ], 'offset_ex';
|
||||
}
|
||||
|
||||
{
|
||||
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon ], 5, -2);
|
||||
is_deeply $result->[0]->pp, [ [
|
||||
[203, 97],
|
||||
[203, 203],
|
||||
[97, 203],
|
||||
[97, 97],
|
||||
[203, 97],
|
||||
], [
|
||||
[143, 143],
|
||||
[143, 157],
|
||||
[157, 157],
|
||||
[157, 143],
|
||||
[143, 143],
|
||||
] ], 'offset2_ex';
|
||||
}
|
||||
|
||||
{
|
||||
my $expolygon2 = Slic3r::ExPolygon->new([
|
||||
[20000000, 0],
|
||||
[20000000, 20000000],
|
||||
[0, 20000000],
|
||||
[0, 0],
|
||||
[20000000, 0],
|
||||
], [
|
||||
[5000000, 5000000],
|
||||
[5000000, 15000000],
|
||||
[15000000, 15000000],
|
||||
[15000000, 5000000],
|
||||
[5000000, 5000000],
|
||||
]);
|
||||
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon2 ], -1, +1);
|
||||
is_deeply $result->[0]->pp, $expolygon2->pp, 'offset2_ex';
|
||||
@ -85,7 +85,7 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
|
||||
my $polygon1 = Slic3r::Polygon->new(@$square);
|
||||
my $polygon2 = Slic3r::Polygon->new(reverse @$hole_in_square);
|
||||
my $result = Slic3r::Geometry::Clipper::diff_ex([$polygon1], [$polygon2]);
|
||||
is_deeply $result->[0]->pp, $expolygon->pp, 'diff_ex';
|
||||
is $result->[0]->area, $expolygon->area, 'diff_ex';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
%{
|
||||
#include <myinit.h>
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Polyline.hpp"
|
||||
%}
|
||||
|
||||
@ -68,5 +69,18 @@ Polyline::rotate(angle, center_sv)
|
||||
center.from_SV_check(center_sv);
|
||||
THIS->rotate(angle, ¢er);
|
||||
|
||||
Polygons
|
||||
Polyline::grow(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtSquare, miterLimit = 3)
|
||||
const float delta
|
||||
double scale
|
||||
ClipperLib::JoinType joinType
|
||||
double miterLimit
|
||||
CODE:
|
||||
Polylines polylines;
|
||||
polylines.push_back(*THIS);
|
||||
offset(polylines, RETVAL, delta, scale, joinType, miterLimit);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
%}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user