Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2022-05-04 10:46:08 +02:00
commit 468f537121
40 changed files with 543 additions and 1066 deletions

View File

@ -9,6 +9,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(_wx_toolkit "-DwxBUILD_TOOLKIT=gtk${_gtk_ver}")
endif()
set(_unicode_utf8 OFF)
if (UNIX) # wxWidgets will not use char as the underlying type for wxString unless its forced to.
set (_unicode_utf8 ON)
endif()
prusaslicer_add_cmake_project(wxWidgets
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag}
@ -23,6 +28,7 @@ prusaslicer_add_cmake_project(wxWidgets
-DwxUSE_MEDIACTRL=OFF
-DwxUSE_DETECT_SM=OFF
-DwxUSE_UNICODE=ON
-DwxUSE_UNICODE_UTF8=${_unicode_utf8}
-DwxUSE_OPENGL=ON
-DwxUSE_LIBPNG=sys
-DwxUSE_ZLIB=sys

View File

@ -42,7 +42,6 @@ use Slic3r::ExtrusionLoop;
use Slic3r::ExtrusionPath;
use Slic3r::Flow;
use Slic3r::GCode::Reader;
use Slic3r::Geometry::Clipper;
use Slic3r::Layer;
use Slic3r::Line;
use Slic3r::Model;

View File

@ -4,19 +4,6 @@ use warnings;
# an ExPolygon is a polygon with holes
use List::Util qw(first);
use Slic3r::Geometry::Clipper qw(union_ex diff_pl);
sub offset {
my $self = shift;
return Slic3r::Geometry::Clipper::offset(\@$self, @_);
}
sub offset_ex {
my $self = shift;
return Slic3r::Geometry::Clipper::offset_ex(\@$self, @_);
}
sub noncollapsing_offset_ex {
my $self = shift;
my ($distance, @params) = @_;

View File

@ -14,10 +14,8 @@ our @EXPORT_OK = qw(
dot
line_intersection
normalize
point_in_segment
polyline_lines
polygon_is_convex
polygon_segment_having_point
scale
unscale
scaled_epsilon
@ -45,30 +43,6 @@ sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
# used by geometry.t, polygon_segment_having_point
sub point_in_segment {
my ($point, $line) = @_;
my ($x, $y) = @$point;
my $line_p = $line->pp;
my @line_x = sort { $a <=> $b } $line_p->[A][X], $line_p->[B][X];
my @line_y = sort { $a <=> $b } $line_p->[A][Y], $line_p->[B][Y];
# check whether the point is in the segment bounding box
return 0 unless $x >= ($line_x[0] - epsilon) && $x <= ($line_x[1] + epsilon)
&& $y >= ($line_y[0] - epsilon) && $y <= ($line_y[1] + epsilon);
# if line is vertical, check whether point's X is the same as the line
if ($line_p->[A][X] == $line_p->[B][X]) {
return abs($x - $line_p->[A][X]) < epsilon ? 1 : 0;
}
# calculate the Y in line at X of the point
my $y3 = $line_p->[A][Y] + ($line_p->[B][Y] - $line_p->[A][Y])
* ($x - $line_p->[A][X]) / ($line_p->[B][X] - $line_p->[A][X]);
return abs($y3 - $y) < epsilon ? 1 : 0;
}
# used by geometry.t
sub polyline_lines {
my ($polyline) = @_;
@ -76,17 +50,6 @@ sub polyline_lines {
return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
}
# given a $polygon, return the (first) segment having $point
# used by geometry.t
sub polygon_segment_having_point {
my ($polygon, $point) = @_;
foreach my $line (@{ $polygon->lines }) {
return $line if point_in_segment($point, $line);
}
return undef;
}
# polygon must be simple (non complex) and ccw
sub polygon_is_convex {
my ($points) = @_;

View File

@ -6,9 +6,8 @@ require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
offset
offset_ex offset2_ex
diff_ex diff union_ex intersection_ex
JT_ROUND JT_MITER JT_SQUARE
intersection intersection_pl diff_pl union);
offset2_ex
diff_ex diff union_ex
union);
1;

View File

@ -5,12 +5,6 @@ use warnings;
# a line is a two-points line
use parent 'Slic3r::Polyline';
sub intersection {
my $self = shift;
my ($line, $require_crossing) = @_;
return Slic3r::Geometry::line_intersection($self, $line, $require_crossing);
}
sub grow {
my $self = shift;
return Slic3r::Polyline->new(@$self)->grow(@_);

View File

@ -5,9 +5,6 @@ use warnings;
use List::Util qw(min max sum first);
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(scale epsilon);
use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex
offset offset_ex offset2_ex JT_MITER);
use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types';

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.4.1-rc1
1.0.1 Fix missing AzteQ Industrial ABS material for 0.6, 0.8 nozzle, enabled elefant foot compensation
1.0.0 Added AzteQ Industrial profiles for 0.8 nozzle, updated spool weight and filament cost, some minor setting improvements
min_slic3r_version = 2.3.2-alpha0
0.0.9 Added AzteQ Industrial materials PC/ABS (Fillamentum), PC-Max (Polymaker), Nylon FX256 (Fillamentum), Added DeltiQ 2 materials Nylon PA12 (Fiberlogy), Nylon CF15 Carbon (Fillamentum), PEBA 90A - FlexFill (Fillamentum), MoldLay (Wax-Alike), disabled retract only when crossing perimeters, some minor setting improvements

View File

@ -6,7 +6,7 @@
name = TriLAB
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.0.0
config_version = 1.0.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/TriLAB/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -118,7 +118,7 @@ complete_objects = 0
default_acceleration = 2000
dont_support_bridges = 0
draft_shield = 0
elefant_foot_compensation = 0.0
elefant_foot_compensation = 0.1
ensure_vertical_shell_thickness = 0
external_perimeter_extrusion_width = 0.45
external_perimeter_speed = 30
@ -338,6 +338,7 @@ support_material_extrusion_width = 0.55
support_material_interface_spacing = 0.6
support_material_xy_spacing = 0.9
top_infill_extrusion_width = 0.6
elefant_foot_compensation = 0.2
[print:DeltiQ 0.30mm Strong @0.6 nozzle]
inherits = DeltiQ 0.30mm Normal @0.6 nozzle
@ -356,7 +357,7 @@ bottom_solid_min_thickness = 1.2
bridge_flow_ratio = 0.90
bridge_speed = 20
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and nozzle_diameter[0]==0.8
elefant_foot_compensation = 0.0
elefant_foot_compensation = 0.2
external_perimeter_extrusion_width = 0.80
external_perimeter_speed = 30
extrusion_width = 0.80
@ -415,7 +416,7 @@ complete_objects = 0
default_acceleration = 2000
dont_support_bridges = 0
draft_shield = 0
elefant_foot_compensation = 0
elefant_foot_compensation = 0.1
ensure_vertical_shell_thickness = 0
external_perimeter_extrusion_width = 0.45
external_perimeter_speed = 30
@ -558,6 +559,7 @@ support_material_extrusion_width = 0.55
support_material_interface_spacing = 0.6
support_material_xy_spacing = 0.9
top_infill_extrusion_width = 0.6
elefant_foot_compensation = 0.2
[print:AzteQ Industrial 0.30mm Strong @0.6 nozzle]
inherits = AzteQ Industrial 0.30mm Normal @0.6 nozzle
@ -579,7 +581,7 @@ bottom_solid_min_thickness = 0.7
bridge_flow_ratio = 0.95
bridge_speed = 30
dont_support_bridges = 0
elefant_foot_compensation = 0
elefant_foot_compensation = 0.2
ensure_vertical_shell_thickness = 0
external_perimeter_extrusion_width = 0.8
external_perimeter_speed = 30
@ -1413,9 +1415,11 @@ filament_spool_weight = 229
[filament:AzteQ Industrial - ABS - ExtraFill (Fillamentum) @0.6 nozzle]
inherits = AzteQ Industrial - ABS - ExtraFill (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_MODEL_AQI.*/ and nozzle_diameter[0]==0.6
[filament:AzteQ Industrial - ABS - ExtraFill (Fillamentum) @0.8 nozzle]
inherits = AzteQ Industrial - ABS - ExtraFill (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_MODEL_AQI.*/ and nozzle_diameter[0]==0.8
extrusion_multiplier = 0.95
[filament:AzteQ Industrial - PC/ABS - (Fillamentum)]

View File

@ -10,6 +10,7 @@
#include <iostream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include "libslic3r.h"
#include "clonable_ptr.hpp"
@ -1989,6 +1990,7 @@ public:
struct SetDeserializeItem {
SetDeserializeItem(const char *opt_key, const char *opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
SetDeserializeItem(const std::string &opt_key, const std::string &opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
SetDeserializeItem(const std::string &opt_key, const std::string_view opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
SetDeserializeItem(const char *opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
SetDeserializeItem(const char *opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}

View File

@ -324,10 +324,10 @@ inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &&polylines, E
polylines.clear();
}
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
{
dst.reserve(dst.size() + polylines.size());
for (Polyline &polyline : polylines)
for (const Polyline &polyline : polylines)
if (polyline.is_valid()) {
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
dst.push_back(extrusion_path);

View File

@ -3661,42 +3661,44 @@ void GCodeProcessor::post_process()
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
};
struct FilamentData
{
double mm{ 0.0 };
double cm3{ 0.0 };
double g{ 0.0 };
double cost{ 0.0 };
};
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
std::vector<double> filament_g(m_result.extruders_count, 0.0);
std::vector<double> filament_cost(m_result.extruders_count, 0.0);
double filament_total_g = 0.0;
double filament_total_cost = 0.0;
FilamentData filament_data;
for (const auto& [role, used] : m_result.print_statistics.used_filaments_per_role) {
filament_data.mm += used.first;
filament_data.g += used.second;
}
for (const auto& [id, volume] : m_result.print_statistics.volumes_per_extruder) {
filament_data.cm3 += volume;
filament_data.cost += volume * double(m_result.filament_densities[id]) * double(m_result.filament_cost[id]) * 0.000001;
filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
filament_cm3[id] = volume * 0.001;
filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]);
filament_cost[id] = filament_g[id] * double(m_result.filament_cost[id]) * 0.001;
filament_total_g += filament_g[id];
filament_total_cost += filament_cost[id];
}
auto process_used_filament = [&filament_data](std::string& gcode_line) {
auto process_tag = [](std::string& gcode_line, const std::string& tag, double value) {
auto process_used_filament = [&](std::string& gcode_line) {
auto process_tag = [](std::string& gcode_line, const std::string& tag, const std::vector<double>& values) {
if (boost::algorithm::istarts_with(gcode_line, tag)) {
char buf[128];
sprintf(buf, "%s %.2lf\n", tag.c_str(), value);
gcode_line = buf;
gcode_line = tag;
char buf[1024];
for (size_t i = 0; i < values.size(); ++i) {
sprintf(buf, i == values.size() - 1 ? " %.2lf\n" : " %.2lf,", values[i]);
gcode_line += buf;
}
return true;
}
return false;
};
bool ret = false;
ret |= process_tag(gcode_line, "; filament used [mm] =", filament_data.mm * 1000.0);
ret |= process_tag(gcode_line, "; filament used [g] =", filament_data.g);
ret |= process_tag(gcode_line, "; total filament used [g] =", filament_data.g);
ret |= process_tag(gcode_line, "; filament used [cm3] =", filament_data.cm3 / 1000.0);
ret |= process_tag(gcode_line, "; filament cost =", filament_data.cost);
ret |= process_tag(gcode_line, "; total filament cost =", filament_data.cost);
ret |= process_tag(gcode_line, "; filament used [mm] =", filament_mm);
ret |= process_tag(gcode_line, "; filament used [g] =", filament_g);
ret |= process_tag(gcode_line, "; total filament used [g] =", { filament_total_g });
ret |= process_tag(gcode_line, "; filament used [cm3] =", filament_cm3);
ret |= process_tag(gcode_line, "; filament cost =", filament_cost);
ret |= process_tag(gcode_line, "; total filament cost =", { filament_total_cost });
return ret;
};

View File

@ -35,6 +35,8 @@ public:
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); }
Point new_XY_scaled(const GCodeReader &reader) const
{ return Point::new_scale(this->new_X(reader), this->new_Y(reader)); }
float dist_X(const GCodeReader &reader) const { return this->has(X) ? (this->x() - reader.x()) : 0; }
float dist_Y(const GCodeReader &reader) const { return this->has(Y) ? (this->y() - reader.y()) : 0; }
float dist_Z(const GCodeReader &reader) const { return this->has(Z) ? (this->z() - reader.z()) : 0; }
@ -134,6 +136,8 @@ public:
float e() const { return m_position[E]; }
float& f() { return m_position[F]; }
float f() const { return m_position[F]; }
Point xy_scaled() const { return Point::new_scale(this->x(), this->y()); }
// Returns 0 for gcfNoExtrusion.
char extrusion_axis() const { return m_extrusion_axis; }

View File

@ -1281,17 +1281,6 @@ PageMode::PageMode(ConfigWizard *parent)
radio_advanced = new wxRadioButton(this, wxID_ANY, _L("Advanced mode"));
radio_expert = new wxRadioButton(this, wxID_ANY, _L("Expert mode"));
append(radio_simple);
append(radio_advanced);
append(radio_expert);
append_text("\n" + _L("The size of the object can be specified in inches"));
check_inch = new wxCheckBox(this, wxID_ANY, _L("Use inches"));
append(check_inch);
}
void PageMode::on_activate()
{
std::string mode { "simple" };
wxGetApp().app_config->get("", "view_mode", mode);
@ -1299,7 +1288,16 @@ void PageMode::on_activate()
else if (mode == "expert") { radio_expert->SetValue(true); }
else { radio_simple->SetValue(true); }
append(radio_simple);
append(radio_advanced);
append(radio_expert);
append_text("\n" + _L("The size of the object can be specified in inches"));
check_inch = new wxCheckBox(this, wxID_ANY, _L("Use inches"));
check_inch->SetValue(wxGetApp().app_config->get("use_inches") == "1");
append(check_inch);
on_activate();
}
void PageMode::serialize_mode(AppConfig *app_config) const
@ -1310,11 +1308,6 @@ void PageMode::serialize_mode(AppConfig *app_config) const
if (radio_advanced->GetValue()) { mode = "advanced"; }
if (radio_expert->GetValue()) { mode = "expert"; }
// If "Mode" page wasn't selected (no one radiobutton is checked),
// we shouldn't to update a view_mode value in app_config
if (mode.empty())
return;
app_config->set("view_mode", mode);
app_config->set("use_inches", check_inch->GetValue() ? "1" : "0");
}

View File

@ -426,8 +426,6 @@ struct PageMode: ConfigWizardPage
PageMode(ConfigWizard *parent);
void serialize_mode(AppConfig *app_config) const;
virtual void on_activate();
};
struct PageVendors: ConfigWizardPage

View File

@ -3941,9 +3941,8 @@ void GCodeViewer::render_legend(float& legend_height)
PartialTimes items;
std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z;
int extruders_count = wxGetApp().extruders_edited_cnt();
std::vector<ColorRGBA> last_color(extruders_count);
for (int i = 0; i < extruders_count; ++i) {
std::vector<ColorRGBA> last_color(m_extruders_count);
for (int i = 0; i < m_extruders_count; ++i) {
last_color[i] = m_tool_colors[i];
}
int last_extruder_id = 1;

View File

@ -3465,7 +3465,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// during the scene manipulation.
#if ENABLE_NEW_RECTANGLE_SELECTION
if (m_picking_enabled && !any_gizmo_active && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled()) && !rectangle_selection_dragging) {
if (m_picking_enabled && (!any_gizmo_active || !evt.CmdDown()) && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled()) && !rectangle_selection_dragging) {
#else
if (m_picking_enabled && (!any_gizmo_active || !evt.CmdDown()) && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled())) {
#endif // ENABLE_NEW_RECTANGLE_SELECTION

View File

@ -706,6 +706,10 @@ void MainFrame::init_tabpanel()
// before the MainFrame is fully set up.
tab->OnActivate();
m_last_selected_tab = m_tabpanel->GetSelection();
#ifdef _MSW_DARK_MODE
if (wxGetApp().tabs_as_menu())
tab->SetFocus();
#endif
}
else
select_tab(size_t(0)); // select Plater
@ -2018,8 +2022,13 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
m_plater->SetFocus();
Layout();
}
else
else {
select(false);
#ifdef _MSW_DARK_MODE
if (wxGetApp().tabs_as_menu() && tab == 0)
m_plater->SetFocus();
#endif
}
// When we run application in ESettingsLayout::New or ESettingsLayout::Dlg mode, tabpanel is hidden from the very beginning
// and as a result Tab::update_changed_tree_ui() function couldn't update m_is_nonsys_values values,

View File

@ -3872,6 +3872,9 @@ void Plater::priv::reload_from_disk()
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
sla::reproject_points_and_holes(old_model_object);
// Fix warning icon in object list
wxGetApp().obj_list()->update_item_error_icon(obj_idx, vol_idx);
}
}
#else

View File

@ -490,9 +490,12 @@ bool PrintHostQueueDialog::load_user_data(int udt, std::vector<int>& vector)
auto* app_config = wxGetApp().app_config;
auto hasget = [app_config](const std::string& name, std::vector<int>& vector)->bool {
if (app_config->has(name)) {
vector.push_back(std::stoi(app_config->get(name)));
std::string val = app_config->get(name);
if (!val.empty() || val[0]!='\0') {
vector.push_back(std::stoi(val));
return true;
}
}
return false;
};
if (udt & UserDataType::UDT_SIZE) {

318
t/fill.t
View File

@ -1,318 +0,0 @@
use Test::More;
use strict;
use warnings;
#plan tests => 43;
# Test of a 100% coverage is off.
plan tests => 19;
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(X Y scale unscale convex_hull);
use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex);
use Slic3r::Surface qw(:types);
use Slic3r::Test;
sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
{
my $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]);
my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_bounding_box($expolygon->bounding_box);
$filler->set_angle(0);
my $surface = Slic3r::Surface->new(
surface_type => S_TYPE_TOP,
expolygon => $expolygon,
);
my $flow = Slic3r::Flow->new(
width => 0.69,
height => 0.4,
nozzle_diameter => 0.50,
);
$filler->set_spacing($flow->spacing);
foreach my $angle (0, 45) {
$surface->expolygon->rotate(Slic3r::Geometry::deg2rad($angle), [0,0]);
my $paths = $filler->fill_surface($surface, layer_height => 0.4, density => 0.4);
is scalar @$paths, 1, 'one continuous path';
}
}
SKIP:
{
skip "The FillRectilinear2 does not fill the surface completely", 1;
my $test = sub {
my ($expolygon, $flow_spacing, $angle, $density) = @_;
my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_bounding_box($expolygon->bounding_box);
$filler->set_angle($angle // 0);
# Adjust line spacing to fill the region.
$filler->set_dont_adjust(0);
$filler->set_link_max_length(scale(1.2*$flow_spacing));
my $surface = Slic3r::Surface->new(
surface_type => S_TYPE_BOTTOM,
expolygon => $expolygon,
);
my $flow = Slic3r::Flow->new(
width => $flow_spacing,
height => 0.4,
nozzle_diameter => $flow_spacing,
);
$filler->set_spacing($flow->spacing);
my $paths = $filler->fill_surface(
$surface,
layer_height => $flow->height,
density => $density // 1,
);
# check whether any part was left uncovered
my @grown_paths = map @{Slic3r::Polyline->new(@$_)->grow(scale $filler->spacing/2)}, @$paths;
my $uncovered = diff_ex([ @$expolygon ], [ @grown_paths ], 1);
# ignore very small dots
my $uncovered_filtered = [ grep $_->area > (scale $flow_spacing)**2, @$uncovered ];
is scalar(@$uncovered_filtered), 0, 'solid surface is fully filled';
if (0 && @$uncovered_filtered) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("uncovered.svg",
no_arrows => 1,
expolygons => [ $expolygon ],
blue_expolygons => [ @$uncovered ],
red_expolygons => [ @$uncovered_filtered ],
polylines => [ @$paths ],
);
exit;
}
};
my $expolygon = Slic3r::ExPolygon->new([
[6883102, 9598327.01296997],
[6883102, 20327272.01297],
[3116896, 20327272.01297],
[3116896, 9598327.01296997],
]);
$test->($expolygon, 0.55);
for (1..20) {
$expolygon->scale(1.05);
$test->($expolygon, 0.55);
}
$expolygon = Slic3r::ExPolygon->new(
[[59515297,5422499],[59531249,5578697],[59695801,6123186],[59965713,6630228],[60328214,7070685],[60773285,7434379],[61274561,7702115],[61819378,7866770],[62390306,7924789],[62958700,7866744],[63503012,7702244],[64007365,7434357],[64449960,7070398],[64809327,6634999],[65082143,6123325],[65245005,5584454],[65266967,5422499],[66267307,5422499],[66269190,8310081],[66275379,17810072],[66277259,20697500],[65267237,20697500],[65245004,20533538],[65082082,19994444],[64811462,19488579],[64450624,19048208],[64012101,18686514],[63503122,18415781],[62959151,18251378],[62453416,18198442],[62390147,18197355],[62200087,18200576],[61813519,18252990],[61274433,18415918],[60768598,18686517],[60327567,19047892],[59963609,19493297],[59695865,19994587],[59531222,20539379],[59515153,20697500],[58502480,20697500],[58502480,5422499]]
);
$test->($expolygon, 0.524341649025257);
$expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [98,0], [98,10], [0,10] ]);
$test->($expolygon, 0.5, 45, 0.99); # non-solid infill
}
{
my $collection = Slic3r::Polyline::Collection->new(
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
is_deeply
[ map $_->[Y], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
[20, 18, 15, 10, 8, 5],
'chained path';
}
{
my $collection = Slic3r::Polyline::Collection->new(
Slic3r::Polyline->new([4,0], [10,0], [15,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);
is_deeply
[ map $_->[X], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
[reverse 4, 10, 15, 10, 15, 20],
'chained path';
}
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
is_deeply
[ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
[20, 18, 15, 10, 8, 5],
'chained path';
}
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);
is_deeply
[ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
[reverse 4, 10, 15, 10, 15, 20],
'chained path';
}
for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
my $config = Slic3r::Config::new_from_defaults;
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
$config->set('fill_pattern', $pattern);
$config->set('top_fill_pattern', $pattern);
$config->set('bottom_fill_pattern', $pattern);
$config->set('perimeters', 1);
$config->set('skirts', 0);
$config->set('fill_density', 20);
$config->set('layer_height', 0.05);
$config->set('perimeter_extruder', 1);
$config->set('infill_extruder', 2);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
ok my $gcode = Slic3r::Test::gcode($print), "successful $pattern infill generation";
my $tool = undef;
my @perimeter_points = my @infill_points = ();
Slic3r::GCode::Reader->new->parse($gcode, sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->perimeter_extruder-1) {
push @perimeter_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
} elsif ($tool == $config->infill_extruder-1) {
push @infill_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
}
}
});
my $convex_hull = convex_hull(\@perimeter_points);
ok !(defined first { !$convex_hull->contains_point($_) } @infill_points), "infill does not exceed perimeters ($pattern)";
}
{
my $config = Slic3r::Config::new_from_defaults;
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
$config->set('infill_only_where_needed', 1);
$config->set('bottom_solid_layers', 0);
$config->set('infill_extruder', 2);
$config->set('infill_extrusion_width', 0.5);
$config->set('wipe_into_infill', 0);
$config->set('fill_density', 40);
$config->set('cooling', [ 0 ]); # for preventing speeds from being altered
$config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
my $test = sub {
my $print = Slic3r::Test::init_print('pyramid', config => $config);
my $tool = undef;
my @infill_extrusions = (); # array of polylines
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->infill_extruder-1) {
push @infill_extrusions, Slic3r::Line->new_scale(
[ $self->X, $self->Y ],
[ $info->{new_X}, $info->{new_Y} ],
);
}
}
});
return 0 if !@infill_extrusions; # prevent calling convex_hull() with no points
my $convex_hull = convex_hull([ map $_->pp, map @$_, @infill_extrusions ]);
return unscale unscale sum(map $_->area, @{offset([$convex_hull], scale(+$config->infill_extrusion_width/2))});
};
my $tolerance = 5; # mm^2
$config->set('solid_infill_below_area', 0);
ok $test->() < $tolerance,
'no infill is generated when using infill_only_where_needed on a pyramid';
$config->set('solid_infill_below_area', 70);
ok abs($test->() - $config->solid_infill_below_area) < $tolerance,
'infill is only generated under the forced solid shells';
}
{
my $config = Slic3r::Config::new_from_defaults;
$config->set('skirts', 0);
$config->set('perimeters', 1);
$config->set('fill_density', 0);
$config->set('top_solid_layers', 0);
$config->set('bottom_solid_layers', 0);
$config->set('solid_infill_below_area', 20000000);
$config->set('solid_infill_every_layers', 2);
$config->set('perimeter_speed', 99);
$config->set('external_perimeter_speed', 99);
$config->set('cooling', [ 0 ]);
$config->set('first_layer_speed', '100%');
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my %layers_with_extrusion = ();
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
$layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
}
}
});
ok !%layers_with_extrusion,
"solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0";
}
{
my $config = Slic3r::Config::new_from_defaults;
$config->set('skirts', 0);
$config->set('perimeters', 3);
$config->set('fill_density', 0);
$config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.35,0.35,0.35,0.35]);
$config->set('infill_extruder', 2);
$config->set('solid_infill_extruder', 2);
$config->set('infill_extrusion_width', 0.52);
$config->set('solid_infill_extrusion_width', 0.52);
$config->set('first_layer_extrusion_width', 0);
my $print = Slic3r::Test::init_print('A', config => $config);
my %infill = (); # Z => [ Line, Line ... ]
my $tool = undef;
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->infill_extruder-1) {
my $z = 1 * $self->Z;
$infill{$z} ||= [];
push @{$infill{$z}}, Slic3r::Line->new_scale(
[ $self->X, $self->Y ],
[ $info->{new_X}, $info->{new_Y} ],
);
}
}
});
my $grow_d = scale($config->infill_extrusion_width)/2;
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
my $diff = diff($layer0_infill, $layer1_infill);
$diff = offset2_ex($diff, -$grow_d, +$grow_d);
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
}
__END__

