Ported "avoid crossing perimeters" and bridging unit tests from Perl
to C++. Further reduced Perl bindings. Got rid of the ExPolygonCollection wrapper, replaced with ExPolygons.
This commit is contained in:
parent
a627614b58
commit
576c167bd5
@ -9,11 +9,4 @@ sub bounding_box {
|
||||
return $self->contour->bounding_box;
|
||||
}
|
||||
|
||||
package Slic3r::ExPolygon::Collection;
|
||||
|
||||
sub size {
|
||||
my $self = shift;
|
||||
return [ Slic3r::Geometry::size_2D([ map @$_, map @$_, @$self ]) ];
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -9,13 +9,6 @@ our @ISA = qw(Exporter);
|
||||
our @EXPORT_OK = qw(
|
||||
PI epsilon
|
||||
|
||||
angle3points
|
||||
collinear
|
||||
dot
|
||||
line_intersection
|
||||
normalize
|
||||
polyline_lines
|
||||
polygon_is_convex
|
||||
scale
|
||||
unscale
|
||||
scaled_epsilon
|
||||
@ -26,7 +19,6 @@ our @EXPORT_OK = qw(
|
||||
chained_path_from
|
||||
deg2rad
|
||||
rad2deg
|
||||
rad2deg_dir
|
||||
);
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
@ -43,136 +35,6 @@ sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
|
||||
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
|
||||
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
|
||||
|
||||
# used by geometry.t
|
||||
sub polyline_lines {
|
||||
my ($polyline) = @_;
|
||||
my @points = @$polyline;
|
||||
return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
|
||||
}
|
||||
|
||||
# polygon must be simple (non complex) and ccw
|
||||
sub polygon_is_convex {
|
||||
my ($points) = @_;
|
||||
for (my $i = 0; $i <= $#$points; $i++) {
|
||||
my $angle = angle3points($points->[$i-1], $points->[$i-2], $points->[$i]);
|
||||
return 0 if $angle < PI;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub normalize {
|
||||
my ($line) = @_;
|
||||
|
||||
my $len = sqrt( ($line->[X]**2) + ($line->[Y]**2) + ($line->[Z]**2) )
|
||||
or return [0, 0, 0]; # to avoid illegal division by zero
|
||||
return [ map $_ / $len, @$line ];
|
||||
}
|
||||
|
||||
# 2D dot product
|
||||
# used by 3DScene.pm
|
||||
sub dot {
|
||||
my ($u, $v) = @_;
|
||||
return $u->[X] * $v->[X] + $u->[Y] * $v->[Y];
|
||||
}
|
||||
|
||||
sub line_intersection {
|
||||
my ($line1, $line2, $require_crossing) = @_;
|
||||
$require_crossing ||= 0;
|
||||
|
||||
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
||||
return (ref $intersection && $intersection->[1] == $require_crossing)
|
||||
? $intersection->[0]
|
||||
: undef;
|
||||
}
|
||||
|
||||
# Used by test cases.
|
||||
sub collinear {
|
||||
my ($line1, $line2, $require_overlapping) = @_;
|
||||
my $intersection = _line_intersection(map @$_, @$line1, @$line2);
|
||||
return 0 unless !ref($intersection)
|
||||
&& ($intersection eq 'parallel collinear'
|
||||
|| ($intersection eq 'parallel vertical' && abs($line1->[A][X] - $line2->[A][X]) < epsilon));
|
||||
|
||||
if ($require_overlapping) {
|
||||
my @box_a = bounding_box([ $line1->[0], $line1->[1] ]);
|
||||
my @box_b = bounding_box([ $line2->[0], $line2->[1] ]);
|
||||
return 0 unless bounding_box_intersect( 2, @box_a, @box_b );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _line_intersection {
|
||||
my ( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 ) = @_;
|
||||
|
||||
my ($x, $y); # The as-yet-undetermined intersection point.
|
||||
|
||||
my $dy10 = $y1 - $y0; # dyPQ, dxPQ are the coordinate differences
|
||||
my $dx10 = $x1 - $x0; # between the points P and Q.
|
||||
my $dy32 = $y3 - $y2;
|
||||
my $dx32 = $x3 - $x2;
|
||||
|
||||
my $dy10z = abs( $dy10 ) < epsilon; # Is the difference $dy10 "zero"?
|
||||
my $dx10z = abs( $dx10 ) < epsilon;
|
||||
my $dy32z = abs( $dy32 ) < epsilon;
|
||||
my $dx32z = abs( $dx32 ) < epsilon;
|
||||
|
||||
my $dyx10; # The slopes.
|
||||
my $dyx32;
|
||||
|
||||
$dyx10 = $dy10 / $dx10 unless $dx10z;
|
||||
$dyx32 = $dy32 / $dx32 unless $dx32z;
|
||||
|
||||
# Now we know all differences and the slopes;
|
||||
# we can detect horizontal/vertical special cases.
|
||||
# E.g., slope = 0 means a horizontal line.
|
||||
|
||||
unless ( defined $dyx10 or defined $dyx32 ) {
|
||||
return "parallel vertical";
|
||||
}
|
||||
elsif ( $dy10z and not $dy32z ) { # First line horizontal.
|
||||
$y = $y0;
|
||||
$x = $x2 + ( $y - $y2 ) * $dx32 / $dy32;
|
||||
}
|
||||
elsif ( not $dy10z and $dy32z ) { # Second line horizontal.
|
||||
$y = $y2;
|
||||
$x = $x0 + ( $y - $y0 ) * $dx10 / $dy10;
|
||||
}
|
||||
elsif ( $dx10z and not $dx32z ) { # First line vertical.
|
||||
$x = $x0;
|
||||
$y = $y2 + $dyx32 * ( $x - $x2 );
|
||||
}
|
||||
elsif ( not $dx10z and $dx32z ) { # Second line vertical.
|
||||
$x = $x2;
|
||||
$y = $y0 + $dyx10 * ( $x - $x0 );
|
||||
}
|
||||
elsif ( abs( $dyx10 - $dyx32 ) < epsilon ) {
|
||||
# The slopes are suspiciously close to each other.
|
||||
# Either we have parallel collinear or just parallel lines.
|
||||
|
||||
# The bounding box checks have already weeded the cases
|
||||
# "parallel horizontal" and "parallel vertical" away.
|
||||
|
||||
my $ya = $y0 - $dyx10 * $x0;
|
||||
my $yb = $y2 - $dyx32 * $x2;
|
||||
|
||||
return "parallel collinear" if abs( $ya - $yb ) < epsilon;
|
||||
return "parallel";
|
||||
}
|
||||
else {
|
||||
# None of the special cases matched.
|
||||
# We have a "honest" line intersection.
|
||||
|
||||
$x = ($y2 - $y0 + $dyx10*$x0 - $dyx32*$x2)/($dyx10 - $dyx32);
|
||||
$y = $y0 + $dyx10 * ($x - $x0);
|
||||
}
|
||||
|
||||
my $h10 = $dx10 ? ($x - $x0) / $dx10 : ($dy10 ? ($y - $y0) / $dy10 : 1);
|
||||
my $h32 = $dx32 ? ($x - $x2) / $dx32 : ($dy32 ? ($y - $y2) / $dy32 : 1);
|
||||
|
||||
return [Slic3r::Point->new($x, $y), $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
|
||||
}
|
||||
|
||||
# 2D
|
||||
sub bounding_box {
|
||||
my ($points) = @_;
|
||||
@ -199,36 +61,4 @@ sub size_2D {
|
||||
);
|
||||
}
|
||||
|
||||
# Used by sub collinear, which is used by test cases.
|
||||
# bounding_box_intersect($d, @a, @b)
|
||||
# Return true if the given bounding boxes @a and @b intersect
|
||||
# in $d dimensions. Used by sub collinear.
|
||||
sub bounding_box_intersect {
|
||||
my ( $d, @bb ) = @_; # Number of dimensions and box coordinates.
|
||||
my @aa = splice( @bb, 0, 2 * $d ); # The first box.
|
||||
# (@bb is the second one.)
|
||||
|
||||
# Must intersect in all dimensions.
|
||||
for ( my $i_min = 0; $i_min < $d; $i_min++ ) {
|
||||
my $i_max = $i_min + $d; # The index for the maximum.
|
||||
return 0 if ( $aa[ $i_max ] + epsilon ) < $bb[ $i_min ];
|
||||
return 0 if ( $bb[ $i_max ] + epsilon ) < $aa[ $i_min ];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Used by test cases.
|
||||
# this assumes a CCW rotation from $p2 to $p3 around $p1
|
||||
sub angle3points {
|
||||
my ($p1, $p2, $p3) = @_;
|
||||
# p1 is the center
|
||||
|
||||
my $angle = atan2($p2->[X] - $p1->[X], $p2->[Y] - $p1->[Y])
|
||||
- atan2($p3->[X] - $p1->[X], $p3->[Y] - $p1->[Y]);
|
||||
|
||||
# we only want to return only positive angles
|
||||
return $angle <= 0 ? $angle + 2*PI() : $angle;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -40,8 +40,6 @@ set(SLIC3R_SOURCES
|
||||
enum_bitmask.hpp
|
||||
ExPolygon.cpp
|
||||
ExPolygon.hpp
|
||||
ExPolygonCollection.cpp
|
||||
ExPolygonCollection.hpp
|
||||
Extruder.cpp
|
||||
Extruder.hpp
|
||||
ExtrusionEntity.cpp
|
||||
|
@ -240,7 +240,7 @@ TResult clipper_union(
|
||||
|
||||
// Perform union of input polygons using the positive rule, convert to ExPolygons.
|
||||
//FIXME is there any benefit of not doing the boolean / using pftEvenOdd?
|
||||
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
|
||||
inline ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
|
||||
{
|
||||
return PolyTreeToExPolygons(clipper_union<ClipperLib::PolyTree>(input, do_union ? ClipperLib::pftNonZero : ClipperLib::pftEvenOdd));
|
||||
}
|
||||
@ -438,7 +438,7 @@ Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta,
|
||||
{ return to_polygons(expolygons_offset(surfaces, delta, joinType, miterLimit)); }
|
||||
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
//FIXME one may spare one Clipper Union call.
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit)); }
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit), /* do union */ false); }
|
||||
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{ return PolyTreeToExPolygons(expolygons_offset_pt(expolygons, delta, joinType, miterLimit)); }
|
||||
Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
@ -713,6 +713,8 @@ Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
|
||||
|
@ -1,17 +1,27 @@
|
||||
#ifndef slic3r_ClipperUtils_hpp_
|
||||
#define slic3r_ClipperUtils_hpp_
|
||||
|
||||
//#define SLIC3R_USE_CLIPPER2
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include "clipper.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "Surface.hpp"
|
||||
|
||||
#ifdef SLIC3R_USE_CLIPPER2
|
||||
|
||||
#include <clipper2.clipper.h>
|
||||
|
||||
#else /* SLIC3R_USE_CLIPPER2 */
|
||||
|
||||
#include "clipper.hpp"
|
||||
// import these wherever we're included
|
||||
using Slic3r::ClipperLib::jtMiter;
|
||||
using Slic3r::ClipperLib::jtRound;
|
||||
using Slic3r::ClipperLib::jtSquare;
|
||||
|
||||
#endif /* SLIC3R_USE_CLIPPER2 */
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static constexpr const float ClipperSafetyOffset = 10.f;
|
||||
@ -298,9 +308,6 @@ namespace ClipperUtils {
|
||||
};
|
||||
}
|
||||
|
||||
// Perform union of input polygons using the non-zero rule, convert to ExPolygons.
|
||||
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union = false);
|
||||
|
||||
// offset Polygons
|
||||
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
|
||||
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
|
||||
@ -429,6 +436,7 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
|
||||
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
|
||||
|
@ -136,11 +136,6 @@ void EdgeGrid::Grid::create(const ExPolygons &expolygons, coord_t resolution)
|
||||
create_from_m_contours(resolution);
|
||||
}
|
||||
|
||||
void EdgeGrid::Grid::create(const ExPolygonCollection &expolygons, coord_t resolution)
|
||||
{
|
||||
create(expolygons.expolygons, resolution);
|
||||
}
|
||||
|
||||
// m_contours has been initialized. Now fill in the edge grid.
|
||||
void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
|
||||
{
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "Point.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "ExPolygonCollection.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace EdgeGrid {
|
||||
@ -112,7 +111,6 @@ public:
|
||||
void create(const std::vector<Points> &polygons, coord_t resolution) { this->create(polygons, resolution, false); }
|
||||
void create(const ExPolygon &expoly, coord_t resolution);
|
||||
void create(const ExPolygons &expolygons, coord_t resolution);
|
||||
void create(const ExPolygonCollection &expolygons, coord_t resolution);
|
||||
|
||||
const std::vector<Contour>& contours() const { return m_contours; }
|
||||
|
||||
@ -123,7 +121,6 @@ public:
|
||||
bool intersect(const Polygons &polygons) { for (size_t i = 0; i < polygons.size(); ++ i) if (intersect(polygons[i])) return true; return false; }
|
||||
bool intersect(const ExPolygon &expoly) { if (intersect(expoly.contour)) return true; for (size_t i = 0; i < expoly.holes.size(); ++ i) if (intersect(expoly.holes[i])) return true; return false; }
|
||||
bool intersect(const ExPolygons &expolygons) { for (size_t i = 0; i < expolygons.size(); ++ i) if (intersect(expolygons[i])) return true; return false; }
|
||||
bool intersect(const ExPolygonCollection &expolygons) { return intersect(expolygons.expolygons); }
|
||||
|
||||
// Test, whether a point is inside a contour.
|
||||
bool inside(const Point &pt);
|
||||
@ -391,7 +388,7 @@ protected:
|
||||
|
||||
// Referencing the source contours.
|
||||
// This format allows one to work with any Slic3r fixed point contour format
|
||||
// (Polygon, ExPolygon, ExPolygonCollection etc).
|
||||
// (Polygon, ExPolygon, ExPolygons etc).
|
||||
std::vector<Contour> m_contours;
|
||||
|
||||
// Referencing a contour and a line segment of m_contours.
|
||||
|
@ -9,7 +9,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygon;
|
||||
typedef std::vector<ExPolygon> ExPolygons;
|
||||
using ExPolygons = std::vector<ExPolygon>;
|
||||
|
||||
class ExPolygon
|
||||
{
|
||||
|
@ -1,136 +0,0 @@
|
||||
#include "ExPolygonCollection.hpp"
|
||||
#include "Geometry/ConvexHull.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
ExPolygonCollection::ExPolygonCollection(const ExPolygon &expolygon)
|
||||
{
|
||||
this->expolygons.push_back(expolygon);
|
||||
}
|
||||
|
||||
ExPolygonCollection::operator Points() const
|
||||
{
|
||||
Points points;
|
||||
Polygons pp = (Polygons)*this;
|
||||
for (Polygons::const_iterator poly = pp.begin(); poly != pp.end(); ++poly) {
|
||||
for (Points::const_iterator point = poly->points.begin(); point != poly->points.end(); ++point)
|
||||
points.push_back(*point);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
ExPolygonCollection::operator Polygons() const
|
||||
{
|
||||
Polygons polygons;
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
|
||||
polygons.push_back(it->contour);
|
||||
for (Polygons::const_iterator ith = it->holes.begin(); ith != it->holes.end(); ++ith) {
|
||||
polygons.push_back(*ith);
|
||||
}
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
ExPolygonCollection::operator ExPolygons&()
|
||||
{
|
||||
return this->expolygons;
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygonCollection::scale(double factor)
|
||||
{
|
||||
for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
|
||||
(*it).scale(factor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygonCollection::translate(double x, double y)
|
||||
{
|
||||
for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
|
||||
(*it).translate(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygonCollection::rotate(double angle, const Point ¢er)
|
||||
{
|
||||
for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
|
||||
(*it).rotate(angle, center);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool ExPolygonCollection::contains(const T &item) const
|
||||
{
|
||||
for (const ExPolygon &poly : this->expolygons)
|
||||
if (poly.contains(item))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
template bool ExPolygonCollection::contains<Point>(const Point &item) const;
|
||||
template bool ExPolygonCollection::contains<Line>(const Line &item) const;
|
||||
template bool ExPolygonCollection::contains<Polyline>(const Polyline &item) const;
|
||||
|
||||
bool
|
||||
ExPolygonCollection::contains_b(const Point &point) const
|
||||
{
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
|
||||
if (it->contains_b(point)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygonCollection::simplify(double tolerance)
|
||||
{
|
||||
ExPolygons expp;
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
|
||||
it->simplify(tolerance, &expp);
|
||||
}
|
||||
this->expolygons = expp;
|
||||
}
|
||||
|
||||
Polygon
|
||||
ExPolygonCollection::convex_hull() const
|
||||
{
|
||||
Points pp;
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it)
|
||||
pp.insert(pp.end(), it->contour.points.begin(), it->contour.points.end());
|
||||
return Slic3r::Geometry::convex_hull(pp);
|
||||
}
|
||||
|
||||
Lines
|
||||
ExPolygonCollection::lines() const
|
||||
{
|
||||
Lines lines;
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
|
||||
Lines ex_lines = it->lines();
|
||||
lines.insert(lines.end(), ex_lines.begin(), ex_lines.end());
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
Polygons
|
||||
ExPolygonCollection::contours() const
|
||||
{
|
||||
Polygons contours;
|
||||
contours.reserve(this->expolygons.size());
|
||||
for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it)
|
||||
contours.push_back(it->contour);
|
||||
return contours;
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygonCollection::append(const ExPolygons &expp)
|
||||
{
|
||||
this->expolygons.insert(this->expolygons.end(), expp.begin(), expp.end());
|
||||
}
|
||||
|
||||
BoundingBox get_extents(const ExPolygonCollection &expolygon)
|
||||
{
|
||||
return get_extents(expolygon.expolygons);
|
||||
}
|
||||
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef slic3r_ExPolygonCollection_hpp_
|
||||
#define slic3r_ExPolygonCollection_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "Polyline.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygonCollection;
|
||||
typedef std::vector<ExPolygonCollection> ExPolygonCollections;
|
||||
|
||||
class ExPolygonCollection
|
||||
{
|
||||
public:
|
||||
ExPolygons expolygons;
|
||||
|
||||
ExPolygonCollection() {}
|
||||
explicit ExPolygonCollection(const ExPolygon &expolygon);
|
||||
explicit ExPolygonCollection(const ExPolygons &expolygons) : expolygons(expolygons) {}
|
||||
explicit operator Points() const;
|
||||
explicit operator Polygons() const;
|
||||
explicit operator ExPolygons&();
|
||||
void scale(double factor);
|
||||
void translate(double x, double y);
|
||||
void rotate(double angle, const Point ¢er);
|
||||
template <class T> bool contains(const T &item) const;
|
||||
bool contains_b(const Point &point) const;
|
||||
void simplify(double tolerance);
|
||||
Polygon convex_hull() const;
|
||||
Lines lines() const;
|
||||
Polygons contours() const;
|
||||
void append(const ExPolygons &expolygons);
|
||||
};
|
||||
|
||||
extern BoundingBox get_extents(const ExPolygonCollection &expolygon);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "ExPolygonCollection.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Extruder.hpp"
|
||||
#include "Flow.hpp"
|
||||
@ -12,14 +12,14 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
|
||||
void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
|
||||
{
|
||||
this->_inflate_collection(intersection_pl(Polylines{ polyline }, collection.expolygons), retval);
|
||||
this->_inflate_collection(intersection_pl(Polylines{ polyline }, collection), retval);
|
||||
}
|
||||
|
||||
void ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
|
||||
void ExtrusionPath::subtract_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
|
||||
{
|
||||
this->_inflate_collection(diff_pl(Polylines{ this->polyline }, collection.expolygons), retval);
|
||||
this->_inflate_collection(diff_pl(Polylines{ this->polyline }, collection), retval);
|
||||
}
|
||||
|
||||
void ExtrusionPath::clip_end(double distance)
|
||||
|
@ -11,7 +11,8 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygonCollection;
|
||||
class ExPolygon;
|
||||
using ExPolygons = std::vector<ExPolygon>;
|
||||
class ExtrusionEntityCollection;
|
||||
class Extruder;
|
||||
|
||||
@ -144,12 +145,12 @@ public:
|
||||
size_t size() const { return this->polyline.size(); }
|
||||
bool empty() const { return this->polyline.empty(); }
|
||||
bool is_closed() const { return ! this->empty() && this->polyline.points.front() == this->polyline.points.back(); }
|
||||
// Produce a list of extrusion paths into retval by clipping this path by ExPolygonCollection.
|
||||
// Produce a list of extrusion paths into retval by clipping this path by ExPolygons.
|
||||
// Currently not used.
|
||||
void intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
|
||||
// Produce a list of extrusion paths into retval by removing parts of this path by ExPolygonCollection.
|
||||
void intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const;
|
||||
// Produce a list of extrusion paths into retval by removing parts of this path by ExPolygons.
|
||||
// Currently not used.
|
||||
void subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
|
||||
void subtract_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const;
|
||||
void clip_end(double distance);
|
||||
void simplify(double tolerance);
|
||||
double length() const override;
|
||||
|
@ -3063,7 +3063,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
|
||||
if (role == erSupportMaterial) {
|
||||
const SupportLayer* support_layer = dynamic_cast<const SupportLayer*>(m_layer);
|
||||
//FIXME support_layer->support_islands.contains should use some search structure!
|
||||
if (support_layer != NULL && support_layer->support_islands.contains(travel))
|
||||
if (support_layer != NULL && ! intersection_pl(travel, support_layer->support_islands).empty())
|
||||
// skip retraction if this is a travel move inside a support material island
|
||||
//FIXME not retracting over a long path may cause oozing, which in turn may result in missing material
|
||||
// at the end of the extrusion path!
|
||||
|
@ -50,13 +50,6 @@ bool contains(const std::vector<T> &vector, const Point &point)
|
||||
}
|
||||
template bool contains(const ExPolygons &vector, const Point &point);
|
||||
|
||||
double rad2deg_dir(double angle)
|
||||
{
|
||||
angle = (angle < PI) ? (-angle + PI/2.0) : (angle + PI/2.0);
|
||||
if (angle < 0) angle += PI;
|
||||
return rad2deg(angle);
|
||||
}
|
||||
|
||||
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval)
|
||||
{
|
||||
Polygons pp;
|
||||
|
@ -291,7 +291,6 @@ bool directions_parallel(double angle1, double angle2, double max_diff = 0);
|
||||
bool directions_perpendicular(double angle1, double angle2, double max_diff = 0);
|
||||
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
|
||||
template<typename T> T rad2deg(T angle) { return T(180.0) * angle / T(PI); }
|
||||
double rad2deg_dir(double angle);
|
||||
template<typename T> constexpr T deg2rad(const T angle) { return T(PI) * angle / T(180.0); }
|
||||
template<typename T> T angle_to_0_2PI(T angle)
|
||||
{
|
||||
|
@ -104,6 +104,17 @@ Polygon convex_hull(const Polygons &polygons)
|
||||
return convex_hull(std::move(pp));
|
||||
}
|
||||
|
||||
Polygon convex_hull(const ExPolygons &expolygons)
|
||||
{
|
||||
Points pp;
|
||||
size_t sz = 0;
|
||||
for (const auto &expoly : expolygons)
|
||||
sz += expoly.contour.size();
|
||||
pp.reserve(sz);
|
||||
for (const auto &expoly : expolygons)
|
||||
pp.insert(pp.end(), expoly.contour.points.begin(), expoly.contour.points.end());
|
||||
return convex_hull(pp);
|
||||
}
|
||||
|
||||
namespace rotcalip {
|
||||
|
||||
|
@ -9,6 +9,7 @@ namespace Geometry {
|
||||
Pointf3s convex_hull(Pointf3s points);
|
||||
Polygon convex_hull(Points points);
|
||||
Polygon convex_hull(const Polygons &polygons);
|
||||
Polygon convex_hull(const ExPolygons &expolygons);
|
||||
|
||||
// Returns true if the intersection of the two convex polygons A and B
|
||||
// is not an empty set.
|
||||
|
@ -5,10 +5,11 @@
|
||||
#include "Flow.hpp"
|
||||
#include "SurfaceCollection.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "ExPolygonCollection.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ExPolygon;
|
||||
using ExPolygons = std::vector<ExPolygon>;
|
||||
class Layer;
|
||||
using LayerPtrs = std::vector<Layer*>;
|
||||
class LayerRegion;
|
||||
@ -191,7 +192,7 @@ class SupportLayer : public Layer
|
||||
public:
|
||||
// Polygons covered by the supports: base, interface and contact areas.
|
||||
// Used to suppress retraction if moving for a support extrusion over these support_islands.
|
||||
ExPolygonCollection support_islands;
|
||||
ExPolygons support_islands;
|
||||
// Extrusion paths for the support base and for the support interface and contacts.
|
||||
ExtrusionEntityCollection support_fills;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "Polyline.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "ExPolygonCollection.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include <iostream>
|
||||
|
@ -1,17 +1,14 @@
|
||||
//#include "igl/random_points_on_mesh.h"
|
||||
//#include "igl/AABB.h"
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
#include "SupportPointGenerator.hpp"
|
||||
#include "Concurrency.hpp"
|
||||
#include "Geometry/ConvexHull.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Tesselate.hpp"
|
||||
#include "ExPolygonCollection.hpp"
|
||||
#include "MinAreaBoundingBox.hpp"
|
||||
#include "libslic3r.h"
|
||||
|
||||
@ -550,7 +547,7 @@ void SupportPointGenerator::uniformly_cover(const ExPolygons& islands, Structure
|
||||
// auto bb = get_extents(islands);
|
||||
|
||||
if (flags & icfIsNew) {
|
||||
auto chull = ExPolygonCollection{islands}.convex_hull();
|
||||
auto chull = Geometry::convex_hull(islands);
|
||||
auto rotbox = MinAreaBoundigBox{chull, MinAreaBoundigBox::pcConvex};
|
||||
Vec2d bbdim = {unscaled(rotbox.width()), unscaled(rotbox.height())};
|
||||
|
||||
|
@ -4283,7 +4283,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
std::stable_sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
|
||||
}
|
||||
if (! polys.empty())
|
||||
expolygons_append(support_layer.support_islands.expolygons, union_ex(polys));
|
||||
expolygons_append(support_layer.support_islands, union_ex(polys));
|
||||
} // for each support_layer_id
|
||||
});
|
||||
|
||||
|
93
t/angles.t
93
t/angles.t
@ -1,93 +0,0 @@
|
||||
use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 34;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(rad2deg_dir angle3points PI);
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is line_atan([ [0, 0], [10, 0] ]), (0), 'E atan2';
|
||||
is line_atan([ [10, 0], [0, 0] ]), (PI), 'W atan2';
|
||||
is line_atan([ [0, 0], [0, 10] ]), (PI/2), 'N atan2';
|
||||
is line_atan([ [0, 10], [0, 0] ]), -(PI/2), 'S atan2';
|
||||
|
||||
is line_atan([ [10, 10], [0, 0] ]), -(PI*3/4), 'SW atan2';
|
||||
is line_atan([ [0, 0], [10, 10] ]), (PI*1/4), 'NE atan2';
|
||||
is line_atan([ [0, 10], [10, 0] ]), -(PI*1/4), 'SE atan2';
|
||||
is line_atan([ [10, 0], [0, 10] ]), (PI*3/4), 'NW atan2';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is line_orientation([ [0, 0], [10, 0] ]), (0), 'E orientation';
|
||||
is line_orientation([ [0, 0], [0, 10] ]), (PI/2), 'N orientation';
|
||||
is line_orientation([ [10, 0], [0, 0] ]), (PI), 'W orientation';
|
||||
is line_orientation([ [0, 10], [0, 0] ]), (PI*3/2), 'S orientation';
|
||||
|
||||
is line_orientation([ [0, 0], [10, 10] ]), (PI*1/4), 'NE orientation';
|
||||
is line_orientation([ [10, 0], [0, 10] ]), (PI*3/4), 'NW orientation';
|
||||
is line_orientation([ [10, 10], [0, 0] ]), (PI*5/4), 'SW orientation';
|
||||
is line_orientation([ [0, 10], [10, 0] ]), (PI*7/4), 'SE orientation';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is line_direction([ [0, 0], [10, 0] ]), (0), 'E direction';
|
||||
is line_direction([ [10, 0], [0, 0] ]), (0), 'W direction';
|
||||
is line_direction([ [0, 0], [0, 10] ]), (PI/2), 'N direction';
|
||||
is line_direction([ [0, 10], [0, 0] ]), (PI/2), 'S direction';
|
||||
|
||||
is line_direction([ [10, 10], [0, 0] ]), (PI*1/4), 'SW direction';
|
||||
is line_direction([ [0, 0], [10, 10] ]), (PI*1/4), 'NE direction';
|
||||
is line_direction([ [0, 10], [10, 0] ]), (PI*3/4), 'SE direction';
|
||||
is line_direction([ [10, 0], [0, 10] ]), (PI*3/4), 'NW direction';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is rad2deg_dir(0), 90, 'E (degrees)';
|
||||
is rad2deg_dir(PI), 270, 'W (degrees)';
|
||||
is rad2deg_dir(PI/2), 0, 'N (degrees)';
|
||||
is rad2deg_dir(-(PI/2)), 180, 'S (degrees)';
|
||||
is rad2deg_dir(PI*1/4), 45, 'NE (degrees)';
|
||||
is rad2deg_dir(PI*3/4), 135, 'NW (degrees)';
|
||||
is rad2deg_dir(PI/6), 60, '30°';
|
||||
is rad2deg_dir(PI/6*2), 30, '60°';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
is angle3points([0,0], [10,0], [0,10]), PI/2, 'CW angle3points';
|
||||
is angle3points([0,0], [0,10], [10,0]), PI/2*3, 'CCW angle3points';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
sub line_atan {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->atan2_;
|
||||
}
|
||||
|
||||
sub line_orientation {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->orientation;
|
||||
}
|
||||
|
||||
sub line_direction {
|
||||
my ($l) = @_;
|
||||
return Slic3r::Line->new(@$l)->direction;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
use Test::More tests => 1;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use List::Util qw(first sum);
|
||||
use Slic3r;
|
||||
use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('avoid_crossing_perimeters', 2);
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2);
|
||||
ok my $gcode = Slic3r::Test::gcode($print), "no crash with avoid_crossing_perimeters and multiple objects";
|
||||
}
|
||||
|
||||
__END__
|
137
t/bridges.t
137
t/bridges.t
@ -1,137 +0,0 @@
|
||||
use Test::More tests => 16;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use List::Util qw(first sum);
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(scale epsilon deg2rad rad2deg);
|
||||
use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $test = sub {
|
||||
my ($bridge_size, $rotate, $expected_angle, $tolerance) = @_;
|
||||
|
||||
my ($x, $y) = @$bridge_size;
|
||||
my $lower = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([-2,-2], [$x+2,-2], [$x+2,$y+2], [-2,$y+2]),
|
||||
Slic3r::Polygon->new_scale([0,0], [0,$y], [$x,$y], [$x,0]),
|
||||
);
|
||||
$lower->translate(scale 20, scale 20); # avoid negative coordinates for easier SVG preview
|
||||
$lower->rotate(deg2rad($rotate), [$x/2,$y/2]);
|
||||
my $bridge = $lower->[1]->clone;
|
||||
$bridge->reverse;
|
||||
$bridge = Slic3r::ExPolygon->new($bridge);
|
||||
|
||||
ok check_angle([$lower], $bridge, $expected_angle, $tolerance), 'correct bridge angle for O-shaped overhang';
|
||||
};
|
||||
|
||||
$test->([20,10], 0, 90);
|
||||
$test->([10,20], 0, 0);
|
||||
$test->([20,10], 45, 135, 20);
|
||||
$test->([20,10], 135, 45, 20);
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [20,0], [20,10], [0,10]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([-2,0], [0,0], [0,10], [-2,10]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
$lower->[1] = $lower->[0]->clone;
|
||||
$lower->[1]->translate(scale 22, 0);
|
||||
|
||||
ok check_angle($lower, $bridge, 0), 'correct bridge angle for two-sided bridge';
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [20,0], [10,10], [0,10]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([0,0], [0,10], [10,10], [10,12], [-2,12], [-2,-2], [22,-2], [22,0]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
ok check_angle($lower, $bridge, 135), 'correct bridge angle for C-shaped overhang';
|
||||
}
|
||||
|
||||
{
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([10,10],[20,10],[20,20], [10,20]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new_scale([10,10],[10,20],[20,20],[30,30],[0,30],[0,0]),
|
||||
),
|
||||
];
|
||||
$_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
|
||||
|
||||
ok check_angle($lower, $bridge, 45, undef, $bridge->area/2), 'correct bridge angle for square overhang with L-shaped anchors';
|
||||
}
|
||||
|
||||
sub check_angle {
|
||||
my ($lower, $bridge, $expected, $tolerance, $expected_coverage) = @_;
|
||||
|
||||
if (ref($lower) eq 'ARRAY') {
|
||||
$lower = Slic3r::ExPolygon::Collection->new(@$lower);
|
||||
}
|
||||
|
||||
$expected_coverage //= -1;
|
||||
$expected_coverage = $bridge->area if $expected_coverage == -1;
|
||||
|
||||
my $bd = Slic3r::BridgeDetector->new($bridge, $lower, scale 0.5);
|
||||
|
||||
$tolerance //= rad2deg($bd->resolution) + epsilon;
|
||||
$bd->detect_angle;
|
||||
my $result = $bd->angle;
|
||||
my $coverage = $bd->coverage;
|
||||
is sum(map $_->area, @$coverage), $expected_coverage, 'correct coverage area';
|
||||
|
||||
# our epsilon is equal to the steps used by the bridge detection algorithm
|
||||
###use XXX; YYY [ rad2deg($result), $expected ];
|
||||
# returned value must be non-negative, check for that too
|
||||
my $delta=rad2deg($result) - $expected;
|
||||
$delta-=180 if $delta>=180 - epsilon;
|
||||
return defined $result && $result>=0 && abs($delta) < $tolerance;
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('top_solid_layers', 0); # to prevent bridging on sparse infill
|
||||
$config->set('bridge_speed', 99);
|
||||
|
||||
my $print = Slic3r::Test::init_print('bridge', config => $config);
|
||||
|
||||
my %extrusions = (); # angle => length
|
||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
||||
my ($self, $cmd, $args, $info) = @_;
|
||||
|
||||
if ($cmd eq 'G1' && ($args->{F} // $self->F)/60 == $config->bridge_speed) {
|
||||
my $line = Slic3r::Line->new_scale(
|
||||
[ $self->X, $self->Y ],
|
||||
[ $info->{new_X}, $info->{new_Y} ],
|
||||
);
|
||||
my $angle = $line->direction;
|
||||
$extrusions{$angle} //= 0;
|
||||
$extrusions{$angle} += $line->length;
|
||||
}
|
||||
});
|
||||
ok !!%extrusions, "bridge is generated";
|
||||
my ($main_angle) = sort { $extrusions{$b} <=> $extrusions{$a} } keys %extrusions;
|
||||
is $main_angle, 0, "bridge has the expected direction";
|
||||
}
|
||||
|
||||
__END__
|
@ -1,87 +0,0 @@
|
||||
use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 11;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use local::lib "$FindBin::Bin/../local-lib";
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(collinear);
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,4], [4,2]),
|
||||
Slic3r::Line->new([2,3], [8,0]),
|
||||
Slic3r::Line->new([6,1], [8,0]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
is collinear($lines[1], $lines[2]), 1, 'collinear';
|
||||
is collinear($lines[0], $lines[2]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# horizontal
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,1], [5,1]),
|
||||
Slic3r::Line->new([2,1], [8,1]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# vertical
|
||||
my @lines = (
|
||||
Slic3r::Line->new([1,0], [1,5]),
|
||||
Slic3r::Line->new([1,2], [1,8]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1]), 1, 'collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# non overlapping
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,1], [5,1]),
|
||||
Slic3r::Line->new([7,1], [10,1]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 1), 0, 'non overlapping';
|
||||
is collinear($lines[0], $lines[1], 0), 1, 'overlapping';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# with one common point
|
||||
my @lines = (
|
||||
Slic3r::Line->new([0,4], [4,2]),
|
||||
Slic3r::Line->new([4,2], [8,0]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 1), 1, 'one common point';
|
||||
is collinear($lines[0], $lines[1], 0), 1, 'one common point';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
# not collinear
|
||||
my @lines = (
|
||||
Slic3r::Line->new([290000000,690525600], [285163380,684761540]),
|
||||
Slic3r::Line->new([285163380,684761540], [193267599,575244400]),
|
||||
);
|
||||
is collinear($lines[0], $lines[1], 0), 0, 'not collinear';
|
||||
is collinear($lines[0], $lines[1], 1), 0, 'not collinear';
|
||||
}
|
||||
|
||||
#==========================================================
|
64
t/geometry.t
64
t/geometry.t
@ -2,7 +2,7 @@ use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 26;
|
||||
plan tests => 11;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
@ -11,7 +11,7 @@ BEGIN {
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
use Slic3r::Geometry qw(PI polygon_is_convex
|
||||
use Slic3r::Geometry qw(PI
|
||||
chained_path_from epsilon scale);
|
||||
|
||||
{
|
||||
@ -27,18 +27,6 @@ use Slic3r::Geometry qw(PI polygon_is_convex
|
||||
|
||||
#==========================================================
|
||||
|
||||
my $line1 = [ [5, 15], [30, 15] ];
|
||||
my $line2 = [ [10, 20], [10, 10] ];
|
||||
is_deeply Slic3r::Geometry::line_intersection($line1, $line2, 1)->arrayref, [10, 15], 'line_intersection';
|
||||
|
||||
#==========================================================
|
||||
|
||||
$line1 = [ [73.6310778185108/0.0000001, 371.74239268924/0.0000001], [73.6310778185108/0.0000001, 501.74239268924/0.0000001] ];
|
||||
$line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ];
|
||||
isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_intersection';
|
||||
|
||||
#==========================================================
|
||||
|
||||
my $polygons = [
|
||||
Slic3r::Polygon->new( # contour, ccw
|
||||
[45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800],
|
||||
@ -57,54 +45,6 @@ my $polygons = [
|
||||
),
|
||||
];
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $p1 = [10, 10];
|
||||
my $p2 = [10, 20];
|
||||
my $p3 = [10, 30];
|
||||
my $p4 = [20, 20];
|
||||
my $p5 = [0, 20];
|
||||
|
||||
is Slic3r::Geometry::angle3points($p2, $p3, $p1), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p3, $p4), PI()/2*3, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p4, $p3), PI()/2, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p5), PI()/2*3, 'angle3points';
|
||||
}
|
||||
|
||||
{
|
||||
my $p1 = [30, 30];
|
||||
my $p2 = [20, 20];
|
||||
my $p3 = [10, 10];
|
||||
my $p4 = [30, 10];
|
||||
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2*3, 'angle3points';
|
||||
is Slic3r::Geometry::angle3points($p2, $p1, $p1), 2*PI(), 'angle3points';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $cw_square = [ [0,0], [0,10], [10,10], [10,0] ];
|
||||
is polygon_is_convex($cw_square), 0, 'cw square is not convex';
|
||||
is polygon_is_convex([ reverse @$cw_square ]), 1, 'ccw square is convex';
|
||||
|
||||
my $convex1 = [ [0,0], [10,0], [10,10], [0,10], [0,6], [4,6], [4,4], [0,4] ];
|
||||
is polygon_is_convex($convex1), 0, 'concave polygon';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
|
||||
is_deeply [ map $_->pp, @{$polyline->lines} ], [
|
||||
[ [0, 0], [10, 0] ],
|
||||
[ [10, 0], [20, 0] ],
|
||||
], 'polyline_lines';
|
||||
}
|
||||
|
||||
#==========================================================
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
add_executable(${_TEST_NAME}_tests
|
||||
${_TEST_NAME}_tests.cpp
|
||||
test_avoid_crossing_perimeters.cpp
|
||||
test_bridges.cpp
|
||||
test_data.cpp
|
||||
test_data.hpp
|
||||
test_extrusion_entity.cpp
|
||||
|
16
tests/fff_print/test_avoid_crossing_perimeters.cpp
Normal file
16
tests/fff_print/test_avoid_crossing_perimeters.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "test_data.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
SCENARIO("Avoid crossing perimeters", "[AvoidCrossingPerimeters]") {
|
||||
WHEN("Two 20mm cubes sliced") {
|
||||
std::string gcode = Slic3r::Test::slice(
|
||||
{ Slic3r::Test::TestMesh::cube_20x20x20, Slic3r::Test::TestMesh::cube_20x20x20 },
|
||||
{ { "avoid_crossing_perimeters", true } });
|
||||
THEN("gcode not empty") {
|
||||
REQUIRE(! gcode.empty());
|
||||
}
|
||||
}
|
||||
}
|
133
tests/fff_print/test_bridges.cpp
Normal file
133
tests/fff_print/test_bridges.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <libslic3r/BridgeDetector.hpp>
|
||||
#include <libslic3r/Geometry.hpp>
|
||||
|
||||
#include "test_data.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
SCENARIO("Bridge detector", "[Bridging]")
|
||||
{
|
||||
auto check_angle = [](const ExPolygons &lower, const ExPolygon &bridge, double expected, double tolerance = -1, double expected_coverage = -1)
|
||||
{
|
||||
if (expected_coverage < 0)
|
||||
expected_coverage = bridge.area();
|
||||
|
||||
BridgeDetector bridge_detector(bridge, lower, scaled<coord_t>(0.5)); // extrusion width
|
||||
if (tolerance < 0)
|
||||
tolerance = Geometry::rad2deg(bridge_detector.resolution) + EPSILON;
|
||||
|
||||
bridge_detector.detect_angle();
|
||||
double result = bridge_detector.angle;
|
||||
Polygons coverage = bridge_detector.coverage();
|
||||
THEN("correct coverage area") {
|
||||
REQUIRE(is_approx(area(coverage), expected_coverage));
|
||||
}
|
||||
// our epsilon is equal to the steps used by the bridge detection algorithm
|
||||
//##use XXX; YYY [ rad2deg($result), $expected ];
|
||||
// returned value must be non-negative, check for that too
|
||||
double delta = Geometry::rad2deg(result) - expected;
|
||||
if (delta >= 180. - EPSILON)
|
||||
delta -= 180;
|
||||
return result >= 0. && std::abs(delta) < tolerance;
|
||||
};
|
||||
GIVEN("O-shaped overhang") {
|
||||
auto test = [&check_angle](const Point &size, double rotate, double expected_angle, double tolerance = -1) {
|
||||
ExPolygon lower{
|
||||
Polygon::new_scale({ {-2,-2}, {size.x()+2,-2}, {size.x()+2,size.y()+2}, {-2,size.y()+2} }),
|
||||
Polygon::new_scale({ {0,0}, {0,size.y()}, {size.x(),size.y()}, {size.x(),0} } )
|
||||
};
|
||||
lower.rotate(Geometry::deg2rad(rotate), size / 2);
|
||||
ExPolygon bridge_expoly(lower.holes.front());
|
||||
bridge_expoly.contour.reverse();
|
||||
return check_angle({ lower }, bridge_expoly, expected_angle, tolerance);
|
||||
};
|
||||
WHEN("Bridge size 20x10") {
|
||||
bool valid = test({20,10}, 0., 90.);
|
||||
THEN("bridging angle is 90 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
WHEN("Bridge size 10x20") {
|
||||
bool valid = test({10,20}, 0., 0.);
|
||||
THEN("bridging angle is 0 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
WHEN("Bridge size 20x10, rotated by 45 degrees") {
|
||||
bool valid = test({20,10}, 45., 135., 20.);
|
||||
THEN("bridging angle is 135 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
WHEN("Bridge size 20x10, rotated by 135 degrees") {
|
||||
bool valid = test({20,10}, 135., 45., 20.);
|
||||
THEN("bridging angle is 45 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("two-sided bridge") {
|
||||
ExPolygon bridge{ Polygon::new_scale({ {0,0}, {20,0}, {20,10}, {0,10} }) };
|
||||
ExPolygons lower { ExPolygon{ Polygon::new_scale({ {-2,0}, {0,0}, {0,10}, {-2,10} }) } };
|
||||
lower.emplace_back(lower.front());
|
||||
lower.back().translate(Point::new_scale(22, 0));
|
||||
THEN("Bridging angle 0 degrees") {
|
||||
REQUIRE(check_angle(lower, bridge, 0));
|
||||
}
|
||||
}
|
||||
GIVEN("for C-shaped overhang") {
|
||||
ExPolygon bridge{ Polygon::new_scale({ {0,0}, {20,0}, {10,10}, {0,10} }) };
|
||||
ExPolygon lower{ Polygon::new_scale({ {0,0}, {0,10}, {10,10}, {10,12}, {-2,12}, {-2,-2}, {22,-2}, {22,0} }) };
|
||||
bool valid = check_angle({ lower }, bridge, 135);
|
||||
THEN("Bridging angle is 135 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
GIVEN("square overhang with L-shaped anchors") {
|
||||
ExPolygon bridge{ Polygon::new_scale({ {10,10}, {20,10}, {20,20}, {10,20} }) };
|
||||
ExPolygon lower{ Polygon::new_scale({ {10,10}, {10,20}, {20,20}, {30,30}, {0,30}, {0,0} }) };
|
||||
bool valid = check_angle({ lower }, bridge, 45., -1., bridge.area() / 2.);
|
||||
THEN("Bridging angle is 45 degrees") {
|
||||
REQUIRE(valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Bridging integration", "[Bridging]") {
|
||||
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({
|
||||
{ "top_solid_layers", 0 },
|
||||
// to prevent bridging on sparse infill
|
||||
{ "bridge_speed", 99 }
|
||||
});
|
||||
|
||||
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::bridge }, config);
|
||||
|
||||
GCodeReader parser;
|
||||
const double bridge_speed = config.opt_float("bridge_speed") * 60.;
|
||||
// angle => length
|
||||
std::map<coord_t, double> extrusions;
|
||||
parser.parse_buffer(gcode, [&extrusions, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||
{
|
||||
// if the command is a T command, set the the current tool
|
||||
if (line.cmd() == "G1" && is_approx<double>(bridge_speed, line.new_F(self))) {
|
||||
// Accumulate lengths of bridging extrusions according to bridging angle.
|
||||
Line l{ self.xy_scaled(), line.new_XY_scaled(self) };
|
||||
size_t angle = scaled<coord_t>(l.direction());
|
||||
auto it = extrusions.find(angle);
|
||||
if (it == extrusions.end())
|
||||
it = extrusions.insert(std::make_pair(angle, 0.)).first;
|
||||
it->second += l.length();
|
||||
}
|
||||
});
|
||||
THEN("bridge is generated") {
|
||||
REQUIRE(! extrusions.empty());
|
||||
}
|
||||
THEN("bridge has the expected direction 0 degrees") {
|
||||
// Bridging with the longest extrusion.
|
||||
auto it_longest_extrusion = std::max_element(extrusions.begin(), extrusions.end(),
|
||||
[](const auto &e1, const auto &e2){ return e1.second < e2.second; });
|
||||
REQUIRE(it_longest_extrusion->first == 0);
|
||||
}
|
||||
}
|
@ -197,8 +197,7 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
|
||||
SCENARIO("Infill does not exceed perimeters", "[Fill]")
|
||||
{
|
||||
auto test = [](const std::string_view pattern) {
|
||||
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({
|
||||
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({
|
||||
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
|
||||
{ "fill_pattern", pattern },
|
||||
{ "top_fill_pattern", pattern },
|
||||
|
@ -294,7 +294,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
|
||||
|
||||
WHEN("clipping a line") {
|
||||
auto line = Polyline::new_scale({ { 152.742,288.086671142818 }, { 152.742,34.166466971035 } });
|
||||
Polylines intersection = intersection_pl({ line }, { circle_with_hole });
|
||||
Polylines intersection = intersection_pl(line, Polygons{ circle_with_hole });
|
||||
THEN("clipped to two pieces") {
|
||||
REQUIRE(intersection.front().length() == Approx((Vec2d(152742000, 215178843) - Vec2d(152742000, 288086661)).norm()));
|
||||
REQUIRE(intersection[1].length() == Approx((Vec2d(152742000, 35166477) - Vec2d(152742000, 108087507)).norm()));
|
||||
|
@ -44,10 +44,8 @@ set(XSP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xsp)
|
||||
#FIXME list the dependecies explicitely, add dependency on the typemap.
|
||||
set(XS_XSP_FILES
|
||||
${XSP_DIR}/BoundingBox.xsp
|
||||
${XSP_DIR}/BridgeDetector.xsp
|
||||
${XSP_DIR}/Config.xsp
|
||||
${XSP_DIR}/ExPolygon.xsp
|
||||
${XSP_DIR}/ExPolygonCollection.xsp
|
||||
${XSP_DIR}/ExtrusionEntityCollection.xsp
|
||||
${XSP_DIR}/ExtrusionLoop.xsp
|
||||
${XSP_DIR}/ExtrusionMultiPath.xsp
|
||||
|
@ -48,11 +48,6 @@ use overload
|
||||
'@{}' => sub { $_[0]->arrayref },
|
||||
'fallback' => 1;
|
||||
|
||||
package Slic3r::ExPolygon::Collection;
|
||||
use overload
|
||||
'@{}' => sub { $_[0]->arrayref },
|
||||
'fallback' => 1;
|
||||
|
||||
package Slic3r::ExtrusionPath::Collection;
|
||||
use overload
|
||||
'@{}' => sub { $_[0]->arrayref },
|
||||
@ -179,7 +174,6 @@ sub new {
|
||||
|
||||
package main;
|
||||
for my $class (qw(
|
||||
Slic3r::BridgeDetector
|
||||
Slic3r::Config
|
||||
Slic3r::Config::Full
|
||||
Slic3r::Config::GCode
|
||||
@ -188,7 +182,6 @@ for my $class (qw(
|
||||
Slic3r::Config::PrintRegion
|
||||
Slic3r::Config::Static
|
||||
Slic3r::ExPolygon
|
||||
Slic3r::ExPolygon::Collection
|
||||
Slic3r::ExtrusionLoop
|
||||
Slic3r::ExtrusionMultiPath
|
||||
Slic3r::ExtrusionPath
|
||||
|
@ -4,7 +4,6 @@
|
||||
namespace Slic3r {
|
||||
|
||||
REGISTER_CLASS(ExPolygon, "ExPolygon");
|
||||
REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
|
||||
REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
|
||||
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
||||
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
||||
@ -29,7 +28,6 @@ REGISTER_CLASS(ModelInstance, "Model::Instance");
|
||||
REGISTER_CLASS(BoundingBox, "Geometry::BoundingBox");
|
||||
REGISTER_CLASS(BoundingBoxf, "Geometry::BoundingBoxf");
|
||||
REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
|
||||
REGISTER_CLASS(BridgeDetector, "BridgeDetector");
|
||||
REGISTER_CLASS(Point, "Point");
|
||||
__REGISTER_CLASS(Vec2d, "Pointf");
|
||||
__REGISTER_CLASS(Vec3d, "Pointf3");
|
||||
|
@ -5,7 +5,7 @@ use warnings;
|
||||
|
||||
use List::Util qw(first sum);
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 21;
|
||||
use Test::More tests => 15;
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
|
||||
@ -81,28 +81,4 @@ is $expolygon->area, 100*100-20*20, 'area';
|
||||
], 'rotate around pure-Perl Point';
|
||||
}
|
||||
|
||||
{
|
||||
my $expolygon2 = $expolygon->clone;
|
||||
$expolygon2->scale(2);
|
||||
my $collection = Slic3r::ExPolygon::Collection->new($expolygon->pp, $expolygon2->pp);
|
||||
is_deeply $collection->pp, [ $expolygon->pp, $expolygon2->pp ],
|
||||
'expolygon collection (pure Perl) roundtrip';
|
||||
|
||||
my $collection2 = Slic3r::ExPolygon::Collection->new($expolygon, $expolygon2);
|
||||
is_deeply $collection->pp, $collection2->pp,
|
||||
'expolygon collection (XS) roundtrip';
|
||||
|
||||
$collection->clear;
|
||||
is scalar(@$collection), 0, 'clear collection';
|
||||
|
||||
$collection->append($expolygon);
|
||||
is scalar(@$collection), 1, 'append to collection';
|
||||
|
||||
my $exp = $collection->[0];
|
||||
$exp->scale(3);
|
||||
is $collection->[0][0][0][0], $exp->[0][0][0], 'collection items are returned by reference';
|
||||
|
||||
is_deeply $collection->[0]->clone->pp, $collection->[0]->pp, 'clone collection item';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
@ -1,43 +0,0 @@
|
||||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "libslic3r/BridgeDetector.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::BridgeDetector} class BridgeDetector {
|
||||
~BridgeDetector();
|
||||
|
||||
bool detect_angle();
|
||||
Polygons coverage();
|
||||
%name{coverage_by_angle} Polygons coverage(double angle);
|
||||
Polylines unsupported_edges();
|
||||
%name{unsupported_edges_by_angle} Polylines unsupported_edges(double angle);
|
||||
double angle()
|
||||
%code{% RETVAL = THIS->angle; %};
|
||||
double resolution()
|
||||
%code{% RETVAL = THIS->resolution; %};
|
||||
%{
|
||||
|
||||
BridgeDetector*
|
||||
BridgeDetector::new(expolygon, lower_slices, extrusion_width)
|
||||
ExPolygon* expolygon;
|
||||
ExPolygonCollection* lower_slices;
|
||||
int extrusion_width;
|
||||
CODE:
|
||||
RETVAL = new BridgeDetector(*expolygon, lower_slices->expolygons, extrusion_width);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
BridgeDetector*
|
||||
BridgeDetector::new_expolygons(expolygons, lower_slices, extrusion_width)
|
||||
ExPolygonCollection* expolygons;
|
||||
ExPolygonCollection* lower_slices;
|
||||
int extrusion_width;
|
||||
CODE:
|
||||
RETVAL = new BridgeDetector(expolygons->expolygons, lower_slices->expolygons, extrusion_width);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
%}
|
||||
};
|
@ -1,81 +0,0 @@
|
||||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "libslic3r/ExPolygonCollection.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::ExPolygon::Collection} class ExPolygonCollection {
|
||||
~ExPolygonCollection();
|
||||
Clone<ExPolygonCollection> clone()
|
||||
%code{% RETVAL = THIS; %};
|
||||
void clear()
|
||||
%code{% THIS->expolygons.clear(); %};
|
||||
void scale(double factor);
|
||||
void translate(double x, double y);
|
||||
void rotate(double angle, Point* center)
|
||||
%code{% THIS->rotate(angle, *center); %};
|
||||
int count()
|
||||
%code{% RETVAL = THIS->expolygons.size(); %};
|
||||
bool contains_point(Point* point)
|
||||
%code{% RETVAL = THIS->contains(*point); %};
|
||||
bool contains_line(Line* line)
|
||||
%code{% RETVAL = THIS->contains(*line); %};
|
||||
bool contains_polyline(Polyline* polyline)
|
||||
%code{% RETVAL = THIS->contains(*polyline); %};
|
||||
void simplify(double tolerance);
|
||||
Polygons polygons()
|
||||
%code{% RETVAL = (Polygons)*THIS; %};
|
||||
Clone<Polygon> convex_hull();
|
||||
%{
|
||||
|
||||
ExPolygonCollection*
|
||||
ExPolygonCollection::new(...)
|
||||
CODE:
|
||||
RETVAL = new ExPolygonCollection ();
|
||||
// ST(0) is class name, others are expolygons
|
||||
RETVAL->expolygons.resize(items-1);
|
||||
for (unsigned int i = 1; i < items; i++) {
|
||||
// Note: a COPY of the input is stored
|
||||
from_SV_check(ST(i), &RETVAL->expolygons[i-1]);
|
||||
}
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
SV*
|
||||
ExPolygonCollection::arrayref()
|
||||
CODE:
|
||||
AV* av = newAV();
|
||||
av_fill(av, THIS->expolygons.size()-1);
|
||||
int i = 0;
|
||||
for (ExPolygons::iterator it = THIS->expolygons.begin(); it != THIS->expolygons.end(); ++it) {
|
||||
av_store(av, i++, perl_to_SV_ref(*it));
|
||||
}
|
||||
RETVAL = newRV_noinc((SV*)av);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
SV*
|
||||
ExPolygonCollection::pp()
|
||||
CODE:
|
||||
AV* av = newAV();
|
||||
av_fill(av, THIS->expolygons.size()-1);
|
||||
int i = 0;
|
||||
for (ExPolygons::iterator it = THIS->expolygons.begin(); it != THIS->expolygons.end(); ++it) {
|
||||
av_store(av, i++, to_SV_pureperl(&*it));
|
||||
}
|
||||
RETVAL = newRV_noinc((SV*)av);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
void
|
||||
ExPolygonCollection::append(...)
|
||||
CODE:
|
||||
for (unsigned int i = 1; i < items; i++) {
|
||||
ExPolygon expolygon;
|
||||
from_SV_check(ST(i), &expolygon);
|
||||
THIS->expolygons.push_back(expolygon);
|
||||
}
|
||||
|
||||
%}
|
||||
};
|
@ -95,22 +95,6 @@ ExtrusionPath::append(...)
|
||||
THIS->polyline.points.push_back(p);
|
||||
}
|
||||
|
||||
ExtrusionEntityCollection*
|
||||
ExtrusionPath::intersect_expolygons(ExPolygonCollection* collection)
|
||||
CODE:
|
||||
RETVAL = new ExtrusionEntityCollection ();
|
||||
THIS->intersect_expolygons(*collection, RETVAL);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
ExtrusionEntityCollection*
|
||||
ExtrusionPath::subtract_expolygons(ExPolygonCollection* collection)
|
||||
CODE:
|
||||
RETVAL = new ExtrusionEntityCollection ();
|
||||
THIS->subtract_expolygons(*collection, RETVAL);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
%}
|
||||
};
|
||||
|
||||
|
@ -64,14 +64,6 @@ rad2deg(angle)
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
double
|
||||
rad2deg_dir(angle)
|
||||
double angle
|
||||
CODE:
|
||||
RETVAL = Slic3r::Geometry::rad2deg_dir(angle);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
double
|
||||
deg2rad(angle)
|
||||
double angle
|
||||
|
@ -3,7 +3,6 @@
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/ExPolygonCollection.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::Layer::Region} class LayerRegion {
|
||||
@ -59,9 +58,6 @@
|
||||
Ref<LayerRegion> get_region(int idx);
|
||||
Ref<LayerRegion> add_region(PrintRegion* print_region);
|
||||
|
||||
ExPolygonCollection* slices()
|
||||
%code%{ RETVAL = new ExPolygonCollection(THIS->lslices); %};
|
||||
|
||||
int ptr()
|
||||
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
||||
|
||||
|
@ -88,10 +88,6 @@ ExPolygon* O_OBJECT_SLIC3R
|
||||
Ref<ExPolygon> O_OBJECT_SLIC3R_T
|
||||
Clone<ExPolygon> O_OBJECT_SLIC3R_T
|
||||
|
||||
ExPolygonCollection* O_OBJECT_SLIC3R
|
||||
Ref<ExPolygonCollection> O_OBJECT_SLIC3R_T
|
||||
Clone<ExPolygonCollection> O_OBJECT_SLIC3R_T
|
||||
|
||||
ExtrusionEntityCollection* O_OBJECT_SLIC3R
|
||||
Ref<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
|
||||
Clone<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
|
||||
@ -163,10 +159,6 @@ GCode* O_OBJECT_SLIC3R
|
||||
Ref<GCode> O_OBJECT_SLIC3R_T
|
||||
Clone<GCode> O_OBJECT_SLIC3R_T
|
||||
|
||||
BridgeDetector* O_OBJECT_SLIC3R
|
||||
Ref<BridgeDetector> O_OBJECT_SLIC3R_T
|
||||
Clone<BridgeDetector> O_OBJECT_SLIC3R_T
|
||||
|
||||
Axis T_UV
|
||||
ExtrusionLoopRole T_UV
|
||||
ExtrusionRole T_UV
|
||||
|
@ -54,9 +54,6 @@
|
||||
%typemap{ExPolygon*};
|
||||
%typemap{Ref<ExPolygon>}{simple};
|
||||
%typemap{Clone<ExPolygon>}{simple};
|
||||
%typemap{ExPolygonCollection*};
|
||||
%typemap{Ref<ExPolygonCollection>}{simple};
|
||||
%typemap{Clone<ExPolygonCollection>}{simple};
|
||||
%typemap{Flow*};
|
||||
%typemap{Ref<Flow>}{simple};
|
||||
%typemap{Clone<Flow>}{simple};
|
||||
@ -87,9 +84,6 @@
|
||||
%typemap{TriangleMesh*};
|
||||
%typemap{Ref<TriangleMesh>}{simple};
|
||||
%typemap{Clone<TriangleMesh>}{simple};
|
||||
%typemap{BridgeDetector*};
|
||||
%typemap{Ref<BridgeDetector>}{simple};
|
||||
%typemap{Clone<BridgeDetector>}{simple};
|
||||
%typemap{SurfaceCollection*};
|
||||
%typemap{Ref<SurfaceCollection>}{simple};
|
||||
%typemap{Clone<SurfaceCollection>}{simple};
|
||||
|
Loading…
Reference in New Issue
Block a user