Merge branch 'master' into fs_emboss

# Conflicts:
#	src/slic3r/GUI/GUI_App.cpp
#	tests/libslic3r/test_indexed_triangle_set.cpp
This commit is contained in:
Filip Sykala 2021-12-01 14:35:42 +01:00
commit d698df2c31
117 changed files with 22758 additions and 9292 deletions

View file

@ -13,7 +13,7 @@ prusaslicer_add_cmake_project(wxWidgets
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag}
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip
URL_HASH SHA256=21ed12eb5c215b00999f0374af652be0a6f785df10d18d0dfec8d81ed4abaea3
URL_HASH SHA256=ed36a2159c781cce07b06378664e683ebd8cb2f51914aba9acd3bfca3d63d7d3
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
CMAKE_ARGS
-DwxBUILD_PRECOMP=ON

View file

@ -13,9 +13,21 @@ This guide describes building PrusaSlicer statically against dependencies pulled
#### 0. Prerequisities
CMake, GNU build tools, git and m4 macro processor have to be installed. Unless that's already the case, install them as usual from your distribution packages. E.g. on Ubuntu, run `sudo apt-get install cmake build-essential git m4`. The names of the packages may be different on different distros.
GNU build tools, CMake, git and other libraries have to be installed on the build machine.
Unless that's already the case, install them as usual from your distribution packages.
E.g. on Ubuntu 20.10, run
```shell
sudo apt-get install -y \
git \
build-essential \
autoconf \
cmake \
libglu1-mesa-dev \
libgtk-3-dev \
libdbus-1-dev \
Although most of dependencies are handled by the build script, PrusaSlicer still expects that some libraries will be available in the system (GTK, MESA, gettext). E.g., on Ubuntu, install the required packages by running `sudo apt-get install libgtk-3-dev libglu1-mesa-dev gettext`. The names of the packages may be different on different distros.
```
The names of the packages may be different on different distros.
#### 1. Cloning the repository

View file

@ -192,7 +192,7 @@ documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-
disabled_tags = SLA
[hint:Insert Custom G-code]
text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the documentation.
text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Left-click the layer in the Preview, Right-click the plus icon and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the documentation.
documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer
disabled_tags = SLA
@ -203,8 +203,8 @@ hypertext_type = menubar
hypertext_menubar_menu_name = Configuration
hypertext_menubar_item_name = Configuration Snapshots
[hint:Minimum wall thickness]
text = Minimum wall thickness\nDid you know that instead of the number of top and bottom layers, you can define the<a>Minimum shell thickness</a>in millimeters? This feature is especially useful when using the variable layer height function.
[hint:Minimum shell thickness]
text = Minimum shell thickness\nDid you know that instead of the number of top and bottom layers, you can define the<a>Minimum shell thickness</a>in millimeters? This feature is especially useful when using the variable layer height function.
hypertext_type = settings
hypertext_settings_opt = top_solid_min_thickness
hypertext_settings_type = 1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,7 @@
min_slic3r_version = 2.4.0-beta0
min_slic3r_version = 2.4.0-beta2
1.4.0-beta3 Added material profiles for Prusament Resins.
1.4.0-beta2 Added SLA material colors. Updated BASF filament profiles.
min_slic3r_version = 2.4.0-beta0
1.4.0-beta1 Updated pad wall slope angle for SLA printers. Updated Filatech Filacarbon profile for Prusa MINI.
1.4.0-beta0 Added multiple Filatech and BASF filament profiles. Added material profiles for SL1S.
min_slic3r_version = 2.4.0-alpha0
@ -16,6 +18,8 @@ min_slic3r_version = 2.4.0-alpha0
1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values.
1.3.0-alpha0 Disabled thick bridges, updated support settings.
min_slic3r_version = 2.3.2-alpha0
1.3.5 Added material profiles for Prusament Resins.
1.3.4 Added material profiles for new Prusament Resins. Added profiles for multiple BASF filaments.
1.3.3 Added multiple profiles for Filatech filaments. Added material profiles for SL1S SPEED. Updated SLA print settings.
1.3.2 Added material profiles for Prusament Resin.
1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).

View file

@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.4.0-beta2
config_version = 1.4.0-beta3
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -2925,7 +2925,6 @@ bridge_fan_speed = 100
filament_type = PET
disable_fan_first_layers = 1
full_fan_speed_layer = 3
filament_notes = "BASF Forward AM Ultrafuse PET\nMaterial profile version 1.0\n\nMaterial Description\nUltrafuse PET is made from a premium PET and prints as easy as PLA, but is much stronger. The filament has a large operating window for printing (temperature vs. speed), so it can be used on every 3D-printer. PET will give you outstanding printing results: a good layer adhesion, a high resolution and it is easy to handle. Ultrafuse PET can be 100% recycled, is watertight and has great colors and finish.\n\nPrinting Recommendations:\nUltrafuse PET can be printed directly onto a clean build plate. For challenging prints, use 3dLac to improve adhesion.\n"
filament_retract_length = 2
filament_retract_speed = 40
@ -4835,7 +4834,47 @@ initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #808080
[sla_material:Prusament Resin Tough Sandstone Model @0.025]
inherits = *common 0.025*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.025]
inherits = *common 0.025*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.025]
inherits = *common 0.025*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.025]
inherits = *common 0.025*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.025]
inherits = *common 0.025*
exposure_time = 4
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Prusa 0.025
[sla_material:Prusa Orange Tough @0.025]
@ -5649,6 +5688,46 @@ material_type = Tough
material_vendor = Prusa Polymers
material_colour = #C0C0C0
[sla_material:Prusament Resin Tough Sandstone Model @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.05]
inherits = *common 0.05*
exposure_time = 6
initial_exposure_time = 35
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Prusa 0.05
[sla_material:Prusa Beige Tough @0.05]
@ -5965,6 +6044,46 @@ material_type = Tough
material_vendor = Prusa Polymers
material_colour = #808080
[sla_material:Prusament Resin Tough Sandstone Model @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.1]
inherits = *common 0.1*
exposure_time = 13
initial_exposure_time = 45
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Prusa 0.1
[sla_material:Prusa Orange Tough @0.1]
@ -6085,6 +6204,46 @@ material_type = Tough
material_vendor = Prusa Polymers
material_colour = #808080
[sla_material:Prusament Resin Tough Sandstone Model @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Made for Prusa 0.025
[sla_material:Prusa Orange Tough @0.025 SL1S]
@ -6331,6 +6490,46 @@ material_type = Tough
material_vendor = Prusa Polymers
material_colour = #808080
[sla_material:Prusament Resin Tough Sandstone Model @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2.4
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Made for Prusa 0.05
[sla_material:Prusa Orange Tough @0.05 SL1S]
@ -6577,6 +6776,46 @@ material_type = Tough
material_vendor = Prusa Polymers
material_colour = #808080
[sla_material:Prusament Resin Tough Sandstone Model @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 3
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F7D190
[sla_material:Prusament Resin Tough Terra Brown @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #7A5C45
[sla_material:Prusament Resin Tough Brick Red @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #B46056
[sla_material:Prusament Resin Tough Grass Green @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #37823F
[sla_material:Prusament Resin Tough Bright Yellow @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
initial_exposure_time = 25
material_type = Tough
material_vendor = Prusa Polymers
material_colour = #F9DB4C
## Made for Prusa 0.1
[sla_material:Prusa Orange Tough @0.1 SL1S]

View file

@ -1,26 +1,7 @@
#version 110
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
const vec3 GREEN = vec3(0.0, 0.7, 0.0);
const vec3 YELLOW = vec3(0.5, 0.7, 0.0);
const vec3 RED = vec3(0.7, 0.0, 0.0);
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
const float EPSILON = 0.0001;
const float BANDS_WIDTH = 10.0;
struct PrintVolumeDetection
{

View file

@ -595,6 +595,19 @@ int CLI::run(int argc, char **argv)
if (start_gui) {
#ifdef SLIC3R_GUI
#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux / unix system
const char *display = boost::nowide::getenv("DISPLAY");
// const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY");
//if (! ((display && *display) || (wayland_display && *wayland_display))) {
if (! (display && *display)) {
// DISPLAY not set.
boost::nowide::cerr << "DISPLAY not set, GUI mode not available." << std::endl << std::endl;
this->print_help(false);
// Indicate an error.
return 1;
}
#endif // some linux / unix system
Slic3r::GUI::GUI_InitParams params;
params.argc = argc;
params.argv = argv;

5
src/fast_float/README.md Normal file
View file

@ -0,0 +1,5 @@
**The fast_float library provides fast header-only implementations for the C++ from_chars functions for float and double types.**
For more information go to https://github.com/fastfloat/fast_float.
THIS DIRECTORY CONTAINS THE fast_float-2.0.0 fe1ce58 SOURCE DISTRIBUTION.

View file

@ -126,7 +126,7 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print,
return top_level_objects_with_brim;
}
static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim)
static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim, const double scaled_resolution)
{
Polygons islands;
for (const PrintObject *object : top_level_objects_with_brim) {
@ -139,7 +139,7 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev
for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) {
Polygons contour_offset = offset(ex_poly.contour, brim_separation, ClipperLib::jtSquare);
for (Polygon &poly : contour_offset)
poly.douglas_peucker(SCALED_RESOLUTION);
poly.douglas_peucker(scaled_resolution);
polygons_append(islands_object, std::move(contour_offset));
}
@ -359,13 +359,14 @@ static void make_inner_brim(const Print &print,
ExtrusionEntityCollection &brim)
{
assert(print.objects().size() == bottom_layers_expolygons.size());
const auto scaled_resolution = scaled<double>(print.config().gcode_resolution.value);
Flow flow = print.brim_flow();
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
Polygons loops;
islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare);
for (size_t i = 0; !islands_ex.empty(); ++i) {
for (ExPolygon &poly_ex : islands_ex)
poly_ex.douglas_peucker(SCALED_RESOLUTION);
poly_ex.douglas_peucker(scaled_resolution);
polygons_append(loops, to_polygons(islands_ex));
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), ClipperLib::jtSquare);
}
@ -380,10 +381,11 @@ static void make_inner_brim(const Print &print,
// Collect islands_area to be merged into the final 1st layer convex hull.
ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cancel, Polygons &islands_area)
{
const auto scaled_resolution = scaled<double>(print.config().gcode_resolution.value);
Flow flow = print.brim_flow();
std::vector<ExPolygons> bottom_layers_expolygons = get_print_bottom_layers_expolygons(print);
ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons);
Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim);
Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim, scaled_resolution);
ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
islands_area = to_polygons(islands_area_ex);
@ -393,7 +395,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
try_cancel();
islands = expand(islands, float(flow.scaled_spacing()), ClipperLib::jtSquare);
for (Polygon &poly : islands)
poly.douglas_peucker(SCALED_RESOLUTION);
poly.douglas_peucker(scaled_resolution);
polygons_append(loops, shrink(islands, 0.5f * float(flow.scaled_spacing())));
}
loops = union_pt_chained_outside_in(loops);

View file

@ -269,15 +269,17 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con
return inside ? (outside ? BuildVolume::ObjectState::Colliding : BuildVolume::ObjectState::Inside) : BuildVolume::ObjectState::Outside;
}
BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set &its, const Transform3f &trafo, bool may_be_below_bed) const
BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& its, const Transform3f& trafo, bool may_be_below_bed, bool ignore_bottom) const
{
switch (m_type) {
case Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon);
BoundingBox3Base<Vec3f> build_volumef(build_volume.min.cast<float>(), build_volume.max.cast<float>());
if (m_max_print_height == 0)
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
BoundingBox3Base<Vec3f> build_volumef(build_volume.min.cast<float>(), build_volume.max.cast<float>());
// The following test correctly interprets intersection of a non-convex object with a rectangular build volume.
//return rectangle_test(its, trafo, to_2d(build_volume.min), to_2d(build_volume.max), build_volume.max.z());
//FIXME This test does NOT correctly interprets intersection of a non-convex object with a rectangular build volume.
@ -286,14 +288,14 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set &i
case Type::Circle:
{
Geometry::Circlef circle { unscaled<float>(m_circle.center), unscaled<float>(m_circle.radius + SceneEpsilon) };
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
object_state_templ(its, trafo, may_be_below_bed, [circle](const Vec3f &pt) { return circle.contains(to_2d(pt)); }) :
object_state_templ(its, trafo, may_be_below_bed, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); });
}
case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom:
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
object_state_templ(its, trafo, may_be_below_bed, [this](const Vec3f &pt) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); }) :
object_state_templ(its, trafo, may_be_below_bed, [this, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); });
case Type::Invalid:
@ -302,18 +304,20 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set &i
}
}
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 &volume_bbox) const
BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& volume_bbox, bool ignore_bottom) const
{
assert(m_type == Type::Rectangle);
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon);
if (m_max_print_height == 0)
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below :
build_volume.contains(volume_bbox) ? ObjectState::Inside :
build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside;
}
bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const BoundingBoxf3 &paths_bbox) const
bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const
{
auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) {
return move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.f && move.height != 0.f;
@ -324,8 +328,10 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const Boun
case Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(epsilon);
if (m_max_print_height == 0)
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.contains(paths_bbox);
}
case Type::Circle:
@ -333,7 +339,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const Boun
const Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + epsilon;
const float r2 = sqr(r);
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || (to_2d(move.position) - c).squaredNorm() <= r2; }) :
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex& move)
@ -342,7 +348,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const Boun
case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom:
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast<double>()); }) :
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex &move)
@ -364,7 +370,7 @@ inline bool all_inside_vertices_normals_interleaved(const std::vector<float> &pa
return true;
}
bool BuildVolume::all_paths_inside_vertices_and_normals_interleaved(const std::vector<float> &paths, const Eigen::AlignedBox<float, 3> &paths_bbox) const
bool BuildVolume::all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& paths_bbox, bool ignore_bottom) const
{
assert(paths.size() % 6 == 0);
static constexpr const double epsilon = BedEpsilon;
@ -372,8 +378,10 @@ bool BuildVolume::all_paths_inside_vertices_and_normals_interleaved(const std::v
case Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(epsilon);
if (m_max_print_height == 0)
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.contains(paths_bbox.min().cast<double>()) && build_volume.contains(paths_bbox.max().cast<double>());
}
case Type::Circle:
@ -381,14 +389,14 @@ bool BuildVolume::all_paths_inside_vertices_and_normals_interleaved(const std::v
const Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + float(epsilon);
const float r2 = sqr(r);
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
all_inside_vertices_normals_interleaved(paths, [c, r2](Vec3f p) { return (to_2d(p) - c).squaredNorm() <= r2; }) :
all_inside_vertices_normals_interleaved(paths, [c, r2, z = m_max_print_height + epsilon](Vec3f p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; });
}
case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom:
return m_max_print_height == 0 ?
return m_max_print_height == 0.0 ?
all_inside_vertices_normals_interleaved(paths, [this](Vec3f p) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(p).cast<double>()); }) :
all_inside_vertices_normals_interleaved(paths, [this, z = m_max_print_height + epsilon](Vec3f p) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(p).cast<double>()) && p.z() <= z; });
default:

View file

@ -80,19 +80,19 @@ public:
// Called by Plater to update Inside / Colliding / Outside state of ModelObjects before slicing.
// Called from Model::update_print_volume_state() -> ModelObject::update_instances_print_volume_state()
// Using SceneEpsilon
ObjectState object_state(const indexed_triangle_set &its, const Transform3f &trafo, bool may_be_below_bed) const;
ObjectState object_state(const indexed_triangle_set &its, const Transform3f &trafo, bool may_be_below_bed, bool ignore_bottom = true) const;
// Called by GLVolumeCollection::check_outside_state() after an object is manipulated with gizmos for example.
// Called for a rectangular bed:
ObjectState volume_state_bbox(const BoundingBoxf3 &volume_bbox) const;
ObjectState volume_state_bbox(const BoundingBoxf3& volume_bbox, bool ignore_bottom = true) const;
// 2) Test called on G-code paths.
// Using BedEpsilon for all tests.
static constexpr const double BedEpsilon = 3. * EPSILON;
// Called on final G-code paths.
//FIXME The test does not take the thickness of the extrudates into account!
bool all_paths_inside(const GCodeProcessorResult &paths, const BoundingBoxf3 &paths_bbox) const;
bool all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom = true) const;
// Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices.
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float> &paths, const Eigen::AlignedBox<float, 3> &bbox) const;
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
private:
// Source definition of the print bed geometry (PrintConfig::bed_shape)

View file

