Merge remote-tracking branch 'origin/master' into profile_changes_reset
This commit is contained in:
commit
3bc7580e8c
27
My Settings
27
My Settings
@ -1,27 +0,0 @@
|
||||
# generated by Slic3r Prusa Edition 1.38.4 on 2017-12-20 at 11:02:03
|
||||
bed_temperature = 0
|
||||
bridge_fan_speed = 100
|
||||
compatible_printers =
|
||||
compatible_printers_condition =
|
||||
cooling = 1
|
||||
disable_fan_first_layers = 3
|
||||
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
|
||||
extrusion_multiplier = 1
|
||||
fan_always_on = 0
|
||||
fan_below_layer_time = 60
|
||||
filament_colour = #29b2b2
|
||||
filament_cost = 0
|
||||
filament_density = 0
|
||||
filament_diameter = 3
|
||||
filament_max_volumetric_speed = 0
|
||||
filament_notes = ""
|
||||
filament_soluble = 0
|
||||
filament_type = PLA
|
||||
first_layer_bed_temperature = 0
|
||||
first_layer_temperature = 205
|
||||
max_fan_speed = 100
|
||||
min_fan_speed = 35
|
||||
min_print_speed = 10
|
||||
slowdown_below_layer_time = 5
|
||||
start_filament_gcode = "; Filament gcode\n"
|
||||
temperature = 200
|
@ -1,8 +1,9 @@
|
||||
# Building Slic3r PE on Microsoft Windows
|
||||
|
||||
The currently supported way of building Slic3r PE on Windows is with MS Visual Studio 2013
|
||||
The currently supported way of building Slic3r PE on Windows is with CMake and MS Visual Studio 2013
|
||||
using our Perl binary distribution (compiled from official Perl sources).
|
||||
You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/).
|
||||
CMake installer can be downloaded from [the official website](https://cmake.org/download/).
|
||||
|
||||
Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work
|
||||
and cannot provide guidance.
|
||||
@ -26,8 +27,8 @@ Apart from wxWidgets and Perl, you will also need additional dependencies:
|
||||
|
||||
We have prepared a binary package of the listed libraries:
|
||||
|
||||
- 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-32.7z)
|
||||
- 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-64.7z)
|
||||
- 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-32.7z)
|
||||
- 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=2%2Fslic3r-destdir-64.7z)
|
||||
|
||||
It is recommended you unpack this package into `C:\local\` as the environment
|
||||
setup script expects it there.
|
||||
|
@ -37,7 +37,7 @@ if ($destdir -eq "") {
|
||||
}
|
||||
|
||||
$BOOST = 'boost_1_63_0'
|
||||
$CURL = 'curl-7.28.0'
|
||||
$CURL = 'curl-7.58.0'
|
||||
$TBB_SHA = 'a0dc9bf76d0120f917b641ed095360448cabc85b'
|
||||
$TBB = "tbb-$TBB_SHA"
|
||||
|
||||
|
@ -96,7 +96,7 @@ use constant MANIPULATION_IDLE => 0;
|
||||
use constant MANIPULATION_DRAGGING => 1;
|
||||
use constant MANIPULATION_LAYER_HEIGHT => 2;
|
||||
|
||||
use constant GIMBALL_LOCK_THETA_MAX => 170;
|
||||
use constant GIMBALL_LOCK_THETA_MAX => 180;
|
||||
|
||||
use constant VARIABLE_LAYER_THICKNESS_BAR_WIDTH => 70;
|
||||
use constant VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT => 22;
|
||||
@ -1316,12 +1316,18 @@ sub Render {
|
||||
$self->mark_volumes_for_layer_height;
|
||||
$self->volumes->set_print_box($self->bed_bounding_box->x_min, $self->bed_bounding_box->y_min, 0.0, $self->bed_bounding_box->x_max, $self->bed_bounding_box->y_max, $self->{config}->get('max_print_height'));
|
||||
$self->volumes->update_outside_state($self->{config}, 0);
|
||||
# do not cull backfaces to show broken geometry, if any
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
$self->{plain_shader}->enable if $self->{plain_shader};
|
||||
$self->volumes->render_VBOs;
|
||||
$self->{plain_shader}->disable;
|
||||
glEnable(GL_CULL_FACE) if ($self->enable_picking);
|
||||
} else {
|
||||
# do not cull backfaces to show broken geometry, if any
|
||||
glDisable(GL_CULL_FACE) if ($self->enable_picking);
|
||||
$self->volumes->render_legacy;
|
||||
glEnable(GL_CULL_FACE) if ($self->enable_picking);
|
||||
}
|
||||
|
||||
# draw cutting plane
|
||||
@ -1358,6 +1364,9 @@ sub draw_volumes {
|
||||
# $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking.
|
||||
my ($self, $fakecolor) = @_;
|
||||
|
||||
# do not cull backfaces to show broken geometry, if any
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
@ -1385,6 +1394,8 @@ sub draw_volumes {
|
||||
}
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (defined $self->cutting_plane_z) {
|
||||
glLineWidth(2);
|
||||
@ -1812,6 +1823,7 @@ sub _fragment_shader_Gouraud {
|
||||
return <<'FRAGMENT';
|
||||
#version 110
|
||||
|
||||
const vec4 OUTSIDE_COLOR = vec4(0.24, 0.42, 0.62, 1.0);
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// x = tainted, y = specular;
|
||||
@ -1824,13 +1836,11 @@ uniform vec4 uniform_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 0.0) + uniform_color * intensity.x;
|
||||
// if the fragment is outside the print volume use predefined color
|
||||
vec4 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? OUTSIDE_COLOR : uniform_color;
|
||||
|
||||
// if the fragment is outside the print volume darken it and set it as transparent
|
||||
if (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO)))
|
||||
gl_FragColor = vec4(mix(gl_FragColor.xyz, ZERO, 0.5), 0.5 * uniform_color.a);
|
||||
else
|
||||
gl_FragColor.a = uniform_color.a;
|
||||
gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 0.0) + color * intensity.x;
|
||||
gl_FragColor.a = color.a;
|
||||
}
|
||||
|
||||
FRAGMENT
|
||||
|
@ -98,6 +98,16 @@ sub new {
|
||||
$self->update;
|
||||
};
|
||||
|
||||
# callback to enable/disable action buttons
|
||||
my $enable_action_buttons = sub {
|
||||
my ($enable) = @_;
|
||||
$self->{btn_export_gcode}->Enable($enable);
|
||||
$self->{btn_reslice}->Enable($enable);
|
||||
$self->{btn_print}->Enable($enable);
|
||||
$self->{btn_send_gcode}->Enable($enable);
|
||||
$self->{btn_export_stl}->Enable($enable);
|
||||
};
|
||||
|
||||
# Initialize 3D plater
|
||||
if ($Slic3r::GUI::have_OpenGL) {
|
||||
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config});
|
||||
@ -113,6 +123,7 @@ sub new {
|
||||
$self->{canvas3D}->set_on_decrease_objects(sub { $self->decrease() });
|
||||
$self->{canvas3D}->set_on_remove_object(sub { $self->remove() });
|
||||
$self->{canvas3D}->set_on_instances_moved($on_instances_moved);
|
||||
$self->{canvas3D}->set_on_enable_action_buttons($enable_action_buttons);
|
||||
$self->{canvas3D}->use_plain_shader(1);
|
||||
$self->{canvas3D}->set_on_wipe_tower_moved(sub {
|
||||
my ($new_pos_3f) = @_;
|
||||
@ -1470,7 +1481,11 @@ sub on_export_completed {
|
||||
# Send $self->{send_gcode_file} to OctoPrint.
|
||||
if ($send_gcode) {
|
||||
my $op = Slic3r::OctoPrint->new($self->{config});
|
||||
$op->send_gcode($self->GetId(), $PROGRESS_BAR_EVENT, $ERROR_EVENT, $self->{send_gcode_file});
|
||||
if ($op->send_gcode($self->{send_gcode_file})) {
|
||||
$self->statusbar->SetStatusText(L("OctoPrint upload finished."));
|
||||
} else {
|
||||
$self->statusbar->SetStatusText("");
|
||||
}
|
||||
}
|
||||
|
||||
$self->{print_file} = undef;
|
||||
@ -1560,7 +1575,7 @@ sub export_amf {
|
||||
return if !@{$self->{objects}};
|
||||
# Ask user for a file name to write into.
|
||||
my $output_file = $self->_get_export_file('AMF') or return;
|
||||
my $res = $self->{model}->store_amf($output_file, $self->{print});
|
||||
my $res = $self->{model}->store_amf($output_file, $self->{print}, $self->{export_option});
|
||||
if ($res)
|
||||
{
|
||||
$self->statusbar->SetStatusText(L("AMF file exported to ").$output_file);
|
||||
@ -1576,7 +1591,7 @@ sub export_3mf {
|
||||
return if !@{$self->{objects}};
|
||||
# Ask user for a file name to write into.
|
||||
my $output_file = $self->_get_export_file('3MF') or return;
|
||||
my $res = $self->{model}->store_3mf($output_file, $self->{print});
|
||||
my $res = $self->{model}->store_3mf($output_file, $self->{print}, $self->{export_option});
|
||||
if ($res)
|
||||
{
|
||||
$self->statusbar->SetStatusText(L("3MF file exported to ").$output_file);
|
||||
@ -1618,11 +1633,13 @@ sub _get_export_file {
|
||||
$output_file =~ s/\.[gG][cC][oO][dD][eE]$/$suffix/;
|
||||
my $dlg = Wx::FileDialog->new($self, L("Save ").$format.L(" file as:"), dirname($output_file),
|
||||
basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{$wildcard}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
Slic3r::GUI::add_export_option($dlg, $format);
|
||||
if ($dlg->ShowModal != wxID_OK) {
|
||||
$dlg->Destroy;
|
||||
return undef;
|
||||
}
|
||||
$output_file = $dlg->GetPath;
|
||||
$self->{export_option} = Slic3r::GUI::get_export_option($dlg);
|
||||
$dlg->Destroy;
|
||||
return $output_file;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use Wx::Locale gettext => 'L';
|
||||
|
||||
__PACKAGE__->mk_accessors(qw(
|
||||
on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly
|
||||
on_remove_object on_increase_objects on_decrease_objects));
|
||||
on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons));
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
@ -176,6 +176,11 @@ sub set_on_model_update {
|
||||
$self->on_model_update($cb);
|
||||
}
|
||||
|
||||
sub set_on_enable_action_buttons {
|
||||
my ($self, $cb) = @_;
|
||||
$self->on_enable_action_buttons($cb);
|
||||
}
|
||||
|
||||
sub reload_scene {
|
||||
my ($self, $force) = @_;
|
||||
|
||||
@ -217,10 +222,12 @@ sub reload_scene {
|
||||
if (!$self->{model}->fits_print_volume($self->{config})) {
|
||||
$self->set_warning_enabled(1);
|
||||
Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume"));
|
||||
$self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons);
|
||||
} else {
|
||||
$self->set_warning_enabled(0);
|
||||
$self->volumes->update_outside_state($self->{config}, 1);
|
||||
Slic3r::GUI::_3DScene::reset_warning_texture();
|
||||
$self->on_enable_action_buttons->(1) if ($self->on_enable_action_buttons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ sub new {
|
||||
$choice_view_type->Append(L("Height"));
|
||||
$choice_view_type->Append(L("Width"));
|
||||
$choice_view_type->Append(L("Speed"));
|
||||
$choice_view_type->Append(L("Volumetric flow rate"));
|
||||
$choice_view_type->Append(L("Tool"));
|
||||
$choice_view_type->SetSelection(0);
|
||||
|
||||
|
@ -54,6 +54,7 @@ add_library(libslic3r STATIC
|
||||
${LIBDIR}/libslic3r/ExtrusionEntityCollection.hpp
|
||||
${LIBDIR}/libslic3r/ExtrusionSimulator.cpp
|
||||
${LIBDIR}/libslic3r/ExtrusionSimulator.hpp
|
||||
${LIBDIR}/libslic3r/FileParserError.hpp
|
||||
${LIBDIR}/libslic3r/Fill/Fill.cpp
|
||||
${LIBDIR}/libslic3r/Fill/Fill.hpp
|
||||
${LIBDIR}/libslic3r/Fill/Fill3DHoneycomb.cpp
|
||||
@ -203,6 +204,10 @@ add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.cpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.hpp
|
||||
${LIBDIR}/slic3r/Config/Snapshot.cpp
|
||||
${LIBDIR}/slic3r/Config/Snapshot.hpp
|
||||
${LIBDIR}/slic3r/Config/Version.cpp
|
||||
${LIBDIR}/slic3r/Config/Version.hpp
|
||||
${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp
|
||||
${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp
|
||||
${LIBDIR}/slic3r/Utils/Http.cpp
|
||||
@ -301,6 +306,11 @@ add_library(Shiny STATIC
|
||||
${LIBDIR}/Shiny/ShinyZone.h
|
||||
)
|
||||
|
||||
add_library(semver STATIC
|
||||
${LIBDIR}/semver/semver.h
|
||||
${LIBDIR}/semver/semver.c
|
||||
)
|
||||
|
||||
# Generate the Slic3r Perl module (XS) typemap file.
|
||||
set(MyTypemap ${CMAKE_CURRENT_BINARY_DIR}/typemap)
|
||||
add_custom_command(
|
||||
|
48
xs/src/libslic3r/FileParserError.hpp
Normal file
48
xs/src/libslic3r/FileParserError.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef slic3r_FileParserError_hpp_
|
||||
#define slic3r_FileParserError_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Generic file parser error, mostly copied from boost::property_tree::file_parser_error
|
||||
class file_parser_error: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
file_parser_error(const std::string &msg, const std::string &file, unsigned long line = 0) :
|
||||
std::runtime_error(format_what(msg, file, line)),
|
||||
m_message(msg), m_filename(file), m_line(line) {}
|
||||
// gcc 3.4.2 complains about lack of throw specifier on compiler
|
||||
// generated dtor
|
||||
~file_parser_error() throw() {}
|
||||
|
||||
// Get error message (without line and file - use what() to get full message)
|
||||
std::string message() const { return m_message; }
|
||||
// Get error filename
|
||||
std::string filename() const { return m_filename; }
|
||||
// Get error line number
|
||||
unsigned long line() const { return m_line; }
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
std::string m_filename;
|
||||
unsigned long m_line;
|
||||
|
||||
// Format error message to be returned by std::runtime_error::what()
|
||||
static std::string format_what(const std::string &msg, const std::string &file, unsigned long l)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << (file.empty() ? "<unspecified file>" : file.c_str());
|
||||
if (l > 0)
|
||||
stream << '(' << l << ')';
|
||||
stream << ": " << msg;
|
||||
return stream.str();
|
||||
}
|
||||
};
|
||||
|
||||
}; // Slic3r
|
||||
|
||||
#endif // slic3r_FileParserError_hpp_
|
@ -41,7 +41,7 @@ static inline Polyline make_wave_horizontal(
|
||||
polyline.points.emplace_back(Point(0, coord_t(clamp(0., height, y0) * scaleFactor)));
|
||||
double phase_offset_sin = (z_sin < 0 ? M_PI : 0) + (flip ? 0 : M_PI);
|
||||
double phase_offset_cos = z_sin < 0 ? M_PI : 0.;
|
||||
for (double x=0.; x < width + segmentSize; x += segmentSize) {
|
||||
for (double x = 0.; x < width + segmentSize; x += segmentSize) {
|
||||
x = std::min(x, width);
|
||||
double a = cos(x + phase_offset_cos);
|
||||
double b = - z_sin;
|
||||
@ -55,17 +55,17 @@ static inline Polyline make_wave_horizontal(
|
||||
return polyline;
|
||||
}
|
||||
|
||||
static Polylines make_gyroid_waves(double gridZ, double density, double layer_width, double width, double height)
|
||||
static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
|
||||
{
|
||||
double scaleFactor = scale_(layer_width) / density;
|
||||
double segmentSize = 0.5 * density;
|
||||
double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
double segmentSize = 0.5 * density_adjusted;
|
||||
//scale factor for 5% : 8 712 388
|
||||
// 1z = 10^-6 mm ?
|
||||
double z = gridZ / scaleFactor;
|
||||
double z_sin = sin(z);
|
||||
double z_cos = cos(z);
|
||||
Polylines result;
|
||||
if (abs(z_sin) <= abs(z_cos)) {
|
||||
if (std::abs(z_sin) <= std::abs(z_cos)) {
|
||||
// Vertical wave
|
||||
double x0 = M_PI * (int)((- 0.5 * M_PI) / M_PI - 1.);
|
||||
bool flip = ((int)(x0 / M_PI + 1.) & 1) != 0;
|
||||
@ -74,7 +74,7 @@ static Polylines make_gyroid_waves(double gridZ, double density, double layer_wi
|
||||
} else {
|
||||
// Horizontal wave
|
||||
bool flip = true;
|
||||
for (double y0 = 0.; y0 < width; y0 += M_PI, flip = !flip)
|
||||
for (double y0 = 0.; y0 < height; y0 += M_PI, flip = !flip)
|
||||
result.emplace_back(make_wave_horizontal(width, height, y0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
}
|
||||
return result;
|
||||
@ -87,17 +87,20 @@ void FillGyroid::_fill_surface_single(
|
||||
ExPolygon &expolygon,
|
||||
Polylines &polylines_out)
|
||||
{
|
||||
// no rotation is supported for this infill pattern
|
||||
// no rotation is supported for this infill pattern (yet)
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
coord_t distance = coord_t(scale_(this->spacing) / (params.density*this->scaling));
|
||||
// Density adjusted to have a good %of weight.
|
||||
double density_adjusted = params.density * 1.75;
|
||||
// Distance between the gyroid waves in scaled coordinates.
|
||||
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
||||
|
||||
// align bounding box to a multiple of our grid module
|
||||
bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
|
||||
bb.merge(_align_to_grid(bb.min, Point(2.*M_PI*distance, 2.*M_PI*distance)));
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = make_gyroid_waves(
|
||||
scale_(this->z),
|
||||
params.density*this->scaling,
|
||||
density_adjusted,
|
||||
this->spacing,
|
||||
ceil(bb.size().x / distance) + 1.,
|
||||
ceil(bb.size().y / distance) + 1.);
|
||||
|
@ -17,10 +17,6 @@ public:
|
||||
virtual bool use_bridge_flow() const { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
// mult of density, to have a good %of weight for each density parameter
|
||||
float scaling = 1.75;
|
||||
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
|
@ -1443,10 +1443,10 @@ namespace Slic3r {
|
||||
IdToObjectDataMap m_objects_data;
|
||||
|
||||
public:
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const Print& print);
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config);
|
||||
|
||||
private:
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const Print& print);
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config);
|
||||
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
|
||||
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
|
||||
bool _add_model_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
@ -1457,13 +1457,13 @@ namespace Slic3r {
|
||||
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model);
|
||||
};
|
||||
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print)
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config)
|
||||
{
|
||||
clear_errors();
|
||||
return _save_model_to_file(filename, model, print);
|
||||
return _save_model_to_file(filename, model, print, export_print_config);
|
||||
}
|
||||
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print)
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print, bool export_print_config)
|
||||
{
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
@ -1502,11 +1502,14 @@ namespace Slic3r {
|
||||
}
|
||||
|
||||
// adds slic3r print config file
|
||||
if (!_add_print_config_file_to_archive(archive, print))
|
||||
if (export_print_config)
|
||||
{
|
||||
mz_zip_writer_end(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
if (!_add_print_config_file_to_archive(archive, print))
|
||||
{
|
||||
mz_zip_writer_end(&archive);
|
||||
boost::filesystem::remove(filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// adds slic3r model config file
|
||||
@ -1863,13 +1866,13 @@ namespace Slic3r {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool store_3mf(const char* path, Model* model, Print* print)
|
||||
bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config)
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr) || (print == nullptr))
|
||||
return false;
|
||||
|
||||
_3MF_Exporter exporter;
|
||||
bool res = exporter.save_model_to_file(path, *model, *print);
|
||||
bool res = exporter.save_model_to_file(path, *model, *print, export_print_config);
|
||||
|
||||
if (!res)
|
||||
exporter.log_errors();
|
||||
|
@ -12,7 +12,7 @@ namespace Slic3r {
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_3mf(const char* path, Model* model, Print* print);
|
||||
extern bool store_3mf(const char* path, Model* model, Print* print, bool export_print_config);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
@ -576,8 +576,7 @@ bool load_amf_archive(const char *path, PresetBundle* bundle, Model *model)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(path).filename().string(), ".zip.amf", ".amf");
|
||||
if (internal_amf_filename != stat.m_filename)
|
||||
if (!boost::iends_with(stat.m_filename, ".amf"))
|
||||
{
|
||||
printf("Found invalid internal filename\n");
|
||||
mz_zip_reader_end(&archive);
|
||||
@ -644,15 +643,20 @@ bool load_amf(const char *path, PresetBundle* bundle, Model *model)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool store_amf(const char *path, Model *model, Print* print)
|
||||
bool store_amf(const char *path, Model *model, Print* print, bool export_print_config)
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr) || (print == nullptr))
|
||||
return false;
|
||||
|
||||
// forces ".zip.amf" extension
|
||||
std::string export_path = path;
|
||||
if (!boost::iends_with(export_path, ".zip.amf"))
|
||||
export_path = boost::filesystem::path(export_path).replace_extension(".zip.amf").string();
|
||||
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
||||
mz_bool res = mz_zip_writer_init_file(&archive, path, 0);
|
||||
mz_bool res = mz_zip_writer_init_file(&archive, export_path.c_str(), 0);
|
||||
if (res == 0)
|
||||
return false;
|
||||
|
||||
@ -661,9 +665,12 @@ bool store_amf(const char *path, Model *model, Print* print)
|
||||
stream << "<amf unit=\"millimeter\">\n";
|
||||
stream << "<metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>\n";
|
||||
|
||||
std::string config = "\n";
|
||||
GCode::append_full_config(*print, config);
|
||||
stream << "<metadata type=\"" << SLIC3R_CONFIG_TYPE << "\">" << config << "</metadata>\n";
|
||||
if (export_print_config)
|
||||
{
|
||||
std::string config = "\n";
|
||||
GCode::append_full_config(*print, config);
|
||||
stream << "<metadata type=\"" << SLIC3R_CONFIG_TYPE << "\">" << config << "</metadata>\n";
|
||||
}
|
||||
|
||||
for (const auto &material : model->materials) {
|
||||
if (material.first.empty())
|
||||
@ -767,20 +774,20 @@ bool store_amf(const char *path, Model *model, Print* print)
|
||||
}
|
||||
stream << "</amf>\n";
|
||||
|
||||
std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(path).filename().string(), ".zip.amf", ".amf");
|
||||
std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(export_path).filename().string(), ".zip.amf", ".amf");
|
||||
std::string out = stream.str();
|
||||
|
||||
if (!mz_zip_writer_add_mem(&archive, internal_amf_filename.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||
{
|
||||
mz_zip_writer_end(&archive);
|
||||
boost::filesystem::remove(path);
|
||||
boost::filesystem::remove(export_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mz_zip_writer_finalize_archive(&archive))
|
||||
{
|
||||
mz_zip_writer_end(&archive);
|
||||
boost::filesystem::remove(path);
|
||||
boost::filesystem::remove(export_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ extern bool load_amf(const char *path, PresetBundle* bundle, Model *model);
|
||||
|
||||
// Save the given model and the config data contained in the given Print into an amf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_amf(const char *path, Model *model, Print* print);
|
||||
extern bool store_amf(const char *path, Model *model, Print* print, bool export_print_config);
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
@ -97,8 +97,8 @@ GCodeAnalyzer::GCodeAnalyzer()
|
||||
void GCodeAnalyzer::reset()
|
||||
{
|
||||
_set_units(Millimeters);
|
||||
_set_positioning_xyz_type(Absolute);
|
||||
_set_positioning_e_type(Relative);
|
||||
_set_global_positioning_type(Absolute);
|
||||
_set_e_local_positioning_type(Absolute);
|
||||
_set_extrusion_role(erNone);
|
||||
_set_extruder_id(DEFAULT_EXTRUDER_ID);
|
||||
_set_mm3_per_mm(Default_mm3_per_mm);
|
||||
@ -177,6 +177,16 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
|
||||
_processG1(line);
|
||||
break;
|
||||
}
|
||||
case 10: // Retract
|
||||
{
|
||||
_processG10(line);
|
||||
break;
|
||||
}
|
||||
case 11: // Unretract
|
||||
{
|
||||
_processG11(line);
|
||||
break;
|
||||
}
|
||||
case 22: // Firmware controlled Retract
|
||||
{
|
||||
_processG22(line);
|
||||
@ -237,13 +247,13 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
|
||||
}
|
||||
|
||||
// Returns the new absolute position on the given axis in dependence of the given parameters
|
||||
float axis_absolute_position_from_G1_line(GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeAnalyzer::EUnits units, GCodeAnalyzer::EPositioningType type, float current_absolute_position)
|
||||
float axis_absolute_position_from_G1_line(GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeAnalyzer::EUnits units, bool is_relative, float current_absolute_position)
|
||||
{
|
||||
float lengthsScaleFactor = (units == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
if (lineG1.has(Slic3r::Axis(axis)))
|
||||
{
|
||||
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
|
||||
return (type == GCodeAnalyzer::Absolute) ? ret : current_absolute_position + ret;
|
||||
return is_relative ? current_absolute_position + ret : ret;
|
||||
}
|
||||
else
|
||||
return current_absolute_position;
|
||||
@ -256,7 +266,11 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
|
||||
float new_pos[Num_Axis];
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? _get_positioning_e_type() : _get_positioning_xyz_type(), _get_axis_position((EAxis)a));
|
||||
bool is_relative = (_get_global_positioning_type() == Relative);
|
||||
if (a == E)
|
||||
is_relative |= (_get_e_local_positioning_type() == Relative);
|
||||
|
||||
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, is_relative, _get_axis_position((EAxis)a));
|
||||
}
|
||||
|
||||
// updates feedrate from line, if present
|
||||
@ -305,6 +319,18 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
|
||||
_store_move(type);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processG10(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// stores retract move
|
||||
_store_move(GCodeMove::Retract);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processG11(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// stores unretract move
|
||||
_store_move(GCodeMove::Unretract);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processG22(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// stores retract move
|
||||
@ -319,12 +345,12 @@ void GCodeAnalyzer::_processG23(const GCodeReader::GCodeLine& line)
|
||||
|
||||
void GCodeAnalyzer::_processG90(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
_set_positioning_xyz_type(Absolute);
|
||||
_set_global_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processG91(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
_set_positioning_xyz_type(Relative);
|
||||
_set_global_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
|
||||
@ -367,12 +393,12 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
|
||||
|
||||
void GCodeAnalyzer::_processM82(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
_set_positioning_e_type(Absolute);
|
||||
_set_e_local_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processM83(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
_set_positioning_e_type(Relative);
|
||||
_set_e_local_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_processT(const GCodeReader::GCodeLine& line)
|
||||
@ -466,24 +492,24 @@ GCodeAnalyzer::EUnits GCodeAnalyzer::_get_units() const
|
||||
return m_state.units;
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_set_positioning_xyz_type(GCodeAnalyzer::EPositioningType type)
|
||||
void GCodeAnalyzer::_set_global_positioning_type(GCodeAnalyzer::EPositioningType type)
|
||||
{
|
||||
m_state.positioning_xyz_type = type;
|
||||
m_state.global_positioning_type = type;
|
||||
}
|
||||
|
||||
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_xyz_type() const
|
||||
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_global_positioning_type() const
|
||||
{
|
||||
return m_state.positioning_xyz_type;
|
||||
return m_state.global_positioning_type;
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_set_positioning_e_type(GCodeAnalyzer::EPositioningType type)
|
||||
void GCodeAnalyzer::_set_e_local_positioning_type(GCodeAnalyzer::EPositioningType type)
|
||||
{
|
||||
m_state.positioning_e_type = type;
|
||||
m_state.e_local_positioning_type = type;
|
||||
}
|
||||
|
||||
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_positioning_e_type() const
|
||||
GCodeAnalyzer::EPositioningType GCodeAnalyzer::_get_e_local_positioning_type() const
|
||||
{
|
||||
return m_state.positioning_e_type;
|
||||
return m_state.e_local_positioning_type;
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_set_extrusion_role(ExtrusionRole extrusion_role)
|
||||
@ -648,14 +674,16 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
float z = FLT_MAX;
|
||||
Polyline polyline;
|
||||
Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
float volumetric_rate = FLT_MAX;
|
||||
GCodePreviewData::Range height_range;
|
||||
GCodePreviewData::Range width_range;
|
||||
GCodePreviewData::Range feedrate_range;
|
||||
GCodePreviewData::Range volumetric_rate_range;
|
||||
|
||||
// constructs the polylines while traversing the moves
|
||||
for (const GCodeMove& move : extrude_moves->second)
|
||||
{
|
||||
if ((data != move.data) || (data.feedrate != move.data.feedrate) || (z != move.start_position.z) || (position != move.start_position))
|
||||
if ((data != move.data) || (z != move.start_position.z) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
|
||||
{
|
||||
// store current polyline
|
||||
polyline.remove_duplicate_points();
|
||||
@ -671,9 +699,11 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
// update current values
|
||||
data = move.data;
|
||||
z = move.start_position.z;
|
||||
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
|
||||
height_range.update_from(move.data.height);
|
||||
width_range.update_from(move.data.width);
|
||||
feedrate_range.update_from(move.data.feedrate);
|
||||
volumetric_rate_range.update_from(volumetric_rate);
|
||||
}
|
||||
else
|
||||
// append end vertex of the move to current polyline
|
||||
@ -688,9 +718,10 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
Helper::store_polyline(polyline, data, z, preview_data);
|
||||
|
||||
// updates preview ranges data
|
||||
preview_data.extrusion.ranges.height.set_from(height_range);
|
||||
preview_data.extrusion.ranges.width.set_from(width_range);
|
||||
preview_data.extrusion.ranges.feedrate.set_from(feedrate_range);
|
||||
preview_data.ranges.height.set_from(height_range);
|
||||
preview_data.ranges.width.set_from(width_range);
|
||||
preview_data.ranges.feedrate.set_from(feedrate_range);
|
||||
preview_data.ranges.volumetric_rate.set_from(volumetric_rate_range);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||
@ -717,6 +748,10 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||
float feedrate = FLT_MAX;
|
||||
unsigned int extruder_id = -1;
|
||||
|
||||
GCodePreviewData::Range height_range;
|
||||
GCodePreviewData::Range width_range;
|
||||
GCodePreviewData::Range feedrate_range;
|
||||
|
||||
// constructs the polylines while traversing the moves
|
||||
for (const GCodeMove& move : travel_moves->second)
|
||||
{
|
||||
@ -745,11 +780,19 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||
type = move_type;
|
||||
feedrate = move.data.feedrate;
|
||||
extruder_id = move.data.extruder_id;
|
||||
height_range.update_from(move.data.height);
|
||||
width_range.update_from(move.data.width);
|
||||
feedrate_range.update_from(move.data.feedrate);
|
||||
}
|
||||
|
||||
// store last polyline
|
||||
polyline.remove_duplicate_points();
|
||||
Helper::store_polyline(polyline, type, direction, feedrate, extruder_id, preview_data);
|
||||
|
||||
// updates preview ranges data
|
||||
preview_data.ranges.height.set_from(height_range);
|
||||
preview_data.ranges.width.set_from(width_range);
|
||||
preview_data.ranges.feedrate.set_from(feedrate_range);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data)
|
||||
|
@ -90,8 +90,8 @@ private:
|
||||
struct State
|
||||
{
|
||||
EUnits units;
|
||||
EPositioningType positioning_xyz_type;
|
||||
EPositioningType positioning_e_type;
|
||||
EPositioningType global_positioning_type;
|
||||
EPositioningType e_local_positioning_type;
|
||||
Metadata data;
|
||||
Pointf3 start_position;
|
||||
float start_extrusion;
|
||||
@ -127,6 +127,12 @@ private:
|
||||
// Move
|
||||
void _processG1(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Retract
|
||||
void _processG10(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Unretract
|
||||
void _processG11(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Firmware controlled Retract
|
||||
void _processG22(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@ -170,11 +176,11 @@ private:
|
||||
void _set_units(EUnits units);
|
||||
EUnits _get_units() const;
|
||||
|
||||
void _set_positioning_xyz_type(EPositioningType type);
|
||||
EPositioningType _get_positioning_xyz_type() const;
|
||||
void _set_global_positioning_type(EPositioningType type);
|
||||
EPositioningType _get_global_positioning_type() const;
|
||||
|
||||
void _set_positioning_e_type(EPositioningType type);
|
||||
EPositioningType _get_positioning_e_type() const;
|
||||
void _set_e_local_positioning_type(EPositioningType type);
|
||||
EPositioningType _get_e_local_positioning_type() const;
|
||||
|
||||
void _set_extrusion_role(ExtrusionRole extrusion_role);
|
||||
ExtrusionRole _get_extrusion_role() const;
|
||||
|
@ -85,6 +85,12 @@ void GCodePreviewData::Range::update_from(float value)
|
||||
max = std::max(max, value);
|
||||
}
|
||||
|
||||
void GCodePreviewData::Range::update_from(const Range& other)
|
||||
{
|
||||
min = std::min(min, other.min);
|
||||
max = std::max(max, other.max);
|
||||
}
|
||||
|
||||
void GCodePreviewData::Range::set_from(const Range& other)
|
||||
{
|
||||
min = other.min;
|
||||
@ -158,9 +164,6 @@ void GCodePreviewData::Extrusion::set_default()
|
||||
view_type = Default_View_Type;
|
||||
|
||||
::memcpy((void*)role_colors, (const void*)Default_Extrusion_Role_Colors, Num_Extrusion_Roles * sizeof(Color));
|
||||
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
|
||||
for (unsigned int i = 0; i < Num_Extrusion_Roles; ++i)
|
||||
{
|
||||
@ -198,6 +201,7 @@ void GCodePreviewData::Travel::set_default()
|
||||
width = Default_Width;
|
||||
height = Default_Height;
|
||||
::memcpy((void*)type_colors, (const void*)Default_Type_Colors, Num_Types * sizeof(Color));
|
||||
|
||||
is_visible = false;
|
||||
}
|
||||
|
||||
@ -228,6 +232,11 @@ GCodePreviewData::GCodePreviewData()
|
||||
|
||||
void GCodePreviewData::set_default()
|
||||
{
|
||||
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.volumetric_rate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
|
||||
extrusion.set_default();
|
||||
travel.set_default();
|
||||
retraction.set_default();
|
||||
@ -237,6 +246,10 @@ void GCodePreviewData::set_default()
|
||||
|
||||
void GCodePreviewData::reset()
|
||||
{
|
||||
ranges.width.reset();
|
||||
ranges.height.reset();
|
||||
ranges.feedrate.reset();
|
||||
ranges.volumetric_rate.reset();
|
||||
extrusion.layers.clear();
|
||||
travel.polylines.clear();
|
||||
retraction.positions.clear();
|
||||
@ -253,19 +266,24 @@ const GCodePreviewData::Color& GCodePreviewData::get_extrusion_role_color(Extrus
|
||||
return extrusion.role_colors[role];
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_height_color(float height) const
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_height_color(float height) const
|
||||
{
|
||||
return extrusion.ranges.height.get_color_at(height);
|
||||
return ranges.height.get_color_at(height);
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_width_color(float width) const
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_width_color(float width) const
|
||||
{
|
||||
return extrusion.ranges.width.get_color_at(width);
|
||||
return ranges.width.get_color_at(width);
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_extrusion_feedrate_color(float feedrate) const
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_feedrate_color(float feedrate) const
|
||||
{
|
||||
return extrusion.ranges.feedrate.get_color_at(feedrate);
|
||||
return ranges.feedrate.get_color_at(feedrate);
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color& GCodePreviewData::get_volumetric_rate_color(float rate) const
|
||||
{
|
||||
return ranges.volumetric_rate.get_color_at(rate);
|
||||
}
|
||||
|
||||
void GCodePreviewData::set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha)
|
||||
@ -334,6 +352,8 @@ std::string GCodePreviewData::get_legend_title() const
|
||||
return L("Width (mm)");
|
||||
case Extrusion::Feedrate:
|
||||
return L("Speed (mm/s)");
|
||||
case Extrusion::VolumetricRate:
|
||||
return L("Volumetric flow rate (mm3/s)");
|
||||
case Extrusion::Tool:
|
||||
return L("Tool");
|
||||
}
|
||||
@ -348,10 +368,11 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
|
||||
{
|
||||
list.reserve(Range::Colors_Count);
|
||||
|
||||
float step = range.step_size();
|
||||
for (unsigned int i = 0; i < Range::Colors_Count; ++i)
|
||||
{
|
||||
char buf[32];
|
||||
char buf[1024];
|
||||
sprintf(buf, "%.*f/%.*f", decimals, scale_factor * (range.min + (float)i * step), decimals, scale_factor * (range.min + (float)(i + 1) * step));
|
||||
list.emplace_back(buf, range.colors[i]);
|
||||
}
|
||||
@ -377,17 +398,22 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
}
|
||||
case Extrusion::Height:
|
||||
{
|
||||
Helper::FillListFromRange(items, extrusion.ranges.height, 3, 1.0f);
|
||||
Helper::FillListFromRange(items, ranges.height, 3, 1.0f);
|
||||
break;
|
||||
}
|
||||
case Extrusion::Width:
|
||||
{
|
||||
Helper::FillListFromRange(items, extrusion.ranges.width, 3, 1.0f);
|
||||
Helper::FillListFromRange(items, ranges.width, 3, 1.0f);
|
||||
break;
|
||||
}
|
||||
case Extrusion::Feedrate:
|
||||
{
|
||||
Helper::FillListFromRange(items, extrusion.ranges.feedrate, 0, 1.0f);
|
||||
Helper::FillListFromRange(items, ranges.feedrate, 0, 1.0f);
|
||||
break;
|
||||
}
|
||||
case Extrusion::VolumetricRate:
|
||||
{
|
||||
Helper::FillListFromRange(items, ranges.volumetric_rate, 3, 1.0f);
|
||||
break;
|
||||
}
|
||||
case Extrusion::Tool:
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
void reset();
|
||||
bool empty() const;
|
||||
void update_from(float value);
|
||||
void update_from(const Range& other);
|
||||
void set_from(const Range& other);
|
||||
float step_size() const;
|
||||
|
||||
@ -44,6 +45,14 @@ public:
|
||||
const Color& get_color_at_max() const;
|
||||
};
|
||||
|
||||
struct Ranges
|
||||
{
|
||||
Range height;
|
||||
Range width;
|
||||
Range feedrate;
|
||||
Range volumetric_rate;
|
||||
};
|
||||
|
||||
struct LegendItem
|
||||
{
|
||||
std::string text;
|
||||
@ -62,6 +71,7 @@ public:
|
||||
Height,
|
||||
Width,
|
||||
Feedrate,
|
||||
VolumetricRate,
|
||||
Tool,
|
||||
Num_View_Types
|
||||
};
|
||||
@ -71,13 +81,6 @@ public:
|
||||
static const std::string Default_Extrusion_Role_Names[Num_Extrusion_Roles];
|
||||
static const EViewType Default_View_Type;
|
||||
|
||||
struct Ranges
|
||||
{
|
||||
Range height;
|
||||
Range width;
|
||||
Range feedrate;
|
||||
};
|
||||
|
||||
struct Layer
|
||||
{
|
||||
float z;
|
||||
@ -91,7 +94,6 @@ public:
|
||||
EViewType view_type;
|
||||
Color role_colors[Num_Extrusion_Roles];
|
||||
std::string role_names[Num_Extrusion_Roles];
|
||||
Ranges ranges;
|
||||
LayersList layers;
|
||||
unsigned int role_flags;
|
||||
|
||||
@ -178,6 +180,7 @@ public:
|
||||
Retraction retraction;
|
||||
Retraction unretraction;
|
||||
Shell shell;
|
||||
Ranges ranges;
|
||||
|
||||
GCodePreviewData();
|
||||
|
||||
@ -186,9 +189,10 @@ public:
|
||||
bool empty() const;
|
||||
|
||||
const Color& get_extrusion_role_color(ExtrusionRole role) const;
|
||||
const Color& get_extrusion_height_color(float height) const;
|
||||
const Color& get_extrusion_width_color(float width) const;
|
||||
const Color& get_extrusion_feedrate_color(float feedrate) const;
|
||||
const Color& get_height_color(float height) const;
|
||||
const Color& get_width_color(float width) const;
|
||||
const Color& get_feedrate_color(float feedrate) const;
|
||||
const Color& get_volumetric_rate_color(float rate) const;
|
||||
|
||||
void set_extrusion_role_color(const std::string& role_name, float red, float green, float blue, float alpha);
|
||||
void set_extrusion_paths_colors(const std::vector<std::string>& colors);
|
||||
|
@ -369,24 +369,24 @@ namespace Slic3r {
|
||||
return _state.units;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_positioning_xyz_type(GCodeTimeEstimator::EPositioningType type)
|
||||
void GCodeTimeEstimator::set_global_positioning_type(GCodeTimeEstimator::EPositioningType type)
|
||||
{
|
||||
_state.positioning_xyz_type = type;
|
||||
_state.global_positioning_type = type;
|
||||
}
|
||||
|
||||
GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_xyz_type() const
|
||||
GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_global_positioning_type() const
|
||||
{
|
||||
return _state.positioning_xyz_type;
|
||||
return _state.global_positioning_type;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_positioning_e_type(GCodeTimeEstimator::EPositioningType type)
|
||||
void GCodeTimeEstimator::set_e_local_positioning_type(GCodeTimeEstimator::EPositioningType type)
|
||||
{
|
||||
_state.positioning_e_type = type;
|
||||
_state.e_local_positioning_type = type;
|
||||
}
|
||||
|
||||
GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_e_type() const
|
||||
GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_e_local_positioning_type() const
|
||||
{
|
||||
return _state.positioning_e_type;
|
||||
return _state.e_local_positioning_type;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
@ -408,8 +408,8 @@ namespace Slic3r {
|
||||
{
|
||||
set_units(Millimeters);
|
||||
set_dialect(gcfRepRap);
|
||||
set_positioning_xyz_type(Absolute);
|
||||
set_positioning_e_type(Relative);
|
||||
set_global_positioning_type(Absolute);
|
||||
set_e_local_positioning_type(Absolute);
|
||||
|
||||
set_feedrate(DEFAULT_FEEDRATE);
|
||||
set_acceleration(DEFAULT_ACCELERATION);
|
||||
@ -628,13 +628,13 @@ namespace Slic3r {
|
||||
}
|
||||
|
||||
// Returns the new absolute position on the given axis in dependence of the given parameters
|
||||
float axis_absolute_position_from_G1_line(GCodeTimeEstimator::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeTimeEstimator::EUnits units, GCodeTimeEstimator::EPositioningType type, float current_absolute_position)
|
||||
float axis_absolute_position_from_G1_line(GCodeTimeEstimator::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeTimeEstimator::EUnits units, bool is_relative, float current_absolute_position)
|
||||
{
|
||||
float lengthsScaleFactor = (units == GCodeTimeEstimator::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
if (lineG1.has(Slic3r::Axis(axis)))
|
||||
{
|
||||
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
|
||||
return (type == GCodeTimeEstimator::Absolute) ? ret : current_absolute_position + ret;
|
||||
return is_relative ? current_absolute_position + ret : ret;
|
||||
}
|
||||
else
|
||||
return current_absolute_position;
|
||||
@ -647,7 +647,11 @@ namespace Slic3r {
|
||||
float new_pos[Num_Axis];
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? get_positioning_e_type() : get_positioning_xyz_type(), get_axis_position((EAxis)a));
|
||||
bool is_relative = (get_global_positioning_type() == Relative);
|
||||
if (a == E)
|
||||
is_relative |= (get_e_local_positioning_type() == Relative);
|
||||
|
||||
new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, is_relative, get_axis_position((EAxis)a));
|
||||
}
|
||||
|
||||
// updates feedrate from line, if present
|
||||
@ -865,14 +869,12 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
set_positioning_xyz_type(Absolute);
|
||||
set_global_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// TODO: THERE ARE DIALECT VARIANTS
|
||||
|
||||
set_positioning_xyz_type(Relative);
|
||||
set_global_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line)
|
||||
@ -922,12 +924,12 @@ namespace Slic3r {
|
||||
|
||||
void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
set_positioning_e_type(Absolute);
|
||||
set_e_local_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM83(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
set_positioning_e_type(Relative);
|
||||
set_e_local_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line)
|
||||
|
@ -61,8 +61,8 @@ namespace Slic3r {
|
||||
{
|
||||
GCodeFlavor dialect;
|
||||
EUnits units;
|
||||
EPositioningType positioning_xyz_type;
|
||||
EPositioningType positioning_e_type;
|
||||
EPositioningType global_positioning_type;
|
||||
EPositioningType e_local_positioning_type;
|
||||
Axis axis[Num_Axis];
|
||||
float feedrate; // mm/s
|
||||
float acceleration; // mm/s^2
|
||||
@ -257,11 +257,11 @@ namespace Slic3r {
|
||||
void set_units(EUnits units);
|
||||
EUnits get_units() const;
|
||||
|
||||
void set_positioning_xyz_type(EPositioningType type);
|
||||
EPositioningType get_positioning_xyz_type() const;
|
||||
void set_global_positioning_type(EPositioningType type);
|
||||
EPositioningType get_global_positioning_type() const;
|
||||
|
||||
void set_positioning_e_type(EPositioningType type);
|
||||
EPositioningType get_positioning_e_type() const;
|
||||
void set_e_local_positioning_type(EPositioningType type);
|
||||
EPositioningType get_e_local_positioning_type() const;
|
||||
|
||||
void add_additional_time(float timeSec);
|
||||
void set_additional_time(float timeSec);
|
||||
|
@ -450,6 +450,8 @@ bool Model::fits_print_volume(const DynamicPrintConfig* config) const
|
||||
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
||||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height")));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min.z = -1e10;
|
||||
return print_volume.contains(transformed_bounding_box());
|
||||
}
|
||||
|
||||
@ -459,6 +461,8 @@ bool Model::fits_print_volume(const FullPrintConfig &config) const
|
||||
return true;
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values));
|
||||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min.z = -1e10;
|
||||
return print_volume.contains(transformed_bounding_box());
|
||||
}
|
||||
|
||||
|
@ -60,9 +60,6 @@ extern std::string timestamp_str();
|
||||
// to be placed at the top of Slic3r generated files.
|
||||
inline std::string header_slic3r_generated() { return std::string("generated by " SLIC3R_FORK_NAME " " SLIC3R_VERSION " " ) + timestamp_str(); }
|
||||
|
||||
// Encode a file into a multi-part HTTP response with a given boundary.
|
||||
std::string octoprint_encode_file_send_request_content(const char *path, bool select, bool print, const char *boundary);
|
||||
|
||||
// Compute the next highest power of 2 of 32-bit v
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html
|
||||
template<typename T>
|
||||
|
@ -263,7 +263,6 @@ namespace PerlUtils {
|
||||
std::string timestamp_str()
|
||||
{
|
||||
const auto now = boost::posix_time::second_clock::local_time();
|
||||
const auto date = now.date();
|
||||
char buf[2048];
|
||||
sprintf(buf, "on %04d-%02d-%02d at %02d:%02d:%02d",
|
||||
// Local date in an ANSII format.
|
||||
@ -272,31 +271,4 @@ std::string timestamp_str()
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string octoprint_encode_file_send_request_content(const char *cpath, bool select, bool print, const char *boundary)
|
||||
{
|
||||
// Read the complete G-code string into a string buffer.
|
||||
// It will throw if the file cannot be open or read.
|
||||
std::stringstream str_stream;
|
||||
{
|
||||
boost::nowide::ifstream ifs(cpath);
|
||||
str_stream << ifs.rdbuf();
|
||||
}
|
||||
|
||||
boost::filesystem::path path(cpath);
|
||||
std::string request = boundary + '\n';
|
||||
request += "Content-Disposition: form-data; name=\"";
|
||||
request += path.stem().string() + "\"; filename=\"" + path.filename().string() + "\"\n";
|
||||
request += "Content-Type: application/octet-stream\n\n";
|
||||
request += str_stream.str();
|
||||
request += boundary + '\n';
|
||||
request += "Content-Disposition: form-data; name=\"select\"\n\n";
|
||||
request += select ? "true\n" : "false\n";
|
||||
request += boundary + '\n';
|
||||
request += "Content-Disposition: form-data; name=\"print\"\n\n";
|
||||
request += print ? "true\n" : "false\n";
|
||||
request += boundary + '\n';
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
617
xs/src/semver/semver.c
Normal file
617
xs/src/semver/semver.c
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* semver.c
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "semver.h"
|
||||
|
||||
#define SLICE_SIZE 50
|
||||
#define DELIMITER "."
|
||||
#define PR_DELIMITER "-"
|
||||
#define MT_DELIMITER "+"
|
||||
#define NUMBERS "0123456789"
|
||||
#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define DELIMITERS DELIMITER PR_DELIMITER MT_DELIMITER
|
||||
#define VALID_CHARS NUMBERS ALPHA DELIMITERS
|
||||
|
||||
static const size_t MAX_SIZE = sizeof(char) * 255;
|
||||
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
|
||||
|
||||
/**
|
||||
* Define comparison operators, storing the
|
||||
* ASCII code per each symbol in hexadecimal notation.
|
||||
*/
|
||||
|
||||
enum operators {
|
||||
SYMBOL_GT = 0x3e,
|
||||
SYMBOL_LT = 0x3c,
|
||||
SYMBOL_EQ = 0x3d,
|
||||
SYMBOL_TF = 0x7e,
|
||||
SYMBOL_CF = 0x5e
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Remove [begin:len-begin] from str by moving len data from begin+len to begin.
|
||||
* If len is negative cut out to the end of the string.
|
||||
*/
|
||||
static int
|
||||
strcut (char *str, int begin, int len) {
|
||||
size_t l;
|
||||
l = strlen(str);
|
||||
|
||||
if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
|
||||
|
||||
if (len < 0) len = l - begin + 1;
|
||||
if (begin + len > (int)l) len = l - begin;
|
||||
memmove(str + begin, str + begin + len, l - len + 1 - begin);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
contains (const char c, const char *matrix, size_t len) {
|
||||
size_t x;
|
||||
for (x = 0; x < len; x++)
|
||||
if ((char) matrix[x] == c) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
has_valid_chars (const char *str, const char *matrix) {
|
||||
size_t i, len, mlen;
|
||||
len = strlen(str);
|
||||
mlen = strlen(matrix);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], matrix, mlen) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
binary_comparison (int x, int y) {
|
||||
if (x == y) return 0;
|
||||
if (x > y) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_int (const char *s) {
|
||||
int valid, num;
|
||||
valid = has_valid_chars(s, NUMBERS);
|
||||
if (valid == 0) return -1;
|
||||
|
||||
num = strtol(s, NULL, 10);
|
||||
if (num > MAX_SAFE_INT) return -1;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string allocated on the heap with the content from sep to end and
|
||||
* terminate buf at sep.
|
||||
*/
|
||||
static char *
|
||||
parse_slice (char *buf, char sep) {
|
||||
char *pr, *part;
|
||||
int plen;
|
||||
|
||||
/* Find separator in buf */
|
||||
pr = strchr(buf, sep);
|
||||
if (pr == NULL) return NULL;
|
||||
/* Length from separator to end of buf */
|
||||
plen = strlen(pr);
|
||||
|
||||
/* Copy from buf into new string */
|
||||
part = calloc(plen + 1, sizeof(*part));
|
||||
if (part == NULL) return NULL;
|
||||
memcpy(part, pr + 1, plen);
|
||||
/* Null terminate new string */
|
||||
part[plen] = '\0';
|
||||
|
||||
/* Terminate buf where separator was */
|
||||
*pr = '\0';
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - In case of error
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse (const char *str, semver_t *ver) {
|
||||
int valid, res;
|
||||
size_t len;
|
||||
char *buf;
|
||||
valid = semver_is_valid(str);
|
||||
if (!valid) return -1;
|
||||
|
||||
len = strlen(str);
|
||||
buf = calloc(len + 1, sizeof(*buf));
|
||||
if (buf == NULL) return -1;
|
||||
strcpy(buf, str);
|
||||
|
||||
ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
|
||||
ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
|
||||
|
||||
res = semver_parse_version(buf, ver);
|
||||
free(buf);
|
||||
#if DEBUG > 0
|
||||
printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - Parse error or invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver) {
|
||||
size_t len;
|
||||
int index, value;
|
||||
char *slice, *next, *endptr;
|
||||
slice = (char *) str;
|
||||
index = 0;
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
switch (index) {
|
||||
case 1: ver->major = value; break;
|
||||
case 2: ver->minor = value; break;
|
||||
case 3: ver->patch = value; break;
|
||||
}
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_prerelease (char *x, char *y) {
|
||||
char *lastx, *lasty, *xptr, *yptr, *endptr;
|
||||
int xlen, ylen, xisnum, yisnum, xnum, ynum;
|
||||
int xn, yn, min, res;
|
||||
if (x == NULL && y == NULL) return 0;
|
||||
if (y == NULL && x) return -1;
|
||||
if (x == NULL && y) return 1;
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
xlen = strlen(x);
|
||||
ylen = strlen(y);
|
||||
|
||||
while (1) {
|
||||
if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
|
||||
xptr = x + xlen;
|
||||
if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
|
||||
yptr = y + ylen;
|
||||
|
||||
xnum = strtol(lastx, &endptr, 10);
|
||||
xisnum = endptr == xptr ? 1 : 0;
|
||||
ynum = strtol(lasty, &endptr, 10);
|
||||
yisnum = endptr == yptr ? 1 : 0;
|
||||
|
||||
if (xisnum && !yisnum) return -1;
|
||||
if (!xisnum && yisnum) return 1;
|
||||
|
||||
if (xisnum && yisnum) {
|
||||
/* Numerical comparison */
|
||||
if (xnum != ynum) return xnum < ynum ? -1 : 1;
|
||||
} else {
|
||||
/* String comparison */
|
||||
xn = xptr - lastx;
|
||||
yn = yptr - lasty;
|
||||
min = xn < yn ? xn : yn;
|
||||
if ((res = strncmp(lastx, lasty, min))) return res < 0 ? -1 : 1;
|
||||
if (xn != yn) return xn < yn ? -1 : 1;
|
||||
}
|
||||
|
||||
lastx = xptr + 1;
|
||||
lasty = yptr + 1;
|
||||
if (lastx == x + xlen + 1 && lasty == y + ylen + 1) break;
|
||||
if (lastx == x + xlen + 1) return -1;
|
||||
if (lasty == y + ylen + 1) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
semver_compare_prerelease (semver_t x, semver_t y) {
|
||||
return compare_prerelease(x.prerelease, y.prerelease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a major, minor and patch binary comparison (x, y).
|
||||
* This function is mostly used internally
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - If versiona are equal
|
||||
* `1` - If x is higher than y
|
||||
* `-1` - If x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = binary_comparison(x.major, y.major)) == 0) {
|
||||
if ((res = binary_comparison(x.minor, y.minor)) == 0) {
|
||||
return binary_comparison(x.patch, y.patch);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two semantic versions (x, y).
|
||||
*
|
||||
* Returns:
|
||||
* - `1` if x is higher than y
|
||||
* - `0` if x is equal to y
|
||||
* - `-1` if x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = semver_compare_version(x, y)) == 0) {
|
||||
return semver_compare_prerelease(x, y);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `equality` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_eq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `non equal to` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_neq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with caret operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y) {
|
||||
if (x.major == y.major) {
|
||||
if (x.major == 0) {
|
||||
return x.minor >= y.minor;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with tilde operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y) {
|
||||
return x.major == y.major
|
||||
&& x.minor == y.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both versions can be satisfied
|
||||
* based on the given comparison operator.
|
||||
*
|
||||
* Allowed operators:
|
||||
*
|
||||
* - `=` - Equality
|
||||
* - `>=` - Higher or equal to
|
||||
* - `<=` - Lower or equal to
|
||||
* - `<` - Lower than
|
||||
* - `>` - Higher than
|
||||
* - `^` - Caret comparison (see https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4)
|
||||
* - `~` - Tilde comparison (see https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1)
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies (semver_t x, semver_t y, const char *op) {
|
||||
int first, second;
|
||||
/* Extract the comparison operator */
|
||||
first = op[0];
|
||||
second = op[1];
|
||||
|
||||
/* Caret operator */
|
||||
if (first == SYMBOL_CF)
|
||||
return semver_satisfies_caret(x, y);
|
||||
|
||||
/* Tilde operator */
|
||||
if (first == SYMBOL_TF)
|
||||
return semver_satisfies_patch(x, y);
|
||||
|
||||
/* Strict equality */
|
||||
if (first == SYMBOL_EQ)
|
||||
return semver_eq(x, y);
|
||||
|
||||
/* Greater than or equal comparison */
|
||||
if (first == SYMBOL_GT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_gte(x, y);
|
||||
}
|
||||
return semver_gt(x, y);
|
||||
}
|
||||
|
||||
/* Lower than or equal comparison */
|
||||
if (first == SYMBOL_LT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_lte(x, y);
|
||||
}
|
||||
return semver_lt(x, y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free heep allocated memory of a given semver.
|
||||
* This is just a convenient function that you
|
||||
* should call when you're done.
|
||||
*/
|
||||
|
||||
void
|
||||
semver_free (semver_t *x) {
|
||||
if (x->metadata) {
|
||||
free(x->metadata);
|
||||
x->metadata = NULL;
|
||||
}
|
||||
if (x->prerelease) {
|
||||
free(x->prerelease);
|
||||
x->prerelease = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders
|
||||
*/
|
||||
|
||||
static void
|
||||
concat_num (char * str, int x, char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
if (sep == NULL) sprintf(buf, "%d", x);
|
||||
else sprintf(buf, "%s%d", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
concat_char (char * str, char * x, char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
sprintf(buf, "%s%s", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as string
|
||||
*/
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest) {
|
||||
if (x->major) concat_num(dest, x->major, NULL);
|
||||
if (x->minor) concat_num(dest, x->minor, DELIMITER);
|
||||
if (x->patch) concat_num(dest, x->patch, DELIMITER);
|
||||
if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
|
||||
if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version bump helpers
|
||||
*/
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x) {
|
||||
x->major++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x) {
|
||||
x->minor++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x) {
|
||||
x->patch++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
static int
|
||||
has_valid_length (const char *s) {
|
||||
return strlen(s) <= MAX_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given semver string is valid
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Valid expression
|
||||
* `0` - Invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_is_valid (const char *s) {
|
||||
return has_valid_length(s)
|
||||
&& has_valid_chars(s, VALID_CHARS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes non-valid characters in the given string.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Valid
|
||||
* `-1` - Invalid input
|
||||
*/
|
||||
|
||||
int
|
||||
semver_clean (char *s) {
|
||||
size_t i, len, mlen;
|
||||
int res;
|
||||
if (has_valid_length(s) == 0) return -1;
|
||||
|
||||
len = strlen(s);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (contains(s[i], VALID_CHARS, mlen) == 0) {
|
||||
res = strcut(s, i, 1);
|
||||
if(res == -1) return -1;
|
||||
--len; --i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
char_to_int (const char * str) {
|
||||
int buf;
|
||||
size_t i,len, mlen;
|
||||
buf = 0;
|
||||
len = strlen(str);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], VALID_CHARS, mlen))
|
||||
buf += (int) str[i];
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as numeric value.
|
||||
* Useful for ordering and filtering.
|
||||
*/
|
||||
|
||||
int
|
||||
semver_numeric (semver_t *x) {
|
||||
int num;
|
||||
char buf[SLICE_SIZE * 3];
|
||||
memset(&buf, 0, SLICE_SIZE * 3);
|
||||
|
||||
if (x->major) concat_num(buf, x->major, NULL);
|
||||
if (x->minor) concat_num(buf, x->minor, NULL);
|
||||
if (x->patch) concat_num(buf, x->patch, NULL);
|
||||
|
||||
num = parse_int(buf);
|
||||
if(num == -1) return -1;
|
||||
|
||||
if (x->prerelease) num += char_to_int(x->prerelease);
|
||||
if (x->metadata) num += char_to_int(x->metadata);
|
||||
|
||||
return num;
|
||||
}
|
105
xs/src/semver/semver.h
Normal file
105
xs/src/semver/semver.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* semver.h
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#ifndef __SEMVER_H
|
||||
#define __SEMVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SEMVER_VERSION
|
||||
#define SEMVER_VERSION "0.2.0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* semver_t struct
|
||||
*/
|
||||
|
||||
typedef struct semver_version_s {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
char * metadata;
|
||||
char * prerelease;
|
||||
} semver_t;
|
||||
|
||||
/**
|
||||
* Set prototypes
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies (semver_t x, semver_t y, const char *op);
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare_prerelease (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_gt (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_gte (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_lt (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_lte (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_eq (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_neq (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_parse (const char *str, semver_t *ver);
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver);
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest);
|
||||
|
||||
int
|
||||
semver_numeric (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x);
|
||||
|
||||
void
|
||||
semver_free (semver_t *x);
|
||||
|
||||
int
|
||||
semver_is_valid (const char *s);
|
||||
|
||||
int
|
||||
semver_clean (char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
308
xs/src/slic3r/Config/Snapshot.cpp
Normal file
308
xs/src/slic3r/Config/Snapshot.cpp
Normal file
@ -0,0 +1,308 @@
|
||||
#include "Snapshot.hpp"
|
||||
#include "../GUI/AppConfig.hpp"
|
||||
#include "../Utils/Time.hpp"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include "../../libslic3r/libslic3r.h"
|
||||
#include "../../libslic3r/Config.hpp"
|
||||
#include "../../libslic3r/FileParserError.hpp"
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
|
||||
#define SLIC3R_SNAPSHOTS_DIR "snapshots"
|
||||
#define SLIC3R_SNAPSHOT_FILE "snapshot.ini"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
namespace Config {
|
||||
|
||||
void Snapshot::clear()
|
||||
{
|
||||
this->id.clear();
|
||||
this->time_captured = 0;
|
||||
this->slic3r_version_captured = Semver::invalid();
|
||||
this->comment.clear();
|
||||
this->reason = SNAPSHOT_UNKNOWN;
|
||||
this->print.clear();
|
||||
this->filaments.clear();
|
||||
this->printer.clear();
|
||||
}
|
||||
|
||||
void Snapshot::load_ini(const std::string &path)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
auto throw_on_parse_error = [&path](const std::string &msg) {
|
||||
throw file_parser_error(std::string("Failed loading the snapshot file. Reason: ") + msg, path);
|
||||
};
|
||||
|
||||
// Load the snapshot.ini file.
|
||||
boost::property_tree::ptree tree;
|
||||
try {
|
||||
boost::nowide::ifstream ifs(path);
|
||||
boost::property_tree::read_ini(ifs, tree);
|
||||
} catch (const std::ifstream::failure &err) {
|
||||
throw file_parser_error(std::string("The snapshot file cannot be loaded. Reason: ") + err.what(), path);
|
||||
} catch (const std::runtime_error &err) {
|
||||
throw_on_parse_error(err.what());
|
||||
}
|
||||
|
||||
// Parse snapshot.ini
|
||||
std::string group_name_vendor = "Vendor:";
|
||||
std::string key_filament = "filament";
|
||||
for (auto §ion : tree) {
|
||||
if (section.first == "snapshot") {
|
||||
// Parse the common section.
|
||||
for (auto &kvp : section.second) {
|
||||
if (kvp.first == "id")
|
||||
this->id = kvp.second.data();
|
||||
else if (kvp.first == "time_captured") {
|
||||
this->time_captured = Slic3r::Utils::parse_time_ISO8601Z(kvp.second.data());
|
||||
if (this->time_captured == (time_t)-1)
|
||||
throw_on_parse_error("invalid timestamp");
|
||||
} else if (kvp.first == "slic3r_version_captured") {
|
||||
auto semver = Semver::parse(kvp.second.data());
|
||||
if (! semver)
|
||||
throw_on_parse_error("invalid slic3r_version_captured semver");
|
||||
this->slic3r_version_captured = *semver;
|
||||
} else if (kvp.first == "comment") {
|
||||
this->comment = kvp.second.data();
|
||||
} else if (kvp.first == "reason") {
|
||||
std::string rsn = kvp.second.data();
|
||||
if (rsn == "upgrade")
|
||||
this->reason = SNAPSHOT_UPGRADE;
|
||||
else if (rsn == "downgrade")
|
||||
this->reason = SNAPSHOT_DOWNGRADE;
|
||||
else if (rsn == "user")
|
||||
this->reason = SNAPSHOT_USER;
|
||||
else
|
||||
this->reason = SNAPSHOT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
} else if (section.first == "presets") {
|
||||
// Load the names of the active presets.
|
||||
for (auto &kvp : section.second) {
|
||||
if (kvp.first == "print") {
|
||||
this->print = kvp.second.data();
|
||||
} else if (boost::starts_with(kvp.first, "filament")) {
|
||||
int idx = 0;
|
||||
if (kvp.first == "filament" || sscanf(kvp.first.c_str(), "filament_%d", &idx) == 1) {
|
||||
if (int(this->filaments.size()) <= idx)
|
||||
this->filaments.resize(idx + 1, std::string());
|
||||
this->filaments[idx] = kvp.second.data();
|
||||
}
|
||||
} else if (kvp.first == "printer") {
|
||||
this->printer = kvp.second.data();
|
||||
}
|
||||
}
|
||||
} else if (boost::starts_with(section.first, group_name_vendor) && section.first.size() > group_name_vendor.size()) {
|
||||
// Vendor specific section.
|
||||
VendorConfig vc;
|
||||
vc.name = section.first.substr(group_name_vendor.size());
|
||||
for (auto &kvp : section.second) {
|
||||
if (boost::starts_with(kvp.first, "model_")) {
|
||||
//model:MK2S = 0.4;xxx
|
||||
//model:MK3 = 0.4;xxx
|
||||
} else if (kvp.first == "version" || kvp.first == "min_slic3r_version" || kvp.first == "max_slic3r_version") {
|
||||
// Version of the vendor specific config bundle bundled with this snapshot.
|
||||
auto semver = Semver::parse(kvp.second.data());
|
||||
if (! semver)
|
||||
throw_on_parse_error("invalid " + kvp.first + " format for " + section.first);
|
||||
if (kvp.first == "version")
|
||||
vc.version = *semver;
|
||||
else if (kvp.first == "min_slic3r_version")
|
||||
vc.min_slic3r_version = *semver;
|
||||
else
|
||||
vc.max_slic3r_version = *semver;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Snapshot::save_ini(const std::string &path)
|
||||
{
|
||||
boost::nowide::ofstream c;
|
||||
c.open(path, std::ios::out | std::ios::trunc);
|
||||
c << "# " << Slic3r::header_slic3r_generated() << std::endl;
|
||||
|
||||
// Export the common "snapshot".
|
||||
c << std::endl << "[snapshot]" << std::endl;
|
||||
c << "id = " << this->id << std::endl;
|
||||
c << "time_captured = " << Slic3r::Utils::format_time_ISO8601Z(this->time_captured) << std::endl;
|
||||
c << "slic3r_version_captured = " << this->slic3r_version_captured.to_string() << std::endl;
|
||||
c << "comment = " << this->comment << std::endl;
|
||||
c << "reason = " << this->reason << std::endl;
|
||||
|
||||
// Export the active presets at the time of the snapshot.
|
||||
c << std::endl << "[presets]" << std::endl;
|
||||
c << "print = " << this->print << std::endl;
|
||||
c << "filament = " << this->filaments.front() << std::endl;
|
||||
for (size_t i = 1; i < this->filaments.size(); ++ i)
|
||||
c << "filament_" << std::to_string(i) << " = " << this->filaments[i] << std::endl;
|
||||
c << "printer = " << this->printer << std::endl;
|
||||
|
||||
// Export the vendor configs.
|
||||
for (const VendorConfig &vc : this->vendor_configs) {
|
||||
c << std::endl << "[Vendor:" << vc.name << "]" << std::endl;
|
||||
c << "version = " << vc.version.to_string() << std::endl;
|
||||
c << "min_slic3r_version = " << vc.min_slic3r_version.to_string() << std::endl;
|
||||
c << "max_slic3r_version = " << vc.max_slic3r_version.to_string() << std::endl;
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
void Snapshot::export_selections(AppConfig &config) const
|
||||
{
|
||||
assert(filaments.size() >= 1);
|
||||
config.clear_section("presets");
|
||||
config.set("presets", "print", print);
|
||||
config.set("presets", "filament", filaments.front());
|
||||
for (int i = 1; i < filaments.size(); ++i) {
|
||||
char name[64];
|
||||
sprintf(name, "filament_%d", i);
|
||||
config.set("presets", name, filaments[i]);
|
||||
}
|
||||
config.set("presets", "printer", printer);
|
||||
}
|
||||
|
||||
size_t SnapshotDB::load_db()
|
||||
{
|
||||
boost::filesystem::path snapshots_dir = SnapshotDB::create_db_dir();
|
||||
|
||||
m_snapshots.clear();
|
||||
|
||||
// Walk over the snapshot directories and load their index.
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(snapshots_dir))
|
||||
if (boost::filesystem::is_directory(dir_entry.status())) {
|
||||
// Try to read "snapshot.ini".
|
||||
boost::filesystem::path path_ini = dir_entry.path() / SLIC3R_SNAPSHOT_FILE;
|
||||
Snapshot snapshot;
|
||||
try {
|
||||
snapshot.load_ini(path_ini.string());
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
continue;
|
||||
}
|
||||
// Check that the name of the snapshot directory matches the snapshot id stored in the snapshot.ini file.
|
||||
if (dir_entry.path().filename().string() != snapshot.id) {
|
||||
errors_cummulative += std::string("Snapshot ID ") + snapshot.id + " does not match the snapshot directory " + dir_entry.path().filename().string() + "\n";
|
||||
continue;
|
||||
}
|
||||
m_snapshots.emplace_back(std::move(snapshot));
|
||||
}
|
||||
|
||||
if (! errors_cummulative.empty())
|
||||
throw std::runtime_error(errors_cummulative);
|
||||
return m_snapshots.size();
|
||||
}
|
||||
|
||||
static void copy_config_dir_single_level(const boost::filesystem::path &path_src, const boost::filesystem::path &path_dst)
|
||||
{
|
||||
if (! boost::filesystem::is_directory(path_dst) &&
|
||||
! boost::filesystem::create_directory(path_dst))
|
||||
throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
|
||||
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
|
||||
boost::filesystem::copy_file(dir_entry.path(), path_dst / dir_entry.path().filename(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||
}
|
||||
|
||||
static void delete_existing_ini_files(const boost::filesystem::path &path)
|
||||
{
|
||||
if (! boost::filesystem::is_directory(path))
|
||||
return;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(path))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
|
||||
boost::filesystem::remove(dir_entry.path());
|
||||
}
|
||||
|
||||
const Snapshot& SnapshotDB::make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
|
||||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
boost::filesystem::path snapshot_db_dir = SnapshotDB::create_db_dir();
|
||||
|
||||
// 1) Prepare the snapshot structure.
|
||||
Snapshot snapshot;
|
||||
// Snapshot header.
|
||||
snapshot.time_captured = Slic3r::Utils::get_current_time_utc();
|
||||
snapshot.id = Slic3r::Utils::format_time_ISO8601Z(snapshot.time_captured);
|
||||
snapshot.slic3r_version_captured = *Semver::parse(SLIC3R_VERSION);
|
||||
snapshot.comment = comment;
|
||||
snapshot.reason = reason;
|
||||
// Active presets at the time of the snapshot.
|
||||
snapshot.print = app_config.get("presets", "print");
|
||||
snapshot.filaments.emplace_back(app_config.get("presets", "filament"));
|
||||
snapshot.printer = app_config.get("presets", "printer");
|
||||
for (unsigned int i = 1; i < 1000; ++ i) {
|
||||
char name[64];
|
||||
sprintf(name, "filament_%d", i);
|
||||
if (! app_config.has("presets", name))
|
||||
break;
|
||||
snapshot.filaments.emplace_back(app_config.get("presets", name));
|
||||
}
|
||||
// Vendor specific config bundles and installed printers.
|
||||
|
||||
// Backup the presets.
|
||||
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
|
||||
for (const char *subdir : { "print", "filament", "printer", "vendor" })
|
||||
copy_config_dir_single_level(data_dir / subdir, snapshot_dir / subdir);
|
||||
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
|
||||
m_snapshots.emplace_back(std::move(snapshot));
|
||||
return m_snapshots.back();
|
||||
}
|
||||
|
||||
void SnapshotDB::restore_snapshot(const std::string &id, AppConfig &app_config)
|
||||
{
|
||||
for (const Snapshot &snapshot : m_snapshots)
|
||||
if (snapshot.id == id) {
|
||||
this->restore_snapshot(snapshot, app_config);
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error(std::string("Snapshot with id " + id + " was not found."));
|
||||
}
|
||||
|
||||
void SnapshotDB::restore_snapshot(const Snapshot &snapshot, AppConfig &app_config)
|
||||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
boost::filesystem::path snapshot_db_dir = SnapshotDB::create_db_dir();
|
||||
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
|
||||
|
||||
// Remove existing ini files and restore the ini files from the snapshot.
|
||||
for (const char *subdir : { "print", "filament", "printer", "vendor" }) {
|
||||
delete_existing_ini_files(data_dir / subdir);
|
||||
copy_config_dir_single_level(snapshot_dir / subdir, data_dir / subdir);
|
||||
}
|
||||
|
||||
// Update app_config from the snapshot.
|
||||
snapshot.export_selections(app_config);
|
||||
|
||||
// Store information about the snapshot.
|
||||
|
||||
}
|
||||
|
||||
boost::filesystem::path SnapshotDB::create_db_dir()
|
||||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
boost::filesystem::path snapshots_dir = data_dir / SLIC3R_SNAPSHOTS_DIR;
|
||||
for (const boost::filesystem::path &path : { data_dir, snapshots_dir }) {
|
||||
boost::filesystem::path subdir = path;
|
||||
subdir.make_preferred();
|
||||
if (! boost::filesystem::is_directory(subdir) &&
|
||||
! boost::filesystem::create_directory(subdir))
|
||||
throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + subdir.string());
|
||||
}
|
||||
return snapshots_dir;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
106
xs/src/slic3r/Config/Snapshot.hpp
Normal file
106
xs/src/slic3r/Config/Snapshot.hpp
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef slic3r_GUI_Snapshot_
|
||||
#define slic3r_GUI_Snapshot_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "../Utils/Semver.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class AppConfig;
|
||||
|
||||
namespace GUI {
|
||||
namespace Config {
|
||||
|
||||
// A snapshot contains:
|
||||
// Slic3r.ini
|
||||
// vendor/
|
||||
// print/
|
||||
// filament/
|
||||
// printer/
|
||||
class Snapshot
|
||||
{
|
||||
public:
|
||||
enum Reason {
|
||||
SNAPSHOT_UNKNOWN,
|
||||
SNAPSHOT_UPGRADE,
|
||||
SNAPSHOT_DOWNGRADE,
|
||||
SNAPSHOT_USER,
|
||||
};
|
||||
|
||||
Snapshot() { clear(); }
|
||||
|
||||
void clear();
|
||||
void load_ini(const std::string &path);
|
||||
void save_ini(const std::string &path);
|
||||
|
||||
// Export the print / filament / printer selections to be activated into the AppConfig.
|
||||
void export_selections(AppConfig &config) const;
|
||||
|
||||
// ID of a snapshot should equal to the name of the snapshot directory.
|
||||
// The ID contains the date/time, reason and comment to be human readable.
|
||||
std::string id;
|
||||
std::time_t time_captured;
|
||||
// Which Slic3r version captured this snapshot?
|
||||
Semver slic3r_version_captured = Semver::invalid();
|
||||
// Comment entered by the user at the start of the snapshot capture.
|
||||
std::string comment;
|
||||
Reason reason;
|
||||
|
||||
// Active presets at the time of the snapshot.
|
||||
std::string print;
|
||||
std::vector<std::string> filaments;
|
||||
std::string printer;
|
||||
|
||||
// Annotation of the vendor configuration stored in the snapshot.
|
||||
// This information is displayed to the user and used to decide compatibility
|
||||
// of the configuration stored in the snapshot with the running Slic3r version.
|
||||
struct VendorConfig {
|
||||
// Name of the vendor contained in this snapshot.
|
||||
std::string name;
|
||||
// Version of the vendor config contained in this snapshot.
|
||||
Semver version = Semver::invalid();
|
||||
// Minimum Slic3r version compatible with this vendor configuration.
|
||||
Semver min_slic3r_version = Semver::zero();
|
||||
// Maximum Slic3r version compatible with this vendor configuration, or empty.
|
||||
Semver max_slic3r_version = Semver::inf();
|
||||
};
|
||||
// List of vendor configs contained in this snapshot.
|
||||
std::vector<VendorConfig> vendor_configs;
|
||||
};
|
||||
|
||||
class SnapshotDB
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Snapshot>::const_iterator const_iterator;
|
||||
|
||||
// Load the snapshot database from the snapshots directory.
|
||||
// If the snapshot directory or its parent does not exist yet, it will be created.
|
||||
// Returns a number of snapshots loaded.
|
||||
size_t load_db();
|
||||
|
||||
// Create a snapshot directory, copy the vendor config bundles, user print/filament/printer profiles,
|
||||
// create an index.
|
||||
const Snapshot& make_snapshot(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment);
|
||||
void restore_snapshot(const std::string &id, AppConfig &app_config);
|
||||
void restore_snapshot(const Snapshot &snapshot, AppConfig &app_config);
|
||||
|
||||
const_iterator begin() const { return m_snapshots.begin(); }
|
||||
const_iterator end() const { return m_snapshots.end(); }
|
||||
const std::vector<Snapshot>& snapshots() const { return m_snapshots; }
|
||||
|
||||
private:
|
||||
// Create the snapshots directory if it does not exist yet.
|
||||
static boost::filesystem::path create_db_dir();
|
||||
|
||||
std::vector<Snapshot> m_snapshots;
|
||||
};
|
||||
|
||||
} // namespace Config
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GUI_Snapshot_ */
|
136
xs/src/slic3r/Config/Version.cpp
Normal file
136
xs/src/slic3r/Config/Version.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "Version.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
|
||||
#include "../../libslic3r/libslic3r.h"
|
||||
#include "../../libslic3r/Config.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
namespace Config {
|
||||
|
||||
static boost::optional<Semver> s_current_slic3r_semver = Semver::parse(SLIC3R_VERSION);
|
||||
|
||||
bool Version::is_current_slic3r_supported() const
|
||||
{
|
||||
return this->is_slic3r_supported(*s_current_slic3r_semver);
|
||||
}
|
||||
|
||||
inline char* left_trim(char *c)
|
||||
{
|
||||
for (; *c == ' ' || *c == '\t'; ++ c);
|
||||
return c;
|
||||
}
|
||||
|
||||
inline char* right_trim(char *start)
|
||||
{
|
||||
char *end = start + strlen(start) - 1;
|
||||
for (; end >= start && (*end == ' ' || *end == '\t'); -- end);
|
||||
*(++ end) = 0;
|
||||
return end;
|
||||
}
|
||||
|
||||
inline std::string unquote_value(char *value, char *end, const std::string &path, int idx_line)
|
||||
{
|
||||
std::string svalue;
|
||||
if (value == end) {
|
||||
// Empty string is a valid string.
|
||||
} else if (*value == '"') {
|
||||
if (++ value < -- end || *end != '"')
|
||||
throw file_parser_error("String not enquoted correctly", path, idx_line);
|
||||
*end = 0;
|
||||
if (! unescape_string_cstyle(value, svalue))
|
||||
throw file_parser_error("Invalid escape sequence inside a quoted string", path, idx_line);
|
||||
}
|
||||
return svalue;
|
||||
}
|
||||
|
||||
inline std::string unquote_version_comment(char *value, char *end, const std::string &path, int idx_line)
|
||||
{
|
||||
std::string svalue;
|
||||
if (value == end) {
|
||||
// Empty string is a valid string.
|
||||
} else if (*value == '"') {
|
||||
if (++ value < -- end || *end != '"')
|
||||
throw file_parser_error("Version comment not enquoted correctly", path, idx_line);
|
||||
*end = 0;
|
||||
if (! unescape_string_cstyle(value, svalue))
|
||||
throw file_parser_error("Invalid escape sequence inside a quoted version comment", path, idx_line);
|
||||
}
|
||||
return svalue;
|
||||
}
|
||||
|
||||
size_t Index::load(const std::string &path)
|
||||
{
|
||||
m_configs.clear();
|
||||
|
||||
boost::nowide::ifstream ifs(path);
|
||||
std::string line;
|
||||
size_t idx_line = 0;
|
||||
Version ver;
|
||||
while (std::getline(ifs, line)) {
|
||||
++ idx_line;
|
||||
// Skip the initial white spaces.
|
||||
char *key = left_trim(const_cast<char*>(line.data()));
|
||||
// Right trim the line.
|
||||
char *end = right_trim(key);
|
||||
// Keyword may only contain alphanumeric characters. Semantic version may in addition contain "+.-".
|
||||
char *key_end = key;
|
||||
bool maybe_semver = false;
|
||||
for (;; ++ key) {
|
||||
if (strchr("+.-", *key) != nullptr)
|
||||
maybe_semver = true;
|
||||
else if (! std::isalnum(*key))
|
||||
break;
|
||||
}
|
||||
if (*key != 0 && *key != ' ' && *key != '\t' && *key != '=')
|
||||
throw file_parser_error("Invalid keyword or semantic version", path, idx_line);
|
||||
*key_end = 0;
|
||||
boost::optional<Semver> semver;
|
||||
if (maybe_semver)
|
||||
semver = Semver::parse(key);
|
||||
char *value = left_trim(key_end);
|
||||
if (*value == '=') {
|
||||
if (semver)
|
||||
throw file_parser_error("Key cannot be a semantic version", path, idx_line);
|
||||
// Verify validity of the key / value pair.
|
||||
std::string svalue = unquote_value(left_trim(++ value), end, path, idx_line);
|
||||
if (key == "min_sic3r_version" || key == "max_slic3r_version") {
|
||||
if (! svalue.empty())
|
||||
semver = Semver::parse(key);
|
||||
if (! semver)
|
||||
throw file_parser_error(std::string(key) + " must referece a valid semantic version", path, idx_line);
|
||||
if (key == "min_sic3r_version")
|
||||
ver.min_slic3r_version = *semver;
|
||||
else
|
||||
ver.max_slic3r_version = *semver;
|
||||
} else {
|
||||
// Ignore unknown keys, as there may come new keys in the future.
|
||||
}
|
||||
}
|
||||
if (! semver)
|
||||
throw file_parser_error("Invalid semantic version", path, idx_line);
|
||||
ver.config_version = *semver;
|
||||
ver.comment = (end <= key_end) ? "" : unquote_version_comment(value, end, path, idx_line);
|
||||
m_configs.emplace_back(ver);
|
||||
}
|
||||
|
||||
return m_configs.size();
|
||||
}
|
||||
|
||||
Index::const_iterator Index::recommended() const
|
||||
{
|
||||
int idx = -1;
|
||||
const_iterator highest = m_configs.end();
|
||||
for (const_iterator it = this->begin(); it != this->end(); ++ it)
|
||||
if (it->is_current_slic3r_supported() &&
|
||||
(highest == this->end() || highest->max_slic3r_version < it->max_slic3r_version))
|
||||
highest = it;
|
||||
return highest;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
75
xs/src/slic3r/Config/Version.hpp
Normal file
75
xs/src/slic3r/Config/Version.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef slic3r_GUI_ConfigIndex_
|
||||
#define slic3r_GUI_ConfigIndex_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../../libslic3r/FileParserError.hpp"
|
||||
#include "../Utils/Semver.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
namespace Config {
|
||||
|
||||
// Configuration bundle version.
|
||||
struct Version
|
||||
{
|
||||
// Version of this config.
|
||||
Semver config_version = Semver::invalid();
|
||||
// Minimum Slic3r version, for which this config is applicable.
|
||||
Semver min_slic3r_version = Semver::zero();
|
||||
// Maximum Slic3r version, for which this config is recommended.
|
||||
// Slic3r should read older configuration and upgrade to a newer format,
|
||||
// but likely there has been a better configuration published, using the new features.
|
||||
Semver max_slic3r_version = Semver::inf();
|
||||
// Single comment line.
|
||||
std::string comment;
|
||||
|
||||
bool is_slic3r_supported(const Semver &slicer_version) const { return slicer_version.in_range(min_slic3r_version, max_slic3r_version); }
|
||||
bool is_current_slic3r_supported() const;
|
||||
};
|
||||
|
||||
// Index of vendor specific config bundle versions and Slic3r compatibilities.
|
||||
// The index is being downloaded from the internet, also an initial version of the index
|
||||
// is contained in the Slic3r installation.
|
||||
//
|
||||
// The index has a simple format:
|
||||
//
|
||||
// min_sic3r_version =
|
||||
// max_slic3r_version =
|
||||
// config_version "comment"
|
||||
// config_version "comment"
|
||||
// ...
|
||||
// min_slic3r_version =
|
||||
// max_slic3r_version =
|
||||
// config_version comment
|
||||
// config_version comment
|
||||
// ...
|
||||
//
|
||||
// The min_slic3r_version, max_slic3r_version keys are applied to the config versions below,
|
||||
// empty slic3r version means an open interval.
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Version>::const_iterator const_iterator;
|
||||
// Read a config index file in the simple format described in the Index class comment.
|
||||
// Throws Slic3r::file_parser_error and the standard std file access exceptions.
|
||||
size_t load(const std::string &path);
|
||||
|
||||
const_iterator begin() const { return m_configs.begin(); }
|
||||
const_iterator end() const { return m_configs.end(); }
|
||||
const std::vector<Version>& configs() const { return m_configs; }
|
||||
// Finds a recommended config to be installed for the current Slic3r version.
|
||||
// Returns configs().end() if such version does not exist in the index. This shall never happen
|
||||
// if the index is valid.
|
||||
const_iterator recommended() const;
|
||||
|
||||
private:
|
||||
std::vector<Version> m_configs;
|
||||
};
|
||||
|
||||
} // namespace Config
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GUI_ConfigIndex_ */
|
@ -194,8 +194,8 @@ void GLIndexedVertexArray::render(
|
||||
|
||||
const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
|
||||
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.75f, 0.0f, 0.75f, 1.0f };
|
||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 1.0f, 0.0f, 1.0f, 1.0f };
|
||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
||||
|
||||
void GLVolume::set_render_color(float r, float g, float b, float a)
|
||||
{
|
||||
@ -627,6 +627,8 @@ void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config,
|
||||
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
||||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height")));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min.z = -1e10;
|
||||
|
||||
for (GLVolume* volume : this->volumes)
|
||||
{
|
||||
@ -642,20 +644,25 @@ void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config,
|
||||
|
||||
std::vector<double> GLVolumeCollection::get_current_print_zs() const
|
||||
{
|
||||
// Collect layer top positions of all volumes.
|
||||
std::vector<double> print_zs;
|
||||
|
||||
for (GLVolume *vol : this->volumes)
|
||||
{
|
||||
for (coordf_t z : vol->print_zs)
|
||||
{
|
||||
double round_z = (double)round(z * 100000.0f) / 100000.0f;
|
||||
if (std::find(print_zs.begin(), print_zs.end(), round_z) == print_zs.end())
|
||||
print_zs.push_back(round_z);
|
||||
}
|
||||
}
|
||||
|
||||
append(print_zs, vol->print_zs);
|
||||
std::sort(print_zs.begin(), print_zs.end());
|
||||
|
||||
// Replace intervals of layers with similar top positions with their average value.
|
||||
int n = int(print_zs.size());
|
||||
int k = 0;
|
||||
for (int i = 0; i < n;) {
|
||||
int j = i + 1;
|
||||
coordf_t zmax = print_zs[i] + EPSILON;
|
||||
for (; j < n && print_zs[j] <= zmax; ++ j) ;
|
||||
print_zs[k ++] = (j > i + 1) ? (0.5 * (print_zs[i] + print_zs[j - 1])) : print_zs[i];
|
||||
i = j;
|
||||
}
|
||||
if (k < n)
|
||||
print_zs.erase(print_zs.begin() + k, print_zs.end());
|
||||
|
||||
return print_zs;
|
||||
}
|
||||
|
||||
@ -2039,6 +2046,8 @@ void _3DScene::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data,
|
||||
return path.width;
|
||||
case GCodePreviewData::Extrusion::Feedrate:
|
||||
return path.feedrate;
|
||||
case GCodePreviewData::Extrusion::VolumetricRate:
|
||||
return path.feedrate * (float)path.mm3_per_mm;
|
||||
case GCodePreviewData::Extrusion::Tool:
|
||||
return (float)path.extruder_id;
|
||||
}
|
||||
@ -2053,11 +2062,13 @@ void _3DScene::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data,
|
||||
case GCodePreviewData::Extrusion::FeatureType:
|
||||
return data.get_extrusion_role_color((ExtrusionRole)(int)value);
|
||||
case GCodePreviewData::Extrusion::Height:
|
||||
return data.get_extrusion_height_color(value);
|
||||
return data.get_height_color(value);
|
||||
case GCodePreviewData::Extrusion::Width:
|
||||
return data.get_extrusion_width_color(value);
|
||||
return data.get_width_color(value);
|
||||
case GCodePreviewData::Extrusion::Feedrate:
|
||||
return data.get_extrusion_feedrate_color(value);
|
||||
return data.get_feedrate_color(value);
|
||||
case GCodePreviewData::Extrusion::VolumetricRate:
|
||||
return data.get_volumetric_rate_color(value);
|
||||
case GCodePreviewData::Extrusion::Tool:
|
||||
{
|
||||
static GCodePreviewData::Color color;
|
||||
@ -2337,7 +2348,7 @@ bool _3DScene::_travel_paths_by_feedrate(const GCodePreviewData& preview_data, G
|
||||
// creates a new volume for each feedrate
|
||||
for (Feedrate& feedrate : feedrates)
|
||||
{
|
||||
GLVolume* volume = new GLVolume(preview_data.get_extrusion_feedrate_color(feedrate.value).rgba);
|
||||
GLVolume* volume = new GLVolume(preview_data.get_feedrate_color(feedrate.value).rgba);
|
||||
if (volume == nullptr)
|
||||
return false;
|
||||
else
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "GUI.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@ -37,6 +38,7 @@
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/combo.h>
|
||||
#include <wx/window.h>
|
||||
#include <wx/settings.h>
|
||||
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
@ -174,6 +176,8 @@ wxFrame *g_wxMainFrame = nullptr;
|
||||
wxNotebook *g_wxTabPanel = nullptr;
|
||||
AppConfig *g_AppConfig = nullptr;
|
||||
PresetBundle *g_PresetBundle= nullptr;
|
||||
wxColour g_color_label_modified;
|
||||
wxColour g_color_label_sys;
|
||||
|
||||
std::vector<Tab *> g_tabs_list;
|
||||
|
||||
@ -182,9 +186,22 @@ wxLocale* g_wxLocale;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup;
|
||||
double m_brim_width = 0.0;
|
||||
|
||||
static void init_label_colours()
|
||||
{
|
||||
auto luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
if (luma >= 128) {
|
||||
g_color_label_modified = wxColour(253, 88, 0);
|
||||
g_color_label_sys = wxColour(26, 132, 57);
|
||||
} else {
|
||||
g_color_label_modified = wxColour(253, 111, 40);
|
||||
g_color_label_sys = wxColour(115, 220, 103);
|
||||
}
|
||||
}
|
||||
|
||||
void set_wxapp(wxApp *app)
|
||||
{
|
||||
g_wxApp = app;
|
||||
init_label_colours();
|
||||
}
|
||||
|
||||
void set_main_frame(wxFrame *main_frame)
|
||||
@ -514,12 +531,25 @@ wxApp* get_app(){
|
||||
return g_wxApp;
|
||||
}
|
||||
|
||||
wxColour* get_modified_label_clr(){
|
||||
return new wxColour(253, 88, 0);
|
||||
const wxColour& get_modified_label_clr() {
|
||||
return g_color_label_modified;
|
||||
}
|
||||
|
||||
wxColour* get_sys_label_clr(){
|
||||
return new wxColour(26, 132, 57);
|
||||
const wxColour& get_sys_label_clr() {
|
||||
return g_color_label_sys;
|
||||
}
|
||||
|
||||
unsigned get_colour_approx_luma(const wxColour &colour)
|
||||
{
|
||||
double r = colour.Red();
|
||||
double g = colour.Green();
|
||||
double b = colour.Blue();
|
||||
|
||||
return std::round(std::sqrt(
|
||||
r * r * .241 +
|
||||
g * g * .691 +
|
||||
b * b * .068
|
||||
));
|
||||
}
|
||||
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
||||
@ -692,4 +722,49 @@ ConfigOptionsGroup* get_optgroup()
|
||||
return m_optgroup.get();
|
||||
}
|
||||
|
||||
wxWindow* export_option_creator(wxWindow* parent)
|
||||
{
|
||||
wxPanel* panel = new wxPanel(parent, -1);
|
||||
wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxCheckBox* cbox = new wxCheckBox(panel, wxID_HIGHEST + 1, L("Export print config"));
|
||||
sizer->AddSpacer(5);
|
||||
sizer->Add(cbox, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
panel->SetSizer(sizer);
|
||||
sizer->SetSizeHints(panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
void add_export_option(wxFileDialog* dlg, const std::string& format)
|
||||
{
|
||||
if ((dlg != nullptr) && (format == "AMF") || (format == "3MF"))
|
||||
{
|
||||
if (dlg->SupportsExtraControl())
|
||||
dlg->SetExtraControlCreator(export_option_creator);
|
||||
}
|
||||
}
|
||||
|
||||
int get_export_option(wxFileDialog* dlg)
|
||||
{
|
||||
if (dlg != nullptr)
|
||||
{
|
||||
wxWindow* wnd = dlg->GetExtraControl();
|
||||
if (wnd != nullptr)
|
||||
{
|
||||
wxPanel* panel = dynamic_cast<wxPanel*>(wnd);
|
||||
if (panel != nullptr)
|
||||
{
|
||||
wxWindow* child = panel->FindWindow(wxID_HIGHEST + 1);
|
||||
if (child != nullptr)
|
||||
{
|
||||
wxCheckBox* cbox = dynamic_cast<wxCheckBox*>(child);
|
||||
if (cbox != nullptr)
|
||||
return cbox->IsChecked() ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} }
|
||||
|
@ -18,6 +18,7 @@ class wxArrayLong;
|
||||
class wxColour;
|
||||
class wxBoxSizer;
|
||||
class wxFlexGridSizer;
|
||||
class wxFileDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -78,8 +79,10 @@ void set_preset_bundle(PresetBundle *preset_bundle);
|
||||
|
||||
AppConfig* get_app_config();
|
||||
wxApp* get_app();
|
||||
wxColour* get_modified_label_clr();
|
||||
wxColour* get_sys_label_clr();
|
||||
|
||||
const wxColour& get_modified_label_clr();
|
||||
const wxColour& get_sys_label_clr();
|
||||
unsigned get_colour_approx_luma(const wxColour &colour);
|
||||
|
||||
void add_debug_menu(wxMenuBar *menu, int event_language_change);
|
||||
|
||||
@ -131,6 +134,8 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
|
||||
|
||||
ConfigOptionsGroup* get_optgroup();
|
||||
|
||||
void add_export_option(wxFileDialog* dlg, const std::string& format);
|
||||
int get_export_option(wxFileDialog* dlg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,14 +334,14 @@ void Tab::update_changed_ui()
|
||||
bool is_modified_value = true;
|
||||
std::string sys_icon = /*wxMSW ? */"sys_lock.png"/* : "lock.png"*/;
|
||||
std::string icon = /*wxMSW ? */"action_undo.png"/* : "arrow_undo.png"*/;
|
||||
wxColour& color = *get_sys_label_clr();
|
||||
wxColour color = get_sys_label_clr();
|
||||
if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) {
|
||||
is_nonsys_value = true;
|
||||
sys_icon = m_nonsys_btn_icon;
|
||||
if(find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
|
||||
color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
else
|
||||
color = *get_modified_label_clr();
|
||||
color = get_modified_label_clr();
|
||||
}
|
||||
if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
|
||||
{
|
||||
@ -455,9 +455,9 @@ void Tab::update_changed_tree_ui()
|
||||
break;
|
||||
}
|
||||
if (sys_page)
|
||||
m_treectrl->SetItemTextColour(cur_item, *get_sys_label_clr());
|
||||
m_treectrl->SetItemTextColour(cur_item, get_sys_label_clr());
|
||||
else if (modified_page)
|
||||
m_treectrl->SetItemTextColour(cur_item, *get_modified_label_clr());
|
||||
m_treectrl->SetItemTextColour(cur_item, get_modified_label_clr());
|
||||
else
|
||||
m_treectrl->SetItemTextColour(cur_item, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
|
||||
|
@ -36,16 +36,20 @@ struct Http::priv
|
||||
::curl_slist *headerlist;
|
||||
std::string buffer;
|
||||
size_t limit;
|
||||
bool cancel;
|
||||
|
||||
std::thread io_thread;
|
||||
Http::CompleteFn completefn;
|
||||
Http::ErrorFn errorfn;
|
||||
Http::ProgressFn progressfn;
|
||||
|
||||
priv(const std::string &url);
|
||||
~priv();
|
||||
|
||||
static bool ca_file_supported(::CURL *curl);
|
||||
static size_t writecb(void *data, size_t size, size_t nmemb, void *userp);
|
||||
static int xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
std::string curl_error(CURLcode curlcode);
|
||||
std::string body_size_error();
|
||||
void http_perform();
|
||||
@ -55,7 +59,8 @@ Http::priv::priv(const std::string &url) :
|
||||
curl(::curl_easy_init()),
|
||||
form(nullptr),
|
||||
form_end(nullptr),
|
||||
headerlist(nullptr)
|
||||
headerlist(nullptr),
|
||||
cancel(false)
|
||||
{
|
||||
if (curl == nullptr) {
|
||||
throw std::runtime_error(std::string("Could not construct Curl object"));
|
||||
@ -112,6 +117,24 @@ size_t Http::priv::writecb(void *data, size_t size, size_t nmemb, void *userp)
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
auto self = static_cast<priv*>(userp);
|
||||
bool cb_cancel = false;
|
||||
|
||||
if (self->progressfn) {
|
||||
Progress progress(dltotal, dlnow, ultotal, ulnow);
|
||||
self->progressfn(progress, cb_cancel);
|
||||
}
|
||||
|
||||
return self->cancel || cb_cancel;
|
||||
}
|
||||
|
||||
int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
return xfercb(userp, dltotal, dlnow, ultotal, ulnow);
|
||||
}
|
||||
|
||||
std::string Http::priv::curl_error(CURLcode curlcode)
|
||||
{
|
||||
return (boost::format("%1% (%2%)")
|
||||
@ -132,6 +155,16 @@ void Http::priv::http_perform()
|
||||
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb);
|
||||
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this));
|
||||
|
||||
::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
#if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 32
|
||||
::curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xfercb);
|
||||
::curl_easy_setopt(curl, CURLOPT_XFERINFODATA, static_cast<void*>(this));
|
||||
(void)xfercb_legacy; // prevent unused function warning
|
||||
#else
|
||||
::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, xfercb);
|
||||
::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, static_cast<void*>(this));
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
#endif
|
||||
@ -149,16 +182,16 @@ void Http::priv::http_perform()
|
||||
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
|
||||
|
||||
if (res != CURLE_OK) {
|
||||
std::string error;
|
||||
if (res == CURLE_WRITE_ERROR) {
|
||||
error = std::move(body_size_error());
|
||||
} else {
|
||||
error = std::move(curl_error(res));
|
||||
};
|
||||
|
||||
if (errorfn) {
|
||||
errorfn(std::move(buffer), std::move(error), http_status);
|
||||
if (res == CURLE_ABORTED_BY_CALLBACK) {
|
||||
Progress dummyprogress(0, 0, 0, 0);
|
||||
bool cancel = true;
|
||||
if (progressfn) { progressfn(dummyprogress, cancel); }
|
||||
}
|
||||
else if (res == CURLE_WRITE_ERROR) {
|
||||
if (errorfn) { errorfn(std::move(buffer), std::move(body_size_error()), http_status); }
|
||||
} else {
|
||||
if (errorfn) { errorfn(std::move(buffer), std::move(curl_error(res)), http_status); }
|
||||
};
|
||||
} else {
|
||||
if (completefn) {
|
||||
completefn(std::move(buffer), http_status);
|
||||
@ -258,6 +291,12 @@ Http& Http::on_error(ErrorFn fn)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_progress(ProgressFn fn)
|
||||
{
|
||||
if (p) { p->progressfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http::Ptr Http::perform()
|
||||
{
|
||||
auto self = std::make_shared<Http>(std::move(*this));
|
||||
@ -277,6 +316,11 @@ void Http::perform_sync()
|
||||
if (p) { p->http_perform(); }
|
||||
}
|
||||
|
||||
void Http::cancel()
|
||||
{
|
||||
if (p) { p->cancel = true; }
|
||||
}
|
||||
|
||||
Http Http::get(std::string url)
|
||||
{
|
||||
return std::move(Http{std::move(url)});
|
||||
@ -297,5 +341,16 @@ bool Http::ca_file_supported()
|
||||
return res;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const Http::Progress &progress)
|
||||
{
|
||||
os << "Http::Progress("
|
||||
<< "dltotal = " << progress.dltotal
|
||||
<< ", dlnow = " << progress.dlnow
|
||||
<< ", ultotal = " << progress.ultotal
|
||||
<< ", ulnow = " << progress.ulnow
|
||||
<< ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -14,9 +14,22 @@ class Http : public std::enable_shared_from_this<Http> {
|
||||
private:
|
||||
struct priv;
|
||||
public:
|
||||
struct Progress
|
||||
{
|
||||
size_t dltotal;
|
||||
size_t dlnow;
|
||||
size_t ultotal;
|
||||
size_t ulnow;
|
||||
|
||||
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) :
|
||||
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Http> Ptr;
|
||||
typedef std::function<void(std::string /* body */, unsigned /* http_status */)> CompleteFn;
|
||||
typedef std::function<void(std::string /* body */, std::string /* error */, unsigned /* http_status */)> ErrorFn;
|
||||
typedef std::function<void(Progress, bool& /* cancel */)> ProgressFn;
|
||||
|
||||
Http(Http &&other);
|
||||
|
||||
@ -37,9 +50,11 @@ public:
|
||||
|
||||
Http& on_complete(CompleteFn fn);
|
||||
Http& on_error(ErrorFn fn);
|
||||
Http& on_progress(ProgressFn fn);
|
||||
|
||||
Ptr perform();
|
||||
void perform_sync();
|
||||
void cancel();
|
||||
|
||||
static bool ca_file_supported();
|
||||
private:
|
||||
@ -48,6 +63,8 @@ private:
|
||||
std::unique_ptr<priv> p;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &, const Http::Progress &);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include "OctoPrint.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
@ -39,36 +40,53 @@ bool OctoPrint::test(wxString &msg) const
|
||||
return res;
|
||||
}
|
||||
|
||||
void OctoPrint::send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print) const
|
||||
bool OctoPrint::send_gcode(const std::string &filename, bool print) const
|
||||
{
|
||||
enum { PROGRESS_RANGE = 1000 };
|
||||
|
||||
const auto errortitle = _(L("Error while uploading to the OctoPrint server"));
|
||||
|
||||
wxProgressDialog progress_dialog(
|
||||
_(L("OctoPrint upload")),
|
||||
_(L("Sending G-code file to the OctoPrint server...")),
|
||||
PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
progress_dialog.Pulse();
|
||||
|
||||
wxString test_msg;
|
||||
if (!test(test_msg)) {
|
||||
auto errormsg = wxString::Format("%s: %s", errortitle, test_msg);
|
||||
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
auto http = Http::post(std::move(make_url("api/files/local")));
|
||||
set_auth(http);
|
||||
http.form_add("print", print ? "true" : "false")
|
||||
.form_add_file("file", filename)
|
||||
.on_complete([=](std::string body, unsigned status) {
|
||||
wxWindow *window = wxWindow::FindWindowById(windowId);
|
||||
if (window == nullptr) { return; }
|
||||
|
||||
wxCommandEvent* evt = new wxCommandEvent(completeEvt);
|
||||
evt->SetString(_(L("G-code file successfully uploaded to the OctoPrint server")));
|
||||
evt->SetInt(100);
|
||||
wxQueueEvent(window, evt);
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
progress_dialog.Update(PROGRESS_RANGE);
|
||||
})
|
||||
.on_error([=](std::string body, std::string error, unsigned status) {
|
||||
wxWindow *window = wxWindow::FindWindowById(windowId);
|
||||
if (window == nullptr) { return; }
|
||||
|
||||
wxCommandEvent* evt_complete = new wxCommandEvent(completeEvt);
|
||||
evt_complete->SetInt(100);
|
||||
wxQueueEvent(window, evt_complete);
|
||||
|
||||
wxCommandEvent* evt_error = new wxCommandEvent(errorEvt);
|
||||
evt_error->SetString(wxString::Format("%s: %s",
|
||||
_(L("Error while uploading to the OctoPrint server")),
|
||||
format_error(error, status)));
|
||||
wxQueueEvent(window, evt_error);
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
auto errormsg = wxString::Format("%s: %s", errortitle, format_error(error, status));
|
||||
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
res = false;
|
||||
})
|
||||
.perform();
|
||||
.on_progress([&](Http::Progress progress, bool &cancel) {
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
res = false;
|
||||
} else if (progress.ultotal > 0) {
|
||||
int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal;
|
||||
cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1)); // Cap the value to prevent premature dialog closing
|
||||
} else {
|
||||
cancel = !progress_dialog.Pulse();
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void OctoPrint::set_auth(Http &http) const
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
OctoPrint(DynamicPrintConfig *config);
|
||||
|
||||
bool test(wxString &curl_msg) const;
|
||||
void send_gcode(int windowId, int completeEvt, int errorEvt, const std::string &filename, bool print = false) const;
|
||||
bool send_gcode(const std::string &filename, bool print = false) const;
|
||||
private:
|
||||
std::string host;
|
||||
std::string apikey;
|
||||
|
114
xs/src/slic3r/Utils/Semver.hpp
Normal file
114
xs/src/slic3r/Utils/Semver.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef slic3r_Semver_hpp_
|
||||
#define slic3r_Semver_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "semver/semver.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class Semver
|
||||
{
|
||||
public:
|
||||
struct Major { const int i; Major(int i) : i(i) {} };
|
||||
struct Minor { const int i; Minor(int i) : i(i) {} };
|
||||
struct Patch { const int i; Patch(int i) : i(i) {} };
|
||||
|
||||
static boost::optional<Semver> parse(const std::string &str)
|
||||
{
|
||||
semver_t ver;
|
||||
if (::semver_parse(str.c_str(), &ver) == 0) {
|
||||
return Semver(ver);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
static const Semver zero()
|
||||
{
|
||||
static semver_t ver = { 0, 0, 0, nullptr, nullptr };
|
||||
return Semver(ver);
|
||||
}
|
||||
|
||||
static const Semver inf()
|
||||
{
|
||||
static semver_t ver = { std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), nullptr, nullptr };
|
||||
return Semver(ver);
|
||||
}
|
||||
|
||||
static const Semver invalid()
|
||||
{
|
||||
static semver_t ver = { -1, 0, 0, nullptr, nullptr };
|
||||
return Semver(ver);
|
||||
}
|
||||
|
||||
Semver(Semver &&other) { *this = std::move(other); }
|
||||
Semver(const Semver &other) { *this = other; }
|
||||
|
||||
Semver &operator=(Semver &&other)
|
||||
{
|
||||
ver = other.ver;
|
||||
other.ver.major = other.ver.minor = other.ver.patch = 0;
|
||||
other.ver.metadata = other.ver.prerelease = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Semver &operator=(const Semver &other)
|
||||
{
|
||||
::semver_free(&ver);
|
||||
ver = other.ver;
|
||||
if (other.ver.metadata != nullptr) { std::strcpy(ver.metadata, other.ver.metadata); }
|
||||
if (other.ver.prerelease != nullptr) { std::strcpy(ver.prerelease, other.ver.prerelease); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Semver() { ::semver_free(&ver); }
|
||||
|
||||
// Comparison
|
||||
bool operator<(const Semver &b) const { return ::semver_compare(ver, b.ver) == -1; }
|
||||
bool operator<=(const Semver &b) const { return ::semver_compare(ver, b.ver) <= 0; }
|
||||
bool operator==(const Semver &b) const { return ::semver_compare(ver, b.ver) == 0; }
|
||||
bool operator!=(const Semver &b) const { return ::semver_compare(ver, b.ver) != 0; }
|
||||
bool operator>=(const Semver &b) const { return ::semver_compare(ver, b.ver) >= 0; }
|
||||
bool operator>(const Semver &b) const { return ::semver_compare(ver, b.ver) == 1; }
|
||||
// We're using '&' instead of the '~' operator here as '~' is unary-only:
|
||||
// Satisfies patch if Major and minor are equal.
|
||||
bool operator&(const Semver &b) const { return ::semver_satisfies_patch(ver, b.ver); }
|
||||
bool operator^(const Semver &b) const { return ::semver_satisfies_caret(ver, b.ver); }
|
||||
bool in_range(const Semver &low, const Semver &high) const { return low <= *this && *this <= high; }
|
||||
|
||||
// Conversion
|
||||
std::string to_string() const {
|
||||
auto res = (boost::format("%1%.%2%.%3%") % ver.major % ver.minor % ver.patch).str();
|
||||
if (ver.prerelease != nullptr) { res += '-'; res += ver.prerelease; }
|
||||
if (ver.metadata != nullptr) { res += '+'; res += ver.metadata; }
|
||||
return res;
|
||||
}
|
||||
|
||||
// Arithmetics
|
||||
Semver& operator+=(const Major &b) { ver.major += b.i; return *this; }
|
||||
Semver& operator+=(const Minor &b) { ver.minor += b.i; return *this; }
|
||||
Semver& operator+=(const Patch &b) { ver.patch += b.i; return *this; }
|
||||
Semver& operator-=(const Major &b) { ver.major -= b.i; return *this; }
|
||||
Semver& operator-=(const Minor &b) { ver.minor -= b.i; return *this; }
|
||||
Semver& operator-=(const Patch &b) { ver.patch -= b.i; return *this; }
|
||||
Semver operator+(const Major &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Minor &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Patch &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator-(const Major &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Minor &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Patch &b) const { Semver res(*this); return res -= b; }
|
||||
|
||||
private:
|
||||
semver_t ver;
|
||||
|
||||
Semver(semver_t ver) : ver(ver) {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif
|
63
xs/src/slic3r/Utils/Time.cpp
Normal file
63
xs/src/slic3r/Utils/Time.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "Time.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
time_t parse_time_ISO8601Z(const std::string &sdate)
|
||||
{
|
||||
int y, M, d, h, m;
|
||||
float s;
|
||||
if (sscanf(sdate.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &M, &d, &h, &m, &s) != 6)
|
||||
return (time_t)-1;
|
||||
struct tm tms;
|
||||
tms.tm_year = y - 1900; // Year since 1900
|
||||
tms.tm_mon = M - 1; // 0-11
|
||||
tms.tm_mday = d; // 1-31
|
||||
tms.tm_hour = h; // 0-23
|
||||
tms.tm_min = m; // 0-59
|
||||
tms.tm_sec = (int)s; // 0-61 (0-60 in C++11)
|
||||
return mktime(&tms);
|
||||
}
|
||||
|
||||
std::string format_time_ISO8601Z(time_t time)
|
||||
{
|
||||
struct tm tms;
|
||||
#ifdef WIN32
|
||||
gmtime_s(time, &tms);
|
||||
#else
|
||||
gmtime_r(&tms, time);
|
||||
#endif
|
||||
char buf[128];
|
||||
sprintf(buf, "%d-%d-%dT%d:%d:%fZ",
|
||||
tms.tm_year + 1900
|
||||
tms.tm_mon + 1
|
||||
tms.tm_mday
|
||||
tms.tm_hour
|
||||
tms.tm_min
|
||||
tms.tm_sec);
|
||||
return buf;
|
||||
}
|
||||
|
||||
time_t get_current_time_utc()
|
||||
{
|
||||
#ifdef WIN32
|
||||
SYSTEMTIME st;
|
||||
::GetSystemTime(&st);
|
||||
std::tm tm;
|
||||
tm.tm_sec = st.wSecond;
|
||||
tm.tm_min = st.wMinute;
|
||||
tm.tm_hour = st.wHour;
|
||||
tm.tm_mday = st.wDay;
|
||||
tm.tm_mon = st.wMonth - 1;
|
||||
tm.tm_year = st.wYear - 1900;
|
||||
tm.tm_isdst = -1;
|
||||
return mktime(&tm);
|
||||
#else
|
||||
return gmtime();
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // namespace Utils
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Utils_Time_hpp_ */
|
22
xs/src/slic3r/Utils/Time.hpp
Normal file
22
xs/src/slic3r/Utils/Time.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef slic3r_Utils_Time_hpp_
|
||||
#define slic3r_Utils_Time_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
// Utilities to convert an UTC time_t to/from an ISO8601 time format,
|
||||
// useful for putting timestamps into file and directory names.
|
||||
// Returns (time_t)-1 on error.
|
||||
extern time_t parse_time_ISO8601Z(const std::string &s);
|
||||
extern std::string format_time_ISO8601Z(time_t time);
|
||||
|
||||
// There is no gmtime() on windows.
|
||||
time_t get_current_time_utc();
|
||||
|
||||
}; // namespace Utils
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Utils_Time_hpp_ */
|
@ -67,3 +67,10 @@ void add_frequently_changed_parameters(SV *ui_parent, SV *ui_sizer, SV *ui_p_siz
|
||||
|
||||
std::string fold_utf8_to_ascii(const char *src)
|
||||
%code%{ RETVAL = Slic3r::fold_utf8_to_ascii(src); %};
|
||||
|
||||
void add_export_option(SV *ui, std::string format)
|
||||
%code%{ Slic3r::GUI::add_export_option((wxFileDialog*)wxPli_sv_2_object(aTHX_ ui, "Wx::FileDialog"), format); %};
|
||||
|
||||
int get_export_option(SV *ui)
|
||||
%code%{ RETVAL = Slic3r::GUI::get_export_option((wxFileDialog*)wxPli_sv_2_object(aTHX_ ui, "Wx::FileDialog")); %};
|
||||
|
@ -104,10 +104,10 @@
|
||||
|
||||
bool store_stl(char *path, bool binary)
|
||||
%code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %};
|
||||
bool store_amf(char *path, Print* print)
|
||||
%code%{ RETVAL = Slic3r::store_amf(path, THIS, print); %};
|
||||
bool store_3mf(char *path, Print* print)
|
||||
%code%{ RETVAL = Slic3r::store_3mf(path, THIS, print); %};
|
||||
bool store_amf(char *path, Print* print, bool export_print_config)
|
||||
%code%{ RETVAL = Slic3r::store_amf(path, THIS, print, export_print_config); %};
|
||||
bool store_3mf(char *path, Print* print, bool export_print_config)
|
||||
%code%{ RETVAL = Slic3r::store_3mf(path, THIS, print, export_print_config); %};
|
||||
|
||||
%{
|
||||
|
||||
|
@ -9,5 +9,5 @@
|
||||
OctoPrint(DynamicPrintConfig *config);
|
||||
~OctoPrint();
|
||||
|
||||
void send_gcode(int windowId, int completeEvt, int errorEvt, std::string filename, bool print = false) const;
|
||||
bool send_gcode(std::string filename, bool print = false) const;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user