View File

@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
plan tests => 30;
plan tests => 27;
BEGIN {
use FindBin;
@ -39,44 +39,6 @@ isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_inters
#==========================================================
{
my $polygon = Slic3r::Polygon->new(
[45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800],
[43749700, 343843000], [45422300, 352251500], [52362100, 362637800], [62748400, 369577600],
[75000000, 372014700], [87251500, 369577600], [97637800, 362637800], [104577600, 352251500],
[107014700, 340000000], [104577600, 327748400], [97637800, 317362100], [87251500, 310422300],
[82789200, 309534700], [69846100, 294726100], [254081000, 294726100], [285273900, 348753500],
[285273900, 461246400], [254081000, 515273900],
);
# this points belongs to $polyline
# note: it's actually a vertex, while we should better check an intermediate point
my $point = Slic3r::Point->new(104577600, 327748400);
local $Slic3r::Geometry::epsilon = 1E-5;
is_deeply Slic3r::Geometry::polygon_segment_having_point($polygon, $point)->pp,
[ [107014700, 340000000], [104577600, 327748400] ],
'polygon_segment_having_point';
}
#==========================================================
{
my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924);
my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]);
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
}
#==========================================================
{
my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924);
my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]);
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
}
#==========================================================
my $polygons = [
Slic3r::Polygon->new( # contour, ccw
[45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800],

View File

@ -14,7 +14,7 @@ use List::Util qw(first);
use Slic3r;
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(PI scale unscale);
use Slic3r::Geometry::Clipper qw(union_ex diff union offset);
use Slic3r::Geometry::Clipper qw(union_ex diff);
use Slic3r::Surface ':types';
use Slic3r::Test;

View File

@ -1,121 +0,0 @@
use Test::More;
use strict;
use warnings;
plan tests => 18;
BEGIN {
use FindBin;
use lib "$FindBin::Bin/../lib";
use local::lib "$FindBin::Bin/../local-lib";
}
use Slic3r;
use Slic3r::Geometry::Clipper qw(intersection_pl);
#==========================================================
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([5, 10], [20, 10])), 1, 'point in horizontal segment';
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(30, 10), Slic3r::Line->new([5, 10], [20, 10])), 0, 'point not in horizontal segment';
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([10, 5], [10, 20])), 1, 'point in vertical segment';
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 30), Slic3r::Line->new([10, 5], [10, 20])), 0, 'point not in vertical segment';
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(15, 15), Slic3r::Line->new([10, 10], [20, 20])), 1, 'point in diagonal segment';
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(20, 15), Slic3r::Line->new([10, 10], [20, 20])), 0, 'point not in diagonal segment';
#==========================================================
my $square = Slic3r::Polygon->new( # ccw
[100, 100],
[200, 100],
[200, 200],
[100, 200],
);
#==========================================================
{
my $hole_in_square = [ # cw
[140, 140],
[140, 160],
[160, 160],
[160, 140],
];
my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
#is $expolygon->contains_point(Slic3r::Point->new(100, 100)), 1, 'corner point is recognized';
#is $expolygon->contains_point(Slic3r::Point->new(100, 180)), 1, 'point on contour is recognized';
#is $expolygon->contains_point(Slic3r::Point->new(140, 150)), 1, 'point on hole contour is recognized';
#is $expolygon->contains_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner is recognized';
{
my $intersection = intersection_pl([Slic3r::Polyline->new([150,180], [150,150])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([150, 180], [150, 160])->length,
'line is clipped to square with hole';
}
{
my $intersection = intersection_pl([Slic3r::Polyline->new([150,150], [150,120])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([150, 140], [150, 120])->length,
'line is clipped to square with hole';
}
{
my $intersection = intersection_pl([Slic3r::Polyline->new([120,180], [180,180])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([120,180], [180,180])->length,
'line is clipped to square with hole';
}
{
my $intersection = intersection_pl([Slic3r::Polyline->new([50, 150], [300, 150])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([100, 150], [140, 150])->length,
'line is clipped to square with hole';
is $intersection->[1]->length, Slic3r::Line->new([160, 150], [200, 150])->length,
'line is clipped to square with hole';
}
{
my $intersection = intersection_pl([Slic3r::Polyline->new([300, 150], [50, 150])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([200, 150], [160, 150])->length,
'reverse line is clipped to square with hole';
is $intersection->[1]->length, Slic3r::Line->new([140, 150], [100, 150])->length,
'reverse line is clipped to square with hole';
}
{
my $intersection = intersection_pl([Slic3r::Polyline->new([100,180], [200,180])], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([100,180], [200,180])->length,
'tangent line is clipped to square with hole';
}
}
#==========================================================
{
my $large_circle = Slic3r::Polygon->new_scale( # ccw
[151.8639,288.1192], [133.2778,284.6011], [115.0091,279.6997], [98.2859,270.8606], [82.2734,260.7933],
[68.8974,247.4181], [56.5622,233.0777], [47.7228,216.3558], [40.1617,199.0172], [36.6431,180.4328],
[34.932,165.2312], [37.5567,165.1101], [41.0547,142.9903], [36.9056,141.4295], [40.199,124.1277],
[47.7776,106.7972], [56.6335,90.084], [68.9831,75.7557], [82.3712,62.3948], [98.395,52.3429],
[115.1281,43.5199], [133.4004,38.6374], [151.9884,35.1378], [170.8905,35.8571], [189.6847,37.991],
[207.5349,44.2488], [224.8662,51.8273], [240.0786,63.067], [254.407,75.4169], [265.6311,90.6406],
[275.6832,106.6636], [281.9225,124.52], [286.8064,142.795], [287.5061,161.696], [286.7874,180.5972],
[281.8856,198.8664], [275.6283,216.7169], [265.5604,232.7294], [254.3211,247.942], [239.9802,260.2776],
[224.757,271.5022], [207.4179,279.0635], [189.5605,285.3035], [170.7649,287.4188],
);
ok $large_circle->is_counter_clockwise, "contour is counter-clockwise";
my $small_circle = Slic3r::Polygon->new_scale( # cw
[158.227,215.9007], [164.5136,215.9007], [175.15,214.5007], [184.5576,210.6044], [190.2268,207.8743],
[199.1462,201.0306], [209.0146,188.346], [213.5135,177.4829], [214.6979,168.4866], [216.1025,162.3325],
[214.6463,151.2703], [213.2471,145.1399], [209.0146,134.9203], [199.1462,122.2357], [189.8944,115.1366],
[181.2504,111.5567], [175.5684,108.8205], [164.5136,107.3655], [158.2269,107.3655], [147.5907,108.7656],
[138.183,112.6616], [132.5135,115.3919], [123.5943,122.2357], [113.7259,134.92], [109.2269,145.7834],
[108.0426,154.7799], [106.638,160.9339], [108.0941,171.9957], [109.4933,178.1264], [113.7259,188.3463],
[123.5943,201.0306], [132.8461,208.1296], [141.4901,211.7094], [147.172,214.4458],
);
ok $small_circle->is_clockwise, "hole is clockwise";
my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle);
my $line = Slic3r::Polyline->new_scale([152.742,288.086671142818], [152.742,34.166466971035]);
my $intersection = intersection_pl([$line], \@$expolygon);
is $intersection->[0]->length, Slic3r::Line->new([152742000, 288086661], [152742000, 215178843])->length,
'line is clipped to square with hole';
is $intersection->[1]->length, Slic3r::Line->new([152742000, 108087507], [152742000, 35166477])->length,
'line is clipped to square with hole';
}
#==========================================================

View File

@ -187,6 +187,19 @@ TriangleMesh mesh(TestMesh m)
return mesh;
}
TriangleMesh mesh(TestMesh min, Vec3d translate, Vec3d scale)
{
TriangleMesh m = mesh(min);
m.translate(translate.cast<float>());
m.scale(scale.cast<float>());
return m;
}
TriangleMesh mesh(TestMesh m, Vec3d translate, double scale)
{
return mesh(m, translate, Vec3d(scale, scale, scale));
}
static bool verbose_gcode()
{
const char *v = std::getenv("SLIC3R_TESTS_GCODE");

View File

@ -5,6 +5,7 @@
#include "libslic3r/ExtrusionEntityCollection.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/ShortestPath.hpp"
#include "libslic3r/libslic3r.h"
#include "test_data.hpp"
@ -83,3 +84,60 @@ SCENARIO("ExtrusionEntityCollection: Polygon flattening", "[ExtrusionEntity]") {
}
}
}
TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
struct Test {
Polylines unchained;
Polylines chained;
Point initial_point;
};
std::vector<Test> tests {
{
{
{ {0,15}, {0,18}, {0,20} },
{ {0,10}, {0,8}, {0,5} }
},
{
{ {0,20}, {0,18}, {0,15} },
{ {0,10}, {0,8}, {0,5} }
},
{ 0,30 }
},
{
{
{ {4,0}, {10,0}, {15,0} },
{ {10,5}, {15,5}, {20,5} }
},
{
{ {20,5}, {15,5}, {10,5} },
{ {15,0}, {10,0}, {4,0} }
},
{ 30,0 }
},
{
{
{ {15,0}, {10,0}, {4,0} },
{ {10,5}, {15,5}, {20,5} }
},
{
{ {20,5}, {15,5}, {10,5} },
{ {15,0}, {10,0}, {4,0} }
},
{ 30,0 }
},
};
for (const Test &test : tests) {
Polylines chained = chain_polylines(test.unchained, &test.initial_point);
REQUIRE(chained == test.chained);
ExtrusionEntityCollection unchained_extrusions;
extrusion_entities_append_paths(unchained_extrusions.entities, test.unchained,
erInternalInfill, 0., 0.4f, 0.3f);
ExtrusionEntityCollection chained_extrusions = unchained_extrusions.chained_path_from(test.initial_point);
REQUIRE(chained_extrusions.entities.size() == test.chained.size());
for (size_t i = 0; i < chained_extrusions.entities.size(); ++ i) {
const Points &p1 = test.chained[i].points;
const Points &p2 = dynamic_cast<const ExtrusionPath*>(chained_extrusions.entities[i])->polyline.points;
REQUIRE(p1 == p2);
}
}
}

View File

@ -7,6 +7,7 @@
#include "libslic3r/Fill/Fill.hpp"
#include "libslic3r/Flow.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SVG.hpp"
#include "libslic3r/libslic3r.h"
@ -14,6 +15,7 @@
#include "test_data.hpp"
using namespace Slic3r;
using namespace std::literals;
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle = 0, double density = 1.0);
@ -43,7 +45,7 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
SECTION("Square") {
Slic3r::Points test_set;
test_set.reserve(4);
std::vector<Vec2d> points {Vec2d(0,0), Vec2d(100,0), Vec2d(100,100), Vec2d(0,100)};
std::vector<Vec2d> points { {0,0}, {100,0}, {100,100}, {0,100} };
for (size_t i = 0; i < 4; ++i) {
std::transform(points.cbegin()+i, points.cend(), std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
std::transform(points.cbegin(), points.cbegin()+i, std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
@ -118,26 +120,28 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
REQUIRE(std::abs(paths[0].length() - static_cast<double>(scale_(3*100 + 2*50))) - SCALED_EPSILON > 0); // path has expected length
}
SECTION("Rotated Square") {
Slic3r::Points square { Point::new_scale(0,0), Point::new_scale(50,0), Point::new_scale(50,50), Point::new_scale(0,50)};
Slic3r::ExPolygon expolygon(square);
SECTION("Rotated Square produces one continuous path") {
Slic3r::ExPolygon expolygon(Polygon::new_scale({ {0, 0}, {50, 0}, {50, 50}, {0, 50} }));
std::unique_ptr<Slic3r::Fill> filler(Slic3r::Fill::new_from_type("rectilinear"));
filler->bounding_box = get_extents(expolygon.contour);
filler->bounding_box = get_extents(expolygon);
filler->angle = 0;
Surface surface(stTop, expolygon);
auto flow = Slic3r::Flow(0.69f, 0.4f, 0.50f);
// width, height, nozzle_dmr
auto flow = Slic3r::Flow(0.69f, 0.4f, 0.5f);
FillParams fill_params;
fill_params.density = 1.0;
for (auto density : { 0.4, 1.0 }) {
fill_params.density = density;
filler->spacing = flow.spacing();
for (auto angle : { 0.0, 45.0}) {
surface.expolygon.rotate(angle, Point(0,0));
Polylines paths = filler->fill_surface(&surface, fill_params);
// one continuous path
REQUIRE(paths.size() == 1);
}
}
}
#if 0 // Disabled temporarily due to precission issues on the Mac VM
SECTION("Solid surface fill") {
@ -190,202 +194,226 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
}
}
/*
SCENARIO("Infill does not exceed perimeters", "[Fill]")
{
my $collection = Slic3r::Polyline::Collection->new(
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
is_deeply
[ map $_->[Y], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
[20, 18, 15, 10, 8, 5],
'chained path';
}
auto test = [](const std::string_view pattern) {
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
{ "fill_pattern", pattern },
{ "top_fill_pattern", pattern },
{ "bottom_fill_pattern", pattern },
{ "perimeters", 1 },
{ "skirts", 0 },
{ "fill_density", 0.2 },
{ "layer_height", 0.05 },
{ "perimeter_extruder", 1 },
{ "infill_extruder", 2 }
});
{
my $collection = Slic3r::Polyline::Collection->new(
Slic3r::Polyline->new([4,0], [10,0], [15,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);
is_deeply
[ map $_->[X], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
[reverse 4, 10, 15, 10, 15, 20],
'chained path';
}
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
);
is_deeply
[ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
[20, 18, 15, 10, 8, 5],
'chained path';
}
{
my $collection = Slic3r::ExtrusionPath::Collection->new(
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
);
is_deeply
[ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
[reverse 4, 10, 15, 10, 15, 20],
'chained path';
}
for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
my $config = Slic3r::Config->new_from_defaults;
$config->set('fill_pattern', $pattern);
$config->set('external_fill_pattern', $pattern);
$config->set('perimeters', 1);
$config->set('skirts', 0);
$config->set('fill_density', 20);
$config->set('layer_height', 0.05);
$config->set('perimeter_extruder', 1);
$config->set('infill_extruder', 2);
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
ok my $gcode = Slic3r::Test::gcode($print), "successful $pattern infill generation";
my $tool = undef;
my @perimeter_points = my @infill_points = ();
Slic3r::GCode::Reader->new->parse($gcode, sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->perimeter_extruder-1) {
push @perimeter_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
} elsif ($tool == $config->infill_extruder-1) {
push @infill_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
WHEN("40mm cube sliced") {
std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::cube_20x20x20, Vec3d::Zero(), 2.0) }, config);
THEN("gcode not empty") {
REQUIRE(! gcode.empty());
}
THEN("infill does not exceed perimeters") {
GCodeReader parser;
const int perimeter_extruder = config.opt_int("perimeter_extruder");
const int infill_extruder = config.opt_int("infill_extruder");
int tool = -1;
Points perimeter_points;
Points infill_points;
parser.parse_buffer(gcode, [&tool, &perimeter_points, &infill_points, perimeter_extruder, infill_extruder]
(Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
{
// if the command is a T command, set the the current tool
if (boost::starts_with(line.cmd(), "T")) {
tool = atoi(line.cmd().data() + 1) + 1;
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
if (tool == perimeter_extruder)
perimeter_points.emplace_back(line.new_XY_scaled(self));
else if (tool == infill_extruder)
infill_points.emplace_back(line.new_XY_scaled(self));
}
});
my $convex_hull = convex_hull(\@perimeter_points);
ok !(defined first { !$convex_hull->contains_point($_) } @infill_points), "infill does not exceed perimeters ($pattern)";
}
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('infill_only_where_needed', 1);
$config->set('bottom_solid_layers', 0);
$config->set('infill_extruder', 2);
$config->set('infill_extrusion_width', 0.5);
$config->set('fill_density', 40);
$config->set('cooling', 0); # for preventing speeds from being altered
$config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
my $test = sub {
my $print = Slic3r::Test::init_print('pyramid', config => $config);
my $tool = undef;
my @infill_extrusions = (); # array of polylines
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->infill_extruder-1) {
push @infill_extrusions, Slic3r::Line->new_scale(
[ $self->X, $self->Y ],
[ $info->{new_X}, $info->{new_Y} ],
);
auto convex_hull = Geometry::convex_hull(perimeter_points);
int num_inside = std::count_if(infill_points.begin(), infill_points.end(), [&convex_hull](const Point &pt){ return convex_hull.contains(pt); });
REQUIRE(num_inside == infill_points.size());
}
}
});
return 0 if !@infill_extrusions; # prevent calling convex_hull() with no points
my $convex_hull = convex_hull([ map $_->pp, map @$_, @infill_extrusions ]);
return unscale unscale sum(map $_->area, @{offset([$convex_hull], scale(+$config->infill_extrusion_width/2))});
};
my $tolerance = 5; # mm^2
$config->set('solid_infill_below_area', 0);
ok $test->() < $tolerance,
'no infill is generated when using infill_only_where_needed on a pyramid';
$config->set('solid_infill_below_area', 70);
ok abs($test->() - $config->solid_infill_below_area) < $tolerance,
'infill is only generated under the forced solid shells';
GIVEN("Rectilinear") { test("rectilinear"sv); }
GIVEN("Honeycomb") { test("honeycomb"sv); }
GIVEN("HilbertCurve") { test("hilbertcurve"sv); }
GIVEN("Concentric") { test("concentric"sv); }
}
SCENARIO("Infill only where needed", "[Fill]")
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('skirts', 0);
$config->set('perimeters', 1);
$config->set('fill_density', 0);
$config->set('top_solid_layers', 0);
$config->set('bottom_solid_layers', 0);
$config->set('solid_infill_below_area', 20000000);
$config->set('solid_infill_every_layers', 2);
$config->set('perimeter_speed', 99);
$config->set('external_perimeter_speed', 99);
$config->set('cooling', 0);
$config->set('first_layer_speed', '100%');
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
{ "infill_only_where_needed", true },
{ "bottom_solid_layers", 0 },
{ "infill_extruder", 2 },
{ "infill_extrusion_width", 0.5 },
{ "wipe_into_infill", false },
{ "fill_density", 0.4 },
// for preventing speeds from being altered
{ "cooling", "0, 0, 0, 0" },
// for preventing speeds from being altered
{ "first_layer_speed", "100%" }
});
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my %layers_with_extrusion = ();
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
auto test = [&config]() -> double {
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::pyramid }, config);
THEN("gcode not empty") {
REQUIRE(! gcode.empty());
}
if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
$layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
GCodeReader parser;
int tool = -1;
const int infill_extruder = config.opt_int("infill_extruder");
Points infill_points;
parser.parse_buffer(gcode, [&tool, &infill_points, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
{
// if the command is a T command, set the the current tool
if (boost::starts_with(line.cmd(), "T")) {
tool = atoi(line.cmd().data() + 1) + 1;
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
if (tool == infill_extruder) {
infill_points.emplace_back(self.xy_scaled());
infill_points.emplace_back(line.new_XY_scaled(self));
}
}
});
// prevent calling convex_hull() with no points
THEN("infill not empty") {
REQUIRE(! infill_points.empty());
}
ok !%layers_with_extrusion,
"solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0";
auto opt_width = config.opt<ConfigOptionFloatOrPercent>("infill_extrusion_width");
REQUIRE(! opt_width->percent);
Polygons convex_hull = expand(Geometry::convex_hull(infill_points), scaled<float>(opt_width->value / 2));
return SCALING_FACTOR * SCALING_FACTOR * std::accumulate(convex_hull.begin(), convex_hull.end(), 0., [](double acc, const Polygon &poly){ return acc + poly.area(); });
};
double tolerance = 5; // mm^2
GIVEN("solid_infill_below_area == 0") {
config.opt_float("solid_infill_below_area") = 0;
WHEN("pyramid is sliced ") {
auto area = test();
THEN("no infill is generated when using infill_only_where_needed on a pyramid") {
REQUIRE(area < tolerance);
}
}
}
GIVEN("solid_infill_below_area == 70") {
config.opt_float("solid_infill_below_area") = 70;
WHEN("pyramid is sliced ") {
auto area = test();
THEN("infill is only generated under the forced solid shells") {
REQUIRE(std::abs(area - 70) < tolerance);
}
}
}
}
SCENARIO("Infill density zero", "[Fill]")
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('skirts', 0);
$config->set('perimeters', 3);
$config->set('fill_density', 0);
$config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.2);
$config->set('nozzle_diameter', [0.35]);
$config->set('infill_extruder', 2);
$config->set('solid_infill_extruder', 2);
$config->set('infill_extrusion_width', 0.52);
$config->set('solid_infill_extrusion_width', 0.52);
$config->set('first_layer_extrusion_width', 0);
WHEN("20mm cube is sliced") {
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "skirts", 0 },
{ "perimeters", 1 },
{ "fill_density", 0 },
{ "top_solid_layers", 0 },
{ "bottom_solid_layers", 0 },
{ "solid_infill_below_area", 20000000 },
{ "solid_infill_every_layers", 2 },
{ "perimeter_speed", 99 },
{ "external_perimeter_speed", 99 },
{ "cooling", "0" },
{ "first_layer_speed", "100%" }
});
my $print = Slic3r::Test::init_print('A', config => $config);
my %infill = (); # Z => [ Line, Line ... ]
my $tool = undef;
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_;
if ($cmd =~ /^T(\d+)/) {
$tool = $1;
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
if ($tool == $config->infill_extruder-1) {
my $z = 1 * $self->Z;
$infill{$z} ||= [];
push @{$infill{$z}}, Slic3r::Line->new_scale(
[ $self->X, $self->Y ],
[ $info->{new_X}, $info->{new_Y} ],
);
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config);
THEN("gcode not empty") {
REQUIRE(! gcode.empty());
}
THEN("solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0") {
GCodeReader parser;
const double perimeter_speed = config.opt_float("perimeter_speed");
std::map<double, double> layers_with_extrusion;
parser.parse_buffer(gcode, [&layers_with_extrusion, perimeter_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) {
if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
double f = line.new_F(self);
if (std::abs(f - perimeter_speed * 60.) > 0.01)
// It is a perimeter.
layers_with_extrusion[self.z()] = f;
}
});
my $grow_d = scale($config->infill_extrusion_width)/2;
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
my $diff = diff($layer0_infill, $layer1_infill);
$diff = offset2_ex($diff, -$grow_d, +$grow_d);
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
REQUIRE(layers_with_extrusion.empty());
}
}
WHEN("A is sliced") {
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "skirts", 0 },
{ "perimeters", 3 },
{ "fill_density", 0 },
{ "layer_height", 0.2 },
{ "first_layer_height", 0.2 },
{ "nozzle_diameter", "0.35,0.35,0.35,0.35" },
{ "infill_extruder", 2 },
{ "solid_infill_extruder", 2 },
{ "infill_extrusion_width", 0.52 },
{ "solid_infill_extrusion_width", 0.52 },
{ "first_layer_extrusion_width", 0 }
});
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::A }, config);
THEN("gcode not empty") {
REQUIRE(! gcode.empty());
}
THEN("no missing parts in solid shell when fill_density is 0") {
GCodeReader parser;
int tool = -1;
const int infill_extruder = config.opt_int("infill_extruder");
std::map<coord_t, Lines> infill;
parser.parse_buffer(gcode, [&tool, &infill, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) {
if (boost::starts_with(line.cmd(), "T")) {
tool = atoi(line.cmd().data() + 1) + 1;
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
if (tool == infill_extruder)
infill[scaled<coord_t>(self.z())].emplace_back(self.xy_scaled(), line.new_XY_scaled(self));
}
});
auto opt_width = config.opt<ConfigOptionFloatOrPercent>("infill_extrusion_width");
REQUIRE(! opt_width->percent);
auto grow_d = scaled<float>(opt_width->value / 2);
auto inflate_lines = [grow_d](const Lines &lines) {
Polygons out;
for (const Line &line : lines)
append(out, offset(Polyline{ line.a, line.b }, grow_d, Slic3r::ClipperLib::jtSquare, 3.));
return union_(out);
};
Polygons layer0_infill = inflate_lines(infill[scaled<coord_t>(0.2)]);
Polygons layer1_infill = inflate_lines(infill[scaled<coord_t>(0.4)]);
ExPolygons poly = opening_ex(diff_ex(layer0_infill, layer1_infill), grow_d);
const double threshold = 2. * sqr(grow_d * 2.);
int missing_parts = std::count_if(poly.begin(), poly.end(), [threshold](const ExPolygon &poly){ return poly.area() > threshold; });
REQUIRE(missing_parts == 0);
}
}
}
/*
{
# GH: #2697
my $config = Slic3r::Config->new_from_defaults;
@ -427,6 +455,78 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
my @holes = map @{$_->holes}, @$covered;
ok sum(map unscale unscale $_->area*-1, @holes) < 1, 'no gaps between top solid infill and perimeters';
}
{
skip "The FillRectilinear2 does not fill the surface completely", 1;
my $test = sub {
my ($expolygon, $flow_spacing, $angle, $density) = @_;
my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_bounding_box($expolygon->bounding_box);
$filler->set_angle($angle // 0);
# Adjust line spacing to fill the region.
$filler->set_dont_adjust(0);
$filler->set_link_max_length(scale(1.2*$flow_spacing));
my $surface = Slic3r::Surface->new(
surface_type => S_TYPE_BOTTOM,
expolygon => $expolygon,
);
my $flow = Slic3r::Flow->new(
width => $flow_spacing,
height => 0.4,
nozzle_diameter => $flow_spacing,
);
$filler->set_spacing($flow->spacing);
my $paths = $filler->fill_surface(
$surface,
layer_height => $flow->height,
density => $density // 1,
);
# check whether any part was left uncovered
my @grown_paths = map @{Slic3r::Polyline->new(@$_)->grow(scale $filler->spacing/2)}, @$paths;
my $uncovered = diff_ex([ @$expolygon ], [ @grown_paths ], 1);
# ignore very small dots
my $uncovered_filtered = [ grep $_->area > (scale $flow_spacing)**2, @$uncovered ];
is scalar(@$uncovered_filtered), 0, 'solid surface is fully filled';
if (0 && @$uncovered_filtered) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("uncovered.svg",
no_arrows => 1,
expolygons => [ $expolygon ],
blue_expolygons => [ @$uncovered ],
red_expolygons => [ @$uncovered_filtered ],
polylines => [ @$paths ],
);
exit;
}
};
my $expolygon = Slic3r::ExPolygon->new([
[6883102, 9598327.01296997],
[6883102, 20327272.01297],
[3116896, 20327272.01297],
[3116896, 9598327.01296997],
]);
$test->($expolygon, 0.55);
for (1..20) {
$expolygon->scale(1.05);
$test->($expolygon, 0.55);
}
$expolygon = Slic3r::ExPolygon->new(
[[59515297,5422499],[59531249,5578697],[59695801,6123186],[59965713,6630228],[60328214,7070685],[60773285,7434379],[61274561,7702115],[61819378,7866770],[62390306,7924789],[62958700,7866744],[63503012,7702244],[64007365,7434357],[64449960,7070398],[64809327,6634999],[65082143,6123325],[65245005,5584454],[65266967,5422499],[66267307,5422499],[66269190,8310081],[66275379,17810072],[66277259,20697500],[65267237,20697500],[65245004,20533538],[65082082,19994444],[64811462,19488579],[64450624,19048208],[64012101,18686514],[63503122,18415781],[62959151,18251378],[62453416,18198442],[62390147,18197355],[62200087,18200576],[61813519,18252990],[61274433,18415918],[60768598,18686517],[60327567,19047892],[59963609,19493297],[59695865,19994587],[59531222,20539379],[59515153,20697500],[58502480,20697500],[58502480,5422499]]
);
$test->($expolygon, 0.524341649025257);
$expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [98,0], [98,10], [0,10] ]);
$test->($expolygon, 0.5, 45, 0.99); # non-solid infill
}
*/
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle, double density)

View File

@ -188,6 +188,46 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
REQUIRE(intersection.front().area() == Approx(match.area()));
}
}
ExPolygons expolygons { ExPolygon { square, hole_in_square } };
WHEN("Clipping line 1") {
Polylines intersection = intersection_pl({ Polyline { { 15, 18 }, { 15, 15 } } }, expolygons);
THEN("line is clipped to square with hole") {
REQUIRE((Vec2f(15, 18) - Vec2f(15, 16)).norm() == Approx(intersection.front().length()));
}
}
WHEN("Clipping line 2") {
Polylines intersection = intersection_pl({ Polyline { { 15, 15 }, { 15, 12 } } }, expolygons);
THEN("line is clipped to square with hole") {
REQUIRE((Vec2f(15, 14) - Vec2f(15, 12)).norm() == Approx(intersection.front().length()));
}
}
WHEN("Clipping line 3") {
Polylines intersection = intersection_pl({ Polyline { { 12, 18 }, { 18, 18 } } }, expolygons);
THEN("line is clipped to square with hole") {
REQUIRE((Vec2f(18, 18) - Vec2f(12, 18)).norm() == Approx(intersection.front().length()));
}
}
WHEN("Clipping line 4") {
Polylines intersection = intersection_pl({ Polyline { { 5, 15 }, { 30, 15 } } }, expolygons);
THEN("line is clipped to square with hole") {
REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection.front().length()));
REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection[1].length()));
}
}
WHEN("Clipping line 5") {
Polylines intersection = intersection_pl({ Polyline { { 30, 15 }, { 5, 15 } } }, expolygons);
THEN("reverse line is clipped to square with hole") {
REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection.front().length()));
REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection[1].length()));
}
}
WHEN("Clipping line 6") {
Polylines intersection = intersection_pl({ Polyline { { 10, 18 }, { 20, 18 } } }, expolygons);
THEN("tangent line is clipped to square with hole") {
REQUIRE((Vec2f(20, 18) - Vec2f(10, 18)).norm() == Approx(intersection.front().length()));
}
}
}
GIVEN("square with hole 2") {
// CCW oriented contour
@ -223,6 +263,44 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
}
}
}
GIVEN("circle") {
Slic3r::ExPolygon circle_with_hole { Polygon::new_scale({
{ 151.8639,288.1192 }, {133.2778,284.6011}, { 115.0091,279.6997 }, { 98.2859,270.8606 }, { 82.2734,260.7933 },
{ 68.8974,247.4181 }, { 56.5622,233.0777 }, { 47.7228,216.3558 }, { 40.1617,199.0172 }, { 36.6431,180.4328 },
{ 34.932,165.2312 }, { 37.5567,165.1101 }, { 41.0547,142.9903 }, { 36.9056,141.4295 }, { 40.199,124.1277 },
{ 47.7776,106.7972 }, { 56.6335,90.084 }, { 68.9831,75.7557 }, { 82.3712,62.3948 }, { 98.395,52.3429 },
{ 115.1281,43.5199 }, { 133.4004,38.6374 }, { 151.9884,35.1378 }, { 170.8905,35.8571 }, { 189.6847,37.991 },
{ 207.5349,44.2488 }, { 224.8662,51.8273 }, { 240.0786,63.067 }, { 254.407,75.4169 }, { 265.6311,90.6406 },
{ 275.6832,106.6636 }, { 281.9225,124.52 }, { 286.8064,142.795 }, { 287.5061,161.696 }, { 286.7874,180.5972 },
{ 281.8856,198.8664 }, { 275.6283,216.7169 }, { 265.5604,232.7294 }, { 254.3211,247.942 }, { 239.9802,260.2776 },
{ 224.757,271.5022 }, { 207.4179,279.0635 }, { 189.5605,285.3035 }, { 170.7649,287.4188 }
}) };
circle_with_hole.holes = { Polygon::new_scale({
{ 158.227,215.9007 }, { 164.5136,215.9007 }, { 175.15,214.5007 }, { 184.5576,210.6044 }, { 190.2268,207.8743 },
{ 199.1462,201.0306 }, { 209.0146,188.346 }, { 213.5135,177.4829 }, { 214.6979,168.4866 }, { 216.1025,162.3325 },
{ 214.6463,151.2703 }, { 213.2471,145.1399 }, { 209.0146,134.9203 }, { 199.1462,122.2357 }, { 189.8944,115.1366 },
{ 181.2504,111.5567 }, { 175.5684,108.8205 }, { 164.5136,107.3655 }, { 158.2269,107.3655 }, { 147.5907,108.7656 },
{ 138.183,112.6616 }, { 132.5135,115.3919 }, { 123.5943,122.2357 }, { 113.7259,134.92 }, { 109.2269,145.7834 },
{ 108.0426,154.7799 }, { 106.638,160.9339 }, { 108.0941,171.9957 }, { 109.4933,178.1264 }, { 113.7259,188.3463 },
{ 123.5943,201.0306 }, { 132.8461,208.1296 }, { 141.4901,211.7094 }, { 147.172,214.4458 }
}) };
THEN("contour is counter-clockwise") {
REQUIRE(circle_with_hole.contour.is_counter_clockwise());
}
THEN("hole is counter-clockwise") {
REQUIRE(circle_with_hole.holes.size() == 1);
REQUIRE(circle_with_hole.holes.front().is_clockwise());
}
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 });
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()));
}
}
}
}
template<e_ordering o = e_ordering::OFF, class P, class Tree>

View File

@ -53,11 +53,8 @@ set(XS_XSP_FILES
${XSP_DIR}/ExtrusionLoop.xsp
${XSP_DIR}/ExtrusionMultiPath.xsp
${XSP_DIR}/ExtrusionPath.xsp
${XSP_DIR}/ExtrusionSimulator.xsp
${XSP_DIR}/Filler.xsp
${XSP_DIR}/Flow.xsp
${XSP_DIR}/GCode.xsp
# ${XSP_DIR}/GCodeSender.xsp
${XSP_DIR}/Geometry.xsp
${XSP_DIR}/Layer.xsp
${XSP_DIR}/Line.xsp

View File

@ -133,23 +133,6 @@ sub clone {
);
}
package Slic3r::ExtrusionSimulator;
sub new {
my ($class, %args) = @_;
return $class->_new();
}
package Slic3r::Filler;
sub fill_surface {
my ($self, $surface, %args) = @_;
$self->set_density($args{density}) if defined($args{density});
$self->set_dont_adjust($args{dont_adjust}) if defined($args{dont_adjust});
$self->set_complete($args{complete}) if defined($args{complete});
return $self->_fill_surface($surface);
}
package Slic3r::Flow;
sub new {
@ -255,19 +238,12 @@ for my $class (qw(
Slic3r::ExtrusionMultiPath
Slic3r::ExtrusionPath
Slic3r::ExtrusionPath::Collection
Slic3r::ExtrusionSimulator
Slic3r::Filler
Slic3r::Flow
Slic3r::GCode
Slic3r::GCode::PlaceholderParser
Slic3r::Geometry::BoundingBox
Slic3r::Geometry::BoundingBoxf
Slic3r::Geometry::BoundingBoxf3
Slic3r::GUI::_3DScene::GLShader
Slic3r::GUI::_3DScene::GLVolume
Slic3r::GUI::Preset
Slic3r::GUI::PresetCollection
Slic3r::GUI::Tab
Slic3r::Layer
Slic3r::Layer::Region
Slic3r::Layer::Support

View File

@ -2,7 +2,6 @@
#include <cstdlib>
#include <ostream>
#include <sstream>
// #include <libslic3r/GCodeSender.hpp>
#ifdef __cplusplus
/* extern "C" { */

View File

@ -9,8 +9,6 @@ REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
REGISTER_CLASS(ExtrusionSimulator, "ExtrusionSimulator");
REGISTER_CLASS(Filler, "Filler");
REGISTER_CLASS(Flow, "Flow");
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
REGISTER_CLASS(GCode, "GCode");

View File

@ -9,16 +9,6 @@
%{
IV
_constant()
ALIAS:
JT_MITER = jtMiter
JT_ROUND = jtRound
JT_SQUARE = jtSquare
CODE:
RETVAL = ix;
OUTPUT: RETVAL
Polygons
offset(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
@ -30,17 +20,6 @@ offset(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
OUTPUT:
RETVAL
ExPolygons
offset_ex(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
const float delta
Slic3r::ClipperLib::JoinType joinType
double miterLimit
CODE:
RETVAL = offset_ex(polygons, delta, joinType, miterLimit);
OUTPUT:
RETVAL
ExPolygons
offset2_ex(polygons, delta1, delta2, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
@ -73,44 +52,6 @@ diff_ex(subject, clip, safety_offset = false)
OUTPUT:
RETVAL
Polylines
diff_pl(subject, clip)
Polylines subject
Polygons clip
CODE:
RETVAL = diff_pl(subject, clip);
OUTPUT:
RETVAL
Polygons
intersection(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
RETVAL = intersection(subject, clip, safety_offset ? ApplySafetyOffset::Yes : ApplySafetyOffset::No);
OUTPUT:
RETVAL
ExPolygons
intersection_ex(subject, clip, safety_offset = false)
Polygons subject
Polygons clip
bool safety_offset
CODE:
RETVAL = intersection_ex(subject, clip, safety_offset ? ApplySafetyOffset::Yes : ApplySafetyOffset::No);
OUTPUT:
RETVAL
Polylines
intersection_pl(subject, clip)
Polylines subject
Polygons clip
CODE:
RETVAL = intersection_pl(subject, clip);
OUTPUT:
RETVAL
Polygons
union(subject, safety_offset = false)
Polygons subject

View File

@ -1,50 +0,0 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "libslic3r/ExtrusionSimulator.hpp"
%}
%name{Slic3r::ExtrusionSimulator} class ExtrusionSimulator {
~ExtrusionSimulator();
%name{_new} ExtrusionSimulator();
Clone<ExtrusionSimulator> clone()
%code{% RETVAL = THIS; %};
void set_image_size(Point *image_size)
%code{% THIS->set_image_size(*image_size); %};
void set_viewport(BoundingBox *viewport)
%code{% THIS->set_viewport(*viewport); %};
void set_bounding_box(BoundingBox *bbox)
%code{% THIS->set_bounding_box(*bbox); %};
void reset_accumulator();
void extrude_to_accumulator(ExtrusionPath *path, Point *shift, ExtrusionSimulationType simulationType)
%code{% THIS->extrude_to_accumulator(*path, *shift, simulationType); %};
void evaluate_accumulator(ExtrusionSimulationType simulationType);
void* image_ptr()
%code{% RETVAL = const_cast<void*>(const_cast<Slic3r::ExtrusionSimulator*>(THIS)->image_ptr()); %};
%{
%}
};
%package{Slic3r::ExtrusionSimulator};
%{
IV
_constant()
ALIAS:
EXTRSIM_SIMPLE = ExtrusionSimulationSimple
EXTRSIM_DONT_SPREAD = ExtrusionSimulationDontSpread
EXTRSIM_SPREAD_NFULL = ExtrisopmSimulationSpreadNotOverfilled
EXTRSIM_SPREAD_FULL = ExtrusionSimulationSpreadFull
EXTRSIM_SPREAD_EXCESS = ExtrusionSimulationSpreadExcess
PROTOTYPE:
CODE:
RETVAL = ix;
OUTPUT: RETVAL
%}

View File

@ -1,65 +0,0 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "libslic3r/Fill/Fill.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/ExtrusionEntityCollection.hpp"
%}
%name{Slic3r::Filler} class Filler {
~Filler();
void set_bounding_box(BoundingBox *bbox)
%code{% THIS->fill->set_bounding_box(*bbox); %};
void set_spacing(coordf_t spacing)
%code{% THIS->fill->spacing = spacing; %};
coordf_t spacing()
%code{% RETVAL = THIS->fill->spacing; %};
void set_layer_id(size_t layer_id)
%code{% THIS->fill->layer_id = layer_id; %};
void set_z(coordf_t z)
%code{% THIS->fill->z = z; %};
void set_angle(float angle)
%code{% THIS->fill->angle = angle; %};
void set_link_max_length(coordf_t len)
%code{% THIS->fill->link_max_length = len; %};
void set_loop_clipping(coordf_t clipping)
%code{% THIS->fill->loop_clipping = clipping; %};
bool use_bridge_flow()
%code{% RETVAL = THIS->fill->use_bridge_flow(); %};
bool no_sort()
%code{% RETVAL = THIS->fill->no_sort(); %};
void set_density(float density)
%code{% THIS->params.density = density; %};
void set_dont_adjust(bool dont_adjust)
%code{% THIS->params.dont_adjust = dont_adjust; %};
PolylineCollection* _fill_surface(Surface *surface)
%code{%
PolylineCollection *pc = NULL;
if (THIS->fill != NULL) {
pc = new PolylineCollection();
pc->polylines = THIS->fill->fill_surface(surface, THIS->params);
}
RETVAL = pc;
%};
%{
Filler*
new_from_type(CLASS, type)
char* CLASS;
std::string type;
CODE:
Filler *filler = new Filler();
filler->fill = Fill::new_from_type(type);
RETVAL = filler;
OUTPUT:
RETVAL
%}
};

View File

@ -1,24 +0,0 @@
%module{Slic3r::XS};
%{
#include <xsinit.h>
#include "libslic3r/GCodeSender.hpp"
%}
%name{Slic3r::GCode::Sender} class GCodeSender {
GCodeSender();
~GCodeSender();
bool connect(std::string port, unsigned int baud_rate);
void disconnect();
bool is_connected();
bool wait_connected(unsigned int timeout = 3);
int queue_size();
void send(std::string s, bool priority = false);
void pause_queue();
void resume_queue();
void purge_queue(bool priority = false);
std::vector<std::string> purge_log();
std::string getT();
std::string getB();
};

View File

@ -41,12 +41,6 @@
Clone<BoundingBox> bounding_box();
Clone<Point> point_projection(Point* point)
%code{% RETVAL = THIS->point_projection(*point); %};
Clone<Point> intersection(Line* line)
%code{%
Point p;
(void)THIS->intersection(*line, &p);
RETVAL = p;
%};
Clone<Point> first_intersection(Line* line)
%code{%
Point p;

View File

@ -82,16 +82,6 @@ Surface::polygons()
OUTPUT:
RETVAL
Surfaces
Surface::offset(delta, joinType = ClipperLib::jtMiter, miterLimit = 3)
const float delta
Slic3r::ClipperLib::JoinType joinType
double miterLimit
CODE:
surfaces_append(RETVAL, offset_ex(THIS->expolygon, delta, joinType, miterLimit), *THIS);
OUTPUT:
RETVAL
%}
};

View File

@ -118,14 +118,6 @@ ExtrusionLoop* O_OBJECT_SLIC3R
Ref<ExtrusionLoop> O_OBJECT_SLIC3R_T
Clone<ExtrusionLoop> O_OBJECT_SLIC3R_T
ExtrusionSimulator* O_OBJECT_SLIC3R
Ref<ExtrusionSimulator> O_OBJECT_SLIC3R_T
Clone<ExtrusionSimulator> O_OBJECT_SLIC3R_T
Filler* O_OBJECT_SLIC3R
Ref<Filler> O_OBJECT_SLIC3R_T
Clone<Filler> O_OBJECT_SLIC3R_T
Flow* O_OBJECT_SLIC3R
Ref<Flow> O_OBJECT_SLIC3R_T
Clone<Flow> O_OBJECT_SLIC3R_T

View File

@ -58,9 +58,6 @@
%typemap{ExPolygonCollection*};
%typemap{Ref<ExPolygonCollection>}{simple};
%typemap{Clone<ExPolygonCollection>}{simple};
%typemap{Filler*};
%typemap{Ref<Filler>}{simple};
%typemap{Clone<Filler>}{simple};
%typemap{Flow*};
%typemap{Ref<Flow>}{simple};
%typemap{Clone<Flow>}{simple};
@ -88,9 +85,6 @@
%typemap{ExtrusionLoop*};
%typemap{Ref<ExtrusionLoop>}{simple};
%typemap{Clone<ExtrusionLoop>}{simple};
%typemap{ExtrusionSimulator*};
%typemap{Ref<ExtrusionSimulator>}{simple};
%typemap{Clone<ExtrusionSimulator>}{simple};
%typemap{TriangleMesh*};
%typemap{Ref<TriangleMesh>}{simple};
%typemap{Clone<TriangleMesh>}{simple};