mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 01:07:57 -06:00
Implement modifier volumes and port _merge_loops() to XS
This commit is contained in:
parent
b17d06f9d1
commit
c8a48b4527
10 changed files with 195 additions and 109 deletions
|
@ -58,69 +58,6 @@ sub flow {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# build polylines from lines
|
|
||||||
sub make_surfaces {
|
|
||||||
my $self = shift;
|
|
||||||
my ($loops) = @_;
|
|
||||||
|
|
||||||
return if !@$loops;
|
|
||||||
$self->slices->clear;
|
|
||||||
$self->slices->append($self->_merge_loops($loops));
|
|
||||||
|
|
||||||
if (0) {
|
|
||||||
require "Slic3r/SVG.pm";
|
|
||||||
Slic3r::SVG::output("surfaces.svg",
|
|
||||||
#polylines => $loops,
|
|
||||||
red_polylines => [ grep $_->is_counter_clockwise, @$loops ],
|
|
||||||
green_polylines => [ grep !$_->is_counter_clockwise, @$loops ],
|
|
||||||
expolygons => [ map $_->expolygon, @{$self->slices} ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _merge_loops {
|
|
||||||
my ($self, $loops, $safety_offset) = @_;
|
|
||||||
|
|
||||||
# Input loops are not suitable for evenodd nor nonzero fill types, as we might get
|
|
||||||
# two consecutive concentric loops having the same winding order - and we have to
|
|
||||||
# respect such order. In that case, evenodd would create wrong inversions, and nonzero
|
|
||||||
# would ignore holes inside two concentric contours.
|
|
||||||
# So we're ordering loops and collapse consecutive concentric loops having the same
|
|
||||||
# winding order.
|
|
||||||
# TODO: find a faster algorithm for this, maybe with some sort of binary search.
|
|
||||||
# If we computed a "nesting tree" we could also just remove the consecutive loops
|
|
||||||
# having the same winding order, and remove the extra one(s) so that we could just
|
|
||||||
# supply everything to offset_ex() instead of performing several union/diff calls.
|
|
||||||
|
|
||||||
# we sort by area assuming that the outermost loops have larger area;
|
|
||||||
# the previous sorting method, based on $b->contains_point($a->[0]), failed to nest
|
|
||||||
# loops correctly in some edge cases when original model had overlapping facets
|
|
||||||
my @abs_area = map abs($_), my @area = map $_->area, @$loops;
|
|
||||||
my @sorted = sort { $abs_area[$b] <=> $abs_area[$a] } 0..$#$loops; # outer first
|
|
||||||
|
|
||||||
# we don't perform a safety offset now because it might reverse cw loops
|
|
||||||
my $slices = [];
|
|
||||||
for my $i (@sorted) {
|
|
||||||
# we rely on the already computed area to determine the winding order
|
|
||||||
# of the loops, since the Orientation() function provided by Clipper
|
|
||||||
# would do the same, thus repeating the calculation
|
|
||||||
$slices = ($area[$i] >= 0)
|
|
||||||
? [ $loops->[$i], @$slices ]
|
|
||||||
: diff($slices, [$loops->[$i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
# perform a safety offset to merge very close facets (TODO: find test case for this)
|
|
||||||
$safety_offset //= scale 0.0499;
|
|
||||||
$slices = offset2_ex($slices, +$safety_offset, -$safety_offset);
|
|
||||||
|
|
||||||
Slic3r::debugf "Layer %d (slice_z = %.2f, print_z = %.2f): %d surface(s) having %d holes detected from %d polylines\n",
|
|
||||||
$self->id, $self->slice_z, $self->print_z,
|
|
||||||
scalar(@$slices), scalar(map @{$_->holes}, @$slices), scalar(@$loops)
|
|
||||||
if $Slic3r::debug;
|
|
||||||
|
|
||||||
return map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), @$slices;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub make_perimeters {
|
sub make_perimeters {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -318,8 +255,8 @@ sub _fill_gaps {
|
||||||
$filler->angle($self->config->fill_angle);
|
$filler->angle($self->config->fill_angle);
|
||||||
$filler->layer_id($self->layer->id);
|
$filler->layer_id($self->layer->id);
|
||||||
|
|
||||||
# we should probably use this code to handle thin walls and remove that logic from
|
# we should probably use this code to handle thin walls
|
||||||
# make_surfaces(), but we need to enable dynamic extrusion width before as we can't
|
# but we need to enable dynamic extrusion width before as we can't
|
||||||
# use zigzag for thin walls.
|
# use zigzag for thin walls.
|
||||||
|
|
||||||
# medial axis-based gap fill should benefit from detection of larger gaps too, so
|
# medial axis-based gap fill should benefit from detection of larger gaps too, so
|
||||||
|
|
|
@ -50,6 +50,7 @@ sub add_object {
|
||||||
$new_object->add_volume(
|
$new_object->add_volume(
|
||||||
material_id => $volume->material_id,
|
material_id => $volume->material_id,
|
||||||
mesh => $volume->mesh->clone,
|
mesh => $volume->mesh->clone,
|
||||||
|
modifier => $volume->modifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (defined $volume->material_id) {
|
if (defined $volume->material_id) {
|
||||||
|
@ -361,7 +362,7 @@ sub raw_mesh {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $mesh = Slic3r::TriangleMesh->new;
|
my $mesh = Slic3r::TriangleMesh->new;
|
||||||
$mesh->merge($_->mesh) for @{ $self->volumes };
|
$mesh->merge($_->mesh) for grep !$_->modifier, @{ $self->volumes };
|
||||||
return $mesh;
|
return $mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,12 +459,12 @@ sub unique_materials {
|
||||||
|
|
||||||
sub facets_count {
|
sub facets_count {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return sum(map $_->mesh->facets_count, @{$self->volumes});
|
return sum(map $_->mesh->facets_count, grep !$_->modifier, @{$self->volumes});
|
||||||
}
|
}
|
||||||
|
|
||||||
sub needed_repair {
|
sub needed_repair {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return (first { !$_->mesh->needed_repair } @{$self->volumes}) ? 0 : 1;
|
return (first { !$_->mesh->needed_repair } grep !$_->modifier, @{$self->volumes}) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub mesh_stats {
|
sub mesh_stats {
|
||||||
|
@ -494,7 +495,7 @@ sub print_info {
|
||||||
printf " needed repair: no\n";
|
printf " needed repair: no\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf " number of facets: %d\n", scalar(map @{$_->facets}, @{$self->volumes});
|
printf " number of facets: %d\n", scalar(map @{$_->facets}, grep !$_->modifier, @{$self->volumes});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,6 +505,7 @@ use Moo;
|
||||||
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
|
has 'object' => (is => 'ro', weak_ref => 1, required => 1);
|
||||||
has 'material_id' => (is => 'rw');
|
has 'material_id' => (is => 'rw');
|
||||||
has 'mesh' => (is => 'rw', required => 1);
|
has 'mesh' => (is => 'rw', required => 1);
|
||||||
|
has 'modifier' => (is => 'rw', defualt => sub { 0 });
|
||||||
|
|
||||||
package Slic3r::Model::Instance;
|
package Slic3r::Model::Instance;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
|
@ -528,8 +528,7 @@ sub export_svg {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
|
|
||||||
# this shouldn't be needed, but we're currently relying on ->make_surfaces() which
|
# is this needed?
|
||||||
# calls ->perimeter_flow
|
|
||||||
$self->init_extruders;
|
$self->init_extruders;
|
||||||
|
|
||||||
$_->slice for @{$self->objects};
|
$_->slice for @{$self->objects};
|
||||||
|
|
|
@ -178,35 +178,57 @@ sub slice {
|
||||||
$layer->region($_) for 0 .. ($regions_count-1);
|
$layer->region($_) for 0 .. ($regions_count-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
# process facets
|
# get array of Z coordinates for slicing
|
||||||
|
my @z = map $_->slice_z, @{$self->layers};
|
||||||
|
|
||||||
|
# slice all non-modifier volumes
|
||||||
for my $region_id (0..$#{$self->region_volumes}) {
|
for my $region_id (0..$#{$self->region_volumes}) {
|
||||||
next if !defined $self->region_volumes->[$region_id];
|
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 0);
|
||||||
|
for my $layer_id (0..$#$expolygons_by_layer) {
|
||||||
# compose mesh
|
|
||||||
my $mesh;
|
|
||||||
foreach my $volume_id (@{$self->region_volumes->[$region_id]}) {
|
|
||||||
if (defined $mesh) {
|
|
||||||
$mesh->merge($self->model_object->volumes->[$volume_id]->mesh);
|
|
||||||
} else {
|
|
||||||
$mesh = $self->model_object->volumes->[$volume_id]->mesh->clone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# transform mesh
|
|
||||||
# we ignore the per-instance transformations currently and only
|
|
||||||
# consider the first one
|
|
||||||
$self->model_object->instances->[0]->transform_mesh($mesh, 1);
|
|
||||||
|
|
||||||
# align mesh to Z = 0 and apply XY shift
|
|
||||||
$mesh->translate((map unscale(-$_), @{$self->_copies_shift}), -$self->model_object->bounding_box->z_min);
|
|
||||||
|
|
||||||
{
|
|
||||||
my $loops = $mesh->slice([ map $_->slice_z, @{$self->layers} ]);
|
|
||||||
for my $layer_id (0..$#$loops) {
|
|
||||||
my $layerm = $self->layers->[$layer_id]->regions->[$region_id];
|
my $layerm = $self->layers->[$layer_id]->regions->[$region_id];
|
||||||
$layerm->make_surfaces($loops->[$layer_id]);
|
$layerm->slices->clear;
|
||||||
|
foreach my $expolygon (@{ $expolygons_by_layer->[$layer_id] }) {
|
||||||
|
$layerm->slices->append(Slic3r::Surface->new(
|
||||||
|
expolygon => $expolygon,
|
||||||
|
surface_type => S_TYPE_INTERNAL,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# then slice all modifier volumes
|
||||||
|
if (@{$self->region_volumes} > 1) {
|
||||||
|
for my $region_id (0..$#{$self->region_volumes}) {
|
||||||
|
my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 1);
|
||||||
|
|
||||||
|
# loop through the other regions and 'steal' the slices belonging to this one
|
||||||
|
for my $other_region_id (0..$#{$self->region_volumes}) {
|
||||||
|
next if $other_region_id == $region_id;
|
||||||
|
|
||||||
|
for my $layer_id (0..$#$expolygons_by_layer) {
|
||||||
|
my $layerm = $self->layers->[$layer_id]->regions->[$region_id];
|
||||||
|
my $other_layerm = $self->layers->[$layer_id]->regions->[$other_region_id];
|
||||||
|
|
||||||
|
my $other_slices = [ map $_->p, @{$other_layerm->slices} ]; # Polygons
|
||||||
|
my $my_parts = intersection_ex(
|
||||||
|
$other_slices,
|
||||||
|
[ map @$_, @{ $expolygons_by_layer->[$layer_id] } ],
|
||||||
|
);
|
||||||
|
next if !@$my_parts;
|
||||||
|
|
||||||
|
# append new parts to our region
|
||||||
|
foreach my $expolygon (@$my_parts) {
|
||||||
|
$layerm->slices->append(Slic3r::Surface->new(
|
||||||
|
expolygon => $expolygon,
|
||||||
|
surface_type => S_TYPE_INTERNAL,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove such parts from original region
|
||||||
|
$other_layerm->slices->clear;
|
||||||
|
$other_layerm->append($_) for @{ diff($other_slices, $my_parts) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# TODO: read slicing_errors
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +307,38 @@ sub slice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _slice_region {
|
||||||
|
my ($self, $region_id, $z, $modifier) = @_;
|
||||||
|
|
||||||
|
return [] if !defined $self->region_volumes->[$region_id];
|
||||||
|
|
||||||
|
# compose mesh
|
||||||
|
my $mesh;
|
||||||
|
foreach my $volume_id (@{$self->region_volumes->[$region_id]}) {
|
||||||
|
my $volume = $self->model_object->volumes->[$volume_id];
|
||||||
|
next if $volume->modifier && !$modifier;
|
||||||
|
next if !$volume->modifier && $modifier;
|
||||||
|
|
||||||
|
if (defined $mesh) {
|
||||||
|
$mesh->merge($volume->mesh);
|
||||||
|
} else {
|
||||||
|
$mesh = $volume->mesh->clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next if !defined $mesh;
|
||||||
|
|
||||||
|
# transform mesh
|
||||||
|
# we ignore the per-instance transformations currently and only
|
||||||
|
# consider the first one
|
||||||
|
$self->model_object->instances->[0]->transform_mesh($mesh, 1);
|
||||||
|
|
||||||
|
# align mesh to Z = 0 and apply XY shift
|
||||||
|
$mesh->translate((map unscale(-$_), @{$self->_copies_shift}), -$self->model_object->bounding_box->z_min);
|
||||||
|
|
||||||
|
# perform actual slicing
|
||||||
|
return $mesh->slice($z);
|
||||||
|
}
|
||||||
|
|
||||||
sub make_perimeters {
|
sub make_perimeters {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
|
|
@ -79,12 +79,12 @@ void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
|
||||||
const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
void diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_ = false);
|
||||||
|
|
||||||
void diff(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
void diff(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
void intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_ = false);
|
||||||
|
|
||||||
void intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
void intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
Polygon::operator Polygons() const
|
||||||
|
{
|
||||||
|
Polygons pp;
|
||||||
|
pp.push_back(*this);
|
||||||
|
return pp;
|
||||||
|
}
|
||||||
|
|
||||||
Point*
|
Point*
|
||||||
Polygon::last_point() const
|
Polygon::last_point() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@ typedef std::vector<Polygon> Polygons;
|
||||||
|
|
||||||
class Polygon : public MultiPoint {
|
class Polygon : public MultiPoint {
|
||||||
public:
|
public:
|
||||||
|
operator Polygons() const;
|
||||||
Point* last_point() const;
|
Point* last_point() const;
|
||||||
Lines lines() const;
|
Lines lines() const;
|
||||||
Polyline* split_at(const Point* point) const;
|
Polyline* split_at(const Point* point) const;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
|
#include <cmath>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -164,7 +165,7 @@ void TriangleMesh::rotate(double angle, Point* center)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
|
TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons>* layers)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This method gets called with a list of unscaled Z coordinates and outputs
|
This method gets called with a list of unscaled Z coordinates and outputs
|
||||||
|
@ -385,7 +386,7 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
|
||||||
free(v_scaled_shared);
|
free(v_scaled_shared);
|
||||||
|
|
||||||
// build loops
|
// build loops
|
||||||
layers.resize(z.size());
|
layers->resize(z.size());
|
||||||
for (std::vector<IntersectionLines>::iterator it = lines.begin(); it != lines.end(); ++it) {
|
for (std::vector<IntersectionLines>::iterator it = lines.begin(); it != lines.end(); ++it) {
|
||||||
int layer_idx = it - lines.begin();
|
int layer_idx = it - lines.begin();
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
|
@ -478,7 +479,7 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
|
||||||
for (IntersectionLinePtrs::iterator lineptr = loop.begin(); lineptr != loop.end(); ++lineptr) {
|
for (IntersectionLinePtrs::iterator lineptr = loop.begin(); lineptr != loop.end(); ++lineptr) {
|
||||||
p.points.push_back((*lineptr)->a);
|
p.points.push_back((*lineptr)->a);
|
||||||
}
|
}
|
||||||
layers[layer_idx].push_back(p);
|
(*layers)[layer_idx].push_back(p);
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf(" Discovered %s polygon of %d points\n", (p.is_counter_clockwise() ? "ccw" : "cw"), (int)p.points.size());
|
printf(" Discovered %s polygon of %d points\n", (p.is_counter_clockwise() ? "ccw" : "cw"), (int)p.points.size());
|
||||||
|
@ -506,6 +507,90 @@ TriangleMesh::slice(const std::vector<double> &z, std::vector<Polygons> &layers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _area_comp {
|
||||||
|
public:
|
||||||
|
_area_comp(std::vector<double>* _aa) : abs_area(_aa) {};
|
||||||
|
bool operator() (const size_t &a, const size_t &b) {
|
||||||
|
return (*this->abs_area)[a] > (*this->abs_area)[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<double>* abs_area;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
TriangleMesh::slice(const std::vector<double> &z, std::vector<ExPolygons>* layers)
|
||||||
|
{
|
||||||
|
std::vector<Polygons> layers_p;
|
||||||
|
this->slice(z, &layers_p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input loops are not suitable for evenodd nor nonzero fill types, as we might get
|
||||||
|
two consecutive concentric loops having the same winding order - and we have to
|
||||||
|
respect such order. In that case, evenodd would create wrong inversions, and nonzero
|
||||||
|
would ignore holes inside two concentric contours.
|
||||||
|
So we're ordering loops and collapse consecutive concentric loops having the same
|
||||||
|
winding order.
|
||||||
|
TODO: find a faster algorithm for this, maybe with some sort of binary search.
|
||||||
|
If we computed a "nesting tree" we could also just remove the consecutive loops
|
||||||
|
having the same winding order, and remove the extra one(s) so that we could just
|
||||||
|
supply everything to offset_ex() instead of performing several union/diff calls.
|
||||||
|
|
||||||
|
we sort by area assuming that the outermost loops have larger area;
|
||||||
|
the previous sorting method, based on $b->contains_point($a->[0]), failed to nest
|
||||||
|
loops correctly in some edge cases when original model had overlapping facets
|
||||||
|
*/
|
||||||
|
|
||||||
|
layers->resize(z.size());
|
||||||
|
|
||||||
|
for (std::vector<Polygons>::const_iterator loops = layers_p.begin(); loops != layers_p.end(); ++loops) {
|
||||||
|
size_t layer_id = loops - layers_p.begin();
|
||||||
|
|
||||||
|
std::vector<double> area;
|
||||||
|
std::vector<double> abs_area;
|
||||||
|
std::vector<size_t> sorted_area; // vector of indices
|
||||||
|
for (Polygons::const_iterator loop = loops->begin(); loop != loops->end(); ++loop) {
|
||||||
|
double a = loop->area();
|
||||||
|
area.push_back(a);
|
||||||
|
abs_area.push_back(std::fabs(a));
|
||||||
|
sorted_area.push_back(loop - loops->begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(sorted_area.begin(), sorted_area.end(), _area_comp(&abs_area)); // outer first
|
||||||
|
|
||||||
|
// we don't perform a safety offset now because it might reverse cw loops
|
||||||
|
Polygons slices;
|
||||||
|
for (std::vector<size_t>::const_iterator loop_idx = sorted_area.begin(); loop_idx != sorted_area.end(); ++loop_idx) {
|
||||||
|
/* we rely on the already computed area to determine the winding order
|
||||||
|
of the loops, since the Orientation() function provided by Clipper
|
||||||
|
would do the same, thus repeating the calculation */
|
||||||
|
Polygons::const_iterator loop = loops->begin() + *loop_idx;
|
||||||
|
if (area[*loop_idx] >= 0) {
|
||||||
|
slices.push_back(*loop);
|
||||||
|
} else {
|
||||||
|
diff(slices, *loop, slices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform a safety offset to merge very close facets (TODO: find test case for this)
|
||||||
|
double safety_offset = scale_(0.0499);
|
||||||
|
ExPolygons ex_slices;
|
||||||
|
offset2_ex(slices, ex_slices, +safety_offset, -safety_offset);
|
||||||
|
|
||||||
|
#ifdef SLIC3R_DEBUG
|
||||||
|
size_t holes_count = 0;
|
||||||
|
for (ExPolygons::const_iterator e = ex_slices.begin(); e != ex_slices.end(); ++e) {
|
||||||
|
holes_count += e->holes.count();
|
||||||
|
}
|
||||||
|
printf("Layer %d (slice_z = %.2f): %d surface(s) having %d holes detected from %d polylines\n",
|
||||||
|
layer_id, z[layer_id], ex_slices.count(), holes_count, loops->count());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ExPolygons* layer = &(*layers)[layer_id];
|
||||||
|
layer->insert(layer->end(), ex_slices.begin(), ex_slices.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TriangleMeshPtrs
|
TriangleMeshPtrs
|
||||||
TriangleMesh::split() const
|
TriangleMesh::split() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,8 @@ class TriangleMesh
|
||||||
void translate(float x, float y, float z);
|
void translate(float x, float y, float z);
|
||||||
void align_to_origin();
|
void align_to_origin();
|
||||||
void rotate(double angle, Point* center);
|
void rotate(double angle, Point* center);
|
||||||
void slice(const std::vector<double> &z, std::vector<Polygons> &layers);
|
void slice(const std::vector<double> &z, std::vector<Polygons>* layers);
|
||||||
|
void slice(const std::vector<double> &z, std::vector<ExPolygons>* layers);
|
||||||
TriangleMeshPtrs split() const;
|
TriangleMeshPtrs split() const;
|
||||||
void merge(const TriangleMesh* mesh);
|
void merge(const TriangleMesh* mesh);
|
||||||
void horizontal_projection(ExPolygons &retval) const;
|
void horizontal_projection(ExPolygons &retval) const;
|
||||||
|
|
|
@ -137,19 +137,19 @@ SV*
|
||||||
TriangleMesh::slice(z)
|
TriangleMesh::slice(z)
|
||||||
std::vector<double>* z
|
std::vector<double>* z
|
||||||
CODE:
|
CODE:
|
||||||
std::vector<Polygons> layers;
|
std::vector<ExPolygons> layers;
|
||||||
THIS->slice(*z, layers);
|
THIS->slice(*z, &layers);
|
||||||
|
|
||||||
AV* layers_av = newAV();
|
AV* layers_av = newAV();
|
||||||
av_extend(layers_av, layers.size()-1);
|
av_extend(layers_av, layers.size()-1);
|
||||||
for (unsigned int i = 0; i < layers.size(); i++) {
|
for (unsigned int i = 0; i < layers.size(); i++) {
|
||||||
AV* polygons_av = newAV();
|
AV* expolygons_av = newAV();
|
||||||
av_extend(polygons_av, layers[i].size()-1);
|
av_extend(expolygons_av, layers[i].size()-1);
|
||||||
unsigned int j = 0;
|
unsigned int j = 0;
|
||||||
for (Polygons::iterator it = layers[i].begin(); it != layers[i].end(); ++it) {
|
for (ExPolygons::iterator it = layers[i].begin(); it != layers[i].end(); ++it) {
|
||||||
av_store(polygons_av, j++, (*it).to_SV_clone_ref());
|
av_store(expolygons_av, j++, (*it).to_SV_clone_ref());
|
||||||
}
|
}
|
||||||
av_store(layers_av, i, newRV_noinc((SV*)polygons_av));
|
av_store(layers_av, i, newRV_noinc((SV*)expolygons_av));
|
||||||
}
|
}
|
||||||
RETVAL = (SV*)newRV_noinc((SV*)layers_av);
|
RETVAL = (SV*)newRV_noinc((SV*)layers_av);
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue