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_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag} # GIT_TAG tm_cross_compile #${_wx_git_tag}
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip 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 DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
CMAKE_ARGS CMAKE_ARGS
-DwxBUILD_PRECOMP=ON -DwxBUILD_PRECOMP=ON

View file

@ -13,9 +13,21 @@ This guide describes building PrusaSlicer statically against dependencies pulled
#### 0. Prerequisities #### 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 #### 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 disabled_tags = SLA
[hint:Insert Custom G-code] [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 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 disabled_tags = SLA
@ -203,8 +203,8 @@ hypertext_type = menubar
hypertext_menubar_menu_name = Configuration hypertext_menubar_menu_name = Configuration
hypertext_menubar_item_name = Configuration Snapshots hypertext_menubar_item_name = Configuration Snapshots
[hint:Minimum wall thickness] [hint:Minimum shell 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. 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_type = settings
hypertext_settings_opt = top_solid_min_thickness hypertext_settings_opt = top_solid_min_thickness
hypertext_settings_type = 1 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. 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-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. 1.4.0-beta0 Added multiple Filatech and BASF filament profiles. Added material profiles for SL1S.
min_slic3r_version = 2.4.0-alpha0 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-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. 1.3.0-alpha0 Disabled thick bridges, updated support settings.
min_slic3r_version = 2.3.2-alpha0 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.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.2 Added material profiles for Prusament Resin.
1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S). 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 name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs. # 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. # 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? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ 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% changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -2925,7 +2925,6 @@ bridge_fan_speed = 100
filament_type = PET filament_type = PET
disable_fan_first_layers = 1 disable_fan_first_layers = 1
full_fan_speed_layer = 3 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_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_length = 2
filament_retract_speed = 40 filament_retract_speed = 40
@ -4836,6 +4835,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 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 ## Prusa 0.025
[sla_material:Prusa Orange Tough @0.025] [sla_material:Prusa Orange Tough @0.025]
@ -5649,6 +5688,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #C0C0C0 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 ## Prusa 0.05
[sla_material:Prusa Beige Tough @0.05] [sla_material:Prusa Beige Tough @0.05]
@ -5965,6 +6044,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 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 ## Prusa 0.1
[sla_material:Prusa Orange Tough @0.1] [sla_material:Prusa Orange Tough @0.1]
@ -6085,6 +6204,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 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 ## Made for Prusa 0.025
[sla_material:Prusa Orange Tough @0.025 SL1S] [sla_material:Prusa Orange Tough @0.025 SL1S]
@ -6331,6 +6490,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 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 ## Made for Prusa 0.05
[sla_material:Prusa Orange Tough @0.05 SL1S] [sla_material:Prusa Orange Tough @0.05 SL1S]
@ -6577,6 +6776,46 @@ material_type = Tough
material_vendor = Prusa Polymers material_vendor = Prusa Polymers
material_colour = #808080 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 ## Made for Prusa 0.1
[sla_material:Prusa Orange Tough @0.1 SL1S] [sla_material:Prusa Orange Tough @0.1 SL1S]

View file

@ -1,26 +1,7 @@
#version 110 #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 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 EPSILON = 0.0001;
const float BANDS_WIDTH = 10.0;
struct PrintVolumeDetection struct PrintVolumeDetection
{ {

View file

@ -595,6 +595,19 @@ int CLI::run(int argc, char **argv)
if (start_gui) { if (start_gui) {
#ifdef SLIC3R_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; Slic3r::GUI::GUI_InitParams params;
params.argc = argc; params.argc = argc;
params.argv = argv; 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; 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; Polygons islands;
for (const PrintObject *object : top_level_objects_with_brim) { 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)) { for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) {
Polygons contour_offset = offset(ex_poly.contour, brim_separation, ClipperLib::jtSquare); Polygons contour_offset = offset(ex_poly.contour, brim_separation, ClipperLib::jtSquare);
for (Polygon &poly : contour_offset) for (Polygon &poly : contour_offset)
poly.douglas_peucker(SCALED_RESOLUTION); poly.douglas_peucker(scaled_resolution);
polygons_append(islands_object, std::move(contour_offset)); polygons_append(islands_object, std::move(contour_offset));
} }
@ -359,13 +359,14 @@ static void make_inner_brim(const Print &print,
ExtrusionEntityCollection &brim) ExtrusionEntityCollection &brim)
{ {
assert(print.objects().size() == bottom_layers_expolygons.size()); assert(print.objects().size() == bottom_layers_expolygons.size());
const auto scaled_resolution = scaled<double>(print.config().gcode_resolution.value);
Flow flow = print.brim_flow(); Flow flow = print.brim_flow();
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing())); ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
Polygons loops; Polygons loops;
islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare); islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare);
for (size_t i = 0; !islands_ex.empty(); ++i) { for (size_t i = 0; !islands_ex.empty(); ++i) {
for (ExPolygon &poly_ex : islands_ex) 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)); polygons_append(loops, to_polygons(islands_ex));
islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), ClipperLib::jtSquare); 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. // 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) 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(); Flow flow = print.brim_flow();
std::vector<ExPolygons> bottom_layers_expolygons = get_print_bottom_layers_expolygons(print); 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); 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())); 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); islands_area = to_polygons(islands_area_ex);
@ -393,7 +395,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
try_cancel(); try_cancel();
islands = expand(islands, float(flow.scaled_spacing()), ClipperLib::jtSquare); islands = expand(islands, float(flow.scaled_spacing()), ClipperLib::jtSquare);
for (Polygon &poly : islands) 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()))); polygons_append(loops, shrink(islands, 0.5f * float(flow.scaled_spacing())));
} }
loops = union_pt_chained_outside_in(loops); 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; 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) { switch (m_type) {
case Type::Rectangle: case Type::Rectangle:
{ {
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon); 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.0)
if (m_max_print_height == 0)
build_volume.max.z() = std::numeric_limits<double>::max(); 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. // 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()); //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. //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: case Type::Circle:
{ {
Geometry::Circlef circle { unscaled<float>(m_circle.center), unscaled<float>(m_circle.radius + SceneEpsilon) }; 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](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)); }); 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: case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom: 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](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>()); }); 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: 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); assert(m_type == Type::Rectangle);
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon); 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(); 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 : return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below :
build_volume.contains(volume_bbox) ? ObjectState::Inside : build_volume.contains(volume_bbox) ? ObjectState::Inside :
build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; 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) { auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) {
return move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.f && move.height != 0.f; 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: case Type::Rectangle:
{ {
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(epsilon); 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(); 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); return build_volume.contains(paths_bbox);
} }
case Type::Circle: 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 Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + epsilon; const float r = unscaled<double>(m_circle.radius) + epsilon;
const float r2 = sqr(r); 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) 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; }) : { 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) 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: case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom: 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) 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>()); }) : { 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) 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; 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); assert(paths.size() % 6 == 0);
static constexpr const double epsilon = BedEpsilon; 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: case Type::Rectangle:
{ {
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(epsilon); 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(); 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>()); return build_volume.contains(paths_bbox.min().cast<double>()) && build_volume.contains(paths_bbox.max().cast<double>());
} }
case Type::Circle: 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 Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + float(epsilon); const float r = unscaled<double>(m_circle.radius) + float(epsilon);
const float r2 = sqr(r); 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](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; }); 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: case Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case Type::Custom: 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](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; }); 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: default:

View file

@ -80,19 +80,19 @@ public:
// Called by Plater to update Inside / Colliding / Outside state of ModelObjects before slicing. // 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() // Called from Model::update_print_volume_state() -> ModelObject::update_instances_print_volume_state()
// Using SceneEpsilon // 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 by GLVolumeCollection::check_outside_state() after an object is manipulated with gizmos for example.
// Called for a rectangular bed: // 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. // 2) Test called on G-code paths.
// Using BedEpsilon for all tests. // Using BedEpsilon for all tests.
static constexpr const double BedEpsilon = 3. * EPSILON; static constexpr const double BedEpsilon = 3. * EPSILON;
// Called on final G-code paths. // Called on final G-code paths.
//FIXME The test does not take the thickness of the extrudates into account! //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. // 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: private:
// Source definition of the print bed geometry (PrintConfig::bed_shape) // 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(PUSH)
cmake_policy(SET CMP0011 NEW) cmake_policy(SET CMP0011 NEW)
find_package(CGAL 4.13.2 REQUIRED) find_package(CGAL 4.13 REQUIRED)
cmake_policy(POP) cmake_policy(POP)
add_library(libslic3r_cgal STATIC MeshBoolean.hpp MeshBoolean.cpp 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. // 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) 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) if (str == nullptr)
return 0; return 0;

View file

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

View file

@ -116,6 +116,7 @@ std::optional<Emboss::Glyph> Private::get_glyph(
Emboss::Glyphs & cache, Emboss::Glyphs & cache,
std::optional<stbtt_fontinfo> &font_info_opt) std::optional<stbtt_fontinfo> &font_info_opt)
{ {
const double RESOLUTION = 0.0125; // TODO: read from printer configuration
auto glyph_item = cache.find(unicode); auto glyph_item = cache.find(unicode);
if (glyph_item != cache.end()) if (glyph_item != cache.end())
return glyph_item->second; return glyph_item->second;
@ -125,7 +126,6 @@ std::optional<Emboss::Glyph> Private::get_glyph(
// can load font info? // can load font info?
if (!font_info_opt.has_value()) return {}; if (!font_info_opt.has_value()) return {};
} }
float flatness = static_cast<float>( float flatness = static_cast<float>(
font.ascent * RESOLUTION / font_prop.size_in_mm); font.ascent * RESOLUTION / font_prop.size_in_mm);
std::optional<Emboss::Glyph> glyph_opt = 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 */ #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
std::vector<SurfaceFill> surface_fills = group_fills(*this); 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 #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.dont_adjust = false; // surface_fill.params.dont_adjust;
params.anchor_length = surface_fill.params.anchor_length; params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max; params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
for (ExPolygon &expoly : surface_fill.expolygons) { for (ExPolygon &expoly : surface_fill.expolygons) {
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. // 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 { 1000.f };
float anchor_length_max { 1000.f }; float anchor_length_max { 1000.f };
// G-code resolution.
double resolution { 0.0125 };
// Don't adjust spacing to fill the space evenly. // Don't adjust spacing to fill the space evenly.
bool dont_adjust { true }; 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.x()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.min.y()) / 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.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) { if (pts.size() >= 2) {
// Convert points to a polyline, upscale. // 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 // 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. // 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; 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(0, 0);
out.emplace_back(1, 0); out.emplace_back(1, 0);
while (r < rmax) { while (r < rmax) {
// Discretization angle to achieve a discretization error lower than RESOLUTION. // Discretization angle to achieve a discretization error lower than resolution.
theta += 2. * acos(1. - RESOLUTION / r); theta += 2. * acos(1. - resolution / r);
r = a + b * theta; r = a + b * theta;
out.emplace_back(r * cos(theta), r * sin(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); 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. // Minimum power of two square to fit the domain.
size_t sz = 2; 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; 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. // 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; 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; } float _layer_angle(size_t idx) const override { return 0.f; }
virtual bool _centered() const = 0; 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 class FillArchimedeanChords : public FillPlanePath
@ -39,7 +39,7 @@ public:
protected: protected:
bool _centered() const override { return true; } 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 class FillHilbertCurve : public FillPlanePath
@ -50,7 +50,7 @@ public:
protected: protected:
bool _centered() const override { return false; } 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 class FillOctagramSpiral : public FillPlanePath
@ -61,7 +61,7 @@ public:
protected: protected:
bool _centered() const override { return true; } 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 } // 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) 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 // This happens for empty projects
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (build_items.size() == 0) { if (build_items.size() == 0) {
add_error("No build item found"); add_error("No build item found");
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return true; return true;
#else
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
} }
stream << " <" << BUILD_TAG << ">\n"; stream << " <" << BUILD_TAG << ">\n";

View file

@ -1544,30 +1544,37 @@ void GCode::process_layers(
const size_t single_object_idx, const size_t single_object_idx,
GCodeOutputStream &output_stream) 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; size_t layer_to_print_idx = 0;
tbb::parallel_pipeline(12, const auto generator = tbb::make_filter<void, GCode::LayerResult>(tbb::filter::serial_in_order,
tbb::make_filter<void, GCode::LayerResult>( [this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
tbb::filter::serial_in_order, if (layer_to_print_idx == layers_to_print.size()) {
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult { fc.stop();
if (layer_to_print_idx == layers_to_print.size()) { return {};
fc.stop(); } else {
return {}; LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
} else { print.throw_if_canceled();
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++]; 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);
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 {
tbb::make_filter<GCode::LayerResult, std::string>( spiral_vase.enable(in.spiral_vase_enable);
tbb::filter::serial_in_order, return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
[&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 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 {
tbb::make_filter<std::string, void>( return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
tbb::filter::serial_in_order, });
[&output_stream](std::string s) { output_stream.write(s); } 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) 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_writer.apply_print_config(print_config);
m_config.apply(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) 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) { for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
// description += ExtrusionLoop::role_to_string(loop.loop_role()); // description += ExtrusionLoop::role_to_string(loop.loop_role());
// description += ExtrusionEntity::role_to_string(path->role); // description += ExtrusionEntity::role_to_string(path->role);
path->simplify(SCALED_RESOLUTION); path->simplify(m_scaled_resolution);
gcode += this->_extrude(*path, description, speed); 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) { for (ExtrusionPath path : multipath.paths) {
// description += ExtrusionLoop::role_to_string(loop.loop_role()); // description += ExtrusionLoop::role_to_string(loop.loop_role());
// description += ExtrusionEntity::role_to_string(path->role); // description += ExtrusionEntity::role_to_string(path->role);
path.simplify(SCALED_RESOLUTION); path.simplify(m_scaled_resolution);
gcode += this->_extrude(path, description, speed); gcode += this->_extrude(path, description, speed);
} }
if (m_wipe.enable) { 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) std::string GCode::extrude_path(ExtrusionPath path, std::string description, double speed)
{ {
// description += ExtrusionEntity::role_to_string(path.role()); // description += ExtrusionEntity::role_to_string(path.role());
path.simplify(SCALED_RESOLUTION); path.simplify(m_scaled_resolution);
std::string gcode = this->_extrude(path, description, speed); std::string gcode = this->_extrude(path, description, speed);
if (m_wipe.enable) { if (m_wipe.enable) {
m_wipe.path = std::move(path.polyline); m_wipe.path = std::move(path.polyline);

View file

@ -345,6 +345,8 @@ private:
methods. */ methods. */
Vec2d m_origin; Vec2d m_origin;
FullPrintConfig m_config; FullPrintConfig m_config;
// scaled G-code resolution
double m_scaled_resolution;
GCodeWriter m_writer; GCodeWriter m_writer;
PlaceholderParser m_placeholder_parser; PlaceholderParser m_placeholder_parser;
// For random number generator etc. // 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::PrusaSlicer, "generated by PrusaSlicer" },
{ EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" }, { EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
{ EProducer::Slic3r, "generated by Slic3r" }, { EProducer::Slic3r, "generated by Slic3r" },
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::SuperSlicer, "generated by SuperSlicer" }, { EProducer::SuperSlicer, "generated by SuperSlicer" },
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::Cura, "Cura_SteamEngine" }, { EProducer::Cura, "Cura_SteamEngine" },
{ EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" }, { EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
{ EProducer::CraftWare, "CraftWare" }, { EProducer::CraftWare, "CraftWare" },
@ -813,9 +811,7 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
} }
GCodeProcessor::GCodeProcessor() GCodeProcessor::GCodeProcessor()
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
: m_options_z_corrector(m_result) : m_options_z_corrector(m_result)
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
{ {
reset(); reset();
m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n"; 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_use_volumetric_e = false;
m_last_default_color_id = 0; m_last_default_color_id = 0;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.reset(); m_options_z_corrector.reset();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_mm3_per_mm_compare.reset(); 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) else if (m_producer == EProducer::Simplify3D)
apply_config_simplify3d(filename); apply_config_simplify3d(filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
else if (m_producer == EProducer::SuperSlicer) else if (m_producer == EProducer::SuperSlicer)
apply_config_superslicer(filename); apply_config_superslicer(filename);
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
} }
// process gcode // process gcode
@ -1375,7 +1367,6 @@ std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(Prin
return ret; return ret;
} }
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule) ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
{ {
// for reference, see: ConfigBase::load_from_gcode_file() // 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); load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config); apply_config(config);
} }
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const 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); store_move_vertex(EMoveType::Color_change);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" }; 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); m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set(); m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::ColorChange); process_custom_gcode_time(CustomGCode::ColorChange);
process_filaments(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); store_move_vertex(EMoveType::Pause_Print);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" }; 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); m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set(); m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::PausePrint); process_custom_gcode_time(CustomGCode::PausePrint);
return; return;
} }
@ -1872,9 +1858,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
store_move_vertex(EMoveType::Custom_GCode); store_move_vertex(EMoveType::Custom_GCode);
CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" }; 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); m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set(); m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
return; return;
} }
@ -1900,9 +1884,7 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{ {
case EProducer::Slic3rPE: case EProducer::Slic3rPE:
case EProducer::Slic3r: case EProducer::Slic3r:
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::SuperSlicer: case EProducer::SuperSlicer:
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); } case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); } case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_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) if (m_forced_height > 0.0f)
m_height = m_forced_height; m_height = m_forced_height;
else { 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; 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) if (m_height == 0.0f)
@ -2469,10 +2447,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
if (m_end_position[Z] == 0.0f) if (m_end_position[Z] == 0.0f)
m_end_position[Z] = m_height; m_end_position[Z] = m_height;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_extruded_last_z = m_end_position[Z]; m_extruded_last_z = m_end_position[Z];
m_options_z_corrector.update(m_height); m_options_z_corrector.update(m_height);
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_height_compare.update(m_height, m_extrusion_role); 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(); } 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 // Helper class used to fix the z for color change, pause print and
// custom gcode markes // custom gcode markes
class OptionsZCorrector class OptionsZCorrector
@ -426,7 +425,6 @@ namespace Slic3r {
m_custom_gcode_per_print_z_id.reset(); m_custom_gcode_per_print_z_id.reset();
} }
}; };
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
struct DataChecker struct DataChecker
@ -532,9 +530,7 @@ namespace Slic3r {
CpColor m_cp_color; CpColor m_cp_color;
bool m_use_volumetric_e; bool m_use_volumetric_e;
SeamsDetector m_seams_detector; SeamsDetector m_seams_detector;
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
OptionsZCorrector m_options_z_corrector; OptionsZCorrector m_options_z_corrector;
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
size_t m_last_default_color_id; size_t m_last_default_color_id;
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time; std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
@ -546,9 +542,7 @@ namespace Slic3r {
PrusaSlicer, PrusaSlicer,
Slic3rPE, Slic3rPE,
Slic3r, Slic3r,
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
SuperSlicer, SuperSlicer,
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
Cura, Cura,
Simplify3D, Simplify3D,
CraftWare, CraftWare,
@ -605,9 +599,7 @@ namespace Slic3r {
private: private:
void apply_config(const DynamicPrintConfig& config); void apply_config(const DynamicPrintConfig& config);
void apply_config_simplify3d(const std::string& filename); void apply_config_simplify3d(const std::string& filename);
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void apply_config_superslicer(const std::string& filename); 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); void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
// Process tags embedded into comments // Process tags embedded into comments

View file

@ -2,6 +2,7 @@
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/format.hpp" #include "libslic3r/format.hpp"
#include "libslic3r/I18N.hpp"
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/log/trivial.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 { 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. // Run post processing script / scripts if defined.
// Returns true if a post-processing script was executed. // Returns true if a post-processing script was executed.
// Returns false if no post-processing script was defined. // 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(); delete_copy();
throw Slic3r::RuntimeError(msg); 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)) { 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) if (!result)
throw Slic3r::RuntimeError("Loading of a model file failed."); throw Slic3r::RuntimeError("Loading of a model file failed.");
#if !ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED for (ModelObject *o : model.objects) {
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)
{
// if (boost::algorithm::iends_with(input_file, ".zip.amf")) // 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 // // 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) { for (const Surface &surface : this->slices->surfaces) {
// detect how many perimeters must be generated for this island // detect how many perimeters must be generated for this island
int loop_number = this->config->perimeters + surface.extra_perimeters - 1; // 0-indexed loops 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; ExPolygons gaps;
if (loop_number >= 0) { if (loop_number >= 0) {
// In case no perimeters are to be generated, loop_number will equal to -1. // 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 // simplify infill contours according to resolution
Polygons pp; Polygons pp;
for (ExPolygon &ex : last) for (ExPolygon &ex : last)
ex.simplify_p(SCALED_RESOLUTION, &pp); ex.simplify_p(m_scaled_resolution, &pp);
// collapse too narrow infill areas // collapse too narrow infill areas
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
// append infill areas to fill_surfaces // append infill areas to fill_surfaces

View file

@ -50,6 +50,7 @@ public:
overhang_flow(flow), solid_infill_flow(flow), overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config), config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_vase), 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), 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) m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1)
{} {}
@ -63,6 +64,7 @@ public:
private: private:
bool m_spiral_vase; bool m_spiral_vase;
double m_scaled_resolution;
double m_ext_mm3_per_mm; double m_ext_mm3_per_mm;
double m_mm3_per_mm; double m_mm3_per_mm;
double m_mm3_per_mm_overhang; 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", "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", "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", "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_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" "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 ( } else if (
opt_key == "first_layer_extrusion_width" opt_key == "first_layer_extrusion_width"
|| opt_key == "min_layer_height" || 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(posPerimeters);
osteps.emplace_back(posInfill); osteps.emplace_back(posInfill);
osteps.emplace_back(posSupportMaterial); 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. // 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. // Find the top-most printable volume of this modifier, or the printable volume itself.
int parent_region_id = this_region_id; const PrintObjectRegions::VolumeRegion &this_region = layer_range.volume_regions[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) const PrintObjectRegions::BoundingBox *this_extents = find_volume_extents(layer_range, *this_region.model_volume);
assert(parent_region_id >= 0); assert(this_extents);
return find_volume_extents(layer_range, *layer_range.volume_regions[parent_region_id].model_volume); 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); 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, // 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. // which may require new regions to be created.
it_model_volume_modifier_last = it_model_volume; it_model_volume_modifier_last = it_model_volume;
int this_region_id = int(&region - layer_range.volume_regions.data()); int next_region_id = int(&region - layer_range.volume_regions.data());
int next_region_id = this_region_id + 1;
const PrintObjectRegions::BoundingBox *bbox = find_volume_extents(layer_range, *region.model_volume); const PrintObjectRegions::BoundingBox *bbox = find_volume_extents(layer_range, *region.model_volume);
assert(bbox); 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]; const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
assert(parent_region.model_volume != region.model_volume); assert(parent_region.model_volume != region.model_volume);
if (parent_region.model_volume->is_model_part() || parent_region.model_volume->is_modifier()) { 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) { layer_range.volume_regions[next_region_id].parent == parent_region_id) {
// A parent region is already overridden. // A parent region is already overridden.
++ next_region_id; ++ 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. // 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); // Only create new region for a modifier, which actually modifies config of it's parent.
assert(parent_bbox != nullptr); if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders);
if (parent_bbox->intersects(*bbox)) config != parent_region.region->config())
// Only create new region for a modifier, which actually modifies config of it's parent. // This modifier newly overrides a region, which it did not before. We need to reslice.
if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, **it_model_volume, num_extruders); return false;
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) { 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 PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[parent_region_id];
const ModelVolume &parent_volume = *parent_region.model_volume; const ModelVolume &parent_volume = *parent_region.model_volume;
if (parent_volume.is_model_part() || parent_volume.is_modifier()) { if (parent_volume.is_model_part() || parent_volume.is_modifier())
const PrintObjectRegions::BoundingBox *parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) {
assert(parent_bbox != nullptr);
if (parent_bbox->intersects(*bbox))
// Only create new region for a modifier, which actually modifies config of it's parent. // 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); if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders);
config != parent_region.region->config()) { 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 }); 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()) } else if (parent_model_part_id == -1 && parent_volume.is_model_part())
parent_model_part_id = parent_region_id; parent_model_part_id = parent_region_id;
} }
} }
if (! added && parent_model_part_id >= 0) if (! added && parent_model_part_id >= 0)
// This modifier does not override any printable volume's configuration, however it may in the future. // 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 }, { "duet", htDuet },
{ "flashair", htFlashAir }, { "flashair", htFlashAir },
{ "astrobox", htAstroBox }, { "astrobox", htAstroBox },
{ "repetier", htRepetier } { "repetier", htRepetier },
{ "mks", htMKS }
}; };
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType) 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("flashair");
def->enum_values.push_back("astrobox"); def->enum_values.push_back("astrobox");
def->enum_values.push_back("repetier"); def->enum_values.push_back("repetier");
def->enum_values.push_back("mks");
def->enum_labels.push_back("PrusaLink"); def->enum_labels.push_back("PrusaLink");
def->enum_labels.push_back("OctoPrint"); def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet"); def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir"); def->enum_labels.push_back("FlashAir");
def->enum_labels.push_back("AstroBox"); def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier"); def->enum_labels.push_back("Repetier");
def->enum_labels.push_back("MKS");
def->mode = comAdvanced; def->mode = comAdvanced;
def->cli = ConfigOptionDef::nocli; def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint)); 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->set_default_value(new ConfigOptionInt(0));
def = this->add("resolution", coFloat); 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 " 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 " "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 " "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->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0)); 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 = this->add("retract_before_travel", coFloats);
def->label = L("Minimum travel after retraction"); def->label = L("Minimum travel after retraction");
def->tooltip = L("Retraction is not triggered when travel moves are shorter than this length."); 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("Rectilinear"));
def->enum_labels.push_back(L("Concentric")); def->enum_labels.push_back(L("Concentric"));
def->mode = comAdvanced; 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 = this->add("support_material_spacing", coFloat);
def->label = L("Pattern spacing"); def->label = L("Pattern spacing");
@ -3937,6 +3952,10 @@ void DynamicPrintConfig::normalize_fdm()
this->opt<ConfigOptionPercent>("fill_density", true)->value = 0; 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) void handle_legacy_sla(DynamicPrintConfig &config)

View file

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

View file

@ -379,11 +379,7 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
int j = i; int j = i;
bool merged = false; bool merged = false;
ExPolygons &expolygons = temp_slices[i].expolygons; ExPolygons &expolygons = temp_slices[i].expolygons;
for (++ j; for (++ j; j < int(temp_slices.size()) && temp_slices[i].region_id == temp_slices[j].region_id; ++ 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)
if (ExPolygons &expolygons2 = temp_slices[j].expolygons; ! expolygons2.empty()) { if (ExPolygons &expolygons2 = temp_slices[j].expolygons; ! expolygons2.empty()) {
if (expolygons.empty()) { if (expolygons.empty()) {
expolygons = std::move(expolygons2); expolygons = std::move(expolygons2);
@ -392,7 +388,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
merged = true; 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))); expolygons = closing_ex(expolygons, float(scale_(EPSILON)));
slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons); slices_by_region[temp_slices[i].region_id][z_idx] = std::move(expolygons);
i = j; i = j;

View file

@ -2354,8 +2354,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
Polygons &layer_support_area = layer_support_areas[layer_id]; Polygons &layer_support_area = layer_support_areas[layer_id];
Polygons *layer_buildplate_covered = buildplate_covered.empty() ? nullptr : &buildplate_covered[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%. // 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())); // 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 task_group.run([&grid_params, &overhangs_projection, &overhangs_projection_raw, &layer, &layer_support_area, layer_buildplate_covered /* , column_propagation_filtering_radius */
#ifdef SLIC3R_DEBUG #ifdef SLIC3R_DEBUG
, iRun, layer_id , iRun, layer_id
#endif /* SLIC3R_DEBUG */ #endif /* SLIC3R_DEBUG */

View file

@ -36,43 +36,6 @@
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS 1 #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 // 2.4.0.beta1 techs
//==================== //====================
@ -91,5 +54,8 @@
// an additional button can be used to set the keyboard focus into the slider // an additional button can be used to set the keyboard focus into the slider
// to allow the user to type in the desired value // to allow the user to type in the desired value
#define ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT (1 && ENABLE_2_4_0_BETA2) #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_ #endif // _prusaslicer_technologies_h_

View file

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

View file

@ -560,9 +560,9 @@ void slice_facet_with_slabs(
// Save the open edge for sure. // Save the open edge for sure.
type = FacetSliceType::Slicing; type = FacetSliceType::Slicing;
} else { } else {
#ifndef NDEBUG
const stl_triangle_vertex_indices &neighbor = mesh_triangles[neighbor_idx]; const stl_triangle_vertex_indices &neighbor = mesh_triangles[neighbor_idx];
float z = *it; 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); 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); assert(num_on_plane == 2 || num_on_plane == 3);
#endif // NDEBUG #endif // NDEBUG
@ -1866,9 +1866,13 @@ std::vector<ExPolygons> slice_mesh_ex(
//FIXME simplify //FIXME simplify
if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour) if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour)
keep_largest_contour_only(expolygons); keep_largest_contour_only(expolygons);
if (resolution != 0.) if (resolution != 0.) {
for (ExPolygon &ex : expolygons) ExPolygons simplified;
ex.simplify(resolution); 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"; // 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) // 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. // with int64_t we don't have to worry anymore about the size of the int.
static constexpr double SCALING_FACTOR = 0.000001; 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; static constexpr double PI = 3.141592653589793238;
// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam. // 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; 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 REALfloat = 1 all numbers are 'float' type
= 0 all numbers are 'double' type = 0 all numbers are 'double' type
*/ */
#define REALfloat 1 #define REALfloat 0
#if (REALfloat == 1) #if (REALfloat == 1)
#define realT float #define realT float

View file

@ -245,6 +245,10 @@ set(SLIC3R_GUI_SOURCES
Utils/UndoRedo.hpp Utils/UndoRedo.hpp
Utils/HexFile.cpp Utils/HexFile.cpp
Utils/HexFile.hpp Utils/HexFile.hpp
Utils/TCPConsole.cpp
Utils/TCPConsole.hpp
Utils/MKS.cpp
Utils/MKS.hpp
) )
if (APPLE) if (APPLE)
@ -258,7 +262,6 @@ if (APPLE)
GUI/InstanceCheckMac.h GUI/InstanceCheckMac.h
) )
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration) FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
endif () endif ()
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) 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}) 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}) target_link_libraries(libslic3r_gui ${DBUS_LIBRARIES})
elseif (APPLE)
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY})
endif() endif()
if (SLIC3R_STATIC) if (SLIC3R_STATIC)
@ -277,10 +284,6 @@ if (SLIC3R_STATIC)
target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0) target_compile_definitions(libslic3r_gui PUBLIC -DwxDEBUG_LEVEL=0)
endif() 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) if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL AND UNIX AND NOT APPLE)
target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE) target_compile_definitions(libslic3r_gui PRIVATE OPENSSL_CERT_OVERRIDE)
endif () 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. // No change, no need to update the UI.
return false; 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 //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)); 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); OnAddBitmap(bitmap);
const int n = wxComboBox::Append(item); 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"); 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) { 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); auto sys_label = new wxStaticText(parent, wxID_ANY, label_text);
sys_label->SetForegroundColour(color); 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")) { if (config->opt_bool("support_material")) {
// Ask only once. // Ask only once.
if (!support_material_overhangs_queried) { if (!m_support_material_overhangs_queried) {
support_material_overhangs_queried = true; m_support_material_overhangs_queried = true;
if (!config->opt_bool("overhangs")/* != 1*/) { if (!config->opt_bool("overhangs")/* != 1*/) {
wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n"
"- Detect bridging perimeters")); "- Detect bridging perimeters"));
@ -182,7 +182,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
} }
} }
else { else {
support_material_overhangs_queried = false; m_support_material_overhangs_queried = false;
} }
if (config->option<ConfigOptionPercent>("fill_density")->value == 100) { if (config->option<ConfigOptionPercent>("fill_density")->value == 100) {

View file

@ -17,15 +17,12 @@ class ModelConfig;
namespace GUI { 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 class ConfigManipulation
{ {
bool is_msg_dlg_already_exist{ false }; bool is_msg_dlg_already_exist{ false };
bool m_is_initialized_support_material_overhangs_queried{ false }; bool m_is_initialized_support_material_overhangs_queried{ false };
bool m_support_material_overhangs_queried{ false };
// function to loading of changed configuration // function to loading of changed configuration
std::function<void()> load_config = nullptr; std::function<void()> load_config = nullptr;
@ -66,7 +63,7 @@ public:
void initialize_support_material_overhangs_queried(bool queried) void initialize_support_material_overhangs_queried(bool queried)
{ {
m_is_initialized_support_material_overhangs_queried = true; 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 unsaved changes was not cheched till this moment
if (!check_unsaved_preset_changes) { if (!check_unsaved_preset_changes) {
if ((check_unsaved_preset_changes = !first_added_filament.empty() || !first_added_sla_material.empty())) { 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)) if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
return false; 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_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); 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)) { 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)) if (!wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))
return false; return false;
} }

View file

@ -26,6 +26,7 @@
#include <cmath> #include <cmath>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <random> #include <random>
#include "Field.hpp" #include "Field.hpp"
#include "format.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 (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist
{ {
if (m_draw_mode == dmSequentialFffPrint) if (m_draw_mode == dmSequentialFffPrint)
return _L("The sequential print is on.\n" return (_L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.\n"); "It's impossible to apply any custom G-code for objects printing sequentually.") + "\n");
// Show mode as a first string of tooltop // Show mode as a first string of tooltop
tooltip = " " + _L("Print mode") + ": "; tooltip = " " + _L("Print mode") + ": ";
@ -1446,6 +1447,18 @@ wxString Control::get_tooltip(int tick/*=-1*/)
std::string space = " "; std::string space = " ";
tooltip = space; tooltip = space;
auto format_gcode = [space](std::string gcode) { 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); boost::replace_all(gcode, "\n", "\n" + space);
return gcode; return gcode;
}; };

View file

@ -115,7 +115,7 @@ class TickCodeInfo
bool m_suppress_plus = false; bool m_suppress_plus = false;
bool m_suppress_minus = false; bool m_suppress_minus = false;
bool m_use_default_colors= 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}; std::vector<std::string>* m_colors {nullptr};

View file

@ -3,6 +3,7 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include "BitmapComboBox.hpp" #include "BitmapComboBox.hpp"
#include "Plater.hpp"
#include <wx/dc.h> #include <wx/dc.h>
#ifdef wxHAS_GENERIC_DATAVIEWCTRL #ifdef wxHAS_GENERIC_DATAVIEWCTRL
@ -222,14 +223,9 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
if (!text_editor || text_editor->GetValue().IsEmpty()) if (!text_editor || text_editor->GetValue().IsEmpty())
return false; return false;
std::string chosen_name = into_u8(text_editor->GetValue()); m_was_unusable_symbol = Slic3r::GUI::Plater::has_illegal_filename_characters(text_editor->GetValue());
const char* unusable_symbols = "<>:/\\|?*\""; if (m_was_unusable_symbol)
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) { return false;
if (chosen_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
m_was_unusable_symbol = true;
return false;
}
}
// The icon can't be edited so get its old value and reuse it. // The icon can't be edited so get its old value and reuse it.
wxVariant valueOld; 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) || 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_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) { if (!check_value) {
m_value.clear(); 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; } break; }
case coPoints: { case coPoints: {
@ -1286,7 +1286,7 @@ void Choice::msw_rescale()
size_t counter = 0; size_t counter = 0;
bool labels = ! m_opt.enum_labels.empty(); bool labels = ! m_opt.enum_labels.empty();
for (const std::string &el : labels ? m_opt.enum_labels : m_opt.enum_values) { 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); field->Append(text);
if (text == selection) if (text == selection)
idx = counter; 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.height >= 0) size.SetHeight(m_opt.height*m_em_unit);
if (m_opt.width >= 0) size.SetWidth(m_opt.width*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); auto temp = new wxStaticText(m_parent, wxID_ANY, legend, wxDefaultPosition, size, wxST_ELLIPSIZE_MIDDLE);
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
temp->SetBackgroundStyle(wxBG_STYLE_PAINT); temp->SetBackgroundStyle(wxBG_STYLE_PAINT);

View file

@ -89,7 +89,6 @@ void GCodeViewer::VBuffer::reset()
count = 0; count = 0;
} }
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::InstanceVBuffer::Ranges::reset() void GCodeViewer::InstanceVBuffer::Ranges::reset()
{ {
for (Range& range : ranges) { for (Range& range : ranges) {
@ -107,7 +106,6 @@ void GCodeViewer::InstanceVBuffer::reset()
buffer.clear(); buffer.clear();
render_ranges.reset(); render_ranges.reset();
} }
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::IBuffer::reset() 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() void GCodeViewer::TBuffer::Model::reset()
{ {
instances.reset(); instances.reset();
} }
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::TBuffer::reset() void GCodeViewer::TBuffer::reset()
{ {
@ -167,9 +163,7 @@ void GCodeViewer::TBuffer::reset()
indices.clear(); indices.clear();
paths.clear(); paths.clear();
render_paths.clear(); render_paths.clear();
#if ENABLE_SEAMS_USING_MODELS
model.reset(); 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) 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.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Tool position") + ":");
ImGui::SameLine(); ImGui::SameLine();
char buf[1024]; char buf[1024];
#if ENABLE_FIX_SEAMS_SYNCH
const Vec3f position = m_world_position + m_world_offset; const Vec3f position = m_world_position + m_world_offset;
sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); 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)); imgui.text(std::string(buf));
// force extra frame to automatically update window size // 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() 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_extrusions.reset_role_visibility_flags();
// m_sequential_view.skip_invisible_moves = true; // m_sequential_view.skip_invisible_moves = true;
} }
#if ENABLE_SEAMS_USING_MODELS
void GCodeViewer::init() void GCodeViewer::init()
{ {
if (m_gl_data_initialized) if (m_gl_data_initialized)
@ -628,7 +581,6 @@ void GCodeViewer::init()
case EMoveType::Retract: case EMoveType::Retract:
case EMoveType::Unretract: case EMoveType::Unretract:
case EMoveType::Seam: { case EMoveType::Seam: {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) { if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel; buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
buffer.shader = "gouraud_light_instanced"; buffer.shader = "gouraud_light_instanced";
@ -646,20 +598,6 @@ void GCodeViewer::init()
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel; buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
} }
break; 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::Wipe:
case EMoveType::Extrude: { case EMoveType::Extrude: {
@ -689,7 +627,6 @@ void GCodeViewer::init()
m_gl_data_initialized = true; m_gl_data_initialized = true;
} }
#endif // ENABLE_SEAMS_USING_MODELS
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized) void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
{ {
@ -879,72 +816,11 @@ void GCodeViewer::reset()
void GCodeViewer::render() 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 #if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.reset_opengl(); m_statistics.reset_opengl();
#if ENABLE_SEAMS_USING_MODELS
m_statistics.total_instances_gpu_size = 0; m_statistics.total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS #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()) if (m_roles.empty())
return; return;
@ -955,9 +831,7 @@ void GCodeViewer::render()
render_legend(legend_height); render_legend(legend_height);
if (m_sequential_view.current.last != m_sequential_view.endpoints.last) { if (m_sequential_view.current.last != m_sequential_view.endpoints.last) {
m_sequential_view.marker.set_world_position(m_sequential_view.current_position); 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); m_sequential_view.marker.set_world_offset(m_sequential_view.current_offset);
#endif // ENABLE_FIX_SEAMS_SYNCH
m_sequential_view.render(legend_height); m_sequential_view.render(legend_height);
} }
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
@ -1501,7 +1375,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
sq_prev_length = sq_length; sq_prev_length = sq_length;
}; };
#if ENABLE_SEAMS_USING_MODELS
// format data into the buffers to be rendered as instanced model // 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) { auto add_model_instance = [](const GCodeProcessorResult::MoveVertex& curr, InstanceBuffer& instances, InstanceIdBuffer& instances_ids, size_t move_id) {
// append position // append position
@ -1517,7 +1390,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
instances_ids.push_back(move_id); instances_ids.push_back(move_id);
}; };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
// format data into the buffers to be rendered as batched model // 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) { 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); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
auto start_time = std::chrono::high_resolution_clock::now(); 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()) if (wxGetApp().is_editor())
m_contained_in_bed = wxGetApp().plater()->build_volume().all_paths_inside(gcode_result, m_paths_bounding_box); 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(); m_sequential_view.gcode_ids.clear();
for (size_t i = 0; i < gcode_result.moves.size(); ++i) { for (size_t i = 0; i < gcode_result.moves.size(); ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i]; const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
if (move.type != EMoveType::Seam) if (move.type != EMoveType::Seam)
m_sequential_view.gcode_ids.push_back(move.gcode_id); 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<MultiVertexBuffer> vertices(m_buffers.size());
std::vector<MultiIndexBuffer> indices(m_buffers.size()); std::vector<MultiIndexBuffer> indices(m_buffers.size());
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer> instances(m_buffers.size()); std::vector<InstanceBuffer> instances(m_buffers.size());
std::vector<InstanceIdBuffer> instances_ids(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()); std::vector<InstancesOffsets> instances_offsets(m_buffers.size());
#endif // ENABLE_FIX_SEAMS_SYNCH
std::vector<float> options_zs; std::vector<float> options_zs;
#if ENABLE_FIX_SEAMS_SYNCH
size_t seams_count = 0; size_t seams_count = 0;
std::vector<size_t> seams_ids; std::vector<size_t> seams_ids;
#endif // ENABLE_FIX_SEAMS_SYNCH
// toolpaths data -> extract vertices from result // toolpaths data -> extract vertices from result
for (size_t i = 0; i < m_moves_count; ++i) { for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i]; const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam) { if (curr.type == EMoveType::Seam) {
++seams_count; ++seams_count;
seams_ids.push_back(i); seams_ids.push_back(i);
} }
size_t move_id = i - seams_count; size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex // skip first vertex
if (i == 0) if (i == 0)
@ -1658,13 +1514,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
const unsigned char id = buffer_id(curr.type); const unsigned char id = buffer_id(curr.type);
TBuffer& t_buffer = m_buffers[id]; TBuffer& t_buffer = m_buffers[id];
MultiVertexBuffer& v_multibuffer = vertices[id]; MultiVertexBuffer& v_multibuffer = vertices[id];
#if ENABLE_SEAMS_USING_MODELS
InstanceBuffer& inst_buffer = instances[id]; InstanceBuffer& inst_buffer = instances[id];
InstanceIdBuffer& inst_id_buffer = instances_ids[id]; InstanceIdBuffer& inst_id_buffer = instances_ids[id];
#if ENABLE_FIX_SEAMS_SYNCH
InstancesOffsets& inst_offsets = instances_offsets[id]; InstancesOffsets& inst_offsets = instances_offsets[id];
#endif // ENABLE_FIX_SEAMS_SYNCH
#endif // ENABLE_SEAMS_USING_MODELS
// ensure there is at least one vertex buffer // ensure there is at least one vertex buffer
if (v_multibuffer.empty()) 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 // if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// add another 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(); 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) { 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()); v_multibuffer.push_back(VertexBuffer());
if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) { if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) {
Path& last_path = t_buffer.paths.back(); Path& last_path = t_buffer.paths.back();
if (prev.type == curr.type && last_path.matches(curr)) 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); 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::Point: { add_vertices_as_point(curr, v_buffer); break; }
case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, 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; } 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: case TBuffer::ERenderPrimitiveType::InstancedModel:
{ {
#if ENABLE_FIX_SEAMS_SYNCH
add_model_instance(curr, inst_buffer, inst_id_buffer, move_id); add_model_instance(curr, inst_buffer, inst_id_buffer, move_id);
inst_offsets.push_back(prev.position - curr.position); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.instances_count; ++m_statistics.instances_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -1718,32 +1552,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
} }
case TBuffer::ERenderPrimitiveType::BatchedModel: 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); 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); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.batched_count; ++m_statistics.batched_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
break; 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 // 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 // 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) { 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) { auto extract_position_at = [](const VertexBuffer& vertices, size_t offset) {
return Vec3f(vertices[offset + 0], vertices[offset + 1], vertices[offset + 2]); 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) { auto extract_move_id = [&seams_ids](size_t id) {
for (int i = seams_ids.size() - 1; i >= 0; --i) { for (int i = seams_ids.size() - 1; i >= 0; --i) {
if (seams_ids[i] < id + i + 1) if (seams_ids[i] < id + i + 1)
@ -1841,7 +1651,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
} }
return id; return id;
}; };
#endif // ENABLE_FIX_SEAMS_SYNCH
size_t vertex_size_floats = t_buffer.vertices.vertex_size_floats(); size_t vertex_size_floats = t_buffer.vertices.vertex_size_floats();
for (const Path& path : t_buffer.paths) { 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; const float half_width = 0.5f * path.width;
for (size_t j = 1; j < path_vertices_count - 1; ++j) { for (size_t j = 1; j < path_vertices_count - 1; ++j) {
size_t curr_s_id = path.sub_paths.front().first.s_id + 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); size_t move_id = extract_move_id(curr_s_id);
const Vec3f& prev = gcode_result.moves[move_id - 1].position; const Vec3f& prev = gcode_result.moves[move_id - 1].position;
const Vec3f& curr = gcode_result.moves[move_id].position; const Vec3f& curr = gcode_result.moves[move_id].position;
const Vec3f& next = gcode_result.moves[move_id + 1].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 // select the subpaths which contains the previous/next segments
if (!path.sub_paths[prev_sub_path_id].contains(curr_s_id)) 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 // dismiss, no more needed
std::vector<size_t>().swap(seams_ids); std::vector<size_t>().swap(seams_ids);
#endif // ENABLE_FIX_SEAMS_SYNCH
for (MultiVertexBuffer& v_multibuffer : vertices) { for (MultiVertexBuffer& v_multibuffer : vertices) {
for (VertexBuffer& v_buffer : v_multibuffer) { 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 // send vertices data to gpu, where needed
for (size_t i = 0; i < m_buffers.size(); ++i) { for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[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) { if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) {
const InstanceBuffer& inst_buffer = instances[i]; const InstanceBuffer& inst_buffer = instances[i];
if (!inst_buffer.empty()) { if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer; t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i]; t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i]; t_buffer.model.instances.offsets = instances_offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
} }
} }
else { else {
@ -1969,25 +1766,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (!inst_buffer.empty()) { if (!inst_buffer.empty()) {
t_buffer.model.instances.buffer = inst_buffer; t_buffer.model.instances.buffer = inst_buffer;
t_buffer.model.instances.s_ids = instances_ids[i]; t_buffer.model.instances.s_ids = instances_ids[i];
#if ENABLE_FIX_SEAMS_SYNCH
t_buffer.model.instances.offsets = instances_offsets[i]; 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]; const MultiVertexBuffer& v_multibuffer = vertices[i];
for (const VertexBuffer& v_buffer : v_multibuffer) { for (const VertexBuffer& v_buffer : v_multibuffer) {
const size_t size_elements = v_buffer.size(); 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.vbos.push_back(static_cast<unsigned int>(id));
t_buffer.vertices.sizes.push_back(size_bytes); t_buffer.vertices.sizes.push_back(size_bytes);
} }
#if ENABLE_SEAMS_USING_MODELS
} }
#endif // ENABLE_SEAMS_USING_MODELS
} }
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
@ -2023,10 +1802,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// dismiss vertices data, no more needed // dismiss vertices data, no more needed
std::vector<MultiVertexBuffer>().swap(vertices); std::vector<MultiVertexBuffer>().swap(vertices);
#if ENABLE_SEAMS_USING_MODELS
std::vector<InstanceBuffer>().swap(instances); std::vector<InstanceBuffer>().swap(instances);
std::vector<InstanceIdBuffer>().swap(instances_ids); std::vector<InstanceIdBuffer>().swap(instances_ids);
#endif // ENABLE_SEAMS_USING_MODELS
// toolpaths data -> extract indices from result // toolpaths data -> extract indices from result
// paths may have been filled while extracting vertices, // 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>; using VboIndexList = std::vector<unsigned int>;
std::vector<VboIndexList> vbo_indices(m_buffers.size()); std::vector<VboIndexList> vbo_indices(m_buffers.size());
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0; seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) { for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i]; const GCodeProcessorResult::MoveVertex& curr = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (curr.type == EMoveType::Seam) if (curr.type == EMoveType::Seam)
++seams_count; ++seams_count;
size_t move_id = i - seams_count; size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
// skip first vertex // skip first vertex
if (i == 0) if (i == 0)
@ -2082,63 +1855,37 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// ensure there is at least one index buffer // ensure there is at least one index buffer
if (i_multibuffer.empty()) { if (i_multibuffer.empty()) {
i_multibuffer.push_back(IndexBuffer()); i_multibuffer.push_back(IndexBuffer());
#if ENABLE_SEAMS_USING_MODELS
if (!t_buffer.vertices.vbos.empty()) if (!t_buffer.vertices.vbos.empty())
#endif // ENABLE_SEAMS_USING_MODELS
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); 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 // if adding the indices for the current segment exceeds the threshold size of the current index buffer
// create another 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(); 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) { 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()); i_multibuffer.push_back(IndexBuffer());
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); 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 && if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { 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(); 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); 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 // if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer
// create another index 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(); 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) { 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()); i_multibuffer.push_back(IndexBuffer());
++curr_vertex_buffer.first; ++curr_vertex_buffer.first;
curr_vertex_buffer.second = 0; curr_vertex_buffer.second = 0;
vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); 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 && if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point &&
t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) { 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(); 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); 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) switch (t_buffer.render_primitive_type)
{ {
case TBuffer::ERenderPrimitiveType::Point: { 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); 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(); curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break; break;
} }
case TBuffer::ERenderPrimitiveType::Line: { 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); 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(); curr_vertex_buffer.second += t_buffer.max_vertices_per_segment();
break; break;
} }
case TBuffer::ERenderPrimitiveType::Triangle: { 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); 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; break;
} }
#if ENABLE_SEAMS_USING_BATCHED_MODELS
case TBuffer::ERenderPrimitiveType::BatchedModel: { case TBuffer::ERenderPrimitiveType::BatchedModel: {
add_indices_as_model_batch(t_buffer.model.data, i_buffer, curr_vertex_buffer.second); 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(); curr_vertex_buffer.second += t_buffer.model.data.vertices_count();
break; break;
} }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
default: { break; } default: { break; }
} }
} }
@ -2192,13 +1925,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// toolpaths data -> send indices data to gpu // toolpaths data -> send indices data to gpu
for (size_t i = 0; i < m_buffers.size(); ++i) { for (size_t i = 0; i < m_buffers.size(); ++i) {
TBuffer& t_buffer = m_buffers[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) { 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]; const MultiIndexBuffer& i_multibuffer = indices[i];
for (const IndexBuffer& i_buffer : i_multibuffer) { for (const IndexBuffer& i_buffer : i_multibuffer) {
const size_t size_elements = i_buffer.size(); 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(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_bytes, i_buffer.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} }
#if ENABLE_SEAMS_USING_MODELS
} }
#endif // ENABLE_SEAMS_USING_MODELS
} }
if (progress_dialog != nullptr) { if (progress_dialog != nullptr) {
@ -2264,34 +1989,22 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
// layers zs / roles / extruder ids -> extract from result // layers zs / roles / extruder ids -> extract from result
size_t last_travel_s_id = 0; size_t last_travel_s_id = 0;
#if ENABLE_FIX_SEAMS_SYNCH
seams_count = 0; seams_count = 0;
#endif // ENABLE_FIX_SEAMS_SYNCH
for (size_t i = 0; i < m_moves_count; ++i) { for (size_t i = 0; i < m_moves_count; ++i) {
const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i]; const GCodeProcessorResult::MoveVertex& move = gcode_result.moves[i];
#if ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Seam) if (move.type == EMoveType::Seam)
++seams_count; ++seams_count;
size_t move_id = i - seams_count; size_t move_id = i - seams_count;
#endif // ENABLE_FIX_SEAMS_SYNCH
if (move.type == EMoveType::Extrude) { if (move.type == EMoveType::Extrude) {
// layers zs // layers zs
const double* const last_z = m_layers.empty() ? nullptr : &m_layers.get_zs().back(); const double* const last_z = m_layers.empty() ? nullptr : &m_layers.get_zs().back();
const double z = static_cast<double>(move.position.z()); const double z = static_cast<double>(move.position.z());
if (last_z == nullptr || z < *last_z - EPSILON || *last_z + EPSILON < 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 }); 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 else
#if ENABLE_FIX_SEAMS_SYNCH
m_layers.get_endpoints().back().last = move_id; m_layers.get_endpoints().back().last = move_id;
#else
m_layers.get_endpoints().back().last = i;
#endif // ENABLE_FIX_SEAMS_SYNCH
// extruder ids // extruder ids
m_extruder_ids.emplace_back(move.extruder_id); m_extruder_ids.emplace_back(move.extruder_id);
// roles // roles
@ -2299,17 +2012,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
m_roles.emplace_back(move.extrusion_role); m_roles.emplace_back(move.extrusion_role);
} }
else if (move.type == EMoveType::Travel) { else if (move.type == EMoveType::Travel) {
#if ENABLE_FIX_SEAMS_SYNCH
if (move_id - last_travel_s_id > 1 && !m_layers.empty()) if (move_id - last_travel_s_id > 1 && !m_layers.empty())
m_layers.get_endpoints().back().last = move_id; m_layers.get_endpoints().back().last = move_id;
last_travel_s_id = 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; 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); 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; ++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 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) { 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 #if ENABLE_GCODE_VIEWER_STATISTICS
Statistics* statistics = const_cast<Statistics*>(&m_statistics); Statistics* statistics = const_cast<Statistics*>(&m_statistics);
statistics->render_paths_size = 0; statistics->render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
statistics->models_instances_size = 0; statistics->models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
const bool top_layer_only = get_app_config()->get("seq_top_layer_only") == "1"; 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) if (!buffer.visible)
continue; continue;
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel || if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { 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) { 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) 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; continue;
@ -2521,7 +2231,6 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
} }
} }
else { else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t i = 0; i < buffer.paths.size(); ++i) { for (size_t i = 0; i < buffer.paths.size(); ++i) {
const Path& path = buffer.paths[i]; const Path& path = buffer.paths[i];
if (path.type == EMoveType::Travel) { 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 // 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 // get the world position from the vertex buffer
bool found = false; bool found = false;
for (const TBuffer& buffer : m_buffers) { 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 || if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { 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) { 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) { if (buffer.model.instances.s_ids[i] == m_sequential_view.current.last) {
size_t offset = i * buffer.model.instances.instance_size_floats(); 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.x() = buffer.model.instances.buffer[offset + 0];
sequential_view->current_position.y() = buffer.model.instances.buffer[offset + 1]; sequential_view->current_position.y() = buffer.model.instances.buffer[offset + 1];
sequential_view->current_position.z() = buffer.model.instances.buffer[offset + 2]; 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]; sequential_view->current_offset = buffer.model.instances.offsets[i];
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true; found = true;
break; break;
} }
} }
} }
else { else {
#endif // ENABLE_SEAMS_USING_MODELS
// searches the path containing the current position // searches the path containing the current position
for (const Path& path : buffer.paths) { for (const Path& path : buffer.paths) {
if (path.contains(m_sequential_view.current.last)) { 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(::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)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
#if ENABLE_FIX_SEAMS_SYNCH
sequential_view->current_offset = Vec3f::Zero(); sequential_view->current_offset = Vec3f::Zero();
#endif // ENABLE_FIX_SEAMS_SYNCH
found = true; found = true;
break; break;
} }
} }
} }
#if ENABLE_SEAMS_USING_MODELS
} }
#endif // ENABLE_SEAMS_USING_MODELS
if (found) if (found)
break; break;
@ -2740,20 +2433,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif #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 // 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) { for (size_t b = 0; b < m_buffers.size(); ++b) {
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]); TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel && if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::InstancedModel &&
buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel) buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::BatchedModel)
#else
if (buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Model)
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
continue; continue;
buffer.model.instances.render_ranges.reset(); 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) { 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) { for (size_t id : buffer.model.instances.s_ids) {
if (has_second_range) { if (has_second_range) {
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
if (id < m_sequential_view.endpoints.first) { 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; ++buffer.model.instances.render_ranges.ranges.front().offset;
if (id <= m_sequential_view.current.first) if (id <= m_sequential_view.current.first)
++buffer.model.instances.render_ranges.ranges.back().offset; ++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 // set sequential data to their final value
sequential_view->endpoints = top_layer_only ? top_layer_endpoints : global_endpoints; 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; 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; sequential_view->global = global_endpoints;
#endif // ENABLE_SEAMS_USING_MODELS
// updates sequential range caps // updates sequential range caps
std::array<SequentialRangeCap, 2>* sequential_range_caps = const_cast<std::array<SequentialRangeCap, 2>*>(&m_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.sizes, unsigned int);
statistics->render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.offsets, size_t); 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.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.s_ids, size_t);
statistics->models_instances_size += SLIC3R_STDVEC_MEMSIZE(buffer.model.instances.render_ranges.ranges, InstanceVBuffer::Ranges::Range); 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(); 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 #endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -3018,7 +2693,6 @@ void GCodeViewer::render_toolpaths()
} }
}; };
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_instanced_model = [this] auto render_as_instanced_model = [this]
#else #else
@ -3044,7 +2718,6 @@ void GCodeViewer::render_toolpaths()
} }
}; };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) { auto render_as_batched_model = [this](TBuffer& buffer, GLShaderProgram& shader) {
#else #else
@ -3102,8 +2775,6 @@ void GCodeViewer::render_toolpaths()
buffer_range.first = buffer_range.last; buffer_range.first = buffer_range.last;
} }
}; };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
auto line_width = [](double zoom) { auto line_width = [](double zoom) {
return (zoom < 5.0) ? 1.0 : (1.0 + 5.0 * (zoom - 5.0) / (100.0 - 5.0)); 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); unsigned char end_id = buffer_id(EMoveType::Count);
for (unsigned char i = begin_id; i < end_id; ++i) { for (unsigned char i = begin_id; i < end_id; ++i) {
#if ENABLE_SEAMS_USING_MODELS
TBuffer& buffer = m_buffers[i]; TBuffer& buffer = m_buffers[i];
#else
const TBuffer& buffer = m_buffers[i];
#endif // ENABLE_SEAMS_USING_MODELS
if (!buffer.visible || !buffer.has_data()) if (!buffer.visible || !buffer.has_data())
continue; continue;
@ -3125,25 +2792,17 @@ void GCodeViewer::render_toolpaths()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
#if ENABLE_SEAMS_USING_MODELS
#if ENABLE_SEAMS_USING_BATCHED_MODELS
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel) { 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); shader->set_uniform("emission_factor", 0.25f);
render_as_instanced_model(buffer, *shader); render_as_instanced_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f); shader->set_uniform("emission_factor", 0.0f);
} }
#if ENABLE_SEAMS_USING_BATCHED_MODELS
else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) { else if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
shader->set_uniform("emission_factor", 0.25f); shader->set_uniform("emission_factor", 0.25f);
render_as_batched_model(buffer, *shader); render_as_batched_model(buffer, *shader);
shader->set_uniform("emission_factor", 0.0f); shader->set_uniform("emission_factor", 0.0f);
} }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
else { else {
#endif // ENABLE_SEAMS_USING_MODELS
for (size_t j = 0; j < buffer.indices.size(); ++j) { for (size_t j = 0; j < buffer.indices.size(); ++j) {
const IBuffer& i_buffer = buffer.indices[j]; const IBuffer& i_buffer = buffer.indices[j];
@ -3184,9 +2843,7 @@ void GCodeViewer::render_toolpaths()
glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
} }
#if ENABLE_SEAMS_USING_MODELS
} }
#endif // ENABLE_SEAMS_USING_MODELS
shader->stop_using(); shader->stop_using();
} }
@ -3297,11 +2954,7 @@ void GCodeViewer::render_legend(float& legend_height)
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; 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, 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 }, 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, double used_filament_m = 0.0, double used_filament_g = 0.0,
std::function<void()> callback = nullptr) { std::function<void()> callback = nullptr) {
@ -3319,19 +2972,7 @@ void GCodeViewer::render_legend(float& legend_height)
} }
case EItemType::Circle: { case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
#if !ENABLE_SEAMS_USING_BATCHED_MODELS draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
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);
break; break;
} }
case EItemType::Hexagon: { 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) { auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
const TBuffer& buffer = m_buffers[buffer_id(move_type)]; const TBuffer& buffer = m_buffers[buffer_id(move_type)];
if (buffer.visible && buffer.has_data()) if (buffer.visible && buffer.has_data())
#if ENABLE_SEAMS_USING_BATCHED_MODELS
append_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text); 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 // 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_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("Multi GL_TRIANGLES:"), m_statistics.gl_multi_triangles_calls_count);
add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count); add_counter(std::string("GL_TRIANGLES:"), m_statistics.gl_triangles_calls_count);
#if ENABLE_SEAMS_USING_MODELS
ImGui::Separator(); ImGui::Separator();
add_counter(std::string("Instanced models:"), m_statistics.gl_instanced_models_calls_count); 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); 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")) { if (ImGui::CollapsingHeader("CPU memory")) {
@ -4213,17 +3846,13 @@ void GCodeViewer::render_statistics()
ImGui::Separator(); ImGui::Separator();
add_memory(std::string("Paths:"), m_statistics.paths_size); add_memory(std::string("Paths:"), m_statistics.paths_size);
add_memory(std::string("Render paths:"), m_statistics.render_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); add_memory(std::string("Models instances:"), m_statistics.models_instances_size);
#endif // ENABLE_SEAMS_USING_MODELS
} }
if (ImGui::CollapsingHeader("GPU memory")) { if (ImGui::CollapsingHeader("GPU memory")) {
add_memory(std::string("Vertices:"), m_statistics.total_vertices_gpu_size); add_memory(std::string("Vertices:"), m_statistics.total_vertices_gpu_size);
add_memory(std::string("Indices:"), m_statistics.total_indices_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); add_memory(std::string("Instances:"), m_statistics.total_instances_gpu_size);
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator(); ImGui::Separator();
add_memory(std::string("Max VBuffer:"), m_statistics.max_vbuffer_gpu_size); add_memory(std::string("Max VBuffer:"), m_statistics.max_vbuffer_gpu_size);
add_memory(std::string("Max IBuffer:"), m_statistics.max_ibuffer_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("Travel segments count:"), m_statistics.travel_segments_count);
add_counter(std::string("Wipe segments count:"), m_statistics.wipe_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); 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); 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); add_counter(std::string("Batched count:"), m_statistics.batched_count);
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
ImGui::Separator(); ImGui::Separator();
add_counter(std::string("VBuffers count:"), m_statistics.vbuffers_count); add_counter(std::string("VBuffers count:"), m_statistics.vbuffers_count);
add_counter(std::string("IBuffers count:"), m_statistics.ibuffers_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 MultiVertexBuffer = std::vector<VertexBuffer>;
using IndexBuffer = std::vector<IBufferType>; using IndexBuffer = std::vector<IBufferType>;
using MultiIndexBuffer = std::vector<IndexBuffer>; using MultiIndexBuffer = std::vector<IndexBuffer>;
#if ENABLE_SEAMS_USING_MODELS
using InstanceBuffer = std::vector<float>; using InstanceBuffer = std::vector<float>;
using InstanceIdBuffer = std::vector<size_t>; using InstanceIdBuffer = std::vector<size_t>;
#endif // ENABLE_SEAMS_USING_MODELS
#if ENABLE_FIX_SEAMS_SYNCH
using InstancesOffsets = std::vector<Vec3f>; using InstancesOffsets = std::vector<Vec3f>;
#endif // ENABLE_FIX_SEAMS_SYNCH
static const std::vector<Color> Extrusion_Role_Colors; static const std::vector<Color> Extrusion_Role_Colors;
static const std::vector<Color> Options_Colors; static const std::vector<Color> Options_Colors;
@ -107,17 +103,10 @@ class GCodeViewer
void reset(); 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 // buffer containing instances data used to render a toolpaths using instanced or batched models
// instance record format: // 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()) // 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 // 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 struct InstanceVBuffer
{ {
// ranges used to render only subparts of the intances // ranges used to render only subparts of the intances
@ -140,7 +129,6 @@ class GCodeViewer
void reset(); void reset();
}; };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
enum class EFormat : unsigned char enum class EFormat : unsigned char
{ {
InstancedModel, InstancedModel,
@ -148,21 +136,17 @@ class GCodeViewer
}; };
EFormat format; EFormat format;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
// cpu-side buffer containing all instances data // cpu-side buffer containing all instances data
InstanceBuffer buffer; InstanceBuffer buffer;
// indices of the moves for all instances // indices of the moves for all instances
std::vector<size_t> s_ids; std::vector<size_t> s_ids;
#if ENABLE_FIX_SEAMS_SYNCH
// position offsets, used to show the correct value of the tool position // position offsets, used to show the correct value of the tool position
InstancesOffsets offsets; InstancesOffsets offsets;
#endif // ENABLE_FIX_SEAMS_SYNCH
Ranges render_ranges; Ranges render_ranges;
size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); } 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 { size_t instance_size_floats() const {
switch (format) switch (format)
{ {
@ -171,14 +155,10 @@ class GCodeViewer
default: { return 0; } 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); } size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
void reset(); void reset();
}; };
#endif // ENABLE_SEAMS_USING_MODELS
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type // ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
struct IBuffer struct IBuffer
@ -313,17 +293,9 @@ class GCodeViewer
{ {
Point, Point,
Line, Line,
#if ENABLE_SEAMS_USING_MODELS
Triangle, Triangle,
#if ENABLE_SEAMS_USING_BATCHED_MODELS
InstancedModel, InstancedModel,
BatchedModel BatchedModel
#else
Model
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#else
Triangle
#endif // ENABLE_SEAMS_USING_MODELS
}; };
ERenderPrimitiveType render_primitive_type; ERenderPrimitiveType render_primitive_type;
@ -332,22 +304,18 @@ class GCodeViewer
VBuffer vertices; VBuffer vertices;
std::vector<IBuffer> indices; std::vector<IBuffer> indices;
#if ENABLE_SEAMS_USING_MODELS
struct Model struct Model
{ {
GLModel model; GLModel model;
Color color; Color color;
InstanceVBuffer instances; InstanceVBuffer instances;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
GLModel::InitializationData data; GLModel::InitializationData data;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void reset(); void reset();
}; };
// contain the buffer for model primitive types // contain the buffer for model primitive types
Model model; Model model;
#endif // ENABLE_SEAMS_USING_MODELS
std::string shader; std::string shader;
std::vector<Path> paths; 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); } 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 { bool has_data() const {
switch (render_primitive_type) switch (render_primitive_type)
{ {
@ -405,23 +372,14 @@ class GCodeViewer
case ERenderPrimitiveType::Triangle: { case ERenderPrimitiveType::Triangle: {
return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0; 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::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
case ERenderPrimitiveType::BatchedModel: { case ERenderPrimitiveType::BatchedModel: {
return model.data.vertices_count() > 0 && model.data.indices_count() && return model.data.vertices_count() > 0 && model.data.indices_count() &&
!vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0; !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; } 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 // helper to render shells
@ -569,36 +527,24 @@ class GCodeViewer
int64_t gl_multi_lines_calls_count{ 0 }; int64_t gl_multi_lines_calls_count{ 0 };
int64_t gl_multi_triangles_calls_count{ 0 }; int64_t gl_multi_triangles_calls_count{ 0 };
int64_t gl_triangles_calls_count{ 0 }; int64_t gl_triangles_calls_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t gl_instanced_models_calls_count{ 0 }; int64_t gl_instanced_models_calls_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t gl_batched_models_calls_count{ 0 }; int64_t gl_batched_models_calls_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
// memory // memory
int64_t results_size{ 0 }; int64_t results_size{ 0 };
int64_t total_vertices_gpu_size{ 0 }; int64_t total_vertices_gpu_size{ 0 };
int64_t total_indices_gpu_size{ 0 }; int64_t total_indices_gpu_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t total_instances_gpu_size{ 0 }; int64_t total_instances_gpu_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
int64_t max_vbuffer_gpu_size{ 0 }; int64_t max_vbuffer_gpu_size{ 0 };
int64_t max_ibuffer_gpu_size{ 0 }; int64_t max_ibuffer_gpu_size{ 0 };
int64_t paths_size{ 0 }; int64_t paths_size{ 0 };
int64_t render_paths_size{ 0 }; int64_t render_paths_size{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t models_instances_size{ 0 }; int64_t models_instances_size{ 0 };
#endif // ENABLE_SEAMS_USING_MODELS
// other // other
int64_t travel_segments_count{ 0 }; int64_t travel_segments_count{ 0 };
int64_t wipe_segments_count{ 0 }; int64_t wipe_segments_count{ 0 };
int64_t extrude_segments_count{ 0 }; int64_t extrude_segments_count{ 0 };
#if ENABLE_SEAMS_USING_MODELS
int64_t instances_count{ 0 }; int64_t instances_count{ 0 };
#if ENABLE_SEAMS_USING_BATCHED_MODELS
int64_t batched_count{ 0 }; int64_t batched_count{ 0 };
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
int64_t vbuffers_count{ 0 }; int64_t vbuffers_count{ 0 };
int64_t ibuffers_count{ 0 }; int64_t ibuffers_count{ 0 };
@ -624,40 +570,28 @@ class GCodeViewer
gl_multi_lines_calls_count = 0; gl_multi_lines_calls_count = 0;
gl_multi_triangles_calls_count = 0; gl_multi_triangles_calls_count = 0;
gl_triangles_calls_count = 0; gl_triangles_calls_count = 0;
#if ENABLE_SEAMS_USING_MODELS
gl_instanced_models_calls_count = 0; gl_instanced_models_calls_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
gl_batched_models_calls_count = 0; gl_batched_models_calls_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
} }
void reset_sizes() { void reset_sizes() {
results_size = 0; results_size = 0;
total_vertices_gpu_size = 0; total_vertices_gpu_size = 0;
total_indices_gpu_size = 0; total_indices_gpu_size = 0;
#if ENABLE_SEAMS_USING_MODELS
total_instances_gpu_size = 0; total_instances_gpu_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
max_vbuffer_gpu_size = 0; max_vbuffer_gpu_size = 0;
max_ibuffer_gpu_size = 0; max_ibuffer_gpu_size = 0;
paths_size = 0; paths_size = 0;
render_paths_size = 0; render_paths_size = 0;
#if ENABLE_SEAMS_USING_MODELS
models_instances_size = 0; models_instances_size = 0;
#endif // ENABLE_SEAMS_USING_MODELS
} }
void reset_others() { void reset_others() {
travel_segments_count = 0; travel_segments_count = 0;
wipe_segments_count = 0; wipe_segments_count = 0;
extrude_segments_count = 0; extrude_segments_count = 0;
#if ENABLE_SEAMS_USING_MODELS
instances_count = 0; instances_count = 0;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
batched_count = 0; batched_count = 0;
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
#endif // ENABLE_SEAMS_USING_MODELS
vbuffers_count = 0; vbuffers_count = 0;
ibuffers_count = 0; ibuffers_count = 0;
} }
@ -672,12 +606,10 @@ public:
GLModel m_model; GLModel m_model;
Vec3f m_world_position; Vec3f m_world_position;
Transform3f m_world_transform; 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 // 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 // the offset is used to show the correct value of tool position in the "ToolPosition" window
// see implementation of render() method // see implementation of render() method
Vec3f m_world_offset; Vec3f m_world_offset;
#endif // ENABLE_FIX_SEAMS_SYNCH
float m_z_offset{ 0.5f }; float m_z_offset{ 0.5f };
bool m_visible{ true }; bool m_visible{ true };
@ -687,9 +619,7 @@ public:
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); } const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
void set_world_position(const Vec3f& position); void set_world_position(const Vec3f& position);
#if ENABLE_FIX_SEAMS_SYNCH
void set_world_offset(const Vec3f& offset) { m_world_offset = offset; } void set_world_offset(const Vec3f& offset) { m_world_offset = offset; }
#endif // ENABLE_FIX_SEAMS_SYNCH
bool is_visible() const { return m_visible; } bool is_visible() const { return m_visible; }
void set_visible(bool visible) { m_visible = visible; } void set_visible(bool visible) { m_visible = visible; }
@ -743,13 +673,9 @@ public:
Endpoints endpoints; Endpoints endpoints;
Endpoints current; Endpoints current;
Endpoints last_current; Endpoints last_current;
#if ENABLE_SEAMS_USING_MODELS
Endpoints global; Endpoints global;
#endif // ENABLE_SEAMS_USING_MODELS
Vec3f current_position{ Vec3f::Zero() }; Vec3f current_position{ Vec3f::Zero() };
#if ENABLE_FIX_SEAMS_SYNCH
Vec3f current_offset{ Vec3f::Zero() }; Vec3f current_offset{ Vec3f::Zero() };
#endif // ENABLE_FIX_SEAMS_SYNCH
Marker marker; Marker marker;
GCodeWindow gcode_window; GCodeWindow gcode_window;
std::vector<unsigned int> gcode_ids; std::vector<unsigned int> gcode_ids;
@ -811,9 +737,7 @@ public:
GCodeViewer(); GCodeViewer();
~GCodeViewer() { reset(); } ~GCodeViewer() { reset(); }
#if ENABLE_SEAMS_USING_MODELS
void init(); void init();
#endif // ENABLE_SEAMS_USING_MODELS
// extract rendering data from the given parameters // extract rendering data from the given parameters
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized); 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()); } float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleFactor()); }
#endif // __WXGTK3__ #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() Size::Size()
: m_width(0) : m_width(0)
, m_height(0) , m_height(0)
@ -1417,10 +1422,8 @@ void GLCanvas3D::render()
if (!is_initialized() && !init()) if (!is_initialized() && !init())
return; return;
#if ENABLE_SEAMS_USING_MODELS
if (!m_main_toolbar.is_enabled()) if (!m_main_toolbar.is_enabled())
m_gcode_viewer.init(); m_gcode_viewer.init();
#endif // ENABLE_SEAMS_USING_MODELS
if (! m_bed.build_volume().valid()) { if (! m_bed.build_volume().valid()) {
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE // 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 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) 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; BoundingBoxf3 volumes_box;
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (!visible_volumes.empty()) { if (!visible_volumes.empty()) {
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
for (const GLVolume* vol : visible_volumes) { for (const GLVolume* vol : visible_volumes) {
volumes_box.merge(vol->transformed_bounding_box()); volumes_box.merge(vol->transformed_bounding_box());
} }
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
} }
else else
// This happens for empty projects // This happens for empty projects
volumes_box = m_bed.extended_bounding_box(); volumes_box = m_bed.extended_bounding_box();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
Camera camera; Camera camera;
camera.set_type(camera_type); camera.set_type(camera_type);
@ -5119,10 +5114,12 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
break; break;
} }
default: default:
case BuildVolume::Type::Convex:
case BuildVolume::Type::Custom: { case BuildVolume::Type::Custom: {
m_volumes.set_print_volume({ static_cast<int>(type), m_volumes.set_print_volume({ static_cast<int>(type),
{ 0.0f, 0.0f, 0.0f, 0.0f }, { -FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX },
{ 0.0f, 0.0f } }); { -FLT_MAX, FLT_MAX } }
);
} }
} }
if (m_requires_check_outside_state) { if (m_requires_check_outside_state) {

View file

@ -623,9 +623,7 @@ public:
void reset_volumes(); void reset_volumes();
ModelInstanceEPrintVolumeState check_volumes_outside_state() const; ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
#if ENABLE_SEAMS_USING_MODELS
void init_gcode_viewer() { m_gcode_viewer.init(); } void init_gcode_viewer() { m_gcode_viewer.init(); }
#endif // ENABLE_SEAMS_USING_MODELS
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); } void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); } 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); } 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 Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t GLModel::InitializationData::vertices_count() const size_t GLModel::InitializationData::vertices_count() const
{ {
size_t ret = 0; size_t ret = 0;
@ -35,7 +34,6 @@ size_t GLModel::InitializationData::indices_count() const
} }
return ret; return ret;
} }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
void GLModel::init_from(const InitializationData& data) 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 void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) const
{ {
if (instances_vbo == 0) 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)); 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) 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; std::vector<Entity> entities;
#if ENABLE_SEAMS_USING_BATCHED_MODELS
size_t vertices_count() const; size_t vertices_count() const;
size_t vertices_size_floats() const { return vertices_count() * 6; } size_t vertices_size_floats() const { return vertices_count() * 6; }
size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); } size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); }
size_t indices_count() const; size_t indices_count() const;
size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); } size_t indices_size_bytes() const { return indices_count() * sizeof(unsigned int); }
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
}; };
private: private:
@ -80,9 +78,7 @@ namespace GUI {
void reset(); void reset();
void render() const; void render() const;
#if ENABLE_SEAMS_USING_MODELS
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const; 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(); } 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; 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 // 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" }); valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
// used to render printbed // used to render printbed
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" }); valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
// used to render options in gcode preview // 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)) 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" }); 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 // used to render extrusion and travel paths as lines in gcode preview
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" }); valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
// used to render objects in 3d editor // used to render objects in 3d editor

View file

@ -12,6 +12,7 @@
#include <exception> #include <exception>
#include <cstdlib> #include <cstdlib>
#include <regex> #include <regex>
#include <string_view>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
@ -97,6 +98,8 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#endif #endif
using namespace std::literals;
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -471,40 +474,82 @@ static bool run_updater_win()
} }
#endif //_WIN32 #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) wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{ {
static const std::string defaults[FT_SIZE] = { const FileWildcards& data = file_wildcards_by_type[file_type];
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL", std::string title;
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", std::string mask;
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", std::string custom_ext_lower;
/* 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",
/* 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()) { if (! custom_extension.empty()) {
// Find the custom extension in the template. // Generate an extension into the title mask and into the list of extensions.
if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) { custom_ext_lower = boost::to_lower_copy(custom_extension);
// The custom extension was not found in the template. const std::string custom_ext_upper = boost::to_upper_copy(custom_extension);
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. if (custom_ext_lower == custom_extension) {
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|"); // Add a lower case version.
out += std::string(";*") + custom_extension; 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(); } 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, RichMessageDialog dlg(nullptr,
_L("You are running a 32 bit build of PrusaSlicer on 64-bit Windows." _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." "\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?"), "\nDo you wish to continue?"),
"PrusaSlicer", wxICON_QUESTION | wxYES_NO); "PrusaSlicer", wxICON_QUESTION | wxYES_NO);
if (dlg.ShowModal() != wxID_YES) if (dlg.ShowModal() != wxID_YES)

View file

@ -67,13 +67,11 @@ enum FileType
FT_TEX, FT_TEX,
FT_SL1, FT_SL1,
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
FT_SL1S,
FT_SIZE, 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 { enum ConfigMenuIDs {
ConfigMenuWizard, ConfigMenuWizard,

View file

@ -523,6 +523,10 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
menu->Destroy(settings_id); 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(); const ConfigOptionMode mode = wxGetApp().get_mode();
if (mode == comAdvanced) { 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, append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second,
[]() { return obj_list()->is_instance_or_object_selected(); }, m_parent); []() { 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) 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) 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"), 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); [](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*/) 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); []() { return plater()->can_split(true) && wxGetApp().get_mode() > comSimple; }, m_parent);
m_object_menu.AppendSeparator(); m_object_menu.AppendSeparator();
// Layers Editing for object // "Height range Modifier" and "Add (volumes)" menu items will be added later in append_menu_items_add_volume()
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()
} }
void MenuFactory::create_sla_object_menu() void MenuFactory::create_sla_object_menu()

View file

@ -4041,18 +4041,8 @@ void ObjectList::rename_item()
if (new_name.IsEmpty()) if (new_name.IsEmpty())
return; return;
bool is_unusable_symbol = false; if (Plater::has_illegal_filename_characters(new_name)) {
std::string chosen_name = Slic3r::normalize_utf8_nfc(new_name.ToUTF8()); Plater::show_illegal_characters_warning(this);
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:")) + " <>:/\\|?*\"");
return; return;
} }
@ -4272,10 +4262,7 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer()); const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer());
if (renderer->WasCanceled()) if (renderer->WasCanceled())
wxTheApp->CallAfter([this]{ wxTheApp->CallAfter([this]{ Plater::show_illegal_characters_warning(this); });
show_error(this, _(L("The supplied name is not valid;")) + "\n" +
_(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
});
#ifdef __WXMSW__ #ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. // 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. // 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; 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: protected:
std::array<float, 4> get_cursor_sphere_left_button_color() const override; 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()); 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}; ImVec2 button_sz = {btn_txt_sz.x + padding.x, btn_txt_sz.y + padding.y};
ImGui::SetCursorPosX(padding.x + sz.x - button_sz.x); 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) ) { if ( imgui->button(btn_txt) ) {
wxGetApp().plater()->optimize_rotation(); wxGetApp().plater()->optimize_rotation();
} }
imgui->disabled_end();
} }
GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow() GLGizmoRotate3D::RotoptimzeWindow::~RotoptimzeWindow()

View file

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

View file

@ -39,7 +39,7 @@ protected:
virtual void on_render() override; virtual void on_render() override;
virtual void on_render_for_picking() override{}; virtual void on_render_for_picking() override{};
virtual CommonGizmosDataID on_get_requirements() const; CommonGizmosDataID on_get_requirements() const override;
private: private:
void apply_simplify(); 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; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
std::string str_label; // let the label string start with "##" to hide the automatic label from ImGui::SliderFloat()
if (boost::algorithm::istarts_with(label, "##")) bool label_visible = !boost::algorithm::istarts_with(label, "##");
str_label = std::string(label); std::string str_label = label_visible ? std::string("##") + std::string(label) : std::string(label);
else {
str_label = std::string("##") + std::string(label); // removes 2nd evenience of "##", if present
this->text(label); std::string::size_type pos = str_label.find("##", 2);
ImGui::SameLine(); 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); bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power);
if (!tooltip.empty() && ImGui::IsItemHovered()) if (!tooltip.empty() && ImGui::IsItemHovered())
@ -515,8 +515,8 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
if (clamp) if (clamp)
*v = std::clamp(*v, v_min, v_max); *v = std::clamp(*v, v_min, v_max);
const ImGuiStyle& style = ImGui::GetStyle();
if (show_edit_btn) { if (show_edit_btn) {
const ImGuiStyle& style = ImGui::GetStyle();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y });
ImGui::SameLine(); ImGui::SameLine();
std::wstring btn_name = ImGui::SliderFloatEditBtnIcon + boost::nowide::widen(str_label); 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(); 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; return ret;
} }

View file

@ -10,7 +10,7 @@ void PlaterJob::on_exception(const std::exception_ptr &eptr)
if (eptr) if (eptr)
std::rethrow_exception(eptr); std::rethrow_exception(eptr);
} catch (std::exception &e) { } 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 bool MainFrame::can_save() const
{ {
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) && return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) && !m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false) &&
m_plater->is_project_dirty(); 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 bool MainFrame::can_save_as() const
{ {
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
return (m_plater != nullptr) && return (m_plater != nullptr) &&
!m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(false); !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() 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"), 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](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(); import_menu->AppendSeparator();
append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"), 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::Separator();
imgui.text_colored(color, _L("Speed:")); imgui.text_colored(color, _L("Speed:"));
float translation_scale = (float)params_copy.translation.scale / Params::DefaultTranslationScale; float translation_scale = float(params_copy.translation.scale) / float(Params::DefaultTranslationScale);
if (imgui.slider_float(_L("Translation") + "##1", &translation_scale, Params::MinTranslationScale, Params::MaxTranslationScale, "%.1f")) { 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_copy.translation.scale = Params::DefaultTranslationScale * double(translation_scale);
params_changed = true; params_changed = true;
} }
@ -517,13 +517,13 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
imgui.text_colored(color, "Vectors:"); imgui.text_colored(color, "Vectors:");
Vec3f translation = m_state.get_first_vector_of_type(State::QueueItem::TranslationType).cast<float>(); 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>(); 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::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
imgui.text_colored(color, "Queue size:"); 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) }; 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); 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)) { 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; break;
case coString: case coString:
ret = static_cast<wxString>(config.opt_string(opt_key)); ret = from_u8(config.opt_string(opt_key));
break; break;
case coStrings: case coStrings:
if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { 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; ret = text_value;
} }
else 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; break;
case coBool: case coBool:
ret = config.opt_bool(opt_key); 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_PROCESS_COMPLETED, SlicingProcessCompletedEvent);
wxDEFINE_EVENT(EVT_EXPORT_BEGAN, wxCommandEvent); 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 // Sidebar widgets
// struct InfoBox : public wxStaticBox // 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 export_gcode(fs::path output_path, bool output_path_on_removable_media, PrintHostJob upload_job);
void reload_from_disk(); 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 = ""); 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 replace_with_stl();
void reload_all_from_disk(); void reload_all_from_disk();
void set_current_panel(wxPanel* panel); void set_current_panel(wxPanel* panel);
@ -1886,6 +1908,9 @@ struct Plater::priv
bool can_reload_from_disk() const; bool can_reload_from_disk() const;
bool can_replace_with_stl() const; bool can_replace_with_stl() const;
bool can_split(bool to_objects) 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); 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); 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()) if (view3D->is_layers_editing_enabled())
view3D->enable_layers_editing(false); view3D->enable_layers_editing(false);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx); model.delete_object(obj_idx);
update(); update();
// Delete object from Sidebar list. Do it after update, so that the GLScene selection is updated with the modified model. // 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()) if (! model.objects[obj_idx]->name.empty())
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str()); snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label); Plater::TakeSnapshot snapshot(q, snapshot_label);
m_ui_jobs.cancel_all();
model.delete_object(obj_idx); model.delete_object(obj_idx);
update(); update();
object_list_changed(); object_list_changed();
@ -2922,6 +2949,8 @@ void Plater::priv::delete_all_objects_from_model()
view3D->get_canvas3d()->reset_sequential_print_clearance(); view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content. // Stop and reset the Print content.
background_process.reset(); background_process.reset();
model.clear_objects(); model.clear_objects();
@ -2952,6 +2981,8 @@ void Plater::priv::reset()
view3D->get_canvas3d()->reset_sequential_print_clearance(); view3D->get_canvas3d()->reset_sequential_print_clearance();
m_ui_jobs.cancel_all();
// Stop and reset the Print content. // Stop and reset the Print content.
this->background_process.reset(); this->background_process.reset();
model.clear_objects(); model.clear_objects();
@ -3051,7 +3082,11 @@ void Plater::priv::split_volume()
void Plater::priv::scale_selection_to_fit_print_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); this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(*config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
} }
void Plater::priv::schedule_background_process() void Plater::priv::schedule_background_process()
@ -3333,7 +3368,6 @@ void Plater::priv::update_sla_scene()
this->update_restart_background_process(true, true); 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) 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(); 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; return true;
} }
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void Plater::priv::replace_with_stl() void Plater::priv::replace_with_stl()
{ {
@ -3439,72 +3472,8 @@ void Plater::priv::replace_with_stl()
return; return;
} }
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
if (!replace_volume_with_stl(object_idx, volume_idx, out_path, _L("Replace with STL"))) if (!replace_volume_with_stl(object_idx, volume_idx, out_path, _L("Replace with STL")))
return; 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 3D scene
update(); update();
@ -3553,9 +3522,7 @@ void Plater::priv::reload_from_disk()
// collects paths of files to load // collects paths of files to load
std::vector<fs::path> input_paths; std::vector<fs::path> input_paths;
std::vector<fs::path> missing_input_paths; std::vector<fs::path> missing_input_paths;
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
std::vector<fs::path> replace_paths; std::vector<fs::path> replace_paths;
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
for (const SelectedVolume& v : selected_volumes) { for (const SelectedVolume& v : selected_volumes) {
const ModelObject* object = model.objects[v.object_idx]; const ModelObject* object = model.objects[v.object_idx];
const ModelVolume* volume = object->volumes[v.volume_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 (!volume->source.input_file.empty()) {
if (fs::exists(volume->source.input_file)) if (fs::exists(volume->source.input_file))
input_paths.push_back(volume->source.input_file); input_paths.push_back(volume->source.input_file);
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
else { else {
// searches the source in the same folder containing the object // searches the source in the same folder containing the object
bool found = false; bool found = false;
@ -3581,10 +3547,6 @@ void Plater::priv::reload_from_disk()
if (!found) if (!found)
missing_input_paths.push_back(volume->source.input_file); 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) 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); missing_input_paths.push_back(volume->name);
@ -3627,7 +3589,6 @@ void Plater::priv::reload_from_disk()
} }
} }
else { else {
#if ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
wxString message = _L("The selected file") + " (" + from_u8(sel_filename) + ") " + 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") + " ?"; _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); //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) if (dlg.ShowModal() == wxID_YES)
replace_paths.push_back(sel_filename_path); replace_paths.push_back(sel_filename_path);
missing_input_paths.pop_back(); 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()); std::sort(input_paths.begin(), input_paths.end());
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), 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()); std::sort(replace_paths.begin(), replace_paths.end());
replace_paths.erase(std::unique(replace_paths.begin(), replace_paths.end()), 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; 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) { for (size_t i = 0; i < replace_paths.size(); ++i) {
const auto& path = replace_paths[i].string(); const auto& path = replace_paths[i].string();
for (const SelectedVolume& sel_v : selected_volumes) { 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()) { if (!fail_list.empty()) {
wxString message = _L("Unable to reload:") + "\n"; 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 export_in_progress = this->background_process.is_export_scheduled();
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside; bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
if (!model.objects.empty() && !export_in_progress && model_fits) { if (!model.objects.empty() && !export_in_progress && model_fits) {
#if ENABLE_SEAMS_USING_MODELS
preview->get_canvas3d()->init_gcode_viewer(); preview->get_canvas3d()->init_gcode_viewer();
#endif // ENABLE_SEAMS_USING_MODELS
q->reslice(); q->reslice();
} }
// keeps current gcode preview, if any // 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); 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 bool Plater::priv::layers_height_allowed() const
{ {
if (printer_technology != ptFFF) 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 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 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" + 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") : (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" _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; using ab = UnsavedChangesDialog::ActionButtons;
int act_buttons = ab::KEEP; int act_buttons = ab::KEEP;
if (saved_project == wxID_NO) if (saved_project == wxID_NO)
@ -5133,7 +5089,8 @@ void Plater::add_model(bool imperial_units/* = false*/)
void Plater::import_sl1_archive() 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() 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(); } 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::update_ui_from_settings() { p->update_ui_from_settings(); }
void Plater::select_view(const std::string& direction) { p->select_view(direction); } void Plater::select_view(const std::string& direction) { p->select_view(direction); }
@ -5456,6 +5418,7 @@ void Plater::remove_selected()
return; return;
Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects")); Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects"));
p->m_ui_jobs.cancel_all();
p->view3D->delete_selected(); p->view3D->delete_selected();
} }
@ -5564,7 +5527,8 @@ void Plater::set_number_of_copies(/*size_t num*/)
void Plater::fill_bed_with_instances() 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 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:"), wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
start_dir, start_dir,
from_path(default_output_file.filename()), 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 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
); );
if (dlg.ShowModal() == wxID_OK) if (dlg.ShowModal() == wxID_OK) {
output_path = into_path(dlg.GetPath()); 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()) { if (! output_path.empty()) {
@ -5881,16 +5852,11 @@ void Plater::export_amf()
bool Plater::export_3mf(const boost::filesystem::path& output_path) bool Plater::export_3mf(const boost::filesystem::path& output_path)
{ {
#if ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
if (p->model.objects.empty()) { 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); 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) if (dialog.ShowModal() != wxID_YES)
return false; return false;
} }
#else
if (p->model.objects.empty())
return false;
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
wxString path; wxString path;
bool export_config = true; bool export_config = true;
@ -6085,11 +6051,12 @@ void Plater::send_gcode()
upload_job.printhost->get_groups(groups); 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) { if (dlg.ShowModal() == wxID_OK) {
upload_job.upload_data.upload_path = dlg.filename(); 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(); upload_job.upload_data.group = dlg.group();
p->export_gcode(fs::path(), false, std::move(upload_job)); 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; update_scheduled = true;
p->sidebar->obj_list()->update_extruder_colors(); 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; update_scheduled = true;
}
else if (opt_key == "printer_model") { else if (opt_key == "printer_model") {
p->reset_gcode_toolpaths(); p->reset_gcode_toolpaths();
// update to force bed selection(for texturing) // update to force bed selection(for texturing)
@ -6439,7 +6408,8 @@ GLCanvas3D* Plater::get_current_canvas3D()
void Plater::arrange() 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() 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::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); } void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); } 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::update_menus() { p->menus.update(); }
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); } 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_replace_with_stl() const { return p->can_replace_with_stl(); }
bool Plater::can_mirror() const { return p->can_mirror(); } bool Plater::can_mirror() const { return p->can_mirror(); }
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); } 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(); } 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::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); }
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); } void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }

View file

@ -178,6 +178,7 @@ public:
void update(); void update();
void stop_jobs(); void stop_jobs();
bool is_any_job_running() const;
void select_view(const std::string& direction); void select_view(const std::string& direction);
void select_view_3D(const std::string& name); void select_view_3D(const std::string& name);
@ -322,6 +323,9 @@ public:
bool can_replace_with_stl() const; bool can_replace_with_stl() const;
bool can_mirror() const; bool can_mirror() const;
bool can_split(bool to_objects) 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 msw_rescale();
void sys_color_changed(); void sys_color_changed();
@ -427,6 +431,10 @@ public:
wxMenu* layer_menu(); wxMenu* layer_menu();
wxMenu* multi_selection_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: private:
struct priv; struct priv;
std::unique_ptr<priv> p; std::unique_ptr<priv> p;

View file

@ -468,7 +468,7 @@ void PreferencesDialog::build(size_t selected_tab)
// Add "Dark Mode" tab // Add "Dark Mode" tab
if (is_editor) { if (is_editor) {
// Add "Dark Mode" tab // 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_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"; 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"); option = Option(def, "dark_color_mode");
m_optgroup_dark_mode->append_single_option_line(option); m_optgroup_dark_mode->append_single_option_line(option);
def.label = L("Use system menu for application"); if (wxPlatformInfo::Get().GetOSMajorVersion() >= 10) // Use system menu just for Window newer then Windows 10
def.type = coBool; // Use menu with ownerdrawn items by default on systems older then Windows 10
def.tooltip = L("If enabled, application will use standart Windows system menu,\n" {
"but on some combination od display scales it can looks ugly. " def.label = L("Use system menu for application");
"If disabled, old UI will be used."); def.type = coBool;
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" }); def.tooltip = L("If enabled, application will use the standart Windows system menu,\n"
option = Option(def, "sys_menu_enabled"); "but on some combination of display scales it can looks ugly. If disabled, old UI will be used.");
m_optgroup_dark_mode->append_single_option_line(option); 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); activate_options_tab(m_optgroup_dark_mode);
} }
@ -519,7 +522,11 @@ void PreferencesDialog::build(size_t selected_tab)
void PreferencesDialog::update_ctrls_alignment() void PreferencesDialog::update_ctrls_alignment()
{ {
int max_ctrl_width{ 0 }; 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) { for (auto og : og_list) {
if (int max = og->custom_ctrl->get_max_win_width(); if (int max = og->custom_ctrl->get_max_win_width();
max_ctrl_width < max) max_ctrl_width < max)

View file

@ -23,7 +23,6 @@
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "MsgDialog.hpp" #include "MsgDialog.hpp"
#include "I18N.hpp" #include "I18N.hpp"
#include "../Utils/PrintHost.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "NotificationManager.hpp" #include "NotificationManager.hpp"
@ -35,13 +34,13 @@ namespace Slic3r {
namespace GUI { namespace GUI {
static const char *CONFIG_KEY_PATH = "printhost_path"; static const char *CONFIG_KEY_PATH = "printhost_path";
static const char *CONFIG_KEY_PRINT = "printhost_print";
static const char *CONFIG_KEY_GROUP = "printhost_group"; 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:")) : 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)) , txt_filename(new wxTextCtrl(this, wxID_ANY))
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr) , combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
, post_upload_action(PrintHostPostUploadAction::None)
{ {
#ifdef __APPLE__ #ifdef __APPLE__
txt_filename->OSXDisableAllSmartSubstitutions(); txt_filename->OSXDisableAllSmartSubstitutions();
@ -77,37 +76,46 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
txt_filename->SetValue(recent_path); txt_filename->SetValue(recent_path);
txt_filename->SetFocus(); 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")); auto* btn_print = add_button(wxID_YES, false, _L("Upload and Print"));
btn_print->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) { btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
wxString path = txt_filename->GetValue(); if (validate_path(txt_filename->GetValue())) {
// .gcode suffix control post_upload_action = PrintHostPostUploadAction::StartPrint;
if (!path.Lower().EndsWith(suffix.Lower())) EndDialog(wxID_OK);
{
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;
} }
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); 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->SetLabel(_L("Upload"));
btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) { btn_ok->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
wxString path = txt_filename->GetValue(); if (validate_path(txt_filename->GetValue())) {
// .gcode suffix control post_upload_action = PrintHostPostUploadAction::None;
if (!path.Lower().EndsWith(suffix.Lower())) EndDialog(wxID_OK);
{
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;
} }
EndDialog(wxID_OK);
}); });
} }
finalize(); finalize();
@ -137,9 +145,9 @@ fs::path PrintHostSendDialog::filename() const
return into_path(txt_filename->GetValue()); 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 std::string PrintHostSendDialog::group() const
@ -165,7 +173,6 @@ void PrintHostSendDialog::EndModal(int ret)
AppConfig *app_config = wxGetApp().app_config; AppConfig *app_config = wxGetApp().app_config;
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path)); 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) { if (combo_groups != nullptr) {
wxString group = combo_groups->GetValue(); wxString group = combo_groups->GetValue();

View file

@ -1,6 +1,7 @@
#ifndef slic3r_PrintHostSendDialog_hpp_ #ifndef slic3r_PrintHostSendDialog_hpp_
#define slic3r_PrintHostSendDialog_hpp_ #define slic3r_PrintHostSendDialog_hpp_
#include <set>
#include <string> #include <string>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
@ -10,34 +11,32 @@
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "MsgDialog.hpp" #include "MsgDialog.hpp"
#include "../Utils/PrintHost.hpp"
class wxButton; class wxButton;
class wxTextCtrl; class wxTextCtrl;
class wxChoice;
class wxComboBox; class wxComboBox;
class wxCheckBox;
class wxDataViewListCtrl; class wxDataViewListCtrl;
namespace Slic3r { namespace Slic3r {
struct PrintHostJob;
namespace GUI { namespace GUI {
class PrintHostSendDialog : public GUI::MsgDialog class PrintHostSendDialog : public GUI::MsgDialog
{ {
public: 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; boost::filesystem::path filename() const;
bool start_print() const; PrintHostPostUploadAction post_action() const;
std::string group() const; std::string group() const;
virtual void EndModal(int ret) override; virtual void EndModal(int ret) override;
private: private:
wxTextCtrl *txt_filename; wxTextCtrl *txt_filename;
wxComboBox *combo_groups; 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/LocalesUtils.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.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> #include <GL/glew.h>
@ -948,6 +951,94 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
wxGetApp().plater()->canvas3D()->requires_check_outside_state(); 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) void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
{ {
if (is_empty() || m_mode == Volume) 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) void Selection::mirror(Axis axis)
{ {

View file

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

View file

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

View file

@ -1650,6 +1650,7 @@ void TabPrint::build()
optgroup->append_single_option_line("slice_closing_radius"); optgroup->append_single_option_line("slice_closing_radius");
optgroup->append_single_option_line("slicing_mode"); optgroup->append_single_option_line("slicing_mode");
optgroup->append_single_option_line("resolution"); 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("xy_size_compensation");
optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487"); 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(); on_presets_changed();
// If current profile is saved, "delete preset" button have to be enabled // If current profile is saved, "delete preset" button have to be enabled
m_btn_delete_preset->Show(); m_btn_delete_preset->Show();
m_btn_delete_preset->GetParent()->Layout();
if (m_type == Preset::TYPE_PRINTER) if (m_type == Preset::TYPE_PRINTER)
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count; 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*/) : MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_before_wizard/* = false*/) :
MsgDialog(nullptr, force_before_wizard ? _L("Opening Configuration Wizard") : _L("Configuration update"), 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" 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) _L("Configuration update is available"), wxICON_ERROR)
{ {
auto *text = new wxStaticText(this, wxID_ANY, _(L( 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)...); return format_wxstr(fmt.ToUTF8().data(), std::forward<TArgs>(args)...);
} }
template<typename... TArgs> 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) { inline std::string format(const wxString& fmt, TArgs&&... args) {
return Slic3r::format(fmt.ToUTF8().data(), std::forward<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 % url
% upload_filename.string() % upload_filename.string()
% upload_parent_path.string() % upload_parent_path.string()
% upload_data.start_print; % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
auto http = Http::post(std::move(url)); auto http = Http::post(std::move(url));
set_auth(http); 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("path", upload_parent_path.string()) // XXX: slashes on windows ???
.form_add_file("file", upload_data.source_path.string(), upload_filename.string()) .form_add_file("file", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) { .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 upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return true; } bool has_auto_discovery() const override { return true; }
bool can_test() 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; } std::string get_host() const override { return host; }
protected: protected:

View file

@ -67,10 +67,10 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
bool dsf = (connectionType == ConnectionType::dsf); bool dsf = (connectionType == ConnectionType::dsf);
auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType); 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.source_path
% upload_data.upload_path % upload_data.upload_path
% upload_data.start_print % int(upload_data.post_action)
% upload_cmd; % upload_cmd;
auto http = (dsf ? Http::put(std::move(upload_cmd)) : Http::post(std::move(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; 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)); error_fn(format_error(body, L("Unknown error occured"), 0));
res = false; res = false;
} else if (upload_data.start_print) { } else if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) {
wxString errormsg; 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) { if (! res) {
error_fn(std::move(errormsg)); error_fn(std::move(errormsg));
} }
@ -230,7 +236,7 @@ std::string Duet::timestamp_str() const
return std::string(buffer); 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); assert(connectionType != ConnectionType::error);
@ -240,14 +246,18 @@ bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionTyp
auto url = dsf auto url = dsf
? (boost::format("%1%machine/code") ? (boost::format("%1%machine/code")
% get_base_url()).str() % 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() % get_base_url()
% Http::url_encode(filename)).str(); % Http::url_encode(filename)).str();
auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url))); auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url)));
if (dsf) { if (dsf) {
http.set_post_body( http.set_post_body(
(boost::format("M32 \"0:/gcodes/%1%\"") (boost::format(simulationMode
? "M37 P\"0:/gcodes/%1%\""
: "M32 \"0:/gcodes/%1%\"")
% filename).str() % filename).str()
); );
} }

View file

@ -25,7 +25,7 @@ public:
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; } bool has_auto_discovery() const override { return false; }
bool can_test() 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 | PrintHostPostUploadAction::StartSimulation; }
std::string get_host() const override { return host; } std::string get_host() const override { return host; }
private: private:
@ -39,7 +39,7 @@ private:
std::string timestamp_str() const; std::string timestamp_str() const;
ConnectionType connect(wxString &msg) const; ConnectionType connect(wxString &msg) const;
void disconnect(ConnectionType connectionType) 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; 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