@ -293,7 +293,7 @@ set(CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE ON CACHE BOOL "" FORCE)
cmake_policy(PUSH)
cmake_policy(SET CMP0011 NEW)
find_package(CGAL 4.13.2 REQUIRED)
find_package(CGAL 4.13 REQUIRED)
cmake_policy(POP)
add_library(libslic3r_cgal STATIC MeshBoolean.hpp MeshBoolean.cpp

View file

@ -740,11 +740,7 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
}
// Load the config keys from the given string.
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
#else
static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{
if (str == nullptr)
return 0;

View file

@ -2017,9 +2017,7 @@ public:
// Set all the nullable values to nils.
void null_nullables();
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
private:
// Set a configuration value from a string.

View file

@ -116,6 +116,7 @@ std::optional<Emboss::Glyph> Private::get_glyph(
Emboss::Glyphs & cache,
std::optional<stbtt_fontinfo> &font_info_opt)
{
const double RESOLUTION = 0.0125; // TODO: read from printer configuration
auto glyph_item = cache.find(unicode);
if (glyph_item != cache.end())
return glyph_item->second;
@ -125,7 +126,6 @@ std::optional<Emboss::Glyph> Private::get_glyph(
// can load font info?
if (!font_info_opt.has_value()) return {};
}
float flatness = static_cast<float>(
font.ascent * RESOLUTION / font_prop.size_in_mm);
std::optional<Emboss::Glyph> glyph_opt =

View file

@ -329,7 +329,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
const auto resolution = this->object()->print()->config().gcode_resolution.value;
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
@ -371,6 +372,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.dont_adjust = false; // surface_fill.params.dont_adjust;
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
for (ExPolygon &expoly : surface_fill.expolygons) {
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.

View file

@ -44,6 +44,9 @@ struct FillParams
float anchor_length { 1000.f };
float anchor_length_max { 1000.f };
// G-code resolution.
double resolution { 0.0125 };
// Don't adjust spacing to fill the space evenly.
bool dont_adjust { true };

View file

@ -31,7 +31,8 @@ void FillPlanePath::_fill_surface_single(
coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)));
coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)),
params.resolution);
if (pts.size() >= 2) {
// Convert points to a polyline, upscale.
@ -58,7 +59,7 @@ void FillPlanePath::_fill_surface_single(
}
// Follow an Archimedean spiral, in polar coordinates: r=a+b\theta
Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution)
{
// Radius to achieve.
coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5;
@ -72,8 +73,8 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m
out.emplace_back(0, 0);
out.emplace_back(1, 0);
while (r < rmax) {
// Discretization angle to achieve a discretization error lower than RESOLUTION.
theta += 2. * acos(1. - RESOLUTION / r);
// Discretization angle to achieve a discretization error lower than resolution.
theta += 2. * acos(1. - resolution / r);
r = a + b * theta;
out.emplace_back(r * cos(theta), r * sin(theta));
}
@ -125,7 +126,7 @@ static inline Point hilbert_n_to_xy(const size_t n)
return Point(x, y);
}
Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */)
{
// Minimum power of two square to fit the domain.
size_t sz = 2;
@ -148,7 +149,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x,
return line;
}
Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */)
{
// Radius to achieve.
coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5;

View file

@ -28,7 +28,7 @@ protected:
float _layer_angle(size_t idx) const override { return 0.f; }
virtual bool _centered() const = 0;
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) = 0;
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) = 0;
};
class FillArchimedeanChords : public FillPlanePath
@ -39,7 +39,7 @@ public:
protected:
bool _centered() const override { return true; }
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override;
};
class FillHilbertCurve : public FillPlanePath
@ -50,7 +50,7 @@ public:
protected:
bool _centered() const override { return false; }
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override;
};
class FillOctagramSpiral : public FillPlanePath
@ -61,7 +61,7 @@ public:
protected:
bool _centered() const override { return true; }
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override;
};
} // namespace Slic3r

View file

@ -2777,16 +2777,10 @@ namespace Slic3r {
bool _3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items)
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
// This happens for empty projects
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (build_items.size() == 0) {
add_error("No build item found");
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return true;
#else
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
stream << " <" << BUILD_TAG << ">\n";

View file

@ -1544,30 +1544,37 @@ void GCode::process_layers(
const size_t single_object_idx,
GCodeOutputStream &output_stream)
{
// The pipeline is fixed: Neither wipe tower nor vase mode are implemented for sequential print.
// The pipeline is variable: The vase mode filter is optional.
size_t layer_to_print_idx = 0;
tbb::parallel_pipeline(12,
tbb::make_filter<void, GCode::LayerResult>(
tbb::filter::serial_in_order,
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
if (layer_to_print_idx == layers_to_print.size()) {
fc.stop();
return {};
} else {
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
print.throw_if_canceled();
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
}
}) &
tbb::make_filter<GCode::LayerResult, std::string>(
tbb::filter::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
}) &
tbb::make_filter<std::string, void>(
tbb::filter::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
));
const auto generator = tbb::make_filter<void, GCode::LayerResult>(tbb::filter::serial_in_order,
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
if (layer_to_print_idx == layers_to_print.size()) {
fc.stop();
return {};
} else {
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
print.throw_if_canceled();
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
}
});
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(tbb::filter::serial_in_order,
[&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in)->GCode::LayerResult {
spiral_vase.enable(in.spiral_vase_enable);
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
});
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(tbb::filter::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in)->std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto output = tbb::make_filter<std::string, void>(tbb::filter::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
);
// The pipeline elements are joined using const references, thus no copying is performed.
if (m_spiral_vase)
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
else
tbb::parallel_pipeline(12, generator & cooling & output);
}
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
@ -2407,6 +2414,7 @@ void GCode::apply_print_config(const PrintConfig &print_config)
{
m_writer.apply_print_config(print_config);
m_config.apply(print_config);
m_scaled_resolution = scaled<double>(print_config.gcode_resolution.value);
}
void GCode::append_full_config(const Print &print, std::string &str)
@ -2558,7 +2566,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
// description += ExtrusionLoop::role_to_string(loop.loop_role());
// description += ExtrusionEntity::role_to_string(path->role);
path->simplify(SCALED_RESOLUTION);
path->simplify(m_scaled_resolution);
gcode += this->_extrude(*path, description, speed);
}
@ -2612,7 +2620,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string
for (ExtrusionPath path : multipath.paths) {
// description += ExtrusionLoop::role_to_string(loop.loop_role());
// description += ExtrusionEntity::role_to_string(path->role);
path.simplify(SCALED_RESOLUTION);
path.simplify(m_scaled_resolution);
gcode += this->_extrude(path, description, speed);
}
if (m_wipe.enable) {
@ -2640,7 +2648,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string des
std::string GCode::extrude_path(ExtrusionPath path, std::string description, double speed)
{
// description += ExtrusionEntity::role_to_string(path.role());
path.simplify(SCALED_RESOLUTION);
path.simplify(m_scaled_resolution);
std::string gcode = this->_extrude(path, description, speed);
if (m_wipe.enable) {
m_wipe.path = std::move(path.polyline);

View file

@ -345,6 +345,8 @@ private:
methods. */
Vec2d m_origin;
FullPrintConfig m_config;
// scaled G-code resolution
double m_scaled_resolution;
GCodeWriter m_writer;
PlaceholderParser m_placeholder_parser;
// For random number generator etc.

View file

@ -748,9 +748,7 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
{ EProducer::PrusaSlicer, "generated by PrusaSlicer" },
{ EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
{ EProducer::Slic3r, "generated by Slic3r" },
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::SuperSlicer, "generated by SuperSlicer" },
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::Cura, "Cura_SteamEngine" },
{ EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
{ EProducer::CraftWare, "CraftWare" },
@ -813,9 +811,7 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
}
GCodeProcessor::GCodeProcessor()
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
: m_options_z_corrector(m_result)
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
{
reset();
m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n";
@ -1179,9 +1175,7 @@ void GCodeProcessor::reset()
m_use_volumetric_e = false;
m_last_default_color_id = 0;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.reset();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_mm3_per_mm_compare.reset();
@ -1238,10 +1232,8 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
}
else if (m_producer == EProducer::Simplify3D)
apply_config_simplify3d(filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
else if (m_producer == EProducer::SuperSlicer)
apply_config_superslicer(filename);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
}
// process gcode
@ -1375,7 +1367,6 @@ std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(Prin
return ret;
}
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// for reference, see: ConfigBase::load_from_gcode_file()
@ -1408,7 +1399,6 @@ void GCodeProcessor::apply_config_superslicer(const std::string& filename)
load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config);
}
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
{
@ -1845,9 +1835,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Color_change);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::ColorChange);
process_filaments(CustomGCode::ColorChange);
}
@ -1860,9 +1848,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Pause_Print);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::PausePrint);
return;
}
@ -1872,9 +1858,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Custom_GCode);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
return;
}
@ -1900,9 +1884,7 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{
case EProducer::Slic3rPE:
case EProducer::Slic3r:
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::SuperSlicer:
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
@ -2455,12 +2437,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_forced_height > 0.0f)
m_height = m_forced_height;
else {
if (m_end_position[Z] > m_extruded_last_z + EPSILON) {
if (m_end_position[Z] > m_extruded_last_z + EPSILON)
m_height = m_end_position[Z] - m_extruded_last_z;
#if !ENABLE_FIX_PREVIEW_OPTIONS_Z
m_extruded_last_z = m_end_position[Z];
#endif // !ENABLE_FIX_PREVIEW_OPTIONS_Z
}
}
if (m_height == 0.0f)
@ -2469,10 +2447,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_end_position[Z] == 0.0f)
m_end_position[Z] = m_height;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_extruded_last_z = m_end_position[Z];
m_options_z_corrector.update(m_height);
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role);

View file

@ -389,7 +389,6 @@ namespace Slic3r {
bool has_first_vertex() const { return m_first_vertex.has_value(); }
};
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
// Helper class used to fix the z for color change, pause print and
// custom gcode markes
class OptionsZCorrector
@ -426,7 +425,6 @@ namespace Slic3r {
m_custom_gcode_per_print_z_id.reset();
}
};
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
struct DataChecker
@ -532,9 +530,7 @@ namespace Slic3r {
CpColor m_cp_color;
bool m_use_volumetric_e;
SeamsDetector m_seams_detector;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
OptionsZCorrector m_options_z_corrector;
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
size_t m_last_default_color_id;
#if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
@ -546,9 +542,7 @@ namespace Slic3r {
PrusaSlicer,
Slic3rPE,
Slic3r,
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
SuperSlicer,
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
Cura,
Simplify3D,
CraftWare,
@ -605,9 +599,7 @@ namespace Slic3r {
private:
void apply_config(const DynamicPrintConfig& config);
void apply_config_simplify3d(const std::string& filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void apply_config_superslicer(const std::string& filename);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
// Process tags embedded into comments

View file

@ -2,6 +2,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/format.hpp"
#include "libslic3r/I18N.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
@ -184,6 +185,11 @@ static int run_script(const std::string &script, const std::string &gcode, std::
namespace Slic3r {
//! macro used to mark string used at localization,
//! return same string
#define L(s) (s)
#define _(s) Slic3r::I18N::translate(s)
// Run post processing script / scripts if defined.
// Returns true if a post-processing script was executed.
// Returns false if no post-processing script was defined.
@ -278,6 +284,15 @@ bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::
delete_copy();
throw Slic3r::RuntimeError(msg);
}
if (! boost::filesystem::exists(gcode_file)) {
const std::string msg = (boost::format(_(L(
"Post-processing script %1% failed.\n\n"
"The post-processing script is expected to change the G-code file %2% in place, but the G-code file was deleted and likely saved under a new name.\n"
"Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n")))
% script % path).str();
BOOST_LOG_TRIVIAL(error) << msg;
throw Slic3r::RuntimeError(msg);
}
}
}
if (boost::filesystem::exists(path_output_name)) {

View file

@ -160,13 +160,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
if (!result)
throw Slic3r::RuntimeError("Loading of a model file failed.");
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (model.objects.empty())
throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty");
#endif // !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
for (ModelObject *o : model.objects)
{
for (ModelObject *o : model.objects) {
// if (boost::algorithm::iends_with(input_file, ".zip.amf"))
// {
// // we remove the .zip part of the extension to avoid it be added to filenames when exporting

View file

@ -322,7 +322,7 @@ void PerimeterGenerator::process()
for (const Surface &surface : this->slices->surfaces) {
// detect how many perimeters must be generated for this island
int loop_number = this->config->perimeters + surface.extra_perimeters - 1; // 0-indexed loops
ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION));
ExPolygons last = union_ex(surface.expolygon.simplify_p(m_scaled_resolution));
ExPolygons gaps;
if (loop_number >= 0) {
// In case no perimeters are to be generated, loop_number will equal to -1.
@ -533,7 +533,7 @@ void PerimeterGenerator::process()
// simplify infill contours according to resolution
Polygons pp;
for (ExPolygon &ex : last)
ex.simplify_p(SCALED_RESOLUTION, &pp);
ex.simplify_p(m_scaled_resolution, &pp);
// collapse too narrow infill areas
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
// append infill areas to fill_surfaces

View file

@ -50,6 +50,7 @@ public:
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_vase),
m_scaled_resolution(scaled<double>(print_config->gcode_resolution.value)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1)
{}
@ -63,6 +64,7 @@ public:
private:
bool m_spiral_vase;
double m_scaled_resolution;
double m_ext_mm3_per_mm;
double m_mm3_per_mm;
double m_mm3_per_mm_overhang;

View file

@ -444,7 +444,7 @@ static std::vector<std::string> s_Preset_print_options {
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects",
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits"
};

View file

@ -214,7 +214,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
} else if (
opt_key == "first_layer_extrusion_width"
|| opt_key == "min_layer_height"
|| opt_key == "max_layer_height") {
|| opt_key == "max_layer_height"
|| opt_key == "gcode_resolution") {
osteps.emplace_back(posPerimeters);
osteps.emplace_back(posInfill);
osteps.emplace_back(posSupportMaterial);

View file

@ -613,13 +613,25 @@ const PrintObjectRegions::BoundingBox* find_volume_extents(const PrintObjectRegi
}
// Find a bounding box of a topmost printable volume referenced by this modifier given this_region_id.
const PrintObjectRegions::BoundingBox* find_modifier_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const int this_region_id)
PrintObjectRegions::BoundingBox find_modifier_volume_extents(const PrintObjectRegions::LayerRangeRegions &layer_range, const int this_region_id)
{
// Find the top-most printable volume of this modifier, or the printable volume itself.
int parent_region_id = this_region_id;
for (; ! layer_range.volume_regions[parent_region_id].model_volume->is_model_part(); parent_region_id = layer_range.volume_regions[parent_region_id].parent)
assert(parent_region_id >= 0);
return find_volume_extents(layer_range, *layer_range.volume_regions[parent_region_id].model_volume);
const PrintObjectRegions::VolumeRegion &this_region = layer_range.volume_regions[this_region_id];
const PrintObjectRegions::BoundingBox *this_extents = find_volume_extents(layer_range, *this_region.model_volume);
assert(this_extents);
PrintObjectRegions::BoundingBox out { *this_extents };
if (! this_region.model_volume->is_model_part())
for (int parent_region_id = this_region.parent;;) {
assert(parent_region_id >= 0);
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
const PrintObjectRegions::BoundingBox *parent_extents = find_volume_extents(layer_range, *parent_region.model_volume);
assert(parent_extents);
out.extend(*parent_extents);
if (parent_region.model_volume->is_model_part())
break;
parent_region_id = parent_region.parent;
}
return out;
}
PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_or_parent_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders);
@ -662,11 +674,10 @@ bool verify_update_print_object_regions(
// if the visited modifier did not modify their properties. Now the visited modifier's configuration may have changed,
// which may require new regions to be created.
it_model_volume_modifier_last = it_model_volume;
int this_region_id = int(&region - layer_range.volume_regions.data());
int next_region_id = this_region_id + 1;
int next_region_id = int(&region - layer_range.volume_regions.data());
const PrintObjectRegions::BoundingBox *bbox = find_volume_extents(layer_range, *region.model_volume);
assert(bbox);
for (int parent_region_id = this_region_id - 1; parent_region_id >= 0; -- parent_region_id) {
for (int parent_region_id = next_region_id - 1; parent_region_id >= 0; -- parent_region_id) {
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
assert(parent_region.model_volume != region.model_volume);
if (parent_region.model_volume->is_model_part() || parent_region.model_volume->is_modifier()) {
@ -680,17 +691,13 @@ bool verify_update_print_object_regions(
layer_range.volume_regions[next_region_id].parent == parent_region_id) {
// A parent region is already overridden.
++ next_region_id;
} else {
} else if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox))
// Such parent region does not exist. If it is needed, then we need to reslice.
const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id);
assert(parent_bbox != nullptr);
if (parent_bbox->intersects(*bbox))
// Only create new region for a modifier, which actually modifies config of it's parent.
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders);
config != parent_region.region->config())
// This modifier newly overrides a region, which it did not before. We need to reslice.
return false;
}
// Only create new region for a modifier, which actually modifies config of it's parent.
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders);
config != parent_region.region->config())
// This modifier newly overrides a region, which it did not before. We need to reslice.
return false;
}
}
}
@ -912,10 +919,8 @@ static PrintObjectRegions* generate_print_object_regions(
for (int parent_region_id = int(layer_range.volume_regions.size()) - 1; parent_region_id >= 0; -- parent_region_id) {
const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
const ModelVolume &parent_volume = *parent_region.model_volume;
if (parent_volume.is_model_part() || parent_volume.is_modifier()) {
const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id);
assert(parent_bbox != nullptr);
if (parent_bbox->intersects(*bbox))
if (parent_volume.is_model_part() || parent_volume.is_modifier())
if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) {
// Only create new region for a modifier, which actually modifies config of it's parent.
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders);
config != parent_region.region->config()) {
@ -923,7 +928,7 @@ static PrintObjectRegions* generate_print_object_regions(
layer_range.volume_regions.push_back({ &volume, parent_region_id, get_create_region(std::move(config)), bbox });
} else if (parent_model_part_id == -1 && parent_volume.is_model_part())
parent_model_part_id = parent_region_id;
}
}
}
if (! added && parent_model_part_id >= 0)
// This modifier does not override any printable volume's configuration, however it may in the future.

View file

@ -72,7 +72,8 @@ static t_config_enum_values s_keys_map_PrintHostType {
{ "duet", htDuet },
{ "flashair", htFlashAir },
{ "astrobox", htAstroBox },
{ "repetier", htRepetier }
{ "repetier", htRepetier },
{ "mks", htMKS }
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType)
@ -1854,12 +1855,14 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("flashair");
def->enum_values.push_back("astrobox");
def->enum_values.push_back("repetier");
def->enum_values.push_back("mks");
def->enum_labels.push_back("PrusaLink");
def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir");
def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier");
def->enum_labels.push_back("MKS");
def->mode = comAdvanced;
def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));
@ -2069,7 +2072,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInt(0));
def = this->add("resolution", coFloat);
def->label = L("Resolution");
def->label = L("Slice resolution");
def->tooltip = L("Minimum detail resolution, used to simplify the input file for speeding up "
"the slicing job and reducing memory usage. High-resolution models often carry "
"more detail than printers can render. Set to zero to disable any simplification "
@ -2079,6 +2082,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("gcode_resolution", coFloat);
def->label = L("G-code resolution");
def->tooltip = L("Maximum deviation of exported G-code paths from their full resolution counterparts. "
"Very high resolution G-code requires huge amount of RAM to slice and preview, "
"also a 3D printer may stutter not being able to process a high resolution G-code in a timely manner. "
"On the other hand, a low resolution G-code will produce a low poly effect and because "
"the G-code reduction is performed at each layer independently, visible artifacts may be produced.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.0125));
def = this->add("retract_before_travel", coFloats);
def->label = L("Minimum travel after retraction");
def->tooltip = L("Retraction is not triggered when travel moves are shorter than this length.");
@ -2688,7 +2703,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Concentric"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SupportMaterialPattern>(smpRectilinear));
def->set_default_value(new ConfigOptionEnum<SupportMaterialInterfacePattern>(smipRectilinear));
def = this->add("support_material_spacing", coFloat);
def->label = L("Pattern spacing");
@ -3937,6 +3952,10 @@ void DynamicPrintConfig::normalize_fdm()
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0;
}
}
if (auto *opt_gcode_resolution = this->opt<ConfigOptionFloat>("gcode_resolution", false); opt_gcode_resolution)
// Resolution will be above 1um.
opt_gcode_resolution->value = std::max(opt_gcode_resolution->value, 0.001);
}
void handle_legacy_sla(DynamicPrintConfig &config)

View file

@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
};
enum PrintHostType {
htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS
};
enum AuthorizationType {
@ -734,6 +734,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionString, printer_model))
((ConfigOptionString, printer_notes))
((ConfigOptionFloat, resolution))
((ConfigOptionFloat, gcode_resolution))
((ConfigOptionFloats, retract_before_travel))
((ConfigOptionBools, retract_layer_change))
((ConfigOptionFloat, skirt_distance))

View file

@ -379,11 +379,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
int j = i;
bool merged = false;
ExPolygons &expolygons = temp_slices[i].expolygons;
for (++ j;
j < int(temp_slices.size()) &&
temp_slices[i].region_id == temp_slices[j].region_id &&
(clip_multipart_objects || temp_slices[i].volume_id == temp_slices[j].volume_id);
++ j)
for (++ j; j < int(temp_slices.size()) && temp_slices[i].region_id == temp_slices[j].region_id; ++ j)
if (ExPolygons &expolygons2 = temp_slices[j].expolygons; ! expolygons2.empty()) {
if (expolygons.empty()) {
expolygons = std::move(expolygons2);
@ -392,7 +388,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
merged = true;
}
}
if (merged)
// Don't unite the regions if ! clip_multipart_objects. In that case it is user's responsibility
// to handle region overlaps. Indeed, one may intentionally let the regions overlap to produce crossing perimeters
// for example.
if (merged && clip_multipart_objects)
expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
i = j;

View file

@ -2354,8 +2354,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
Polygons &layer_support_area = layer_support_areas[layer_id];
Polygons *layer_buildplate_covered = buildplate_covered.empty() ? nullptr : &buildplate_covered[layer_id];
// Filtering the propagated support columns to two extrusions, overlapping by maximum 20%.
float column_propagation_filtering_radius = scaled<float>(0.8 * 0.5 * (m_support_params.support_material_flow.spacing() + m_support_params.support_material_flow.width()));
task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered, column_propagation_filtering_radius
// float column_propagation_filtering_radius = scaled<float>(0.8 * 0.5 * (m_support_params.support_material_flow.spacing() + m_support_params.support_material_flow.width()));
task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered /* , column_propagation_filtering_radius */
#ifdef SLIC3R_DEBUG
, iRun, layer_id
#endif /* SLIC3R_DEBUG */

View file

@ -36,43 +36,6 @@
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS 1
//====================
// 2.4.0.alpha1 techs
//====================
#define ENABLE_2_4_0_ALPHA1 1
// Enable implementation of retract acceleration in gcode processor
#define ENABLE_RETRACT_ACCELERATION (1 && ENABLE_2_4_0_ALPHA1)
// Enable rendering seams (and other options) in preview using models
#define ENABLE_SEAMS_USING_MODELS (1 && ENABLE_2_4_0_ALPHA1)
// Enable save and save as commands to be enabled also when the plater is empty and allow to load empty projects
#define ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED (1 && ENABLE_2_4_0_ALPHA1)
//====================
// 2.4.0.alpha2 techs
//====================
#define ENABLE_2_4_0_ALPHA2 1
// Enable rendering seams (and other options) in preview using batched models on systems not supporting OpenGL 3.3
#define ENABLE_SEAMS_USING_BATCHED_MODELS (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_2_4_0_ALPHA2)
// Enable fixing the z position of color change, pause print and custom gcode markers in preview
#define ENABLE_FIX_PREVIEW_OPTIONS_Z (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_2_4_0_ALPHA2)
// Enable replacing a missing file during reload from disk command
#define ENABLE_RELOAD_FROM_DISK_REPLACE_FILE (1 && ENABLE_2_4_0_ALPHA2)
// Enable fixing the synchronization of seams with the horizontal slider in preview
#define ENABLE_FIX_SEAMS_SYNCH (1 && ENABLE_2_4_0_ALPHA2)
//====================
// 2.4.0.alpha3 techs
//====================
#define ENABLE_2_4_0_ALPHA3 1
// Enable fixing loading of gcode files generated with SuperSlicer in GCodeViewer
#define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3)
//====================
// 2.4.0.beta1 techs
//====================
@ -91,5 +54,8 @@
// an additional button can be used to set the keyboard focus into the slider
// to allow the user to type in the desired value
#define ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT (1 && ENABLE_2_4_0_BETA2)
// Enable fit print volume command for circular printbeds
#define ENABLE_ENHANCED_PRINT_VOLUME_FIT (1 && ENABLE_2_4_0_BETA2)
#endif // _prusaslicer_technologies_h_

View file

@ -1090,7 +1090,7 @@ indexed_triangle_set its_convex_hull(const std::vector<Vec3f> &pts)
centroid += pt;
centroid /= float(pts.size());
#endif // NDEBUG
for (const orgQhull::QhullFacet facet : qhull.facetList()) {
for (const orgQhull::QhullFacet &facet : qhull.facetList()) {
// Collect face vertices first, allocate unique vertices in dst_vertices based on QHull's vertex ID.
Vec3i indices;
int cnt = 0;

View file

@ -560,9 +560,9 @@ void slice_facet_with_slabs(
// Save the open edge for sure.
type = FacetSliceType::Slicing;
} else {
#ifndef NDEBUG
const stl_triangle_vertex_indices &neighbor = mesh_triangles[neighbor_idx];
float z = *it;
#ifndef NDEBUG
int num_on_plane = (mesh_vertices[neighbor(0)].z() == z) + (mesh_vertices[neighbor(1)].z() == z) + (mesh_vertices[neighbor(2)].z() == z);
assert(num_on_plane == 2 || num_on_plane == 3);
#endif // NDEBUG
@ -1866,9 +1866,13 @@ std::vector<ExPolygons> slice_mesh_ex(
//FIXME simplify
if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour)
keep_largest_contour_only(expolygons);
if (resolution != 0.)
for (ExPolygon &ex : expolygons)
ex.simplify(resolution);
if (resolution != 0.) {
ExPolygons simplified;
simplified.reserve(expolygons.size());
for (const ExPolygon &ex : expolygons)
append(simplified, ex.simplify(resolution));
expolygons = std::move(simplified);
}
}
});
// BOOST_LOG_TRIVIAL(debug) << "slice_mesh make_expolygons in parallel - end";

View file

@ -47,9 +47,6 @@ static constexpr double EPSILON = 1e-4;
// int32_t fits an interval of (-2147.48mm, +2147.48mm)
// with int64_t we don't have to worry anymore about the size of the int.
static constexpr double SCALING_FACTOR = 0.000001;
// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm.
static constexpr double RESOLUTION = 0.0125;
#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
static constexpr double PI = 3.141592653589793238;
// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam.
static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15;

View file

@ -139,7 +139,7 @@ Code flags --
REALfloat = 1 all numbers are 'float' type
= 0 all numbers are 'double' type
*/
#define REALfloat 1
#define REALfloat 0
#if (REALfloat == 1)
#define realT float

View file

@ -245,6 +245,10 @@ set(SLIC3R_GUI_SOURCES
Utils/UndoRedo.hpp
Utils/HexFile.cpp
Utils/HexFile.hpp
Utils/TCPConsole.cpp
Utils/TCPConsole.hpp
Utils/MKS.cpp
Utils/MKS.hpp
)
if (APPLE)
@ -258,7 +262,6 @@ if (APPLE)
GUI/InstanceCheckMac.h
)
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
endif ()
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
@ -267,8 +270,12 @@ encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (MSVC)
target_link_libraries(libslic3r_gui Setupapi.lib)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
elseif (APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()
if (SLIC3R_STATIC)
@ -277,10 +284,6 @@ if (SLIC3R_STATIC)
target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0)
endif()
if(APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif()
if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL AND UNIX AND NOT APPLE)
target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE)
endif ()

View file

@ -174,7 +174,7 @@ bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, c
}
if (m_build_volume.bed_shape() == bed_shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
if (m_build_volume.bed_shape() == bed_shape && m_build_volume.max_print_height() == max_print_height && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
// No change, no need to update the UI.
return false;

View file

@ -167,7 +167,12 @@ int BitmapComboBox::Append(const wxString& item)
//3. Set this empty bitmap to the at list one item and BitmapCombobox will be recreated correct
wxBitmap bitmap(1, int(1.6 * wxGetApp().em_unit() + 1));
bitmap.SetWidth(0);
{
// bitmap.SetWidth(0); is depricated now
// so, use next code
bitmap.UnShare();// AllocExclusive();
bitmap.GetGDIImageData()->m_width = 0;
}
OnAddBitmap(bitmap);
const int n = wxComboBox::Append(item);

View file

@ -21,7 +21,13 @@ void ButtonsDescription::FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWi
ScalableBitmap bmp_delete_focus = ScalableBitmap(parent, "cross_focus");
auto add_color = [grid_sizer, parent](wxColourPickerCtrl** color_picker, const wxColour& color, const wxColour& def_color, wxString label_text) {
//
// wrap the label_text to the max 80 characters
if (label_text.Len() > 80) {
size_t brack_pos = label_text.find_last_of(" ", 79);
if (brack_pos > 0 && brack_pos < 80)
label_text.insert(brack_pos + 1, "\n");
}
auto sys_label = new wxStaticText(parent, wxID_ANY, label_text);
sys_label->SetForegroundColour(color);

View file

@ -162,8 +162,8 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_bool("support_material")) {
// Ask only once.
if (!support_material_overhangs_queried) {
support_material_overhangs_queried = true;
if (!m_support_material_overhangs_queried) {
m_support_material_overhangs_queried = true;
if (!config->opt_bool("overhangs")/* != 1*/) {
wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n"
"- Detect bridging perimeters"));
@ -182,7 +182,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
}
}
else {
support_material_overhangs_queried = false;
m_support_material_overhangs_queried = false;
}
if (config->option<ConfigOptionPercent>("fill_density")->value == 100) {

View file

@ -17,15 +17,12 @@ class ModelConfig;
namespace GUI {
// This variable have to be static because of use its value from Preset configuration
// and from object/parts configuration from the Settings in sidebar
static bool support_material_overhangs_queried {false};
class ConfigManipulation
{
bool is_msg_dlg_already_exist{ false };
bool m_is_initialized_support_material_overhangs_queried{ false };
bool m_support_material_overhangs_queried{ false };
// function to loading of changed configuration
std::function<void()> load_config = nullptr;
@ -66,7 +63,7 @@ public:
void initialize_support_material_overhangs_queried(bool queried)
{
m_is_initialized_support_material_overhangs_queried = true;
support_material_overhangs_queried = queried;
m_support_material_overhangs_queried = queried;
}
};

View file

@ -2713,7 +2713,9 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
// if unsaved changes was not cheched till this moment
if (!check_unsaved_preset_changes) {
if ((check_unsaved_preset_changes = !first_added_filament.empty() || !first_added_sla_material.empty())) {
header = format_wxstr(_L("A new %1% was installed and it will be activated."), !first_added_filament.empty() ? _L("Filament") : _L("SLA material"));
header = !first_added_filament.empty() ?
_L("A new filament was installed and it will be activated.") :
_L("A new SLA material was installed and it will be activated.");
if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
return false;
}
@ -2721,7 +2723,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
bool is_filaments_changed = app_config->get_section(AppConfig::SECTION_FILAMENTS) != appconfig_new.get_section(AppConfig::SECTION_FILAMENTS);
bool is_sla_materials_changed = app_config->get_section(AppConfig::SECTION_MATERIALS) != appconfig_new.get_section(AppConfig::SECTION_MATERIALS);
if ((check_unsaved_preset_changes = is_filaments_changed || is_sla_materials_changed)) {
header = format_wxstr(_L("Some %1% were uninstalled."), is_filaments_changed ? _L("Filaments") : _L("SLA materials"));
header = is_filaments_changed ? _L("Some filaments were uninstalled.") : _L("Some SLA materials were uninstalled.");
if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
return false;
}

View file

@ -26,6 +26,7 @@
#include <cmath>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <random>
#include "Field.hpp"
#include "format.hpp"
@ -1406,8 +1407,8 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist
{
if (m_draw_mode == dmSequentialFffPrint)
return _L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.\n");
return (_L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.") + "\n");
// Show mode as a first string of tooltop
tooltip = " " + _L("Print mode") + ": ";
@ -1446,6 +1447,18 @@ wxString Control::get_tooltip(int tick/*=-1*/)
std::string space = " ";
tooltip = space;
auto format_gcode = [space](std::string gcode) {
// when the tooltip is too long, it starts to flicker, see: https://github.com/prusa3d/PrusaSlicer/issues/7368
// so we limit the number of lines shown
std::vector<std::string> lines;
boost::split(lines, gcode, boost::is_any_of("\n"), boost::token_compress_off);
static const size_t MAX_LINES = 10;
if (lines.size() > MAX_LINES) {
gcode = lines.front() + '\n';
for (size_t i = 1; i < MAX_LINES; ++i) {
gcode += lines[i] + '\n';
}
gcode += "[" + into_u8(_L("continue")) + "]\n";
}
boost::replace_all(gcode, "\n", "\n" + space);
return gcode;
};

View file

@ -115,7 +115,7 @@ class TickCodeInfo
bool m_suppress_plus = false;
bool m_suppress_minus = false;
bool m_use_default_colors= false;
int m_default_color_idx = 0;
// int m_default_color_idx = 0;
std::vector<std::string>* m_colors {nullptr};

View file

@ -3,6 +3,7 @@
#include "GUI.hpp"
#include "I18N.hpp"
#include "BitmapComboBox.hpp"
#include "Plater.hpp"
#include <wx/dc.h>
#ifdef wxHAS_GENERIC_DATAVIEWCTRL
@ -222,14 +223,9 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
if (!text_editor || text_editor->GetValue().IsEmpty())
return false;
std::string chosen_name = into_u8(text_editor->GetValue());
const char* unusable_symbols = "<>:/\\|?*\"";
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
if (chosen_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
m_was_unusable_symbol = true;
return false;
}
}
m_was_unusable_symbol = Slic3r::GUI::Plater::has_illegal_filename_characters(text_editor->GetValue());
if (m_was_unusable_symbol)
return false;
// The icon can't be edited so get its old value and reuse it.
wxVariant valueOld;

View file

@ -316,7 +316,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
}
else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > /*1*/m_opt.max_literal)) &&
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
(m_value.empty() || into_u8(str) != boost::any_cast<std::string>(m_value)))
{
if (!check_value) {
m_value.clear();
@ -340,7 +340,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
}
}
m_value = std::string(str.ToUTF8().data());
m_value = into_u8(str);
break; }
case coPoints: {
@ -1286,7 +1286,7 @@ void Choice::msw_rescale()
size_t counter = 0;
bool labels = ! m_opt.enum_labels.empty();
for (const std::string &el : labels ? m_opt.enum_labels : m_opt.enum_values) {
wxString text = labels ? _(el) : wxString::FromUTF8(el.c_str());
wxString text = labels ? _(el) : from_u8(el);
field->Append(text);
if (text == selection)
idx = counter;
@ -1574,7 +1574,7 @@ void StaticText::BUILD()
if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit);
if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit);
const wxString legend = wxString::FromUTF8(m_opt.get_default_value<ConfigOptionString>()->value.c_str());
const wxString legend = from_u8(m_opt.get_default_value<ConfigOptionString>()->value);
auto temp = new wxStaticText(m_parent, wxID_ANY, legend, wxDefaultPosition, size, wxST_ELLIPSIZE_MIDDLE);
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);

View file

@ -89,7 +89,6 @@ void GCodeViewer::VBuffer::reset()
count = 0;
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::InstanceVBuffer::Ranges::reset()
{
for (Range& range : ranges) {
@ -107,7 +106,6 @@ void GCodeViewer::InstanceVBuffer::reset()
buffer.clear();
render_ranges.reset();
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::IBuffer::reset()
{
@ -150,12 +148,10 @@ bool GCodeViewer::Path::matches(const GCodeProcessorResult::MoveVertex& move) co
}
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::TBuffer::Model::reset()
{
instances.reset();
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::TBuffer::reset()
{
@ -167,9 +163,7 @@ void GCodeViewer::TBuffer::reset()
indices.clear();
paths.clear();
render_paths.clear();
#if ENABLE_SEAMS_USING_MODELS
model.reset();
#endif // ENABLE_SEAMS_USING_MODELS
}
void GCodeViewer::TBuffer::add_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id)
@ -270,12 +264,8 @@ void GCodeViewer::SequentialView::Marker::render() const
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Tool position") + ":");
ImGui::SameLine();
char buf[1024];
#if ENABLE_FIX_SEAMS_SYNCH
const Vec3f position = m_world_position + m_world_offset;
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z());
#else
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", m_world_position.x(), m_world_position.y(), m_world_position.z());
#endif // ENABLE_FIX_SEAMS_SYNCH
imgui.text(std::string(buf));
// force extra frame to automatically update window size
@ -567,48 +557,11 @@ const GCodeViewer::Color GCodeViewer::Neutral_Color = { 0.25f, 0.25f, 0.25f, 1.0
GCodeViewer::GCodeViewer()
{
#if !ENABLE_SEAMS_USING_MODELS
// initializes non OpenGL data of TBuffers
// OpenGL data are initialized into render().init_gl_data()
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
switch (buffer_type(i))
{
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
break;
}
case EMoveType::Travel: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line;
buffer.vertices.format = VBuffer::EFormat::PositionNormal1;
break;
}
}
}
set_toolpath_move_type_visible(EMoveType::Extrude, true);
#endif // !ENABLE_SEAMS_USING_MODELS
m_extrusions.reset_role_visibility_flags();
// m_sequential_view.skip_invisible_moves = true;
}
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::init()
{
if (m_gl_data_initialized)
@ -628,7 +581,6 @@ void GCodeViewer::init()
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
buffer.shader = "gouraud_light_instanced";
@ -646,20 +598,6 @@ void GCodeViewer::init()
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
}
break;
#else
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
buffer.shader = "gouraud_light_instanced";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
}
else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
}
break;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
@ -689,7 +627,6 @@ void GCodeViewer::init()
m_gl_data_initialized = true;
}
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
{
@ -879,72 +816,11 @@ void GCodeViewer::reset()
void GCodeViewer::render()
{
#if !ENABLE_SEAMS_USING_MODELS
auto init_gl_data = [this]() {
// initializes opengl data of TBuffers
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& buffer = m_buffers[i];
EMoveType type = buffer_type(i);
switch (type)
{
default: { break; }
case EMoveType::Tool_change:
case EMoveType::Color_change:
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
buffer.shader = "gouraud_light_instanced";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
}
else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
}
break;
}
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
break;
}
case EMoveType::Travel: {
buffer.shader = "toolpaths_lines";
break;
}
}
}
// initializes tool marker
m_sequential_view.marker.init();
// initializes point sizes
std::array<int, 2> point_sizes;
::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
m_gl_data_initialized = true;
};
#endif // !ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.reset_opengl();
#if ENABLE_SEAMS_USING_MODELS
m_statistics.total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS
#if !ENABLE_SEAMS_USING_MODELS
// OpenGL data must be initialized after the glContext has been created.
// This is ensured when this method is called by GLCanvas3D::_render_gcode().
if (!m_gl_data_initialized)
init_gl_data();
#endif // !ENABLE_SEAMS_USING_MODELS
if (m_roles.empty())
return;
@ -955,9 +831,7 @@ void GCodeViewer::render()
render_legend(legend_height);
if (m_sequential_view.current.last != m_sequential_view.endpoints.last) {
m_sequential_view.marker.set_world_position(m_sequential_view.current_position);
#if ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.marker.set_world_offset(m_sequential_view.current_offset);
#endif // ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.render(legend_height);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -1501,7 +1375,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
sq_prev_length = sq_length;
};
#if ENABLE_SEAMS_USING_MODELS
// format data into the buffers to be rendered as instanced model
auto add_model_instance = [](const GCodeProcessorResult::MoveVertex& curr, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
// append position
@ -1517,7 +1390,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
instances_ids.push_back(move_id);
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// format data into the buffers to be rendered as batched model
auto add_vertices_as_model_batch = [](const GCodeProcessorResult::MoveVertex& curr, const GLModel::InitializationData& data, VertexBuffer& vertices, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
const double width = static_cast<double>(1.5f * curr.width);
@ -1558,8 +1430,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto start_time = std::chrono::high_resolution_clock::now();
@ -1599,46 +1469,32 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (wxGetApp().is_editor())
m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(gcode_result, m_paths_bounding_box);
#if ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.gcode_ids.clear();
for (size_t i = 0; i < gcode_result.moves.size(); ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
if (move.type != EMoveType::Seam)
m_sequential_view.gcode_ids.push_back(move.gcode_id);
}
#else
for (const GCodeProcessorResult::MoveVertex& move : gcode_result.moves) {
m_sequential_view.gcode_ids.push_back(move.gcode_id);
}
#endif // ENABLE_FIX_SEAMS_SYNCH
std::vector<MultiVertexBuffer> vertices(m_buffers.size());
std::vector<MultiIndexBuffer> indices(m_buffers.size());
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer> instances(m_buffers.size());
std::vector<InstanceIdBuffer> instances_ids(m_buffers.size());
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_FIX_SEAMS_SYNCH
std::vector<InstancesOffsets> instances_offsets(m_buffers.size());
#endif // ENABLE_FIX_SEAMS_SYNCH
std::vector<float> options_zs;
#if ENABLE_FIX_SEAMS_SYNCH
size_t seams_count = 0;
std::vector<size_t> seams_ids;
#endif // ENABLE_FIX_SEAMS_SYNCH
// toolpaths data -> extract vertices from result
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam) {
++seams_count;
seams_ids.push_back(i);
}
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex
if (i == 0)
@ -1658,13 +1514,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
const unsigned char id = buffer_id(curr.type);
TBuffer& t_buffer = m_buffers[id];
MultiVertexBuffer& v_multibuffer = vertices[id];
#if ENABLE_SEAMS_USING_MODELS
InstanceBuffer& inst_buffer = instances[id];
InstanceIdBuffer& inst_id_buffer = instances_ids[id];
#if ENABLE_FIX_SEAMS_SYNCH
InstancesOffsets& inst_offsets = instances_offsets[id];
#endif // ENABLE_FIX_SEAMS_SYNCH
#endif // ENABLE_SEAMS_USING_MODELS
// ensure there is at least one vertex buffer
if (v_multibuffer.empty())
@ -1672,21 +1524,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// add another vertex buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
#else
if (v_multibuffer.back().size() * sizeof(float) > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
v_multibuffer.push_back(VertexBuffer());
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
Path& last_path = t_buffer.paths.back();
if (prev.type == curr.type && last_path.matches(curr))
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(v_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -1696,21 +1540,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
{
case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; }
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; }
#if ENABLE_FIX_SEAMS_SYNCH
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, move_id); break; }
#else
case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast<unsigned int>(v_multibuffer.size()) - 1, v_buffer, i); break; }
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::InstancedModel:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
inst_offsets.push_back(prev.position - curr.position);
#else
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -1718,32 +1552,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
case TBuffer::ERenderPrimitiveType::BatchedModel:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, move_id);
inst_offsets.push_back(prev.position - curr.position);
#else
add_vertices_as_model_batch(curr, t_buffer.model.data, v_buffer, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.batched_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
#else
case TBuffer::ERenderPrimitiveType::Model:
{
#if ENABLE_FIX_SEAMS_SYNCH
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
#else
add_model_instance(curr, inst_buffer, inst_id_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
break;
}
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}
// collect options zs for later use
@ -1755,11 +1570,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
// smooth toolpaths corners for the given TBuffer using triangles
#if ENABLE_FIX_SEAMS_SYNCH
auto smooth_triangle_toolpaths_corners = [&gcode_result, &seams_ids](const TBuffer& t_buffer, MultiVertexBuffer& v_multibuffer) {
#else
auto smooth_triangle_toolpaths_corners = [&gcode_result](const TBuffer& t_buffer, MultiVertexBuffer& v_multibuffer) {
#endif // ENABLE_FIX_SEAMS_SYNCH
auto extract_position_at = [](const VertexBuffer& vertices, size_t offset) {
return Vec3f(vertices[offset + 0], vertices[offset + 1], vertices[offset + 2]);
};
@ -1833,7 +1644,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
};
#if ENABLE_FIX_SEAMS_SYNCH
auto extract_move_id = [&seams_ids](size_t id) {
for (int i = seams_ids.size() - 1; i >= 0; --i) {
if (seams_ids[i] < id + i + 1)
@ -1841,7 +1651,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
return id;
};
#endif // ENABLE_FIX_SEAMS_SYNCH
size_t vertex_size_floats = t_buffer.vertices.vertex_size_floats();
for (const Path& path : t_buffer.paths) {
@ -1853,16 +1662,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
const float half_width = 0.5f * path.width;
for (size_t j = 1; j < path_vertices_count - 1; ++j) {
size_t curr_s_id = path.sub_paths.front().first.s_id + j;
#if ENABLE_FIX_SEAMS_SYNCH
size_t move_id = extract_move_id(curr_s_id);
const Vec3f& prev = gcode_result.moves[move_id - 1].position;
const Vec3f& curr = gcode_result.moves[move_id].position;
const Vec3f& next = gcode_result.moves[move_id + 1].position;
#else
const Vec3f& prev = gcode_result.moves[curr_s_id - 1].position;
const Vec3f& curr = gcode_result.moves[curr_s_id].position;
const Vec3f& next = gcode_result.moves[curr_s_id + 1].position;
#endif // ENABLE_FIX_SEAMS_SYNCH
// select the subpaths which contains the previous/next segments
if (!path.sub_paths[prev_sub_path_id].contains(curr_s_id))
@ -1929,10 +1732,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
}
#if ENABLE_FIX_SEAMS_SYNCH
// dismiss, no more needed
std::vector<size_t>().swap(seams_ids);
#endif // ENABLE_FIX_SEAMS_SYNCH
for (MultiVertexBuffer& v_multibuffer : vertices) {
for (VertexBuffer& v_buffer : v_multibuffer) {
@ -1951,16 +1752,12 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// send vertices data to gpu, where needed
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[i];
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
else {
@ -1969,25 +1766,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
#else
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
else {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
const MultiVertexBuffer& v_multibuffer = vertices[i];
for (const VertexBuffer& v_buffer : v_multibuffer) {
const size_t size_elements = v_buffer.size();
@ -2010,9 +1791,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
t_buffer.vertices.vbos.push_back(static_cast<unsigned int>(id));
t_buffer.vertices.sizes.push_back(size_bytes);
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@ -2023,10 +1802,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// dismiss vertices data, no more needed
std::vector<MultiVertexBuffer>().swap(vertices);
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer>().swap(instances);
std::vector<InstanceIdBuffer>().swap(instances_ids);
#endif // ENABLE_SEAMS_USING_MODELS
// toolpaths data -> extract indices from result
// paths may have been filled while extracting vertices,
@ -2043,18 +1820,14 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
using VboIndexList = std::vector<unsigned int>;
std::vector<VboIndexList> vbo_indices(m_buffers.size());
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam)
++seams_count;
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex
if (i == 0)
@ -2082,63 +1855,37 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// ensure there is at least one index buffer
if (i_multibuffer.empty()) {
i_multibuffer.push_back(IndexBuffer());
#if ENABLE_SEAMS_USING_MODELS
if (!t_buffer.vertices.vbos.empty())
#endif // ENABLE_SEAMS_USING_MODELS
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
}
// if adding the indices for the current segment exceeds the threshold size of the current index buffer
// create another index buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t indiced_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.indices_size_bytes() : t_buffer.max_indices_per_segment_size_bytes();
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - indiced_size_to_add) {
#else
if (i_multibuffer.back().size() * sizeof(IBufferType) >= IBUFFER_THRESHOLD_BYTES - t_buffer.max_indices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
i_multibuffer.push_back(IndexBuffer());
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
Path& last_path = t_buffer.paths.back();
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
// if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// create another index buffer
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_size_to_add = (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) ? t_buffer.model.data.vertices_size_bytes() : t_buffer.max_vertices_per_segment_size_bytes();
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - vertices_size_to_add) {
#else
if (curr_vertex_buffer.second * t_buffer.vertices.vertex_size_bytes() > t_buffer.vertices.max_size_bytes() - t_buffer.max_vertices_per_segment_size_bytes()) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
i_multibuffer.push_back(IndexBuffer());
++curr_vertex_buffer.first;
curr_vertex_buffer.second = 0;
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
Path& last_path = t_buffer.paths.back();
#if ENABLE_FIX_SEAMS_SYNCH
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, move_id - 1);
#else
last_path.add_sub_path(prev, static_cast<unsigned int>(i_multibuffer.size()) - 1, 0, i - 1);
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -2147,38 +1894,24 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
switch (t_buffer.render_primitive_type)
{
case TBuffer::ERenderPrimitiveType::Point: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_point(curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_point(curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break;
}
case TBuffer::ERenderPrimitiveType::Line: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_line(prev, curr, t_buffer, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break;
}
case TBuffer::ERenderPrimitiveType::Triangle: {
#if ENABLE_FIX_SEAMS_SYNCH
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, move_id);
#else
add_indices_as_solid(prev, curr, next, t_buffer, curr_vertex_buffer.second, static_cast<unsigned int>(i_multibuffer.size()) - 1, i_buffer, i);
#endif // ENABLE_FIX_SEAMS_SYNCH
break;
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::BatchedModel: {
add_indices_as_model_batch(t_buffer.model.data, i_buffer, curr_vertex_buffer.second);
curr_vertex_buffer.second += t_buffer.model.data.vertices_count();
break;
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
default: { break; }
}
}
@ -2192,13 +1925,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// toolpaths data -> send indices data to gpu
for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[i];
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel) {
#else
if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
const MultiIndexBuffer& i_multibuffer = indices[i];
for (const IndexBuffer& i_buffer : i_multibuffer) {
const size_t size_elements = i_buffer.size();
@ -2221,9 +1948,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_bytes, i_buffer.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
if (progress_dialog != nullptr) {
@ -2264,34 +1989,22 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// layers zs / roles / extruder ids -> extract from result
size_t last_travel_s_id = 0;
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Seam)
++seams_count;
size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Extrude) {
// layers zs
const double* const last_z = m_layers.empty() ? nullptr : &m_layers.get_zs().back();
const double z = static_cast<double>(move.position.z());
if (last_z == nullptr || z < *last_z - EPSILON || *last_z + EPSILON < z)
#if ENABLE_FIX_SEAMS_SYNCH
m_layers.append(z, { last_travel_s_id, move_id });
#else
m_layers.append(z, { last_travel_s_id, i });
#endif // ENABLE_FIX_SEAMS_SYNCH
else
#if ENABLE_FIX_SEAMS_SYNCH
m_layers.get_endpoints().back().last = move_id;
#else
m_layers.get_endpoints().back().last = i;
#endif // ENABLE_FIX_SEAMS_SYNCH
// extruder ids
m_extruder_ids.emplace_back(move.extruder_id);
// roles
@ -2299,17 +2012,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
m_roles.emplace_back(move.extrusion_role);
}
else if (move.type == EMoveType::Travel) {
#if ENABLE_FIX_SEAMS_SYNCH
if (move_id - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_endpoints().back().last = move_id;
last_travel_s_id = move_id;
#else
if (i - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_endpoints().back().last = i;
last_travel_s_id = i;
#endif // ENABLE_FIX_SEAMS_SYNCH
}
}
@ -2361,8 +2067,19 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
instance_ids[i] = i;
}
size_t current_volumes_count = m_shells.volumes.volumes.size();
m_shells.volumes.load_object(model_obj, object_id, instance_ids, "object", initialized);
// adjust shells' z if raft is present
const SlicingParameters& slicing_parameters = obj->slicing_parameters();
if (slicing_parameters.object_print_z_min != 0.0) {
const Vec3d z_offset = slicing_parameters.object_print_z_min * Vec3d::UnitZ();
for (size_t i = current_volumes_count; i < m_shells.volumes.volumes.size(); ++i) {
GLVolume* v = m_shells.volumes.volumes[i];
v->set_volume_offset(v->get_volume_offset() + z_offset);
}
}
++object_id;
}
@ -2442,7 +2159,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
return m_layers.get_endpoints_at(min_id).first <= id && id <= m_layers.get_endpoints_at(max_id).last;
};
return in_layers_range(path.sub_paths.front().first.s_id) || in_layers_range(path.sub_paths.back().last.s_id);
return in_layers_range(path.sub_paths.front().first.s_id) && in_layers_range(path.sub_paths.back().last.s_id);
};
auto is_travel_in_layers_range = [this](size_t path_id, size_t min_id, size_t max_id) {
@ -2474,9 +2191,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#if ENABLE_GCODE_VIEWER_STATISTICS
Statistics* statistics = const_cast<Statistics*>(&m_statistics);
statistics->render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
statistics->models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS
const bool top_layer_only = get_app_config()->get("seq_top_layer_only") == "1";
@ -2497,13 +2212,8 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (!buffer.visible)
continue;
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t id : buffer.model.instances.s_ids) {
if (id < m_layers.get_endpoints_at(m_layers_z_range[0]).first || m_layers.get_endpoints_at(m_layers_z_range[1]).last < id)
continue;
@ -2521,7 +2231,6 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t i = 0; i < buffer.paths.size(); ++i) {
const Path& path = buffer.paths[i];
if (path.type == EMoveType::Travel) {
@ -2555,9 +2264,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
}
// update current sequential position
@ -2567,30 +2274,21 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
// get the world position from the vertex buffer
bool found = false;
for (const TBuffer& buffer : m_buffers) {
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t i = 0; i < buffer.model.instances.s_ids.size(); ++i) {
if (buffer.model.instances.s_ids[i] == m_sequential_view.current.last) {
size_t offset = i * buffer.model.instances.instance_size_floats();
sequential_view->current_position.x() = buffer.model.instances.buffer[offset + 0];
sequential_view->current_position.y() = buffer.model.instances.buffer[offset + 1];
sequential_view->current_position.z() = buffer.model.instances.buffer[offset + 2];
#if ENABLE_FIX_SEAMS_SYNCH
sequential_view->current_offset = buffer.model.instances.offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true;
break;
}
}
}
else {
#endif // ENABLE_SEAMS_USING_MODELS
// searches the path containing the current position
for (const Path& path : buffer.paths) {
if (path.contains(m_sequential_view.current.last)) {
@ -2622,18 +2320,13 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, static_cast<GLintptr>(index * buffer.vertices.vertex_size_bytes()), static_cast<GLsizeiptr>(3 * sizeof(float)), static_cast<void*>(sequential_view->current_position.data())));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if ENABLE_FIX_SEAMS_SYNCH
sequential_view->current_offset = Vec3f::Zero();
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true;
break;
}
}
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
if (found)
break;
@ -2740,20 +2433,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif
}
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// second pass: for buffers using instanced and batched models, update the instances render ranges
#else
// second pass: for buffers using instanced models, update the instances render ranges
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
for (size_t b = 0; b < m_buffers.size(); ++b) {
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel &&
buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel)
#else
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model)
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
continue;
buffer.model.instances.render_ranges.reset();
@ -2769,11 +2453,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (m_sequential_view.current.first <= buffer.model.instances.s_ids.back() && buffer.model.instances.s_ids.front() <= m_sequential_view.current.last) {
for (size_t id : buffer.model.instances.s_ids) {
if (has_second_range) {
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
if (id < m_sequential_view.endpoints.first) {
#else
if (id <= m_sequential_view.endpoints.first) {
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
++buffer.model.instances.render_ranges.ranges.front().offset;
if (id <= m_sequential_view.current.first)
++buffer.model.instances.render_ranges.ranges.back().offset;
@ -2796,14 +2476,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
}
}
#endif // ENABLE_SEAMS_USING_MODELS
// set sequential data to their final value
sequential_view->endpoints = top_layer_only ? top_layer_endpoints : global_endpoints;
sequential_view->current.first = !top_layer_only && keep_sequential_current_first ? std::clamp(sequential_view->current.first, sequential_view->endpoints.first, sequential_view->endpoints.last) : sequential_view->endpoints.first;
#if ENABLE_SEAMS_USING_MODELS
sequential_view->global = global_endpoints;
#endif // ENABLE_SEAMS_USING_MODELS
// updates sequential range caps
std::array<SequentialRangeCap, 2>* sequential_range_caps = const_cast<std::array<SequentialRangeCap, 2>*>(&m_sequential_range_caps);
@ -2925,11 +2602,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
statistics->render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.sizes, unsigned int);
statistics->render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.offsets, size_t);
}
#if ENABLE_SEAMS_USING_MODELS
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.buffer, float);
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.s_ids, size_t);
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.render_ranges.ranges, InstanceVBuffer::Ranges::Range);
#endif // ENABLE_SEAMS_USING_MODELS
}
statistics->refresh_paths_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -3018,7 +2693,6 @@ void GCodeViewer::render_toolpaths()
}
};
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_instanced_model = [this]
#else
@ -3044,7 +2718,6 @@ void GCodeViewer::render_toolpaths()
}
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) {
#else
@ -3102,8 +2775,6 @@ void GCodeViewer::render_toolpaths()
buffer_range.first = buffer_range.last;
}
};
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
auto line_width = [](double zoom) {
return (zoom < 5.0) ? 1.0 : (1.0 + 5.0 * (zoom - 5.0) / (100.0 - 5.0));
@ -3113,11 +2784,7 @@ void GCodeViewer::render_toolpaths()
unsigned char end_id = buffer_id(EMoveType::Count);
for (unsigned char i = begin_id; i < end_id; ++i) {
#if ENABLE_SEAMS_USING_MODELS
TBuffer& buffer = m_buffers[i];
#else
const TBuffer& buffer = m_buffers[i];
#endif // ENABLE_SEAMS_USING_MODELS
if (!buffer.visible || !buffer.has_data())
continue;
@ -3125,25 +2792,17 @@ void GCodeViewer::render_toolpaths()
if (shader != nullptr) {
shader->start_using();
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
#else
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Model) {
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
shader->set_uniform("emission_factor", 0.25f);
render_as_instanced_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f);
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
shader->set_uniform("emission_factor", 0.25f);
render_as_batched_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f);
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t j = 0; j < buffer.indices.size(); ++j) {
const IBuffer& i_buffer = buffer.indices[j];
@ -3184,9 +2843,7 @@ void GCodeViewer::render_toolpaths()
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
shader->stop_using();
}
@ -3297,11 +2954,7 @@ void GCodeViewer::render_legend(float& legend_height)
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
#if ENABLE_SEAMS_USING_BATCHED_MODELS
auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
#else
auto append_item = [this, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array<float, 4>& offsets = { 0.0f, 0.0f, 0.0f, 0.0f },
double used_filament_m = 0.0, double used_filament_g = 0.0,
std::function<void()> callback = nullptr) {
@ -3319,19 +2972,7 @@ void GCodeViewer::render_legend(float& legend_height)
}
case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
#if !ENABLE_SEAMS_USING_BATCHED_MODELS
if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") {
draw_list->AddCircleFilled(center, 0.5f * icon_size,
ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
float radius = 0.5f * icon_size;
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
radius = 0.5f * icon_size * 0.01f * 33.0f;
draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
}
else
#endif // !ENABLE_SEAMS_USING_BATCHED_MODELS
draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
break;
}
case EItemType::Hexagon: {
@ -3971,11 +3612,7 @@ void GCodeViewer::render_legend(float& legend_height)
auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
const TBuffer& buffer = m_buffers[buffer_id(move_type)];
if (buffer.visible && buffer.has_data())
#if ENABLE_SEAMS_USING_BATCHED_MODELS
append_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#else
append_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
};
// options section
@ -4198,13 +3835,9 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Multi GL_LINES:"), m_statistics.gl_multi_lines_calls_count);
add_counter(std::string("Multi GL_TRIANGLES:"), m_statistics.gl_multi_triangles_calls_count);
add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count);
#if ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_counter(std::string("Instanced models:"), m_statistics.gl_instanced_models_calls_count);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
add_counter(std::string("Batched models:"), m_statistics.gl_batched_models_calls_count);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
}
if (ImGui::CollapsingHeader("CPU memory")) {
@ -4213,17 +3846,13 @@ void GCodeViewer::render_statistics()
ImGui::Separator();
add_memory(std::string("Paths:"), m_statistics.paths_size);
add_memory(std::string("Render paths:"), m_statistics.render_paths_size);
#if ENABLE_SEAMS_USING_MODELS
add_memory(std::string("Models instances:"), m_statistics.models_instances_size);
#endif // ENABLE_SEAMS_USING_MODELS
}
if (ImGui::CollapsingHeader("GPU memory")) {
add_memory(std::string("Vertices:"), m_statistics.total_vertices_gpu_size);
add_memory(std::string("Indices:"), m_statistics.total_indices_gpu_size);
#if ENABLE_SEAMS_USING_MODELS
add_memory(std::string("Instances:"), m_statistics.total_instances_gpu_size);
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_memory(std::string("Max VBuffer:"), m_statistics.max_vbuffer_gpu_size);
add_memory(std::string("Max IBuffer:"), m_statistics.max_ibuffer_gpu_size);
@ -4233,12 +3862,8 @@ void GCodeViewer::render_statistics()
add_counter(std::string("Travel segments count:"), m_statistics.travel_segments_count);
add_counter(std::string("Wipe segments count:"), m_statistics.wipe_segments_count);
add_counter(std::string("Extrude segments count:"), m_statistics.extrude_segments_count);
#if ENABLE_SEAMS_USING_MODELS
add_counter(std::string("Instances count:"), m_statistics.instances_count);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
add_counter(std::string("Batched count:"), m_statistics.batched_count);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator();
add_counter(std::string("VBuffers count:"), m_statistics.vbuffers_count);
add_counter(std::string("IBuffers count:"), m_statistics.ibuffers_count);

View file

@ -27,13 +27,9 @@ class GCodeViewer
using MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>;
using MultiIndexBuffer = std::vector<IndexBuffer>;
#if ENABLE_SEAMS_USING_MODELS
using InstanceBuffer = std::vector<float>;
using InstanceIdBuffer = std::vector<size_t>;
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_FIX_SEAMS_SYNCH
using InstancesOffsets = std::vector<Vec3f>;
#endif // ENABLE_FIX_SEAMS_SYNCH
static const std::vector<Color> Extrusion_Role_Colors;
static const std::vector<Color> Options_Colors;
@ -107,17 +103,10 @@ class GCodeViewer
void reset();
};
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// buffer containing instances data used to render a toolpaths using instanced or batched models
// instance record format:
// instanced models: 5 floats -> position.x|position.y|position.z|width|height (which are sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced())
// batched models: 3 floats -> position.x|position.y|position.z
#else
// buffer containing instances data used to render a toolpaths using instanced models
// instance record format: 5 floats -> position.x|position.y|position.z|width|height
// which is sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced()
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
struct InstanceVBuffer
{
// ranges used to render only subparts of the intances
@ -140,7 +129,6 @@ class GCodeViewer
void reset();
};
#if ENABLE_SEAMS_USING_BATCHED_MODELS
enum class EFormat : unsigned char
{
InstancedModel,
@ -148,21 +136,17 @@ class GCodeViewer
};
EFormat format;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// cpu-side buffer containing all instances data
InstanceBuffer buffer;
// indices of the moves for all instances
std::vector<size_t> s_ids;
#if ENABLE_FIX_SEAMS_SYNCH
// position offsets, used to show the correct value of the tool position
InstancesOffsets offsets;
#endif // ENABLE_FIX_SEAMS_SYNCH
Ranges render_ranges;
size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); }
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t instance_size_floats() const {
switch (format)
{
@ -171,14 +155,10 @@ class GCodeViewer
default: { return 0; }
}
}
#else
size_t instance_size_floats() const { return 5; }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
void reset();
};
#endif // ENABLE_SEAMS_USING_MODELS
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
struct IBuffer
@ -313,17 +293,9 @@ class GCodeViewer
{
Point,
Line,
#if ENABLE_SEAMS_USING_MODELS
Triangle,
#if ENABLE_SEAMS_USING_BATCHED_MODELS
InstancedModel,
BatchedModel
#else
Model
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#else
Triangle
#endif // ENABLE_SEAMS_USING_MODELS
};
ERenderPrimitiveType render_primitive_type;
@ -332,22 +304,18 @@ class GCodeViewer
VBuffer vertices;
std::vector<IBuffer> indices;
#if ENABLE_SEAMS_USING_MODELS
struct Model
{
GLModel model;
Color color;
InstanceVBuffer instances;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
GLModel::InitializationData data;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void reset();
};
// contain the buffer for model primitive types
Model model;
#endif // ENABLE_SEAMS_USING_MODELS
std::string shader;
std::vector<Path> paths;
@ -396,7 +364,6 @@ class GCodeViewer
}
size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
#if ENABLE_SEAMS_USING_MODELS
bool has_data() const {
switch (render_primitive_type)
{
@ -405,23 +372,14 @@ class GCodeViewer
case ERenderPrimitiveType::Triangle: {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
case ERenderPrimitiveType::BatchedModel: {
return model.data.vertices_count() > 0 && model.data.indices_count() &&
!vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#else
case ERenderPrimitiveType::Model: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
default: { return false; }
}
}
#else
bool has_data() const {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
}
#endif // ENABLE_SEAMS_USING_MODELS
};
// helper to render shells
@ -569,36 +527,24 @@ class GCodeViewer
int64_t gl_multi_lines_calls_count{ 0 };
int64_t gl_multi_triangles_calls_count{ 0 };
int64_t gl_triangles_calls_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t gl_instanced_models_calls_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t gl_batched_models_calls_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
// memory
int64_t results_size{ 0 };
int64_t total_vertices_gpu_size{ 0 };
int64_t total_indices_gpu_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t total_instances_gpu_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
int64_t max_vbuffer_gpu_size{ 0 };
int64_t max_ibuffer_gpu_size{ 0 };
int64_t paths_size{ 0 };
int64_t render_paths_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t models_instances_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
// other
int64_t travel_segments_count{ 0 };
int64_t wipe_segments_count{ 0 };
int64_t extrude_segments_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t instances_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t batched_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
int64_t vbuffers_count{ 0 };
int64_t ibuffers_count{ 0 };
@ -624,40 +570,28 @@ class GCodeViewer
gl_multi_lines_calls_count = 0;
gl_multi_triangles_calls_count = 0;
gl_triangles_calls_count = 0;
#if ENABLE_SEAMS_USING_MODELS
gl_instanced_models_calls_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
gl_batched_models_calls_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
}
void reset_sizes() {
results_size = 0;
total_vertices_gpu_size = 0;
total_indices_gpu_size = 0;
#if ENABLE_SEAMS_USING_MODELS
total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
max_vbuffer_gpu_size = 0;
max_ibuffer_gpu_size = 0;
paths_size = 0;
render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
}
void reset_others() {
travel_segments_count = 0;
wipe_segments_count = 0;
extrude_segments_count = 0;
#if ENABLE_SEAMS_USING_MODELS
extrude_segments_count = 0;
instances_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
batched_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
vbuffers_count = 0;
ibuffers_count = 0;
}
@ -672,12 +606,10 @@ public:
GLModel m_model;
Vec3f m_world_position;
Transform3f m_world_transform;
#if ENABLE_FIX_SEAMS_SYNCH
// for seams, the position of the marker is on the last endpoint of the toolpath containing it
// the offset is used to show the correct value of tool position in the "ToolPosition" window
// see implementation of render() method
Vec3f m_world_offset;
#endif // ENABLE_FIX_SEAMS_SYNCH
float m_z_offset{ 0.5f };
bool m_visible{ true };
@ -687,9 +619,7 @@ public:
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_position(const Vec3f& position);
#if ENABLE_FIX_SEAMS_SYNCH
void set_world_offset(const Vec3f& offset) { m_world_offset = offset; }
#endif // ENABLE_FIX_SEAMS_SYNCH
bool is_visible() const { return m_visible; }
void set_visible(bool visible) { m_visible = visible; }
@ -743,13 +673,9 @@ public:
Endpoints endpoints;
Endpoints current;
Endpoints last_current;
#if ENABLE_SEAMS_USING_MODELS
Endpoints global;
#endif // ENABLE_SEAMS_USING_MODELS
Vec3f current_position{ Vec3f::Zero() };
#if ENABLE_FIX_SEAMS_SYNCH
Vec3f current_offset{ Vec3f::Zero() };
#endif // ENABLE_FIX_SEAMS_SYNCH
Marker marker;
GCodeWindow gcode_window;
std::vector<unsigned int> gcode_ids;
@ -811,9 +737,7 @@ public:
GCodeViewer();
~GCodeViewer() { reset(); }
#if ENABLE_SEAMS_USING_MODELS
void init();
#endif // ENABLE_SEAMS_USING_MODELS
// extract rendering data from the given parameters
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);

View file

@ -95,6 +95,11 @@ RetinaHelper::~RetinaHelper() {}
float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleFactor()); }
#endif // __WXGTK3__
// Fixed the collision between BuildVolume::Type::Convex and macro Convex defined inside /usr/include/X11/X.h that is included by WxWidgets 3.0.
#if defined(__linux__) && defined(Convex)
#undef Convex
#endif
Size::Size()
: m_width(0)
, m_height(0)
@ -1417,10 +1422,8 @@ void GLCanvas3D::render()
if (!is_initialized() && !init())
return;
#if ENABLE_SEAMS_USING_MODELS
if (!m_main_toolbar.is_enabled())
m_gcode_viewer.init();
#endif // ENABLE_SEAMS_USING_MODELS
if (! m_bed.build_volume().valid()) {
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
@ -3751,7 +3754,8 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos)
double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const
{
return factor * m_bed.build_volume().bounding_volume().max_size();
const BoundingBoxf& bbox = m_bed.build_volume().bounding_volume2d();
return factor * std::max(bbox.size()[0], bbox.size()[1]);
}
void GLCanvas3D::set_cursor(ECursorType type)
@ -4126,24 +4130,15 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
}
}
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (visible_volumes.empty())
return;
#endif // !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
BoundingBoxf3 volumes_box;
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (!visible_volumes.empty()) {
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
for (const GLVolume* vol : visible_volumes) {
volumes_box.merge(vol->transformed_bounding_box());
}
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
else
// This happens for empty projects
volumes_box = m_bed.extended_bounding_box();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
Camera camera;
camera.set_type(camera_type);
@ -5119,10 +5114,12 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
break;
}
default:
case BuildVolume::Type::Convex:
case BuildVolume::Type::Custom: {
m_volumes.set_print_volume({ static_cast<int>(type),
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f } });
{ -FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX },
{ -FLT_MAX, FLT_MAX } }
);
}
}
if (m_requires_check_outside_state) {

View file

@ -623,9 +623,7 @@ public:
void reset_volumes();
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
#if ENABLE_SEAMS_USING_MODELS
void init_gcode_viewer() { m_gcode_viewer.init(); }
#endif // ENABLE_SEAMS_USING_MODELS
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }

View file

@ -17,7 +17,6 @@
namespace Slic3r {
namespace GUI {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t GLModel::InitializationData::vertices_count() const
{
size_t ret = 0;
@ -35,7 +34,6 @@ size_t GLModel::InitializationData::indices_count() const
}
return ret;
}
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void GLModel::init_from(const InitializationData& data)
{
@ -231,7 +229,6 @@ void GLModel::render() const
}
}
#if ENABLE_SEAMS_USING_MODELS
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) const
{
if (instances_vbo == 0)
@ -308,7 +305,6 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#endif // ENABLE_SEAMS_USING_MODELS
void GLModel::send_to_gpu(RenderData& data, const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
{

View file

@ -49,14 +49,12 @@ namespace GUI {
std::vector<Entity> entities;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_count() const;
size_t vertices_size_floats() const { return vertices_count() * 6; }
size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); }
size_t indices_count() const;
size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
};
private:
@ -80,9 +78,7 @@ namespace GUI {
void reset();
void render() const;
#if ENABLE_SEAMS_USING_MODELS
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
#endif // ENABLE_SEAMS_USING_MODELS
bool is_initialized() const { return !m_render_data.empty(); }

View file

@ -33,31 +33,13 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview
#else
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
// used to render printbed
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
// used to render options in gcode preview
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
#else
#if ENABLE_SEAMS_USING_MODELS
if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 3))
valid &= append_shader("gouraud_light_instanced", { "gouraud_light_instanced.vs", "gouraud_light_instanced.fs" });
else {
#endif // ENABLE_SEAMS_USING_MODELS
valid &= append_shader("options_110", { "options_110.vs", "options_110.fs" });
if (GUI::wxGetApp().is_glsl_version_greater_or_equal_to(1, 20))
valid &= append_shader("options_120", { "options_120.vs", "options_120.fs" });
#if ENABLE_SEAMS_USING_MODELS
}
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// used to render extrusion and travel paths as lines in gcode preview
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
// used to render objects in 3d editor

View file

@ -12,6 +12,7 @@
#include <exception>
#include <cstdlib>
#include <regex>
#include <string_view>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
@ -97,6 +98,8 @@
#include <gtk/gtk.h>
#endif
using namespace std::literals;
namespace Slic3r {
namespace GUI {
@ -471,40 +474,82 @@ static bool run_updater_win()
}
#endif //_WIN32
struct FileWildcards {
std::string_view title;
std::vector<std::string_view> file_extensions;
};
static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
/* FT_STL */ { "STL files"sv, { ".stl"sv } },
/* FT_OBJ */ { "OBJ files"sv, { ".obj"sv } },
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".g"sv, ".ngc"sv } },
/* FT_MODEL */ { "Known files"sv, { ".stl"sv, ".obj"sv, ".3mf"sv, ".amf"sv, ".zip.amf"sv, ".xml"sv } },
/* FT_PROJECT */ { "Project files"sv, { ".3mf"sv, ".amf"sv, ".zip.amf"sv } },
/* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } },
/* FT_INI */ { "INI files"sv, { ".ini"sv } },
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
};
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
// The function accepts a custom extension parameter. If the parameter is provided, the custom extension
// will be added as a fist to the list. This is important for a "file save" dialog on OSX, which strips
// an extension from the provided initial file name and substitutes it with the default extension (the first one in the template).
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{
static const std::string defaults[FT_SIZE] = {
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL",
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ",
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML",
/* FT_3MF */ "3MF files (*.3mf)|*.3mf;*.3MF;",
/* FT_GCODE */ "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC",
/* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF",
/* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
/* FT_FONTS */ "Font files (*.ttf, *.tte, *.ttc, *.dfont)|*.ttf;*.tte;*.ttc;*.dfont;*.TTF;*.TTE;*.TTC;*.DFONT",
/* FT_GALLERY */ "Known files (*.stl, *.obj)|*.stl;*.STL;*.obj;*.OBJ",
const FileWildcards& data = file_wildcards_by_type[file_type];
std::string title;
std::string mask;
std::string custom_ext_lower;
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
/* FT_SL1 */ "Masked SLA files (*.sl1, *.sl1s)|*.sl1;*.SL1;*.sl1s;*.SL1S",
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
/* FT_SL1S */ "Masked SLA files (*.sl1s, *.sl1)|*.sl1s;*.SL1S;*.sl1;*.SL1",
};
std::string out = defaults[file_type];
if (! custom_extension.empty()) {
// Find the custom extension in the template.
if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) {
// The custom extension was not found in the template.
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it.
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|");
out += std::string(";*") + custom_extension;
// Generate an extension into the title mask and into the list of extensions.
custom_ext_lower = boost::to_lower_copy(custom_extension);
const std::string custom_ext_upper = boost::to_upper_copy(custom_extension);
if (custom_ext_lower == custom_extension) {
// Add a lower case version.
title = std::string("*") + custom_ext_lower;
mask = title;
// Add an upper case version.
mask += ";*";
mask += custom_ext_upper;
} else if (custom_ext_upper == custom_extension) {
// Add an upper case version.
title = std::string("*") + custom_ext_upper;
mask = title;
// Add a lower case version.
mask += ";*";
mask += custom_ext_lower;
} else {
// Add the mixed case version only.
title = std::string("*") + custom_extension;
mask = title;
}
}
return from_u8(out);
for (const std::string_view &ext : data.file_extensions)
// Only add an extension if it was not added first as the custom extension.
if (ext != custom_ext_lower) {
if (title.empty()) {
title = "*";
title += ext;
mask = title;
} else {
title += ", *";
title += ext;
mask += ";*";
mask += ext;
}
mask += ";*";
mask += boost::to_upper_copy(std::string(ext));
}
return GUI::format_wxstr("%s (%s)|%s", data.title, title, mask);
}
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
@ -990,7 +1035,7 @@ bool GUI_App::on_init_inner()
RichMessageDialog dlg(nullptr,
_L("You are running a 32 bit build of PrusaSlicer on 64-bit Windows."
"\n32 bit build of PrusaSlicer will likely not be able to utilize all the RAM available in the system."
"\nPlease download and install a 64 bit build of PrusaSlice from https://www.prusa3d.cz/prusaslicer/."
"\nPlease download and install a 64 bit build of PrusaSlicer from https://www.prusa3d.cz/prusaslicer/."
"\nDo you wish to continue?"),
"PrusaSlicer", wxICON_QUESTION | wxYES_NO);
if (dlg.ShowModal() != wxID_YES)

View file

@ -67,13 +67,11 @@ enum FileType
FT_TEX,
FT_SL1,
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
FT_SL1S,
FT_SIZE,
};
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string());
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string{});
enum ConfigMenuIDs {
ConfigMenuWizard,

View file

@ -523,6 +523,10 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
menu->Destroy(settings_id);
}
// Update "Height range Modifier" item (delete old & create new)
if (const auto range_id = menu->FindItem(_L("Height range Modifier")); range_id != wxNOT_FOUND)
menu->Destroy(range_id);
const ConfigOptionMode mode = wxGetApp().get_mode();
if (mode == comAdvanced) {
@ -552,6 +556,8 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second,
[]() { return obj_list()->is_instance_or_object_selected(); }, m_parent);
}
append_menu_item_layers_editing(menu);
}
wxMenuItem* MenuFactory::append_menu_item_layers_editing(wxMenu* menu)
@ -825,8 +831,14 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
void MenuFactory::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu)
{
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
append_menu_item(menu, wxID_ANY, _L("Scale to print volume"), _L("Scale the selected object to fit the print volume"),
[](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu,
[]() { return plater()->can_scale_to_print_volume(); }, m_parent);
#else
append_menu_item(menu, wxID_ANY, _L("Scale to print volume"), _L("Scale the selected object to fit the print volume"),
[](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
}
void MenuFactory::append_menu_items_convert_unit(wxMenu* menu, int insert_pos/* = 1*/)
@ -997,11 +1009,7 @@ void MenuFactory::create_object_menu()
[]() { return plater()->can_split(true) && wxGetApp().get_mode() > comSimple; }, m_parent);
m_object_menu.AppendSeparator();
// Layers Editing for object
append_menu_item_layers_editing(&m_object_menu);
m_object_menu.AppendSeparator();
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
// "Height range Modifier" and "Add (volumes)" menu items will be added later in append_menu_items_add_volume()
}
void MenuFactory::create_sla_object_menu()

View file

@ -4041,18 +4041,8 @@ void ObjectList::rename_item()
if (new_name.IsEmpty())
return;
bool is_unusable_symbol = false;
std::string chosen_name = Slic3r::normalize_utf8_nfc(new_name.ToUTF8());
const char* unusable_symbols = "<>:/\\|?*\"";
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
if (chosen_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
is_unusable_symbol = true;
}
}
if (is_unusable_symbol) {
show_error(this, _(L("The supplied name is not valid;")) + "\n" +
_(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
if (Plater::has_illegal_filename_characters(new_name)) {
Plater::show_illegal_characters_warning(this);
return;
}
@ -4272,10 +4262,7 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer());
if (renderer->WasCanceled())
wxTheApp->CallAfter([this]{
show_error(this, _(L("The supplied name is not valid;")) + "\n" +
_(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
});
wxTheApp->CallAfter([this]{ Plater::show_illegal_characters_warning(this); });
#ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.

View file

@ -97,7 +97,7 @@ public:
// will be also extended to support additional states, requiring at least one state to remain free out of 19 states.
static const constexpr size_t EXTRUDERS_LIMIT = 16;
virtual const float get_cursor_radius_min() const { return CursorRadiusMin; }
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
protected:
std::array<float, 4> get_cursor_sphere_left_button_color() const override;

View file

@ -553,9 +553,15 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
auto btn_txt_sz = ImGui::CalcTextSize(btn_txt.c_str());
ImVec2 button_sz = {btn_txt_sz.x + padding.x, btn_txt_sz.y + padding.y};
ImGui::SetCursorPosX(padding.x + sz.x - button_sz.x);
if (wxGetApp().plater()->is_any_job_running())
imgui->disabled_begin(true);
if ( imgui->button(btn_txt) ) {
wxGetApp().plater()->optimize_rotation();
}
imgui->disabled_end();
}
GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow()

View file

@ -107,7 +107,7 @@ void GLGizmoSimplify::add_simplify_suggestion_notification(
if (big_ids.empty()) return;
for (size_t object_id : big_ids) {
std::string t = GUI::format(_u8L(
std::string t = GUI::format(_L(
"Processing model '%1%' with more than 1M triangles "
"could be slow. It is highly recommend to reduce "
"amount of triangles."), objects[object_id]->name);
@ -474,7 +474,7 @@ void GLGizmoSimplify::apply_simplify() {
int object_idx = selection.get_object_idx();
auto plater = wxGetApp().plater();
plater->take_snapshot(_u8L("Simplify ") + m_volume->name);
plater->take_snapshot(GUI::format(_u8L("Simplify %1%"), m_volume->name));
plater->clear_before_change_mesh(object_idx);
ModelVolume* mv = get_model_volume(selection, wxGetApp().model());

View file

@ -39,7 +39,7 @@ protected:
virtual void on_render() override;
virtual void on_render_for_picking() override{};
virtual CommonGizmosDataID on_get_requirements() const;
CommonGizmosDataID on_get_requirements() const override;
private:
void apply_simplify();

View file

@ -499,14 +499,14 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
{
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
std::string str_label;
if (boost::algorithm::istarts_with(label, "##"))
str_label = std::string(label);
else {
str_label = std::string("##") + std::string(label);
this->text(label);
ImGui::SameLine();
}
// let the label string start with "##" to hide the automatic label from ImGui::SliderFloat()
bool label_visible = !boost::algorithm::istarts_with(label, "##");
std::string str_label = label_visible ? std::string("##") + std::string(label) : std::string(label);
// removes 2nd evenience of "##", if present
std::string::size_type pos = str_label.find("##", 2);
if (pos != std::string::npos)
str_label = str_label.substr(0, pos) + str_label.substr(pos + 2);
bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power);
if (!tooltip.empty() && ImGui::IsItemHovered())
@ -515,8 +515,8 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
if (clamp)
*v = std::clamp(*v, v_min, v_max);
const ImGuiStyle& style = ImGui::GetStyle();
if (show_edit_btn) {
const ImGuiStyle& style = ImGui::GetStyle();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y });
ImGui::SameLine();
std::wstring btn_name = ImGui::SliderFloatEditBtnIcon + boost::nowide::widen(str_label);
@ -534,6 +534,19 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
ImGui::PopStyleVar();
}
if (label_visible) {
// if the label is visible, hide the part of it that should be hidden
std::string out_label = std::string(label);
std::string::size_type pos = out_label.find("##");
if (pos != std::string::npos)
out_label = out_label.substr(0, pos);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y });
ImGui::SameLine();
this->text(out_label.c_str());
ImGui::PopStyleVar();
}
return ret;
}

View file

@ -10,7 +10,7 @@ void PlaterJob::on_exception(const std::exception_ptr &eptr)
if (eptr)
std::rethrow_exception(eptr);
} catch (std::exception &e) {
show_error(m_plater, _(L("An unexpected error occured: ")) + e.what());
show_error(m_plater, _(L("An unexpected error occured")) + ": "+ e.what());
}
}

View file

@ -831,26 +831,15 @@ bool MainFrame::can_start_new_project() const
bool MainFrame::can_save() const
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
m_plater->is_project_dirty();
#else
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
!m_plater->get_project_filename().empty() && m_plater->is_project_dirty();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
bool MainFrame::can_save_as() const
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
#else
return (m_plater != nullptr) && !m_plater->model().objects.empty() &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false);
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
}
void MainFrame::save_project()
@ -1214,7 +1203,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S archive") + dots, _L("Load an SL1 / Sl1S archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
[this](){return m_plater != nullptr && !m_plater->is_any_job_running(); }, this);
import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"),

View file

@ -468,9 +468,9 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
ImGui::Separator();
imgui.text_colored(color, _L("Speed:"));
float translation_scale = (float)params_copy.translation.scale / Params::DefaultTranslationScale;
if (imgui.slider_float(_L("Translation") + "##1", &translation_scale, Params::MinTranslationScale, Params::MaxTranslationScale, "%.1f")) {
params_copy.translation.scale = Params::DefaultTranslationScale * (double)translation_scale;
float translation_scale = float(params_copy.translation.scale) / float(Params::DefaultTranslationScale);
if (imgui.slider_float(_L("Translation"), &translation_scale, float(Params::MinTranslationScale), float(Params::MaxTranslationScale), "%.1f")) {
params_copy.translation.scale = Params::DefaultTranslationScale * double(translation_scale);
params_changed = true;
}
@ -517,13 +517,13 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
imgui.text_colored(color, "Vectors:");
Vec3f translation = m_state.get_first_vector_of_type(State::QueueItem::TranslationType).cast<float>();
Vec3f rotation = m_state.get_first_vector_of_type(State::QueueItem::RotationType).cast<float>();
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Translation##2", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
imgui.text_colored(color, "Queue size:");
int input_queue_size_current[2] = { int(m_state.input_queue_size_current()), int(m_state.input_queue_max_size_achieved) };
ImGui::InputInt2("Current##4", input_queue_size_current, ImGuiInputTextFlags_ReadOnly);
ImGui::InputInt2("Current", input_queue_size_current, ImGuiInputTextFlags_ReadOnly);
int input_queue_size_param = int(params_copy.input_queue_max_size);
if (ImGui::InputInt("Max size", &input_queue_size_param, 1, 1, ImGuiInputTextFlags_ReadOnly)) {

View file

@ -870,7 +870,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
}
break;
case coString:
ret = static_cast<wxString>(config.opt_string(opt_key));
ret = from_u8(config.opt_string(opt_key));
break;
case coStrings:
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") {
@ -891,7 +891,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
ret = text_value;
}
else
ret = static_cast<wxString>(config.opt_string(opt_key, static_cast<unsigned int>(idx)));
ret = from_u8(config.opt_string(opt_key, static_cast<unsigned int>(idx)));
break;
case coBool:
ret = config.opt_bool(opt_key);

View file

@ -119,6 +119,30 @@ wxDEFINE_EVENT(EVT_SLICING_COMPLETED, wxCommandEvent);
wxDEFINE_EVENT(EVT_PROCESS_COMPLETED, SlicingProcessCompletedEvent);
wxDEFINE_EVENT(EVT_EXPORT_BEGAN, wxCommandEvent);
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
{
std::string name = into_u8(wxs_name);
return has_illegal_filename_characters(name);
}
bool Plater::has_illegal_filename_characters(const std::string& name)
{
const char* illegal_characters = "<>:/\\|?*\"";
for (size_t i = 0; i < std::strlen(illegal_characters); i++)
if (name.find_first_of(illegal_characters[i]) != std::string::npos)
return true;
return false;
}
void Plater::show_illegal_characters_warning(wxWindow* parent)
{
show_error(parent, _L("The supplied name is not valid;") + "\n" +
_L("the following characters are not allowed:") + " <>:/\\|?*\"");
}
// Sidebar widgets
// struct InfoBox : public wxStaticBox
@ -1825,9 +1849,7 @@ struct Plater::priv
}
void export_gcode(fs::path output_path, bool output_path_on_removable_media, PrintHostJob upload_job);
void reload_from_disk();
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
bool replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const wxString& snapshot = "");
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void replace_with_stl();
void reload_all_from_disk();
void set_current_panel(wxPanel* panel);
@ -1886,6 +1908,9 @@ struct Plater::priv
bool can_reload_from_disk() const;
bool can_replace_with_stl() const;
bool can_split(bool to_objects) const;
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool can_scale_to_print_volume() const;
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type);
ThumbnailsList generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type);
@ -2891,6 +2916,7 @@ void Plater::priv::remove(size_t obj_idx)
if (view3D->is_layers_editing_enabled())
view3D->enable_layers_editing(false);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx);
update();
// Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model.
@ -2905,6 +2931,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
if (! model.objects[obj_idx]->name.empty())
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx);
update();
object_list_changed();
@ -2922,6 +2949,8 @@ void Plater::priv::delete_all_objects_from_model()
view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content.
background_process.reset();
model.clear_objects();
@ -2952,6 +2981,8 @@ void Plater::priv::reset()
view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content.
this->background_process.reset();
model.clear_objects();
@ -3051,7 +3082,11 @@ void Plater::priv::split_volume()
void Plater::priv::scale_selection_to_fit_print_volume()
{
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(this->bed.build_volume());
#else
this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(*config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
}
void Plater::priv::schedule_background_process()
@ -3333,7 +3368,6 @@ void Plater::priv::update_sla_scene()
this->update_restart_background_process(true, true);
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const wxString& snapshot)
{
const std::string path = new_path.string();
@ -3401,7 +3435,6 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
return true;
}
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void Plater::priv::replace_with_stl()
{
@ -3439,72 +3472,8 @@ void Plater::priv::replace_with_stl()
return;
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
if (!replace_volume_with_stl(object_idx, volume_idx, out_path, _L("Replace with STL")))
return;
#else
const auto& path = out_path.string();
wxBusyCursor wait;
wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
Model new_model;
try {
new_model = Model::read_from_file(path, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances);
for (ModelObject* model_object : new_model.objects) {
model_object->center_around_origin();
model_object->ensure_on_bed();
}
}
catch (std::exception&) {
// error while loading
return;
}
if (new_model.objects.size() > 1 || new_model.objects[0]->volumes.size() > 1) {
MessageDialog dlg(q, _L("Unable to replace with more than one volume"), _L("Error during replace"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
dlg.ShowModal();
return;
}
Plater::TakeSnapshot snapshot(q, _L("Replace with STL"));
ModelObject* old_model_object = model.objects[object_idx];
ModelVolume* old_volume = old_model_object->volumes[volume_idx];
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
ModelObject* new_model_object = new_model.objects[0];
old_model_object->add_volume(*new_model_object->volumes[0]);
ModelVolume* new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
assert(! old_volume->source.is_converted_from_inches || ! old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
else if (old_volume->source.is_converted_from_meters)
new_volume->convert_from_meters();
new_volume->supported_facets.assign(old_volume->supported_facets);
new_volume->seam_facets.assign(old_volume->seam_facets);
new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets);
std::swap(old_model_object->volumes[volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
if (!sinking)
old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
// if object has just one volume, rename object too
if (old_model_object->volumes.size() == 1)
old_model_object->name = old_model_object->volumes[0]->name;
// update new name in ObjectList
sidebar->obj_list()->update_name_in_list(object_idx, volume_idx);
sla::reproject_points_and_holes(old_model_object);
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
// update 3D scene
update();
@ -3553,9 +3522,7 @@ void Plater::priv::reload_from_disk()
// collects paths of files to load
std::vector<fs::path> input_paths;
std::vector<fs::path> missing_input_paths;
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::vector<fs::path> replace_paths;
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
for (const SelectedVolume& v : selected_volumes) {
const ModelObject* object = model.objects[v.object_idx];
const ModelVolume* volume = object->volumes[v.volume_idx];
@ -3563,7 +3530,6 @@ void Plater::priv::reload_from_disk()
if (!volume->source.input_file.empty()) {
if (fs::exists(volume->source.input_file))
input_paths.push_back(volume->source.input_file);
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
else {
// searches the source in the same folder containing the object
bool found = false;
@ -3581,10 +3547,6 @@ void Plater::priv::reload_from_disk()
if (!found)
missing_input_paths.push_back(volume->source.input_file);
}
#else
else
missing_input_paths.push_back(volume->source.input_file);
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
}
else if (!object->input_file.empty() && volume->is_model_part() && !volume->name.empty() && !volume->source.is_from_builtin_objects)
missing_input_paths.push_back(volume->name);
@ -3627,7 +3589,6 @@ void Plater::priv::reload_from_disk()
}
}
else {
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
wxString message = _L("The selected file") + " (" + from_u8(sel_filename) + ") " +
_L("differs from the original file") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to replace it") + " ?";
//wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
@ -3635,23 +3596,14 @@ void Plater::priv::reload_from_disk()
if (dlg.ShowModal() == wxID_YES)
replace_paths.push_back(sel_filename_path);
missing_input_paths.pop_back();
#else
wxString message = _L("It is not allowed to change the file to reload") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to retry") + " ?";
//wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
MessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES)
return;
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
}
}
std::sort(input_paths.begin(), input_paths.end());
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end());
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::sort(replace_paths.begin(), replace_paths.end());
replace_paths.erase(std::unique(replace_paths.begin(), replace_paths.end()), replace_paths.end());
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::vector<wxString> fail_list;
@ -3747,7 +3699,6 @@ void Plater::priv::reload_from_disk()
}
}
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
for (size_t i = 0; i < replace_paths.size(); ++i) {
const auto& path = replace_paths[i].string();
for (const SelectedVolume& sel_v : selected_volumes) {
@ -3759,7 +3710,6 @@ void Plater::priv::reload_from_disk()
}
}
}
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
if (!fail_list.empty()) {
wxString message = _L("Unable to reload:") + "\n";
@ -3873,9 +3823,7 @@ void Plater::priv::set_current_panel(wxPanel* panel)
bool export_in_progress = this->background_process.is_export_scheduled();
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
if (!model.objects.empty() && !export_in_progress && model_fits) {
#if ENABLE_SEAMS_USING_MODELS
preview->get_canvas3d()->init_gcode_viewer();
#endif // ENABLE_SEAMS_USING_MODELS
q->reslice();
}
// keeps current gcode preview, if any
@ -4526,6 +4474,14 @@ bool Plater::priv::can_split(bool to_objects) const
return sidebar->obj_list()->is_splittable(to_objects);
}
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::priv::can_scale_to_print_volume() const
{
const BuildVolume::Type type = this->bed.build_volume().type();
return !view3D->get_canvas3d()->get_selection().is_empty() && (type == BuildVolume::Type::Rectangle || type == BuildVolume::Type::Circle);
}
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::priv::layers_height_allowed() const
{
if (printer_technology != ptFFF)
@ -4603,7 +4559,7 @@ void Plater::priv::set_bed_shape(const Pointfs& shape, const double max_print_he
bool Plater::priv::can_delete() const
{
return !get_selection().is_empty() && !get_selection().is_wipe_tower() && !m_ui_jobs.is_any_running();
return !get_selection().is_empty() && !get_selection().is_wipe_tower();
}
bool Plater::priv::can_delete_all() const
@ -5051,7 +5007,7 @@ void Plater::new_project()
wxString header = _L("Creating a new project while some presets are modified.") + "\n" +
(saved_project == wxID_YES ? _L("You can keep presets modifications to the new project or discard them") :
_L("You can keep presets modifications to the new project, discard them or save changes as new presets.\n"
"Note, if changes will be saved than new project wouldn't keep them"));
"Note, if changes will be saved then new project wouldn't keep them"));
using ab = UnsavedChangesDialog::ActionButtons;
int act_buttons = ab::KEEP;
if (saved_project == wxID_NO)
@ -5133,7 +5089,8 @@ void Plater::add_model(bool imperial_units/* = false*/)
void Plater::import_sl1_archive()
{
p->m_ui_jobs.import_sla_arch();
if (!p->m_ui_jobs.is_any_running())
p->m_ui_jobs.import_sla_arch();
}
void Plater::extract_config_from_project()
@ -5417,6 +5374,11 @@ void Plater::update() { p->update(); }
void Plater::stop_jobs() { p->m_ui_jobs.stop_all(); }
bool Plater::is_any_job_running() const
{
return p->m_ui_jobs.is_any_running();
}
void Plater::update_ui_from_settings() { p->update_ui_from_settings(); }
void Plater::select_view(const std::string& direction) { p->select_view(direction); }
@ -5456,6 +5418,7 @@ void Plater::remove_selected()
return;
Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects"));
p->m_ui_jobs.cancel_all();
p->view3D->delete_selected();
}
@ -5564,7 +5527,8 @@ void Plater::set_number_of_copies(/*size_t num*/)
void Plater::fill_bed_with_instances()
{
p->m_ui_jobs.fill_bed();
if (!p->m_ui_jobs.is_any_running())
p->m_ui_jobs.fill_bed();
}
bool Plater::is_selection_empty() const
@ -5689,11 +5653,18 @@ void Plater::export_gcode(bool prefer_removable)
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
start_dir,
from_path(default_output_file.filename()),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : boost::iequals(ext, ".sl1s") ? FT_SL1S : FT_SL1, ext),
GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_SL1, ext),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
if (dlg.ShowModal() == wxID_OK)
if (dlg.ShowModal() == wxID_OK) {
output_path = into_path(dlg.GetPath());
while (has_illegal_filename_characters(output_path.filename().string())) {
show_illegal_characters_warning(this);
dlg.SetFilename(from_path(output_path.filename()));
if (dlg.ShowModal() == wxID_OK)
output_path = into_path(dlg.GetPath());
}
}
}
if (! output_path.empty()) {
@ -5881,16 +5852,11 @@ void Plater::export_amf()
bool Plater::export_3mf(const boost::filesystem::path& output_path)
{
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (p->model.objects.empty()) {
MessageDialog dialog(nullptr, _L("The plater is empty.\nDo you want to save the project?"), _L("Save project"), wxYES_NO);
if (dialog.ShowModal() != wxID_YES)
return false;
}
#else
if (p->model.objects.empty())
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
wxString path;
bool export_config = true;
@ -6085,11 +6051,12 @@ void Plater::send_gcode()
upload_job.printhost->get_groups(groups);
}
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print(), groups);
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->get_post_upload_actions(), groups);
if (dlg.ShowModal() == wxID_OK) {
upload_job.upload_data.upload_path = dlg.filename();
upload_job.upload_data.start_print = dlg.start_print();
upload_job.upload_data.post_action = dlg.post_action();
upload_job.upload_data.group = dlg.group();
p->export_gcode(fs::path(), false, std::move(upload_job));
}
}
@ -6260,8 +6227,10 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
update_scheduled = true;
p->sidebar->obj_list()->update_extruder_colors();
}
else if(opt_key == "max_print_height")
else if (opt_key == "max_print_height") {
bed_shape_changed = true;
update_scheduled = true;
}
else if (opt_key == "printer_model") {
p->reset_gcode_toolpaths();
// update to force bed selection(for texturing)
@ -6439,7 +6408,8 @@ GLCanvas3D* Plater::get_current_canvas3D()
void Plater::arrange()
{
p->m_ui_jobs.arrange();
if (!p->m_ui_jobs.is_any_running())
p->m_ui_jobs.arrange();
}
void Plater::set_current_canvas_as_dirty()
@ -6610,7 +6580,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
void Plater::optimize_rotation() { p->m_ui_jobs.optimize_rotation();}
void Plater::optimize_rotation() { if (!p->m_ui_jobs.is_any_running()) p->m_ui_jobs.optimize_rotation(); }
void Plater::update_menus() { p->menus.update(); }
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
@ -6846,6 +6816,10 @@ bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
bool Plater::can_replace_with_stl() const { return p->can_replace_with_stl(); }
bool Plater::can_mirror() const { return p->can_mirror(); }
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); }
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool Plater::can_scale_to_print_volume() const { return p->can_scale_to_print_volume(); }
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); }
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }

View file

