XS interface completed, including new Line class

This commit is contained in:
Alessandro Ranellucci 2013-07-15 22:57:22 +02:00
parent 9af2a1c007
commit ab6b3d41a7
33 changed files with 435 additions and 257 deletions

View file

@ -1,4 +1,4 @@
package Slic3r::ExPolygon;
gpackage Slic3r::ExPolygon;
use strict;
use warnings;
@ -34,7 +34,7 @@ sub clone {
# no-op for legacy with ::XS
sub arrayref { $_[0] }
sub arrayref_pp { [ map $_->arrayref_pp, @{$_[0]} ] }
sub pp { [ map $_->pp, @{$_[0]} ] }
sub contour {
my $self = shift;
@ -108,7 +108,7 @@ sub noncollapsing_offset_ex {
sub encloses_point {
my $self = shift;
my ($point) = @_;
return Boost::Geometry::Utils::point_covered_by_polygon($point->arrayref, $self->arrayref_pp);
return Boost::Geometry::Utils::point_covered_by_polygon($point->arrayref, $self->pp);
}
# A version of encloses_point for use when hole borders do not matter.
@ -141,7 +141,7 @@ sub clip_line {
my $self = shift;
my ($line) = @_; # line must be a Slic3r::Line object
return Boost::Geometry::Utils::polygon_multi_linestring_intersection($self->arrayref_pp, [$line->arrayref_pp]);
return Boost::Geometry::Utils::polygon_multi_linestring_intersection($self->pp, [$line->pp]);
}
sub simplify {
@ -150,7 +150,7 @@ sub simplify {
# it would be nice to have a multilinestring_simplify method in B::G::U
my @simplified = Slic3r::Geometry::Clipper::simplify_polygons(
[ map Boost::Geometry::Utils::linestring_simplify($_, $tolerance), @{$self->arrayref_pp} ],
[ map Boost::Geometry::Utils::linestring_simplify($_, $tolerance), @{$self->pp} ],
);
return @{ Slic3r::Geometry::Clipper::union_ex([ @simplified ]) };
}

View file

@ -90,7 +90,7 @@ sub fill_surface {
# path is more straight
@paths = map Slic3r::Polyline->new(@$_),
@{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
$surface->expolygon->arrayref_pp,
$surface->expolygon->pp,
\@polygons,
) };

View file

@ -66,7 +66,7 @@ sub fill_surface {
# clip paths against a slightly offsetted expolygon, so that the first and last paths
# are kept even if the expolygon has vertical sides
my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
+($expolygon->offset_ex(scaled_epsilon))[0]->arrayref_pp, # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
+($expolygon->offset_ex(scaled_epsilon))[0]->pp, # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
[ @{ $self->cache->{$cache_id} } ],
) };

View file

@ -891,7 +891,7 @@ sub repaint {
# if sequential printing is enabled and we have more than one object
if ($parent->{config}->complete_objects && (map @{$_->instances}, @{$parent->{objects}}) > 1) {
my $convex_hull = Slic3r::Polygon->new(@{convex_hull([ map @{$_->contour->arrayref_pp}, @{$parent->{object_previews}->[-1][2]} ])});
my $convex_hull = Slic3r::Polygon->new(@{convex_hull([ map @{$_->contour->pp}, @{$parent->{object_previews}->[-1][2]} ])});
my ($clearance) = @{offset([$convex_hull], $parent->{config}->extruder_clearance_radius / 2 * $parent->{scaling_factor}, 100, JT_ROUND)};
$dc->SetPen($parent->{clearance_pen});
$dc->SetBrush($parent->{transparent_brush});

View file

@ -179,8 +179,8 @@ sub traverse_pt {
sub _convert {
my $polygons = shift;
$polygons = $polygons->arrayref_pp if ref $polygons eq 'Slic3r::ExPolygon::XS';
$polygons = [ map $_->arrayref_pp, @$polygons ] if @$polygons && ref $polygons->[0] eq 'Slic3r::Polygon';
$polygons = $polygons->pp if ref $polygons eq 'Slic3r::ExPolygon::XS';
$polygons = [ map $_->pp, @$polygons ] if @$polygons && ref $polygons->[0] eq 'Slic3r::Polygon';
return $polygons;
}

View file

@ -22,7 +22,7 @@ sub wkt {
sub is_counter_clockwise {
my $self = shift;
return Slic3r::Geometry::Clipper::is_counter_clockwise($self->arrayref_pp);
return Slic3r::Geometry::Clipper::is_counter_clockwise($self->pp);
}
sub make_counter_clockwise {
@ -57,12 +57,12 @@ sub remove_acute_vertices {
sub encloses_point {
my $self = shift;
my ($point) = @_;
return Boost::Geometry::Utils::point_covered_by_polygon($point->arrayref, [$self->arrayref_pp]);
return Boost::Geometry::Utils::point_covered_by_polygon($point->arrayref, [$self->pp]);
}
sub area {
my $self = shift;
return Slic3r::Geometry::Clipper::area($self->arrayref_pp);
return Slic3r::Geometry::Clipper::area($self->pp);
}
sub grow {

View file

@ -18,7 +18,7 @@ sub new {
}
sub arrayref { $_[0] }
sub arrayref_pp {
sub pp {
my $self = shift;
if (ref($self->[0]) eq 'Slic3r::Point') {
return [ map $_->arrayref, @$self ];
@ -68,7 +68,7 @@ sub simplify {
my $self = shift;
my $tolerance = shift || 10;
my $simplified = Boost::Geometry::Utils::linestring_simplify($self->arrayref_pp, $tolerance);
my $simplified = Boost::Geometry::Utils::linestring_simplify($self->pp, $tolerance);
return (ref $self)->new(@$simplified);
}
@ -79,7 +79,7 @@ sub reverse {
sub length {
my $self = shift;
return Boost::Geometry::Utils::linestring_length($self->arrayref_pp);
return Boost::Geometry::Utils::linestring_length($self->pp);
}
sub grow {
@ -119,7 +119,7 @@ sub clip_with_expolygon {
my $self = shift;
my ($expolygon) = @_;
my $result = Boost::Geometry::Utils::polygon_multi_linestring_intersection($expolygon->arrayref_pp, [$self->arrayref_pp]);
my $result = Boost::Geometry::Utils::polygon_multi_linestring_intersection($expolygon->pp, [$self->pp]);
bless $_, 'Slic3r::Polyline' for @$result;
return @$result;
}

View file

@ -763,7 +763,7 @@ sub write_gcode {
my @islands = ();
foreach my $obj_idx (0 .. $#{$self->objects}) {
my $convex_hull = convex_hull([
map @{$_->contour->arrayref_pp}, map @{$_->slices}, @{$self->objects->[$obj_idx]->layers},
map @{$_->contour->pp}, map @{$_->slices}, @{$self->objects->[$obj_idx]->layers},
]);
# discard layers only containing thin walls (offset would fail on an empty polygon)
if (@$convex_hull) {

View file

@ -25,7 +25,7 @@ use Slic3r;
[0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0],
);
$polyline = $polyline->simplify(1);
is_deeply $polyline->arrayref_pp, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker';
is_deeply $polyline->pp, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker';
}
{
@ -33,7 +33,7 @@ use Slic3r;
[0,0], [50,50], [100,0], [125,-25], [150,50],
);
$polyline = $polyline->simplify(25);
is_deeply $polyline->arrayref_pp, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker';
is_deeply $polyline->pp, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker';
}
{

View file

@ -158,7 +158,7 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po
{
my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
is_deeply [ map $_->arrayref_pp, $polyline->lines ], [
is_deeply [ map $_->pp, $polyline->lines ], [
[ [0, 0], [10, 0] ],
[ [10, 0], [20, 0] ],
], 'polyline_lines';
@ -170,7 +170,7 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po
my $polyline = Slic3r::Polygon->new([0, 0], [10, 0], [5, 5]);
my $result = $polyline->split_at_index(1);
is ref($result), 'Slic3r::Polyline', 'split_at_index returns polyline';
is_deeply $result->arrayref_pp, [ [10, 0], [5, 5], [0, 0], [10, 0] ], 'split_at_index';
is_deeply $result->pp, [ [10, 0], [5, 5], [0, 0], [10, 0] ], 'split_at_index';
}
#==========================================================

View file

@ -11,16 +11,16 @@ package Slic3r::Point;
use overload
'@{}' => sub { $_[0]->arrayref };
package Slic3r::ExPolygon::XS;
package Slic3r::ExPolygon;
use overload
'@{}' => sub { $_[0]->arrayref };
package Slic3r::Polyline::XS;
package Slic3r::Polyline;
use overload
'@{}' => sub { $_[0]->arrayref },
'fallback' => 1;
package Slic3r::Polygon::XS;
package Slic3r::Polygon;
use overload
'@{}' => sub { $_[0]->arrayref };

View file

@ -19,7 +19,10 @@ class ExPolygon
Polygon contour;
Polygons holes;
bool in_collection;
SV* to_SV(bool pureperl = false, bool pureperl_children = false);
void from_SV(SV* poly_sv);
void from_SV_check(SV* poly_sv);
SV* to_SV();
SV* to_SV_pureperl();
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
@ -55,48 +58,60 @@ ExPolygon::rotate(double angle, Point* center)
}
SV*
ExPolygon::to_SV(bool pureperl, bool pureperl_children)
{
if (pureperl) {
const unsigned int num_holes = this->holes.size();
AV* av = newAV();
av_extend(av, num_holes); // -1 +1
av_store(av, 0, this->contour.to_SV(pureperl_children, pureperl_children));
for (unsigned int i = 0; i < num_holes; i++) {
av_store(av, i+1, this->holes[i].to_SV(pureperl_children, pureperl_children));
}
return sv_bless(newRV_noinc((SV*)av), gv_stashpv("Slic3r::ExPolygon", GV_ADD));
} else {
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::ExPolygon::XS", this );
return sv;
ExPolygon::to_SV() {
const unsigned int num_holes = this->holes.size();
AV* av = newAV();
av_extend(av, num_holes); // -1 +1
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Polygon", new Polygon(this->contour) );
av_store(av, 0, sv);
for (unsigned int i = 0; i < num_holes; i++) {
sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Polygon", new Polygon(this->holes[i]) );
av_store(av, i+1, sv);
}
return newRV_noinc((SV*)av);
}
SV*
ExPolygon::to_SV_pureperl()
{
const unsigned int num_holes = this->holes.size();
AV* av = newAV();
av_extend(av, num_holes); // -1 +1
av_store(av, 0, this->contour.to_SV_pureperl());
for (unsigned int i = 0; i < num_holes; i++) {
av_store(av, i+1, this->holes[i].to_SV_pureperl());
}
return newRV_noinc((SV*)av);
}
void
perl2expolygon(SV* expoly_sv, ExPolygon& expoly)
ExPolygon::from_SV(SV* expoly_sv)
{
AV* expoly_av = (AV*)SvRV(expoly_sv);
const unsigned int num_polygons = av_len(expoly_av)+1;
expoly.holes.resize(num_polygons-1);
this->holes.resize(num_polygons-1);
SV** polygon_sv = av_fetch(expoly_av, 0, 0);
expoly.contour.from_SV(*polygon_sv);
this->contour.from_SV(*polygon_sv);
for (unsigned int i = 0; i < num_polygons-1; i++) {
polygon_sv = av_fetch(expoly_av, i+1, 0);
expoly.holes[i].from_SV(*polygon_sv);
this->holes[i].from_SV(*polygon_sv);
}
}
void
perl2expolygon_check(SV* expoly_sv, ExPolygon& expoly)
ExPolygon::from_SV_check(SV* expoly_sv)
{
if (sv_isobject(expoly_sv) && (SvTYPE(SvRV(expoly_sv)) == SVt_PVMG)) {
// a XS ExPolygon was supplied
expoly = *(ExPolygon *)SvIV((SV*)SvRV( expoly_sv ));
*this = *(ExPolygon *)SvIV((SV*)SvRV( expoly_sv ));
} else {
// a Perl arrayref was supplied
perl2expolygon(expoly_sv, expoly);
this->from_SV(expoly_sv);
}
}

107
xs/src/Line.hpp Normal file
View file

@ -0,0 +1,107 @@
#ifndef slic3r_Line_hpp_
#define slic3r_Line_hpp_
extern "C" {
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
}
#include "Point.hpp"
#include <algorithm>
namespace Slic3r {
class Line
{
public:
Point a;
Point b;
Line() {};
explicit Line(Point _a, Point _b): a(_a), b(_b) {};
void from_SV(SV* line_sv);
void from_SV_check(SV* line_sv);
SV* to_SV();
SV* to_SV_pureperl();
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
void reverse();
};
typedef std::vector<Line> Lines;
void
Line::scale(double factor)
{
this->a.scale(factor);
this->b.scale(factor);
}
void
Line::translate(double x, double y)
{
this->a.translate(x, y);
this->b.translate(x, y);
}
void
Line::rotate(double angle, Point* center)
{
this->a.rotate(angle, center);
this->b.rotate(angle, center);
}
void
Line::reverse()
{
std::swap(this->a, this->b);
}
void
Line::from_SV(SV* line_sv)
{
AV* line_av = (AV*)SvRV(line_sv);
this->a.from_SV_check(*av_fetch(line_av, 0, 0));
this->b.from_SV_check(*av_fetch(line_av, 1, 0));
}
void
Line::from_SV_check(SV* line_sv)
{
if (sv_isobject(line_sv) && (SvTYPE(SvRV(line_sv)) == SVt_PVMG)) {
*this = *(Line*)SvIV((SV*)SvRV( line_sv ));
} else {
this->from_SV(line_sv);
}
}
SV*
Line::to_SV() {
AV* av = newAV();
av_extend(av, 1);
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Point", new Point(this->a) );
av_store(av, 0, sv);
sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Point", new Point(this->b) );
av_store(av, 1, sv);
return newRV_noinc((SV*)av);
}
SV*
Line::to_SV_pureperl() {
AV* av = newAV();
av_extend(av, 1);
av_store(av, 0, this->a.to_SV_pureperl());
av_store(av, 1, this->b.to_SV_pureperl());
return newRV_noinc((SV*)av);
}
}
#endif

110
xs/src/MultiPoint.hpp Normal file
View file

@ -0,0 +1,110 @@
#ifndef slic3r_MultiPoint_hpp_
#define slic3r_MultiPoint_hpp_
extern "C" {
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
}
#include "Point.hpp"
#include <algorithm>
#include <vector>
namespace Slic3r {
class MultiPoint
{
public:
Points points;
void from_SV(SV* poly_sv);
void from_SV_check(SV* poly_sv);
SV* to_SV();
SV* to_SV_pureperl();
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
void reverse();
};
void
MultiPoint::scale(double factor)
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).scale(factor);
}
}
void
MultiPoint::translate(double x, double y)
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).translate(x, y);
}
}
void
MultiPoint::rotate(double angle, Point* center)
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).rotate(angle, center);
}
}
void
MultiPoint::reverse()
{
std::reverse(this->points.begin(), this->points.end());
}
void
MultiPoint::from_SV(SV* poly_sv)
{
AV* poly_av = (AV*)SvRV(poly_sv);
const unsigned int num_points = av_len(poly_av)+1;
this->points.resize(num_points);
for (unsigned int i = 0; i < num_points; i++) {
SV** point_sv = av_fetch(poly_av, i, 0);
this->points[i].from_SV_check(*point_sv);
}
}
void
MultiPoint::from_SV_check(SV* poly_sv)
{
if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) {
*this = *(MultiPoint*)SvIV((SV*)SvRV( poly_sv ));
} else {
this->from_SV(poly_sv);
}
}
SV*
MultiPoint::to_SV() {
const unsigned int num_points = this->points.size();
AV* av = newAV();
av_extend(av, num_points-1);
for (unsigned int i = 0; i < num_points; i++) {
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Point", new Point(this->points[i]) );
av_store(av, i, sv);
}
return newRV_noinc((SV*)av);
}
SV*
MultiPoint::to_SV_pureperl() {
const unsigned int num_points = this->points.size();
AV* av = newAV();
av_extend(av, num_points-1);
for (unsigned int i = 0; i < num_points; i++) {
av_store(av, i, this->points[i].to_SV_pureperl());
}
return newRV_noinc((SV*)av);
}
}
#endif

View file

@ -19,7 +19,9 @@ class Point
long x;
long y;
explicit Point(long _x = 0, long _y = 0): x(_x), y(_y) {};
SV* to_SV(bool pureperl = false);
void from_SV(SV* point_sv);
void from_SV_check(SV* point_sv);
SV* to_SV_pureperl();
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
@ -58,35 +60,29 @@ Point::coincides_with(Point* point)
}
SV*
Point::to_SV(bool pureperl) {
if (pureperl) {
AV* av = newAV();
av_fill(av, 1);
av_store(av, 0, newSViv(this->x));
av_store(av, 1, newSViv(this->y));
return newRV_noinc((SV*)av);
} else {
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::Point", new Point(*this) );
return sv;
}
Point::to_SV_pureperl() {
AV* av = newAV();
av_fill(av, 1);
av_store(av, 0, newSViv(this->x));
av_store(av, 1, newSViv(this->y));
return newRV_noinc((SV*)av);
}
void
perl2point(SV* point_sv, Point& point)
Point::from_SV(SV* point_sv)
{
AV* point_av = (AV*)SvRV(point_sv);
point.x = (unsigned long)SvIV(*av_fetch(point_av, 0, 0));
point.y = (unsigned long)SvIV(*av_fetch(point_av, 1, 0));
AV* point_av = (AV*)SvRV(point_sv);
this->x = (unsigned long)SvIV(*av_fetch(point_av, 0, 0));
this->y = (unsigned long)SvIV(*av_fetch(point_av, 1, 0));
}
void
perl2point_check(SV* point_sv, Point& point)
Point::from_SV_check(SV* point_sv)
{
if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
point = *(Point*)SvIV((SV*)SvRV( point_sv ));
*this = *(Point*)SvIV((SV*)SvRV( point_sv ));
} else {
perl2point(point_sv, point);
this->from_SV(point_sv);
}
}

View file

@ -13,12 +13,7 @@ extern "C" {
namespace Slic3r {
class Polygon : public Polyline {
protected:
char* perl_class() {
return (char*)"Slic3r::Polygon";
}
};
class Polygon : public MultiPoint {};
typedef std::vector<Polygon> Polygons;

View file

@ -8,94 +8,26 @@ extern "C" {
#include "ppport.h"
}
#include "Point.hpp"
#include <algorithm>
#include <string>
#include <vector>
#include "Line.hpp"
#include "MultiPoint.hpp"
namespace Slic3r {
class Polyline
{
class Polyline : public MultiPoint {
public:
Points points;
void from_SV(SV* poly_sv);
void from_SV_check(SV* poly_sv);
SV* to_SV(bool pureperl = false, bool pureperl_children = false);
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, Point* center);
void reverse();
protected:
virtual char* perl_class() {
return (char*)"Slic3r::Polyline";
}
Lines lines();
};
typedef std::vector<Polyline> Polylines;
void
Polyline::scale(double factor)
Lines
Polyline::lines()
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).scale(factor);
Lines lines;
for (int i = 0; i < this->points.size()-1; i++) {
lines.push_back(Line(this->points[i], this->points[i+1]));
}
}
void
Polyline::translate(double x, double y)
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).translate(x, y);
}
}
void
Polyline::rotate(double angle, Point* center)
{
for (Points::iterator it = points.begin(); it != points.end(); ++it) {
(*it).rotate(angle, center);
}
}
void
Polyline::reverse()
{
std::reverse(this->points.begin(), this->points.end());
}
void
Polyline::from_SV(SV* poly_sv)
{
AV* poly_av = (AV*)SvRV(poly_sv);
const unsigned int num_points = av_len(poly_av)+1;
this->points.resize(num_points);
for (unsigned int i = 0; i < num_points; i++) {
SV** point_sv = av_fetch(poly_av, i, 0);
perl2point_check(*point_sv, this->points[i]);
}
}
void
Polyline::from_SV_check(SV* poly_sv)
{
if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) {
*this = *(Polyline*)SvIV((SV*)SvRV( poly_sv ));
} else {
this->from_SV(poly_sv);
}
}
SV*
Polyline::to_SV(bool pureperl, bool pureperl_children) {
const unsigned int num_points = this->points.size();
AV* av = newAV();
av_extend(av, num_points-1);
for (unsigned int i = 0; i < num_points; i++) {
av_store(av, i, this->points[i].to_SV(pureperl_children));
}
return sv_bless(newRV_noinc((SV*)av), gv_stashpv(this->perl_class(), GV_ADD));
return lines;
}
}

View file

@ -4,7 +4,7 @@ use strict;
use warnings;
use Slic3r::XS;
use Test::More tests => 15;
use Test::More tests => 17;
use constant PI => 4 * atan2(1, 1);
@ -21,28 +21,29 @@ my $hole_in_square = [ # cw
[160, 140],
];
my $expolygon = Slic3r::ExPolygon::XS->new($square, $hole_in_square);
is_deeply [ @{$expolygon->arrayref_pp} ], [$square, $hole_in_square], 'expolygon roundtrip';
my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
my $arrayref = $expolygon->arrayref;
isa_ok $arrayref, 'Slic3r::ExPolygon', 'Perl expolygon is blessed';
is ref($expolygon->pp), 'ARRAY', 'expolygon pp is unblessed';
is_deeply $expolygon->pp, [$square, $hole_in_square], 'expolygon roundtrip';
my $arrayref_pp = $expolygon->arrayref_pp;
isa_ok $arrayref_pp, 'Slic3r::ExPolygon', 'Perl expolygon is blessed';
isa_ok $arrayref_pp->[0], 'Slic3r::Polygon', 'Perl polygons are blessed';
isnt ref($arrayref_pp->[0][0]), 'Slic3r::Point', 'Perl polygon points are not blessed';
is ref($expolygon->arrayref), 'ARRAY', 'expolygon arrayref is unblessed';
isa_ok $expolygon->[0], 'Slic3r::Polygon', 'expolygon polygon is blessed';
isa_ok $expolygon->[0][0], 'Slic3r::Point', 'expolygon point is blessed';
{
my $clone = $expolygon->clone;
is_deeply [ @{$clone->arrayref_pp} ], [$square, $hole_in_square], 'clone';
# The following tests implicitely check that modifying clones
# does not modify the original one.
my $polygon = $expolygon->[0];
$polygon->scale(2);
isnt $expolygon->[0][0][0], $polygon->[0][0], 'a copy of polygons is returned';
}
is_deeply $expolygon->clone->pp, [$square, $hole_in_square], 'clone';
# The following tests implicitely check that modifying clones
# does not modify the original one.
{
my $expolygon2 = $expolygon->clone;
$expolygon2->scale(2.5);
is_deeply [ @{$expolygon2->arrayref_pp} ], [
is_deeply $expolygon2->pp, [
[map [ 2.5*$_->[0], 2.5*$_->[1] ], @$square],
[map [ 2.5*$_->[0], 2.5*$_->[1] ], @$hole_in_square]
], 'scale';
@ -51,7 +52,7 @@ isnt ref($arrayref_pp->[0][0]), 'Slic3r::Point', 'Perl polygon points are not bl
{
my $expolygon2 = $expolygon->clone;
$expolygon2->translate(10, -5);
is_deeply [ @{$expolygon2->arrayref_pp} ], [
is_deeply $expolygon2->pp, [
[map [ $_->[0]+10, $_->[1]-5 ], @$square],
[map [ $_->[0]+10, $_->[1]-5 ], @$hole_in_square]
], 'translate';
@ -60,7 +61,7 @@ isnt ref($arrayref_pp->[0][0]), 'Slic3r::Point', 'Perl polygon points are not bl
{
my $expolygon2 = $expolygon->clone;
$expolygon2->rotate(PI/2, Slic3r::Point->new(150,150));
is_deeply [ @{$expolygon2->arrayref_pp} ], [
is_deeply $expolygon2->pp, [
[ @$square[1,2,3,0] ],
[ @$hole_in_square[3,0,1,2] ]
], 'rotate around Point';
@ -69,7 +70,7 @@ isnt ref($arrayref_pp->[0][0]), 'Slic3r::Point', 'Perl polygon points are not bl
{
my $expolygon2 = $expolygon->clone;
$expolygon2->rotate(PI/2, [150,150]);
is_deeply [ @{$expolygon2->arrayref_pp} ], [
is_deeply $expolygon2->pp, [
[ @$square[1,2,3,0] ],
[ @$hole_in_square[3,0,1,2] ]
], 'rotate around pure-Perl Point';
@ -78,19 +79,27 @@ isnt ref($arrayref_pp->[0][0]), 'Slic3r::Point', 'Perl polygon points are not bl
{
my $expolygon2 = $expolygon->clone;
$expolygon2->scale(2);
my $collection = Slic3r::ExPolygon::Collection->new($expolygon->arrayref_pp, $expolygon2->arrayref_pp);
is_deeply [ @{$collection->arrayref_pp} ], [ $expolygon->arrayref_pp, $expolygon2->arrayref_pp ],
'expolygon collection';
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->arrayref_pp} ], [ @{$collection2->arrayref_pp} ],
'expolygon collection with XS expolygons';
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';
is_deeply $collection->[0]->clone->arrayref_pp, $expolygon->arrayref_pp, 'clone collection item';
my $exp = $collection->[0];
$exp->scale(3);
### we store a copy, not the original by reference
###is_deeply $expolygon->pp, $exp->pp, 'input is stored by reference in collection';
is_deeply $collection->[0]->pp, $exp->pp, 'collection items are returned by reference';
is_deeply $collection->[0]->clone->pp, $collection->[0]->pp, 'clone collection item';
}
__END__

View file

@ -19,7 +19,7 @@ my $hole_in_square = [ # cw
[160, 140],
];
my $expolygon = Slic3r::ExPolygon::XS->new($square, $hole_in_square);
my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
my $surface = Slic3r::Surface->new(
expolygon => $expolygon,
surface_type => Slic3r::Surface::S_TYPE_INTERNAL,
@ -27,8 +27,8 @@ my $surface = Slic3r::Surface->new(
$surface = $surface->clone;
isa_ok $surface->expolygon, 'Slic3r::ExPolygon::XS', 'expolygon';
is_deeply [ @{$surface->expolygon->arrayref_pp} ], [$square, $hole_in_square], 'expolygon roundtrip';
isa_ok $surface->expolygon, 'Slic3r::ExPolygon', 'expolygon';
is_deeply [ @{$surface->expolygon->pp} ], [$square, $hole_in_square], 'expolygon roundtrip';
is $surface->surface_type, Slic3r::Surface::S_TYPE_INTERNAL, 'surface_type';
$surface->surface_type(Slic3r::Surface::S_TYPE_BOTTOM);
@ -43,7 +43,7 @@ is $surface->extra_perimeters, 2, 'extra_perimeters';
{
my $collection = Slic3r::Surface::Collection->new($surface, $surface->clone);
is scalar(@$collection), 2, 'collection has the right number of items';
is_deeply $collection->[0]->expolygon->arrayref_pp, [$square, $hole_in_square],
is_deeply $collection->[0]->expolygon->pp, [$square, $hole_in_square],
'collection returns a correct surface expolygon';
$collection->clear;
is scalar(@$collection), 0, 'clear collection';

View file

@ -13,11 +13,10 @@ my $square = [ # ccw
[100, 200],
];
my $polygon = Slic3r::Polygon::XS->new(@$square);
is_deeply [ @{$polygon->arrayref_pp} ], [ @$square ], 'polygon roundtrip';
my $polygon = Slic3r::Polygon->new(@$square);
is_deeply [ @{$polygon->pp} ], [ @$square ], 'polygon roundtrip';
my $arrayref = $polygon->arrayref;
isa_ok $arrayref, 'Slic3r::Polygon', 'Perl polygon is blessed';
isa_ok $arrayref->[0], 'Slic3r::Point', 'Perl points are blessed';
is ref($polygon->arrayref), 'ARRAY', 'polygon arrayref is unblessed';
isa_ok $polygon->[0], 'Slic3r::Point', 'polygon point is blessed';
__END__

View file

@ -13,20 +13,20 @@ my $points = [
];
my $path = Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polyline::XS->new(@$points),
polyline => Slic3r::Polyline->new(@$points),
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
);
isa_ok $path->as_polyline, 'Slic3r::Polyline::XS', 'path polyline';
is_deeply [ @{ $path->as_polyline->arrayref_pp } ], [ @$points ], 'path points roundtrip';
isa_ok $path->as_polyline, 'Slic3r::Polyline', 'path polyline';
is_deeply $path->as_polyline->pp, $points, 'path points roundtrip';
$path->reverse;
is_deeply [ @{ $path->as_polyline->arrayref_pp } ], [ reverse @$points ], 'reverse path';
is_deeply $path->as_polyline->pp, [ reverse @$points ], 'reverse path';
$path->append([ 150, 150 ]);
is scalar(@{ $path }), 4, 'append to path';
is scalar(@$path), 4, 'append to path';
$path->pop_back;
is scalar(@{ $path }), 3, 'pop_back from path';
is scalar(@$path), 3, 'pop_back from path';
$path = $path->clone;

View file

@ -14,11 +14,11 @@ my $square = [
];
my $loop = Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon::XS->new(@$square),
polygon => Slic3r::Polygon->new(@$square),
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
);
isa_ok $loop->as_polygon, 'Slic3r::Polygon::XS', 'loop polygon';
is_deeply [ @{ $loop->as_polygon->arrayref_pp } ], [ @$square ], 'polygon points roundtrip';
isa_ok $loop->as_polygon, 'Slic3r::Polygon', 'loop polygon';
is_deeply $loop->as_polygon->pp, $square, 'polygon points roundtrip';
$loop = $loop->clone;

View file

@ -5,13 +5,13 @@
#include "ExPolygon.hpp"
%}
%name{Slic3r::ExPolygon::XS} class ExPolygon {
%name{Slic3r::ExPolygon} class ExPolygon {
ExPolygon* clone()
%code{% const char* CLASS = "Slic3r::ExPolygon::XS"; RETVAL = new ExPolygon(*THIS); RETVAL->in_collection = false; %};
%code{% const char* CLASS = "Slic3r::ExPolygon"; RETVAL = new ExPolygon(*THIS); RETVAL->in_collection = false; %};
SV* arrayref()
%code{% RETVAL = THIS->to_SV(true, false); %};
SV* arrayref_pp()
%code{% RETVAL = THIS->to_SV(true, true); %};
%code{% RETVAL = THIS->to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->to_SV_pureperl(); %};
void scale(double factor);
void translate(double x, double y);
%{
@ -42,29 +42,9 @@ ExPolygon::rotate(angle, center_sv)
double angle;
SV* center_sv;
CODE:
Point* center;
if (sv_isobject(center_sv) && (SvTYPE(SvRV(center_sv)) == SVt_PVMG)) {
center = (Point*)SvIV((SV*)SvRV( center_sv ));
THIS->rotate(angle, center);
} else {
center = new Point;
perl2point(center_sv, *center);
THIS->rotate(angle, center);
delete center;
}
Point center;
center.from_SV_check(center_sv);
THIS->rotate(angle, &center);
%}
};
%package{Slic3r::ExPolygon::XS};
%{
PROTOTYPES: DISABLE
std::string
hello_world()
CODE:
RETVAL = "Hello world!";
OUTPUT:
RETVAL
%}

View file

@ -23,7 +23,8 @@ ExPolygonCollection::new(...)
// ST(0) is class name, others are expolygons
RETVAL->expolygons.resize(items-1);
for (unsigned int i = 1; i < items; i++) {
perl2expolygon_check(ST(i), RETVAL->expolygons[i-1]);
// Note: a COPY of the input is stored
RETVAL->expolygons[i-1].from_SV_check(ST(i));
RETVAL->expolygons[i-1].in_collection = true;
}
OUTPUT:
@ -36,20 +37,22 @@ ExPolygonCollection::arrayref()
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++, (*it).to_SV(false, false));
SV* sv = newSV(0);
sv_setref_pv( sv, "Slic3r::ExPolygon", &*it );
av_store(av, i++, sv);
}
RETVAL = newRV_noinc((SV*)av);
OUTPUT:
RETVAL
SV*
ExPolygonCollection::arrayref_pp()
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++, (*it).to_SV(true, true));
av_store(av, i++, (*it).to_SV_pureperl());
}
RETVAL = newRV_noinc((SV*)av);
OUTPUT:
@ -59,8 +62,10 @@ void
ExPolygonCollection::append(...)
CODE:
for (unsigned int i = 1; i < items; i++) {
THIS->expolygons.push_back(*(ExPolygon *)SvIV((SV*)SvRV( ST(i) )));
THIS->expolygons.back().in_collection = true;
ExPolygon expolygon;
expolygon.from_SV_check( ST(i) );
expolygon.in_collection = true;
THIS->expolygons.push_back(expolygon);
}
%}

View file

@ -8,11 +8,11 @@
%name{Slic3r::ExtrusionLoop} class ExtrusionLoop {
~ExtrusionLoop();
SV* arrayref()
%code{% RETVAL = THIS->polygon.to_SV(true, false); %};
SV* arrayref_pp()
%code{% RETVAL = THIS->polygon.to_SV(true, true); %};
%code{% RETVAL = THIS->polygon.to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->polygon.to_SV_pureperl(); %};
Polygon* as_polygon()
%code{% const char* CLASS = "Slic3r::Polygon::XS"; RETVAL = new Polygon(THIS->polygon); %};
%code{% const char* CLASS = "Slic3r::Polygon"; RETVAL = new Polygon(THIS->polygon); %};
void set_polygon(SV* polygon_sv)
%code{% THIS->polygon.from_SV_check(polygon_sv); %};
%{

View file

@ -8,11 +8,11 @@
%name{Slic3r::ExtrusionPath} class ExtrusionPath {
~ExtrusionPath();
SV* arrayref()
%code{% RETVAL = THIS->polyline.to_SV(true, false); %};
SV* arrayref_pp()
%code{% RETVAL = THIS->polyline.to_SV(true, true); %};
%code{% RETVAL = THIS->polyline.to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->polyline.to_SV_pureperl(); %};
Polyline* as_polyline()
%code{% const char* CLASS = "Slic3r::Polyline::XS"; RETVAL = new Polyline(THIS->polyline); %};
%code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = new Polyline(THIS->polyline); %};
void set_polyline(SV* polyline_sv)
%code{% THIS->polyline.from_SV_check(polyline_sv); %};
void pop_back()
@ -71,7 +71,7 @@ ExtrusionPath::append(...)
CODE:
for (unsigned int i = 1; i < items; i++) {
Point p;
perl2point_check(ST(i), p);
p.from_SV_check(ST(i));
THIS->polyline.points.push_back(p);
}

30
xs/xsp/Line.xsp Normal file
View file

@ -0,0 +1,30 @@
%module{Slic3r::XS};
%{
#include <myinit.h>
#include "Line.hpp"
%}
%name{Slic3r::Line} class Line {
~Line();
Line* clone()
%code{% const char* CLASS = "Slic3r::Line"; RETVAL = new Line(*THIS); %};
SV* arrayref()
%code{% RETVAL = THIS->to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->to_SV_pureperl(); %};
void reverse();
%{
Line*
Line::new(...)
CODE:
RETVAL = new Line ();
// ST(0) is class name, ST(1) and ST(2) are endpoints
RETVAL->a.from_SV_check( ST(1) );
RETVAL->b.from_SV_check( ST(2) );
OUTPUT:
RETVAL
%}
};

View file

@ -13,7 +13,7 @@
void scale(double factor);
void translate(double x, double y);
SV* arrayref()
%code{% RETVAL = THIS->to_SV(true); %};
%code{% RETVAL = THIS->to_SV_pureperl(); %};
unsigned long x()
%code{% RETVAL = THIS->x; %};
unsigned long y()
@ -27,7 +27,7 @@ Point::rotate(angle, center_sv)
SV* center_sv;
CODE:
Point center;
perl2point_check(center_sv, center);
center.from_SV_check(center_sv);
THIS->rotate(angle, &center);
bool
@ -35,7 +35,7 @@ Point::coincides_with(point_sv)
SV* point_sv;
CODE:
Point point;
perl2point_check(point_sv, point);
point.from_SV_check(point_sv);
RETVAL = THIS->coincides_with(&point);
OUTPUT:
RETVAL

View file

@ -5,14 +5,16 @@
#include "Polygon.hpp"
%}
%name{Slic3r::Polygon::XS} class Polygon {
%name{Slic3r::Polygon} class Polygon {
~Polygon();
Polygon* clone()
%code{% const char* CLASS = "Slic3r::Polygon::XS"; RETVAL = new Polygon(*THIS); %};
%code{% const char* CLASS = "Slic3r::Polygon"; RETVAL = new Polygon(*THIS); %};
SV* arrayref()
%code{% RETVAL = THIS->to_SV(true, false); %};
SV* arrayref_pp()
%code{% RETVAL = THIS->to_SV(true, true); %};
%code{% RETVAL = THIS->to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->to_SV_pureperl(); %};
void scale(double factor);
void translate(double x, double y);
%{
Polygon*
@ -22,7 +24,7 @@ Polygon::new(...)
// ST(0) is class name, ST(1) is first point
RETVAL->points.resize(items-1);
for (unsigned int i = 1; i < items; i++) {
perl2point(ST(i), RETVAL->points[i-1]);
RETVAL->points[i-1].from_SV_check( ST(i) );
}
OUTPUT:
RETVAL

View file

@ -5,14 +5,14 @@
#include "Polyline.hpp"
%}
%name{Slic3r::Polyline::XS} class Polyline {
%name{Slic3r::Polyline} class Polyline {
~Polyline();
Polyline* clone()
%code{% const char* CLASS = "Slic3r::Polyline::XS"; RETVAL = new Polyline(*THIS); %};
%code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = new Polyline(*THIS); %};
SV* arrayref()
%code{% RETVAL = THIS->to_SV(true, false); %};
SV* arrayref_pp()
%code{% RETVAL = THIS->to_SV(true, true); %};
%code{% RETVAL = THIS->to_SV(); %};
SV* pp()
%code{% RETVAL = THIS->to_SV_pureperl(); %};
void pop_back()
%code{% THIS->points.pop_back(); %};
void reverse();
@ -25,7 +25,7 @@ Polyline::new(...)
// ST(0) is class name, ST(1) is first point
RETVAL->points.resize(items-1);
for (unsigned int i = 1; i < items; i++) {
perl2point(ST(i), RETVAL->points[i-1]);
RETVAL->points[i-1].from_SV_check( ST(i) );
}
OUTPUT:
RETVAL
@ -35,11 +35,7 @@ Polyline::append(...)
CODE:
for (unsigned int i = 1; i < items; i++) {
Point p;
if (sv_isobject(ST(i)) && (SvTYPE(SvRV(ST(i))) == SVt_PVMG)) {
p = *(Point*)SvIV((SV*)SvRV( ST(i) ));
} else {
perl2point(ST(i), p);
}
p.from_SV_check( ST(1) );
THIS->points.push_back(p);
}

View file

@ -7,7 +7,7 @@
%name{Slic3r::Surface} class Surface {
ExPolygon* expolygon()
%code{% const char* CLASS = "Slic3r::ExPolygon::XS"; RETVAL = new ExPolygon(THIS->expolygon); %};
%code{% const char* CLASS = "Slic3r::ExPolygon"; RETVAL = new ExPolygon(THIS->expolygon); %};
double thickness()
%code{% RETVAL = THIS->thickness; %};
unsigned short thickness_layers()

View file

@ -18,6 +18,7 @@ SurfaceCollection::new(...)
// ST(0) is class name, others are surfaces
RETVAL->surfaces.resize(items-1);
for (unsigned int i = 1; i < items; i++) {
// Note: a COPY of the input is stored
RETVAL->surfaces[i-1] = *(Surface *)SvIV((SV*)SvRV( ST(i) ));
RETVAL->surfaces[i-1].in_collection = true;
}

View file

@ -1,6 +1,7 @@
ZTable* O_OBJECT
TriangleMesh* O_OBJECT
Point* O_OBJECT
Line* O_OBJECT
Polyline* O_OBJECT
Polygon* O_OBJECT
ExPolygon* O_OBJECT