@ -178,6 +178,7 @@ public:
void update();
void stop_jobs();
bool is_any_job_running() const;
void select_view(const std::string& direction);
void select_view_3D(const std::string& name);
@ -322,6 +323,9 @@ public:
bool can_replace_with_stl() const;
bool can_mirror() const;
bool can_split(bool to_objects) const;
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool can_scale_to_print_volume() const;
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void msw_rescale();
void sys_color_changed();
@ -427,6 +431,10 @@ public:
wxMenu* layer_menu();
wxMenu* multi_selection_menu();
static bool has_illegal_filename_characters(const wxString& name);
static bool has_illegal_filename_characters(const std::string& name);
static void show_illegal_characters_warning(wxWindow* parent);
private:
struct priv;
std::unique_ptr<priv> p;

View file

@ -468,7 +468,7 @@ void PreferencesDialog::build(size_t selected_tab)
// Add "Dark Mode" tab
if (is_editor) {
// Add "Dark Mode" tab
m_optgroup_dark_mode = create_options_tab(_L("Dark mode IU (experimental)"), tabs);
m_optgroup_dark_mode = create_options_tab(_L("Dark mode (experimental)"), tabs);
m_optgroup_dark_mode->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
};
@ -481,14 +481,17 @@ void PreferencesDialog::build(size_t selected_tab)
option = Option(def, "dark_color_mode");
m_optgroup_dark_mode->append_single_option_line(option);
def.label = L("Use system menu for application");
def.type = coBool;
def.tooltip = L("If enabled, application will use standart Windows system menu,\n"
"but on some combination od display scales it can looks ugly. "
"If disabled, old UI will be used.");
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" });
option = Option(def, "sys_menu_enabled");
m_optgroup_dark_mode->append_single_option_line(option);
if (wxPlatformInfo::Get().GetOSMajorVersion() >= 10) // Use system menu just for Window newer then Windows 10
// Use menu with ownerdrawn items by default on systems older then Windows 10
{
def.label = L("Use system menu for application");
def.type = coBool;
def.tooltip = L("If enabled, application will use the standart Windows system menu,\n"
"but on some combination of display scales it can looks ugly. If disabled, old UI will be used.");
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" });
option = Option(def, "sys_menu_enabled");
m_optgroup_dark_mode->append_single_option_line(option);
}
activate_options_tab(m_optgroup_dark_mode);
}
@ -519,7 +522,11 @@ void PreferencesDialog::build(size_t selected_tab)
void PreferencesDialog::update_ctrls_alignment()
{
int max_ctrl_width{ 0 };
std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get() };
std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
#ifdef _WIN32
, m_optgroup_dark_mode.get()
#endif // _WIN32
};
for (auto og : og_list) {
if (int max = og->custom_ctrl->get_max_win_width();
max_ctrl_width < max)

View file

@ -23,7 +23,6 @@
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
#include "I18N.hpp"
#include "../Utils/PrintHost.hpp"
#include "MainFrame.hpp"
#include "libslic3r/AppConfig.hpp"
#include "NotificationManager.hpp"
@ -35,13 +34,13 @@ namespace Slic3r {
namespace GUI {
static const char *CONFIG_KEY_PATH = "printhost_path";
static const char *CONFIG_KEY_PRINT = "printhost_print";
static const char *CONFIG_KEY_GROUP = "printhost_group";
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print, const wxArrayString &groups)
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUploadActions post_actions, const wxArrayString &groups)
: MsgDialog(static_cast<wxWindow*>(wxGetApp().mainframe), _L("Send G-Code to printer host"), _L("Upload to Printer Host with the following filename:"))
, txt_filename(new wxTextCtrl(this, wxID_ANY))
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
, post_upload_action(PrintHostPostUploadAction::None)
{
#ifdef __APPLE__
txt_filename->OSXDisableAllSmartSubstitutions();
@ -77,38 +76,47 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
txt_filename->SetValue(recent_path);
txt_filename->SetFocus();
wxString suffix = recent_path.substr(recent_path.find_last_of('.'));
m_valid_suffix = recent_path.substr(recent_path.find_last_of('.'));
// .gcode suffix control
auto validate_path = [this](const wxString &path) -> bool {
if (! path.Lower().EndsWith(m_valid_suffix.Lower())) {
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), m_valid_suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return false;
}
return true;
};
if (can_start_print) {
if (post_actions.has(PrintHostPostUploadAction::StartPrint)) {
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Print"));
btn_print->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
wxString path = txt_filename->GetValue();
// .gcode suffix control
if (!path.Lower().EndsWith(suffix.Lower()))
{
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return;
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::StartPrint;
EndDialog(wxID_OK);
}
start_print_selected = true;
EndDialog(wxID_OK);
});
});
}
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Simulate"));
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::StartSimulation;
EndDialog(wxID_OK);
}
});
}
add_button(wxID_CANCEL);
if (auto* btn_ok = get_button(wxID_NO); btn_ok != NULL) {
if (auto* btn_ok = get_button(wxID_OK); btn_ok != NULL) {
btn_ok->SetLabel(_L("Upload"));
btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
wxString path = txt_filename->GetValue();
// .gcode suffix control
if (!path.Lower().EndsWith(suffix.Lower()))
{
MessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
if (msg_wingow.ShowModal() == wxID_NO)
return;
btn_ok->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::None;
EndDialog(wxID_OK);
}
EndDialog(wxID_OK);
});
});
}
finalize();
@ -137,9 +145,9 @@ fs::path PrintHostSendDialog::filename() const
return into_path(txt_filename->GetValue());
}
bool PrintHostSendDialog::start_print() const
PrintHostPostUploadAction PrintHostSendDialog::post_action() const
{
return start_print_selected;
return post_upload_action;
}
std::string PrintHostSendDialog::group() const
@ -165,8 +173,7 @@ void PrintHostSendDialog::EndModal(int ret)
AppConfig *app_config = wxGetApp().app_config;
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0");
if (combo_groups != nullptr) {
wxString group = combo_groups->GetValue();
app_config->set("recent", CONFIG_KEY_GROUP, into_u8(group));

View file

@ -1,6 +1,7 @@
#ifndef slic3r_PrintHostSendDialog_hpp_
#define slic3r_PrintHostSendDialog_hpp_
#include <set>
#include <string>
#include <boost/filesystem/path.hpp>
@ -10,34 +11,32 @@
#include "GUI_Utils.hpp"
#include "MsgDialog.hpp"
#include "../Utils/PrintHost.hpp"
class wxButton;
class wxTextCtrl;
class wxChoice;
class wxComboBox;
class wxCheckBox;
class wxDataViewListCtrl;
namespace Slic3r {
struct PrintHostJob;
namespace GUI {
class PrintHostSendDialog : public GUI::MsgDialog
{
public:
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print, const wxArrayString& groups);
PrintHostSendDialog(const boost::filesystem::path &path, PrintHostPostUploadActions post_actions, const wxArrayString& groups);
boost::filesystem::path filename() const;
bool start_print() const;
PrintHostPostUploadAction post_action() const;
std::string group() const;
virtual void EndModal(int ret) override;
private:
wxTextCtrl *txt_filename;
wxComboBox *combo_groups;
bool start_print_selected { false };
PrintHostPostUploadAction post_upload_action;
wxString m_valid_suffix;
};

View file

@ -15,6 +15,9 @@
#include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.hpp"
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
#include "libslic3r/BuildVolume.hpp"
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
#include <GL/glew.h>
@ -948,6 +951,94 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
{
auto fit = [this](double s, const Vec3d& offset) {
if (s <= 0.0 || s == 1.0)
return;
wxGetApp().plater()->take_snapshot(_L("Scale To Fit"));
TransformationType type;
type.set_world();
type.set_relative();
type.set_joint();
// apply scale
start_dragging();
scale(s * Vec3d::Ones(), type);
wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot
// center selection on print bed
start_dragging();
translate(offset);
wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
wxGetApp().obj_manipul()->set_dirty();
};
auto fit_rectangle = [this, fit](const BuildVolume& volume) {
const BoundingBoxf3 print_volume = volume.bounding_volume();
const Vec3d print_volume_size = print_volume.size();
// adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
const Vec3d box_size = get_bounding_box().size() + 0.02 * Vec3d::Ones();
const double sx = (box_size.x() != 0.0) ? print_volume_size.x() / box_size.x() : 0.0;
const double sy = (box_size.y() != 0.0) ? print_volume_size.y() / box_size.y() : 0.0;
const double sz = (box_size.z() != 0.0) ? print_volume_size.z() / box_size.z() : 0.0;
if (sx != 0.0 && sy != 0.0 && sz != 0.0)
fit(std::min(sx, std::min(sy, sz)), print_volume.center() - get_bounding_box().center());
};
auto fit_circle = [this, fit](const BuildVolume& volume) {
const Geometry::Circled& print_circle = volume.circle();
double print_circle_radius = unscale<double>(print_circle.radius);
if (print_circle_radius == 0.0)
return;
Points points;
double max_z = 0.0;
for (unsigned int i : m_list) {
const GLVolume& v = *(*m_volumes)[i];
TriangleMesh hull_3d = *v.convex_hull();
hull_3d.transform(v.world_matrix());
max_z = std::max(max_z, hull_3d.bounding_box().size().z());
const Polygon hull_2d = hull_3d.convex_hull();
points.insert(points.end(), hull_2d.begin(), hull_2d.end());
}
if (points.empty())
return;
const Geometry::Circled circle = Geometry::smallest_enclosing_circle_welzl(points);
// adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
const double circle_radius = unscale<double>(circle.radius) + 0.01;
if (circle_radius == 0.0 || max_z == 0.0)
return;
const double s = std::min(print_circle_radius / circle_radius, volume.max_print_height() / max_z);
const Vec3d sel_center = get_bounding_box().center();
const Vec3d offset = s * (Vec3d(unscale<double>(circle.center.x()), unscale<double>(circle.center.y()), 0.5 * max_z) - sel_center);
const Vec3d print_center = { unscale<double>(print_circle.center.x()), unscale<double>(print_circle.center.y()), 0.5 * volume.max_print_height() };
fit(s, print_center - (sel_center + offset));
};
if (is_empty() || m_mode == Volume)
return;
switch (volume.type())
{
case BuildVolume::Type::Rectangle: { fit_rectangle(volume); break; }
case BuildVolume::Type::Circle: { fit_circle(volume); break; }
default: { break; }
}
}
#else
void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
{
if (is_empty() || m_mode == Volume)
@ -990,6 +1081,7 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
}
}
}
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void Selection::mirror(Axis axis)
{

View file

@ -17,6 +17,9 @@ class GLArrow;
class GLCurvedArrow;
class DynamicPrintConfig;
class GLShaderProgram;
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
class BuildVolume;
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
using GLVolumePtrs = std::vector<GLVolume*>;
using ModelObjectPtrs = std::vector<ModelObject*>;
@ -320,7 +323,11 @@ public:
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type);
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_to_fit_print_volume(const BuildVolume& volume);
#else
void scale_to_fit_print_volume(const DynamicPrintConfig& config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void mirror(Axis axis);
void translate(unsigned int object_idx, const Vec3d& displacement);

View file

@ -70,7 +70,7 @@ public:
SendSystemInfoDialog(wxWindow* parent);
private:
wxString send_info();
bool send_info(wxString& message);
const std::string m_system_info_json;
wxButton* m_btn_show_data;
wxButton* m_btn_send;
@ -649,8 +649,11 @@ SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent)
m_btn_send->Bind(wxEVT_BUTTON, [this](const wxEvent&)
{
if (wxString out = send_info(); !out.IsEmpty()) {
InfoDialog(nullptr, wxEmptyString, out).ShowModal();
wxString message;
bool success = send_info(message);
if (! message.IsEmpty())
InfoDialog(nullptr, wxEmptyString, message).ShowModal();
if (success) {
save_version();
EndModal(0);
}
@ -679,7 +682,7 @@ void SendSystemInfoDialog::on_dpi_changed(const wxRect&)
// This actually sends the info.
wxString SendSystemInfoDialog::send_info()
bool SendSystemInfoDialog::send_info(wxString& message)
{
std::atomic<int> job_done = false; // Flag to communicate between threads.
struct Result {
@ -723,9 +726,8 @@ wxString SendSystemInfoDialog::send_info()
job_done = true; // In case the user closed the dialog, let the other thread know
sending_thread.join(); // and wait until it terminates.
if (result.value == Result::Cancelled)
return "";
return result.str;
message = result.value == Result::Cancelled ? wxString("") : result.str;
return result.value == Result::Success;
}

View file

@ -1650,6 +1650,7 @@ void TabPrint::build()
optgroup->append_single_option_line("slice_closing_radius");
optgroup->append_single_option_line("slicing_mode");
optgroup->append_single_option_line("resolution");
optgroup->append_single_option_line("gcode_resolution");
optgroup->append_single_option_line("xy_size_compensation");
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");
@ -3569,6 +3570,7 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
on_presets_changed();
// If current profile is saved, "delete preset" button have to be enabled
m_btn_delete_preset->Show();
m_btn_delete_preset->GetParent()->Layout();
if (m_type == Preset::TYPE_PRINTER)
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;

View file

@ -93,7 +93,7 @@ bool MsgUpdateSlic3r::disable_version_check() const
MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_before_wizard/* = false*/) :
MsgDialog(nullptr, force_before_wizard ? _L("Opening Configuration Wizard") : _L("Configuration update"),
force_before_wizard ? _L("PrusaSlicer is not using the newest configuration available.\n"
"Configuration Wizard may not offer the latest printers, filaments and SLA materials to be installed. ") :
"Configuration Wizard may not offer the latest printers, filaments and SLA materials to be installed.") :
_L("Configuration update is available"), wxICON_ERROR)
{
auto *text = new wxStaticText(this, wxID_ANY, _(L(

View file

@ -30,6 +30,14 @@ inline wxString format_wxstr(const wxString& fmt, TArgs&&... args) {
return format_wxstr(fmt.ToUTF8().data(), std::forward<TArgs>(args)...);
}
template<typename... TArgs>
inline std::string format(const char* fmt, TArgs&&... args) {
return Slic3r::format(fmt, std::forward<TArgs>(args)...);
}
template<typename... TArgs>
inline std::string format(const std::string& fmt, TArgs&&... args) {
return Slic3r::format(fmt, std::forward<TArgs>(args)...);
}
template<typename... TArgs>
inline std::string format(const wxString& fmt, TArgs&&... args) {
return Slic3r::format(fmt.ToUTF8().data(), std::forward<TArgs>(args)...);
}

View file

@ -115,11 +115,11 @@ bool AstroBox::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print;
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
auto http = Http::post(std::move(url));
set_auth(http);
http.form_add("print", upload_data.start_print ? "true" : "false")
http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ???
.form_add_file("file", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) {

View file

@ -26,7 +26,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; }
std::string get_host() const override { return host; }
protected:

View file

@ -67,10 +67,10 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
bool dsf = (connectionType == ConnectionType::dsf);
auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType);
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, post_action: %3%, command: %4%")
% upload_data.source_path
% upload_data.upload_path
% upload_data.start_print
% int(upload_data.post_action)
% upload_cmd;
auto http = (dsf ? Http::put(std::move(upload_cmd)) : Http::post(std::move(upload_cmd)));
@ -87,9 +87,15 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Request completed but error code was received: %1%") % err_code;
error_fn(format_error(body, L("Unknown error occured"), 0));
res = false;
} else if (upload_data.start_print) {
} else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
wxString errormsg;
res = start_print(errormsg, upload_data.upload_path.string(), connectionType);
res = start_print(errormsg, upload_data.upload_path.string(), connectionType, false);
if (! res) {
error_fn(std::move(errormsg));
}
} else if (upload_data.post_action == PrintHostPostUploadAction::StartSimulation) {
wxString errormsg;
res = start_print(errormsg, upload_data.upload_path.string(), connectionType, true);
if (! res) {
error_fn(std::move(errormsg));
}
@ -230,7 +236,7 @@ std::string Duet::timestamp_str() const
return std::string(buffer);
}
bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const
bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const
{
assert(connectionType != ConnectionType::error);
@ -240,14 +246,18 @@ bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionTyp
auto url = dsf
? (boost::format("%1%machine/code")
% get_base_url()).str()
: (boost::format("%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"")
: (boost::format(simulationMode
? "%1%rr_gcode?gcode=M37%%20P\"0:/gcodes/%2%\""
: "%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"")
% get_base_url()
% Http::url_encode(filename)).str();
auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url)));
if (dsf) {
http.set_post_body(
(boost::format("M32 \"0:/gcodes/%1%\"")
(boost::format(simulationMode
? "M37 P\"0:/gcodes/%1%\""
: "M32 \"0:/gcodes/%1%\"")
% filename).str()
);
}

View file

@ -25,7 +25,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint | PrintHostPostUploadAction::StartSimulation; }
std::string get_host() const override { return host; }
private:
@ -39,7 +39,7 @@ private:
std::string timestamp_str() const;
ConnectionType connect(wxString &msg) const;
void disconnect(ConnectionType connectionType) const;
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const;
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType, bool simulationMode) const;
int get_err_code_from_body(const std::string &body) const;
};

Some files were not shown because too many files have changed in this diff Show more