Merge remote-tracking branch 'origin/master' into ys_msw_dpi

This commit is contained in:
YuSanka 2019-04-10 10:01:20 +02:00
commit a74c608c7a
78 changed files with 36526 additions and 31007 deletions

309
README.md
View file

@ -20,9 +20,8 @@ All user facing code is written in C++, and some legacy code as well as unit
tests are written in Perl. Perl is not required for either development or use
of Slic3r.
The C++ API is public and its use in other projects is encouraged.
The goal is to make Slic3r fully modular so that any part of its logic
can be used separately.
The slicing core is the `libslic3r` library, which can be built and used in a standalone way.
The command line interface is a thin wrapper over `libslic3r`.
### What are Slic3r's main features?
@ -67,309 +66,13 @@ Sure! You can do the following to find things that are available to help with:
### What's Slic3r license?
Slic3r is licensed under the _GNU Affero General Public License, version 3_.
The author is Alessandro Ranellucci.
Slic3r PE is licensed under the _GNU Affero General Public License, version 3_.
The Prusa Edition is originally based on Slic3r by Alessandro Ranellucci.
The [Silk icon set](http://www.famfamfam.com/lab/icons/silk/) used in Slic3r is
licensed under the _Creative Commons Attribution 3.0 License_.
The author of the Silk icon set is Mark James.
### How can I invoke slic3r.pl using the command line?
### How can I use Slic3r PE from the command line?
Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
--help Output this usage screen and exit
--version Output the version of Slic3r and exit
--save <file> Save configuration to the specified file
--load <file> Load configuration from the specified file. It can be used
more than once to load options from multiple files.
-o, --output <file> File to output gcode to (by default, the file will be saved
into the same directory as the input file using the
--output-filename-format to generate the filename.) If a
directory is specified for this option, the output will
be saved under that directory, and the filename will be
generated by --output-filename-format.
Non-slicing actions (no G-code will be generated):
--repair Repair given STL files and save them as <name>_fixed.obj
--cut <z> Cut given input files at given Z (relative) and export
them as <name>_upper.stl and <name>_lower.stl
--split Split the shells contained in given STL file into several STL files
--info Output information about the supplied file(s) and exit
-j, --threads <num> Number of threads to use (1+, default: 2)
GUI options:
--gui Forces the GUI launch instead of command line slicing (if you
supply a model file, it will be loaded into the plater)
--no-plater Disable the plater tab
--no-gui Forces the command line slicing instead of gui.
This takes precedence over --gui if both are present.
--autosave <file> Automatically export current configuration to the specified file
Output options:
--output-filename-format
Output file name format; all config options enclosed in brackets
will be replaced by their values, as well as [input_filename_base]
and [input_filename] (default: [input_filename_base].gcode)
--post-process Generated G-code will be processed with the supplied script;
call this more than once to process through multiple scripts.
--export-png Export zipped PNG files containing slices instead of G-code.
-m, --merge If multiple files are supplied, they will be composed into a single
print rather than processed individually.
Printer options:
--nozzle-diameter Diameter of nozzle in mm (default: 0.5)
--print-center Coordinates in mm of the point to center the print around
(default: 100,100)
--z-offset Additional height in mm to add to vertical coordinates
(+/-, default: 0)
--gcode-flavor The type of G-code to generate (reprap/teacup/repetier/makerware/sailfish/mach3/machinekit/smoothie/no-extrusion,
default: reprap)
--use-relative-e-distances Enable this to get relative E values (default: no)
--use-firmware-retraction Enable firmware-controlled retraction using G10/G11 (default: no)
--use-volumetric-e Express E in cubic millimeters and prepend M200 (default: no)
--gcode-comments Make G-code verbose by adding comments (default: no)
Filament options:
--filament-diameter Diameter in mm of your raw filament (default: 3)
--extrusion-multiplier
Change this to alter the amount of plastic extruded. There should be
very little need to change this value, which is only useful to
compensate for filament packing (default: 1)
--temperature Extrusion temperature in degree Celsius, set 0 to disable (default: 200)
--first-layer-temperature Extrusion temperature for the first layer, in degree Celsius,
set 0 to disable (default: same as --temperature)
--bed-temperature Heated bed temperature in degree Celsius, set 0 to disable (default: 0)
--first-layer-bed-temperature Heated bed temperature for the first layer, in degree Celsius,
set 0 to disable (default: same as --bed-temperature)
Speed options:
--travel-speed Speed of non-print moves in mm/s (default: 130)
--perimeter-speed Speed of print moves for perimeters in mm/s (default: 30)
--small-perimeter-speed
Speed of print moves for small perimeters in mm/s or % over perimeter speed
(default: 30)
--external-perimeter-speed
Speed of print moves for the external perimeter in mm/s or % over perimeter speed
(default: 70%)
--infill-speed Speed of print moves in mm/s (default: 60)
--solid-infill-speed Speed of print moves for solid surfaces in mm/s or % over infill speed
(default: 60)
--top-solid-infill-speed Speed of print moves for top surfaces in mm/s or % over solid infill speed
(default: 50)
--support-material-speed
Speed of support material print moves in mm/s (default: 60)
--support-material-interface-speed
Speed of support material interface print moves in mm/s or % over support material
speed (default: 100%)
--bridge-speed Speed of bridge print moves in mm/s (default: 60)
--gap-fill-speed Speed of gap fill print moves in mm/s (default: 20)
--first-layer-speed Speed of print moves for bottom layer, expressed either as an absolute
value or as a percentage over normal speeds (default: 30%)
Acceleration options:
--perimeter-acceleration
Overrides firmware's default acceleration for perimeters. (mm/s^2, set zero
to disable; default: 0)
--infill-acceleration
Overrides firmware's default acceleration for infill. (mm/s^2, set zero
to disable; default: 0)
--bridge-acceleration
Overrides firmware's default acceleration for bridges. (mm/s^2, set zero
to disable; default: 0)
--first-layer-acceleration
Overrides firmware's default acceleration for first layer. (mm/s^2, set zero
to disable; default: 0)
--default-acceleration
Acceleration will be reset to this value after the specific settings above
have been applied. (mm/s^2, set zero to disable; default: 0)
Accuracy options:
--layer-height Layer height in mm (default: 0.3)
--first-layer-height Layer height for first layer (mm or %, default: 0.35)
--infill-every-layers
Infill every N layers (default: 1)
--solid-infill-every-layers
Force a solid layer every N layers (default: 0)
Print options:
--perimeters Number of perimeters/horizontal skins (range: 0+, default: 3)
--top-solid-layers Number of solid layers to do for top surfaces (range: 0+, default: 3)
--bottom-solid-layers Number of solid layers to do for bottom surfaces (range: 0+, default: 3)
--solid-layers Shortcut for setting the two options above at once
--fill-density Infill density (range: 0%-100%, default: 40%)
--fill-angle Infill angle in degrees (range: 0-90, default: 45)
--fill-pattern Pattern to use to fill non-solid layers (default: honeycomb)
--solid-fill-pattern Pattern to use to fill solid layers (default: rectilinear)
--start-gcode Load initial G-code from the supplied file. This will overwrite
the default command (home all axes [G28]).
--end-gcode Load final G-code from the supplied file. This will overwrite
the default commands (turn off temperature [M104 S0],
home X axis [G28 X], disable motors [M84]).
--before-layer-gcode Load before-layer-change G-code from the supplied file (default: nothing).
--layer-gcode Load after-layer-change G-code from the supplied file (default: nothing).
--toolchange-gcode Load tool-change G-code from the supplied file (default: nothing).
--seam-position Position of loop starting points (random/nearest/aligned, default: aligned).
--external-perimeters-first Reverse perimeter order. (default: no)
--spiral-vase Experimental option to raise Z gradually when printing single-walled vases
(default: no)
--only-retract-when-crossing-perimeters
Disable retraction when travelling between infill paths inside the same island.
(default: no)
--solid-infill-below-area
Force solid infill when a region has a smaller area than this threshold
(mm^2, default: 70)
--infill-only-where-needed
Only infill under ceilings (default: no)
--infill-first Make infill before perimeters (default: no)
Quality options (slower slicing):
--extra-perimeters Add more perimeters when needed (default: yes)
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
--thin-walls Detect single-width walls (default: yes)
--overhangs Experimental option to use bridge flow, speed and fan for overhangs
(default: yes)
Support material options:
--support-material Generate support material for overhangs
--support-material-threshold
Overhang threshold angle (range: 0-90, set 0 for automatic detection,
default: 0)
--support-material-pattern
Pattern to use for support material (default: honeycomb)
--support-material-spacing
Spacing between pattern lines (mm, default: 2.5)
--support-material-angle
Support material angle in degrees (range: 0-90, default: 0)
--support-material-contact-distance
Vertical distance between object and support material
(0+, default: 0.2)
--support-material-interface-layers
Number of perpendicular layers between support material and object (0+, default: 3)
--support-material-interface-spacing
Spacing between interface pattern lines (mm, set 0 to get a solid layer, default: 0)
--raft-layers Number of layers to raise the printed objects by (range: 0+, default: 0)
--support-material-enforce-layers
Enforce support material on the specified number of layers from bottom,
regardless of --support-material and threshold (0+, default: 0)
--dont-support-bridges
Experimental option for preventing support material from being generated under bridged areas (default: yes)
Retraction options:
--retract-length Length of retraction in mm when pausing extrusion (default: 1)
--retract-speed Speed for retraction in mm/s (default: 30)
--retract-restart-extra
Additional amount of filament in mm to push after
compensating retraction (default: 0)
--retract-before-travel
Only retract before travel moves of this length in mm (default: 2)
--retract-lift Lift Z by the given distance in mm when retracting (default: 0)
--retract-lift-above Only lift Z when above the specified height (default: 0)
--retract-lift-below Only lift Z when below the specified height (default: 0)
--retract-layer-change
Enforce a retraction before each Z move (default: no)
--wipe Wipe the nozzle while doing a retraction (default: no)
Retraction options for multi-extruder setups:
--retract-length-toolchange
Length of retraction in mm when disabling tool (default: 10)
--retract-restart-extra-toolchange
Additional amount of filament in mm to push after
switching tool (default: 0)
Cooling options:
--cooling Enable fan and cooling control
--min-fan-speed Minimum fan speed (default: 35%)
--max-fan-speed Maximum fan speed (default: 100%)
--bridge-fan-speed Fan speed to use when bridging (default: 100%)
--fan-below-layer-time Enable fan if layer print time is below this approximate number
of seconds (default: 60)
--slowdown-below-layer-time Slow down if layer print time is below this approximate number
of seconds (default: 30)
--min-print-speed Minimum print speed (mm/s, default: 10)
--disable-fan-first-layers Disable fan for the first N layers (default: 1)
--fan-always-on Keep fan always on at min fan speed, even for layers that don't need
cooling
Skirt options:
--skirts Number of skirts to draw (0+, default: 1)
--skirt-distance Distance in mm between innermost skirt and object
(default: 6)
--skirt-height Height of skirts to draw (expressed in layers, 0+, default: 1)
--min-skirt-length Generate no less than the number of loops required to consume this length
of filament on the first layer, for each extruder (mm, 0+, default: 0)
--brim-width Width of the brim that will get added to each object to help adhesion
(mm, default: 0)
Transform options:
--scale Factor for scaling input object (default: 1)
--rotate Rotation angle in degrees (0-360, default: 0)
--duplicate Number of items with auto-arrange (1+, default: 1)
--duplicate-grid Number of items with grid arrangement (default: 1,1)
--duplicate-distance Distance in mm between copies (default: 6)
--dont-arrange Don't arrange the objects on the build plate. The model coordinates
define the absolute positions on the build plate.
The option --print-center will be ignored.
--xy-size-compensation
Grow/shrink objects by the configured absolute distance (mm, default: 0)
Sequential printing options:
--complete-objects When printing multiple objects and/or copies, complete each one before
starting the next one; watch out for extruder collisions (default: no)
--extruder-clearance-radius Radius in mm above which extruder won't collide with anything
(default: 20)
--extruder-clearance-height Maximum vertical extruder depth; i.e. vertical distance from
extruder tip and carriage bottom (default: 20)
Miscellaneous options:
--notes Notes to be added as comments to the output file
--resolution Minimum detail resolution (mm, set zero for full resolution, default: 0)
Flow options (advanced):
--extrusion-width Set extrusion width manually; it accepts either an absolute value in mm
(like 0.65) or a percentage over layer height (like 200%)
--first-layer-extrusion-width
Set a different extrusion width for first layer
--perimeter-extrusion-width
Set a different extrusion width for perimeters
--external-perimeter-extrusion-width
Set a different extrusion width for external perimeters
--infill-extrusion-width
Set a different extrusion width for infill
--solid-infill-extrusion-width
Set a different extrusion width for solid infill
--top-infill-extrusion-width
Set a different extrusion width for top infill
--support-material-extrusion-width
Set a different extrusion width for support material
--infill-overlap Overlap between infill and perimeters (default: 15%)
--bridge-flow-ratio Multiplier for extrusion when bridging (> 0, default: 1)
Multiple extruder options:
--extruder-offset Offset of each extruder, if firmware doesn't handle the displacement
(can be specified multiple times, default: 0x0)
--perimeter-extruder
Extruder to use for perimeters and brim (1+, default: 1)
--infill-extruder Extruder to use for infill (1+, default: 1)
--solid-infill-extruder Extruder to use for solid infill (1+, default: 1)
--support-material-extruder
Extruder to use for support material, raft and skirt (1+, default: 1)
--support-material-interface-extruder
Extruder to use for support material interface (1+, default: 1)
--ooze-prevention Drop temperature and park extruders outside a full skirt for automatic wiping
(default: no)
--ooze-prevention Drop temperature and park extruders outside a full skirt for automatic wiping
(default: no)
--standby-temperature-delta
Temperature difference to be applied when an extruder is not active and
--ooze-prevention is enabled (default: -5)
If you want to change a preset file, just do
slic3r.pl --load config.ini --layer-height 0.25 --save config.ini
If you want to slice a file overriding an option contained in your preset file:
slic3r.pl --load config.ini --layer-height 0.25 file.stl
Please refer to the [Command Line Interface](https://github.com/prusa3d/Slic3r/wiki/Command-Line-Interface) wiki page.

15
resources/icons/cross.svg Normal file
View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="cross">
<g>
<line fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="2" y2="14"/>
</g>
<g>
<line fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="2" x2="14" y2="14"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 659 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="flag_x5F_green">
<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="14" y2="14"/>
<path fill="#8CC63F" d="M13,2C8.2,2,5.8,4.4,1,4.4v7.2c4.8,0,7.2-2.4,12-2.4V2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 591 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="flag_x5F_red">
<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="14" y2="14"/>
<path fill="#ED1C24" d="M13,2C8.2,2,5.8,4.4,1,4.4v7.2c4.8,0,7.2-2.4,12-2.4V2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 589 B

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="layers">
<g>
<g>
<rect x="1" y="13" fill="#FFFFFF" width="14" height="2"/>
</g>
<g>
<rect x="1" y="10.6" fill="#FFFFFF" width="14" height="1.74"/>
</g>
<g>
<rect x="1" y="8.19" fill="#FFFFFF" width="14" height="1.47"/>
</g>
<g>
<rect x="1" y="5.79" fill="#ED6B21" width="14" height="1.2"/>
</g>
<g>
<rect x="1" y="3.39" fill="#ED6B21" width="14" height="0.93"/>
</g>
<g>
<rect x="1" y="0.99" fill="#FFFFFF" width="14" height="0.67"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 845 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="lock_x5F_closed">
<path fill="none" stroke="#808080" stroke-width="2" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2c1,0,3,0,4,0c2,0,2,2,2,2v4"/>
<path fill="#808080" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91
c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 729 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="lock_x5F_closed">
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2c1,0,3,0,4,0c2,0,2,2,2,2v4"/>
<path fill="#FFFFFF" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91
c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 729 B

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="lock_x5F_open">
<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2
c1,0,3,0,4,0c2,0,2,2,2,2v1"/>
<path fill="#ED6B21" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91
c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 753 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="question">
<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M4,5c0,0,0,0,0-1s1-2,2-2
s3,0,4,0c2,0,2,2,2,3v1c0,1-1,2-2,2S9,8,9,8s1,0,0,0s-2,1-2,2s0,1,0,1"/>
<circle fill="#ED6B21" cx="7" cy="14" r="1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 615 B

10
resources/icons/resin.svg Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="resin">
<rect x="4" y="7" fill="#ED6B21" width="8" height="8"/>
<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="M4.5,15h6.99c0.28,0,0.5-0.23,0.5-0.5V6
c0-1-2-1-2-2s0-1,0-1h1V1.5C11,1.23,10.77,1,10.5,1H5.5C5.23,1,5,1.23,5,1.5V3h1v1c0,1-2,1-2,2v8.5C4,14.77,4.23,15,4.5,15z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 671 B

24
resources/icons/save.svg Normal file
View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="save">
<g>
<path fill="#808080" d="M12,2c1.44,0,2,0.56,2,2v10L2,14L2,2H12 M12,1H2C1.45,1,1,1.45,1,2V14c0,0.55,0.45,1,1,1h12
c0.55,0,1-0.45,1-1l0-10C15,2,14,1,12,1L12,1z"/>
</g>
<g>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="8" x2="10" y2="8"/>
</g>
<g>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="10" x2="10" y2="10"/>
</g>
<g>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="12" x2="7" y2="12"/>
</g>
<g>
<path fill="#ED6B21" d="M11,1H5C4.45,1,4,1.45,4,2V5c0,0.55,0.45,1,1,1H11c0.55,0,1-0.45,1-1V2C12,1.45,11.55,1,11,1z M6,4.5
C6,4.78,5.78,5,5.5,5S5,4.78,5,4.5v-2C5,2.22,5.22,2,5.5,2S6,2.22,6,2.5V4.5z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

12
resources/icons/undo.svg Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="undo">
<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M3,11
c0.91,1.78,2.76,3,4.89,3c3.04,0,5.5-2.46,5.5-5.5c0-3.04-2.46-5.5-5.5-5.5c-0.17,0-0.34,0.01-0.5,0.03"/>
<polygon fill="#ED6B21" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
7.39,1 7.39,5 4.39,3 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 746 B

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

@ -8,11 +8,17 @@ src/slic3r/GUI/ConfigWizard.cpp
src/slic3r/GUI/Field.cpp
src/slic3r/GUI/FirmwareDialog.cpp
src/slic3r/GUI/GLCanvas3D.cpp
src/slic3r/GUI/GLGizmo.cpp
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI_App.cpp
src/slic3r/GUI/GUI_ObjectList.cpp
src/slic3r/GUI/GUI_ObjectManipulation.cpp
src/slic3r/GUI/GUI_ObjectSettings.cpp
src/slic3r/GUI/GUI_Preview.cpp
src/slic3r/GUI/KBShortcutsDialog.cpp
src/slic3r/GUI/MainFrame.cpp
@ -23,15 +29,22 @@ src/slic3r/GUI/Preset.cpp
src/slic3r/GUI/PresetBundle.cpp
src/slic3r/GUI/PresetHints.cpp
src/slic3r/GUI/PrintHostDialogs.cpp
src/slic3r/GUI/ProgressStatusBar.cpp
src/slic3r/GUI/RammingChart.cpp
src/slic3r/GUI/SysInfoDialog.cpp
src/slic3r/GUI/Tab.cpp
src/slic3r/GUI/Tab.hpp
src/slic3r/GUI/UpdateDialogs.cpp
src/slic3r/GUI/WipeTowerDialog.cpp
src/slic3r/GUI/wxExtensions.cpp
src/slic3r/Utils/Duet.cpp
src/slic3r/Utils/OctoPrint.cpp
src/slic3r/Utils/PresetUpdater.cpp
src/slic3r/Utils/FixModelByWin10.cpp
src/libslic3r/Zipper.cpp
src/libslic3r/SLA/SLASupportTree.cpp
src/libslic3r/Print.cpp
src/libslic3r/SLAPrint.cpp
src/libslic3r/PrintBase.cpp
src/libslic3r/PrintConfig.cpp
src/libslic3r/GCode/PreviewData.cpp

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

@ -1455,4 +1455,28 @@ Transformation Transformation::operator * (const Transformation& other) const
return Transformation(get_matrix() * other.get_matrix());
}
Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
return
// From the current coordinate system to world.
Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) *
// From world to the initial coordinate system.
Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ());
}
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
#ifndef NDEBUG
if (std::abs(angle) > 1e-8) {
assert(std::abs(axis.x()) < 1e-8);
assert(std::abs(axis.y()) < 1e-8);
}
#endif /* NDEBUG */
return (axis.z() < 0) ? -angle : angle;
}
} }

View file

@ -262,6 +262,13 @@ public:
Transformation operator * (const Transformation& other) const;
};
// Rotation when going from the first coordinate system with rotation rot_xyz_from applied
// to a coordinate system with rot_xyz_to applied.
extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);
// Rotation by Z to align rot_xyz_from to rot_xyz_to.
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to);
} }
#endif

View file

@ -2260,11 +2260,33 @@ void PrintConfigDef::init_sla_params()
def->mode = comExpert;
def->default_value = new ConfigOptionFloat(50.);
def = this->add("printer_correction", coFloats);
def = this->add("relative_correction", coFloats);
def->label = L("Printer scaling correction");
def->full_label = L("Printer scaling correction");
def->tooltip = L("Printer scaling correction");
def->min = 0;
def->mode = comExpert;
def->default_value = new ConfigOptionFloats( { 1., 1., 1. } );
def = this->add("absolute_correction", coFloat);
def->label = L("Printer absolute correction");
def->full_label = L("Printer absolute correction");
def->tooltip = L("Will inflate or deflate the sliced 2D polygons according "
"to the sign of the correction.");
def->mode = comExpert;
def->default_value = new ConfigOptionFloat(0.0);
def = this->add("gamma_correction", coFloat);
def->label = L("Printer gamma correction");
def->full_label = L("Printer gamma correction");
def->tooltip = L("This will apply a gamma correction to the rasterized 2D "
"polygons. A gamma value of zero means thresholding with "
"the threshold in the middle. This behaviour eliminates "
"antialiasing without losing holes in polygons.");
def->min = 0;
def->mode = comExpert;
def->default_value = new ConfigOptionFloat(1.0);
// SLA Material settings.
def = this->add("initial_layer_height", coFloat);
@ -2296,16 +2318,11 @@ void PrintConfigDef::init_sla_params()
def->min = 0;
def->default_value = new ConfigOptionFloat(15);
def = this->add("material_correction_printing", coFloats);
def->full_label = L("Correction for expansion when printing");
def->tooltip = L("Correction for expansion when printing");
def->min = 0;
def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } );
def = this->add("material_correction_curing", coFloats);
def->full_label = L("Correction for expansion after curing");
def->tooltip = L("Correction for expansion after curing");
def = this->add("material_correction", coFloats);
def->full_label = L("Correction for expansion");
def->tooltip = L("Correction for expansion");
def->min = 0;
def->mode = comExpert;
def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } );
def = this->add("material_notes", coString);
@ -2490,7 +2507,7 @@ void PrintConfigDef::init_sla_params()
def->tooltip = L("No support points will be placed closer than this threshold.");
def->sidetext = L("mm");
def->min = 0;
def->default_value = new ConfigOptionFloat(0.f);
def->default_value = new ConfigOptionFloat(1.f);
def = this->add("pad_enable", coBool);
def->label = L("Use pad");

View file

@ -1056,16 +1056,14 @@ public:
ConfigOptionFloat initial_layer_height;
ConfigOptionFloat exposure_time;
ConfigOptionFloat initial_exposure_time;
ConfigOptionFloats material_correction_printing;
ConfigOptionFloats material_correction_curing;
ConfigOptionFloats material_correction;
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
OPT_PTR(initial_layer_height);
OPT_PTR(exposure_time);
OPT_PTR(initial_exposure_time);
OPT_PTR(material_correction_printing);
OPT_PTR(material_correction_curing);
OPT_PTR(material_correction);
}
};
@ -1081,7 +1079,9 @@ public:
ConfigOptionInt display_pixels_x;
ConfigOptionInt display_pixels_y;
ConfigOptionEnum<SLADisplayOrientation> display_orientation;
ConfigOptionFloats printer_correction;
ConfigOptionFloats relative_correction;
ConfigOptionFloat absolute_correction;
ConfigOptionFloat gamma_correction;
ConfigOptionFloat fast_tilt_time;
ConfigOptionFloat slow_tilt_time;
ConfigOptionFloat area_fill;
@ -1096,7 +1096,9 @@ protected:
OPT_PTR(display_pixels_x);
OPT_PTR(display_pixels_y);
OPT_PTR(display_orientation);
OPT_PTR(printer_correction);
OPT_PTR(relative_correction);
OPT_PTR(absolute_correction);
OPT_PTR(gamma_correction);
OPT_PTR(fast_tilt_time);
OPT_PTR(slow_tilt_time);
OPT_PTR(area_fill);

View file

@ -138,6 +138,7 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP>
double m_exp_time_s = .0, m_exp_time_first_s = .0;
double m_layer_height = .0;
Raster::Origin m_o = Raster::Origin::TOP_LEFT;
double m_gamma;
double m_used_material = 0.0;
int m_cnt_fade_layers = 0;
@ -194,7 +195,8 @@ public:
unsigned width_px, unsigned height_px,
double layer_height,
double exp_time, double exp_time_first,
RasterOrientation ro = RO_PORTRAIT):
RasterOrientation ro = RO_PORTRAIT,
double gamma = 1.0):
m_res(width_px, height_px),
m_pxdim(width_mm/width_px, height_mm/height_px),
m_exp_time_s(exp_time),
@ -203,7 +205,8 @@ public:
// Here is the trick with the orientation.
m_o(ro == RO_LANDSCAPE? Raster::Origin::BOTTOM_LEFT :
Raster::Origin::TOP_LEFT )
Raster::Origin::TOP_LEFT ),
m_gamma(gamma)
{
}
@ -228,12 +231,12 @@ public:
inline void begin_layer(unsigned lyr) {
if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1);
m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_o);
m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_o, m_gamma);
}
inline void begin_layer() {
m_layers_rst.emplace_back();
m_layers_rst.front().raster.reset(m_res, m_pxdim, m_o);
m_layers_rst.front().raster.reset(m_res, m_pxdim, m_o, m_gamma);
}
inline void finish_layer(unsigned lyr_id) {

View file

@ -19,6 +19,12 @@
namespace Slic3r {
const Polygon& contour(const ExPolygon& p) { return p.contour; }
const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; }
const Polygons& holes(const ExPolygon& p) { return p.holes; }
const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; }
class Raster::Impl {
public:
using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24;
@ -37,14 +43,17 @@ public:
private:
Raster::Resolution m_resolution;
Raster::PixelDim m_pxdim;
// Raster::PixelDim m_pxdim;
Raster::PixelDim m_pxdim_scaled; // used for scaled coordinate polygons
TBuffer m_buf;
TRawBuffer m_rbuf;
TPixelRenderer m_pixfmt;
TRawRenderer m_raw_renderer;
TRendererAA m_renderer;
std::function<double(double)> m_gammafn;
Origin m_o;
inline void flipy(agg::path_storage& path) const {
path.flip_y(0, m_resolution.height_px);
}
@ -52,8 +61,10 @@ private:
public:
inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd,
Origin o):
m_resolution(res), m_pxdim(pd),
Origin o, double gamma = 1.0):
m_resolution(res),
// m_pxdim(pd),
m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm),
m_buf(res.pixels()),
m_rbuf(reinterpret_cast<TPixelRenderer::value_type*>(m_buf.data()),
res.width_px, res.height_px,
@ -64,43 +75,26 @@ public:
m_o(o)
{
m_renderer.color(ColorWhite);
// If we would like to play around with gamma
// ras.gamma(agg::gamma_power(1.0));
if(gamma > 0) m_gammafn = agg::gamma_power(gamma);
else m_gammafn = agg::gamma_threshold(0.5);
clear();
}
void draw(const ExPolygon &poly) {
template<class P> void draw(const P &poly) {
agg::rasterizer_scanline_aa<> ras;
agg::scanline_p8 scanlines;
ras.gamma(m_gammafn);
auto&& path = to_path(poly.contour);
auto&& path = to_path(contour(poly));
if(m_o == Origin::TOP_LEFT) flipy(path);
ras.add_path(path);
for(auto h : poly.holes) {
auto&& holepath = to_path(h);
if(m_o == Origin::TOP_LEFT) flipy(holepath);
ras.add_path(holepath);
}
agg::render_scanlines(ras, scanlines, m_renderer);
}
void draw(const ClipperLib::Polygon &poly) {
agg::rasterizer_scanline_aa<> ras;
agg::scanline_p8 scanlines;
auto&& path = to_path(poly.Contour);
if(m_o == Origin::TOP_LEFT) flipy(path);
ras.add_path(path);
for(auto h : poly.Holes) {
for(auto& h : holes(poly)) {
auto&& holepath = to_path(h);
if(m_o == Origin::TOP_LEFT) flipy(holepath);
ras.add_path(holepath);
@ -120,40 +114,34 @@ public:
inline Origin origin() const /*noexcept*/ { return m_o; }
private:
double getPx(const Point& p) {
return p(0) * SCALING_FACTOR/m_pxdim.w_mm;
inline double getPx(const Point& p) {
return p(0) * m_pxdim_scaled.w_mm;
}
double getPy(const Point& p) {
return p(1) * SCALING_FACTOR/m_pxdim.h_mm;
inline double getPy(const Point& p) {
return p(1) * m_pxdim_scaled.h_mm;
}
agg::path_storage to_path(const Polygon& poly)
{
agg::path_storage path;
auto it = poly.points.begin();
path.move_to(getPx(*it), getPy(*it));
while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it));
path.line_to(getPx(poly.points.front()), getPy(poly.points.front()));
return path;
}
double getPx(const ClipperLib::IntPoint& p) {
return p.X * SCALING_FACTOR/m_pxdim.w_mm;
}
double getPy(const ClipperLib::IntPoint& p) {
return p.Y * SCALING_FACTOR/m_pxdim.h_mm;
}
agg::path_storage to_path(const ClipperLib::Path& poly)
inline agg::path_storage to_path(const Polygon& poly)
{
return to_path(poly.points);
}
inline double getPx(const ClipperLib::IntPoint& p) {
return p.X * m_pxdim_scaled.w_mm;
}
inline double getPy(const ClipperLib::IntPoint& p) {
return p.Y * m_pxdim_scaled.h_mm;
}
template<class PointVec> agg::path_storage to_path(const PointVec& poly)
{
agg::path_storage path;
auto it = poly.begin();
path.move_to(getPx(*it), getPy(*it));
while(++it != poly.end())
path.line_to(getPx(*it), getPy(*it));
@ -166,8 +154,8 @@ private:
const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255);
const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0);
Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o):
m_impl(new Impl(r, pd, o)) {}
Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o, double g):
m_impl(new Impl(r, pd, o, g)) {}
Raster::Raster() {}
@ -176,19 +164,20 @@ Raster::~Raster() {}
Raster::Raster(Raster &&m):
m_impl(std::move(m.m_impl)) {}
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd)
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
double g)
{
// Free up the unnecessary memory and make sure it stays clear after
// an exception
auto o = m_impl? m_impl->origin() : Origin::TOP_LEFT;
reset(r, pd, o);
reset(r, pd, o, g);
}
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
Raster::Origin o)
Raster::Origin o, double gamma)
{
m_impl.reset();
m_impl.reset(new Impl(r, pd, o));
m_impl.reset(new Impl(r, pd, o, gamma));
}
void Raster::reset()

View file

@ -99,8 +99,9 @@ public:
};
/// Constructor taking the resolution and the pixel dimension.
explicit Raster(const Resolution& r, const PixelDim& pd,
Origin o = Origin::BOTTOM_LEFT );
Raster(const Resolution& r, const PixelDim& pd,
Origin o = Origin::BOTTOM_LEFT, double gamma = 1.0);
Raster();
Raster(const Raster& cpy) = delete;
Raster& operator=(const Raster& cpy) = delete;
@ -108,8 +109,8 @@ public:
~Raster();
/// Reallocated everything for the given resolution and pixel dimension.
void reset(const Resolution& r, const PixelDim& pd);
void reset(const Resolution& r, const PixelDim& pd, Origin o);
void reset(const Resolution& r, const PixelDim& pd, double gamma = 1.0);
void reset(const Resolution& r, const PixelDim& pd, Origin o, double gamma);
/**
* Release the allocated resources. Drawing in this state ends in

View file

@ -19,7 +19,7 @@ public:
float minimal_distance;
float head_diameter;
///////////////
inline float support_force() const { return 10.f / density_relative; } // a force one point can support (arbitrary force unit)
inline float support_force() const { return 7.7f / density_relative; } // a force one point can support (arbitrary force unit)
inline float tear_pressure() const { return 1.f; } // pressure that the display exerts (the force unit per mm2)
};

View file

@ -3,6 +3,7 @@
#include "SLA/SLABasePool.hpp"
#include "SLA/SLAAutoSupports.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
#include "MTUtils.hpp"
#include <unordered_set>
@ -85,17 +86,32 @@ void SLAPrint::clear()
}
// Transformation without rotation around Z and without a shift by X and Y.
static Transform3d sla_trafo(const ModelObject &model_object)
static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object)
{
Vec3d corr = p.relative_correction();
ModelInstance &model_instance = *model_object.instances.front();
Vec3d offset = model_instance.get_offset();
Vec3d rotation = model_instance.get_rotation();
offset(0) = 0.;
offset(1) = 0.;
rotation(2) = 0.;
Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
if (model_instance.is_left_handed())
trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo;
offset(Z) *= corr(Z);
auto trafo = Transform3d::Identity();
trafo.translate(offset);
trafo.scale(corr);
trafo.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
trafo.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY()));
trafo.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX()));
trafo.scale(model_instance.get_scaling_factor());
trafo.scale(model_instance.get_mirror());
if (model_instance.is_left_handed())
trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo;
return trafo;
}
@ -103,13 +119,18 @@ static Transform3d sla_trafo(const ModelObject &model_object)
static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object)
{
std::vector<SLAPrintObject::Instance> instances;
for (ModelInstance *model_instance : model_object.instances)
if (model_instance->is_printable()) {
instances.emplace_back(
model_instance->id(),
Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)),
float(model_instance->get_rotation(Z)));
}
assert(! model_object.instances.empty());
if (! model_object.instances.empty()) {
Vec3d rotation0 = model_object.instances.front()->get_rotation();
rotation0(2) = 0.;
for (ModelInstance *model_instance : model_object.instances)
if (model_instance->is_printable()) {
instances.emplace_back(
model_instance->id(),
Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)),
float(Geometry::rotation_diff_z(rotation0, model_instance->get_rotation())));
}
}
return instances;
}
@ -121,12 +142,12 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
// Make a copy of the config, normalize it.
DynamicPrintConfig config(config_in);
config.option("sla_print_settings_id", true);
config.option("sla_material_settings_id", true);
config.option("printer_settings_id", true);
config.option("sla_print_settings_id", true);
config.option("sla_material_settings_id", true);
config.option("printer_settings_id", true);
config.normalize();
// Collect changes to print config.
t_config_option_keys print_diff = m_print_config.diff(config);
t_config_option_keys print_diff = m_print_config.diff(config);
t_config_option_keys printer_diff = m_printer_config.diff(config);
t_config_option_keys material_diff = m_material_config.diff(config);
t_config_option_keys object_diff = m_default_object_config.diff(config);
@ -143,23 +164,24 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
tbb::mutex::scoped_lock lock(this->state_mutex());
// The following call may stop the background processing.
bool invalidate_all_model_objects = false;
if (! print_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(print_diff));
update_apply_status(this->invalidate_state_by_config_options(print_diff, invalidate_all_model_objects));
if (! printer_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(printer_diff));
update_apply_status(this->invalidate_state_by_config_options(printer_diff, invalidate_all_model_objects));
if (! material_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(material_diff));
update_apply_status(this->invalidate_state_by_config_options(material_diff, invalidate_all_model_objects));
// Apply variables to placeholder parser. The placeholder parser is currently used
// only to generate the output file name.
if (! placeholder_parser_diff.empty()) {
if (! placeholder_parser_diff.empty()) {
// update_apply_status(this->invalidate_step(slapsRasterize));
PlaceholderParser &pp = this->placeholder_parser();
pp.apply_config(config);
PlaceholderParser &pp = this->placeholder_parser();
pp.apply_config(config);
// Set the profile aliases for the PrintBase::output_filename()
pp.set("print_preset", config.option("sla_print_settings_id")->clone());
pp.set("material_preset", config.option("sla_material_settings_id")->clone());
pp.set("printer_preset", config.option("printer_settings_id")->clone());
pp.set("print_preset", config.option("sla_print_settings_id")->clone());
pp.set("material_preset", config.option("sla_material_settings_id")->clone());
pp.set("printer_preset", config.option("printer_settings_id")->clone());
}
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
@ -187,7 +209,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
std::set<ModelObjectStatus> model_object_status;
// 1) Synchronize model objects.
if (model.id() != m_model.id()) {
if (model.id() != m_model.id() || invalidate_all_model_objects) {
// Kill everything, initialize from scratch.
// Stop background processing.
this->call_cancel_callback();
@ -306,106 +328,91 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
assert(it_status != model_object_status.end());
assert(it_status->status != ModelObjectStatus::Deleted);
// PrintObject for this ModelObject, if it exists.
auto it_print_object_status = print_object_status.end();
if (it_status->status != ModelObjectStatus::New) {
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
const ModelObject &model_object_new = *model.objects[idx_model_object];
it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id()));
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
it_print_object_status = print_object_status.end();
// Check whether a model part volume was added or removed, their transformations or order changed.
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
bool sla_trafo_differs =
model_object.instances.empty() != model_object_new.instances.empty() ||
(! model_object.instances.empty() &&
(! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)) ||
model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed()));
if (model_parts_differ || sla_trafo_differs) {
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
if (it_print_object_status != print_object_status.end()) {
update_apply_status(it_print_object_status->print_object->invalidate_all_steps());
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
}
// Copy content of the ModelObject including its ID, do not change the parent.
model_object.assign_copy(model_object_new);
} else {
// Synchronize Object's config.
bool object_config_changed = model_object.config != model_object_new.config;
if (object_config_changed)
model_object.config = model_object_new.config;
if (! object_diff.empty() || object_config_changed) {
SLAPrintObjectConfig new_config = m_default_object_config;
normalize_and_apply_config(new_config, model_object.config);
if (it_print_object_status != print_object_status.end()) {
t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config);
if (! diff.empty()) {
update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff));
it_print_object_status->print_object->config_apply_only(new_config, diff, true);
}
}
}
/*if (model_object.sla_support_points != model_object_new.sla_support_points) {
model_object.sla_support_points = model_object_new.sla_support_points;
if (it_print_object_status != print_object_status.end())
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
}
if (model_object.sla_points_status != model_object_new.sla_points_status) {
// Change of this status should invalidate support points. The points themselves are not enough, there are none
// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
// invalidate - that would keep stopping the background processing without a reason.
if (model_object.sla_points_status != sla::PointsStatus::Generating)
if (it_print_object_status != print_object_status.end())
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
model_object.sla_points_status = model_object_new.sla_points_status;
}*/
// PrintObject for this ModelObject, if it exists.
auto it_print_object_status = print_object_status.end();
if (it_status->status != ModelObjectStatus::New) {
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
const ModelObject &model_object_new = *model.objects[idx_model_object];
it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id()));
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
it_print_object_status = print_object_status.end();
// Check whether a model part volume was added or removed, their transformations or order changed.
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
bool sla_trafo_differs =
model_object.instances.empty() != model_object_new.instances.empty() ||
(! model_object.instances.empty() &&
(! sla_trafo(*this, model_object).isApprox(sla_trafo(*this, model_object_new)) ||
model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed()));
if (model_parts_differ || sla_trafo_differs) {
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
if (it_print_object_status != print_object_status.end()) {
update_apply_status(it_print_object_status->print_object->invalidate_all_steps());
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
}
// Copy content of the ModelObject including its ID, do not change the parent.
model_object.assign_copy(model_object_new);
} else {
// Synchronize Object's config.
bool object_config_changed = model_object.config != model_object_new.config;
if (object_config_changed)
model_object.config = model_object_new.config;
if (! object_diff.empty() || object_config_changed) {
SLAPrintObjectConfig new_config = m_default_object_config;
normalize_and_apply_config(new_config, model_object.config);
if (it_print_object_status != print_object_status.end()) {
t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config);
if (! diff.empty()) {
update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff));
it_print_object_status->print_object->config_apply_only(new_config, diff, true);
}
}
}
bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified;
bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified;
if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) {
if (it_print_object_status != print_object_status.end())
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified;
bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified;
if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) {
if (it_print_object_status != print_object_status.end())
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
model_object.sla_points_status = model_object_new.sla_points_status;
model_object.sla_support_points = model_object_new.sla_support_points;
}
model_object.sla_points_status = model_object_new.sla_points_status;
model_object.sla_support_points = model_object_new.sla_support_points;
}
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
model_object.name = model_object_new.name;
model_object.input_file = model_object_new.input_file;
model_object.clear_instances();
model_object.instances.reserve(model_object_new.instances.size());
for (const ModelInstance *model_instance : model_object_new.instances) {
model_object.instances.emplace_back(new ModelInstance(*model_instance));
model_object.instances.back()->set_model_object(&model_object);
}
}
}
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
model_object.name = model_object_new.name;
model_object.input_file = model_object_new.input_file;
model_object.clear_instances();
model_object.instances.reserve(model_object_new.instances.size());
for (const ModelInstance *model_instance : model_object_new.instances) {
model_object.instances.emplace_back(new ModelInstance(*model_instance));
model_object.instances.back()->set_model_object(&model_object);
}
}
}
std::vector<SLAPrintObject::Instance> new_instances = sla_instances(model_object);
if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) {
// The SLAPrintObject is already there.
if (new_instances.empty()) {
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
} else {
if (new_instances != it_print_object_status->print_object->instances()) {
// Instances changed.
it_print_object_status->print_object->set_instances(new_instances);
if (new_instances.empty()) {
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted;
} else {
if (new_instances != it_print_object_status->print_object->instances()) {
// Instances changed.
it_print_object_status->print_object->set_instances(new_instances);
update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval));
}
print_objects_new.emplace_back(it_print_object_status->print_object);
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused;
}
} else if (! new_instances.empty()) {
}
print_objects_new.emplace_back(it_print_object_status->print_object);
const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused;
}
} else if (! new_instances.empty()) {
auto print_object = new SLAPrintObject(this, &model_object);
// FIXME: this invalidates the transformed mesh in SLAPrintObject
// which is expensive to calculate (especially the raw_mesh() call)
print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed());
print_object->set_trafo(sla_trafo(*this, model_object), model_object.instances.front()->is_left_handed());
print_object->set_instances(std::move(new_instances));
print_object->config_apply(config, true);
@ -440,56 +447,56 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
// After calling the apply() function, set_task() may be called to limit the task to be processed by process().
void SLAPrint::set_task(const TaskParams &params)
{
// Grab the lock for the Print / PrintObject milestones.
tbb::mutex::scoped_lock lock(this->state_mutex());
// Grab the lock for the Print / PrintObject milestones.
tbb::mutex::scoped_lock lock(this->state_mutex());
int n_object_steps = int(params.to_object_step) + 1;
if (n_object_steps == 0)
n_object_steps = (int)slaposCount;
int n_object_steps = int(params.to_object_step) + 1;
if (n_object_steps == 0)
n_object_steps = (int)slaposCount;
if (params.single_model_object.valid()) {
if (params.single_model_object.valid()) {
// Find the print object to be processed with priority.
SLAPrintObject *print_object = nullptr;
size_t idx_print_object = 0;
for (; idx_print_object < m_objects.size(); ++ idx_print_object)
if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
print_object = m_objects[idx_print_object];
break;
}
assert(print_object != nullptr);
SLAPrintObject *print_object = nullptr;
size_t idx_print_object = 0;
for (; idx_print_object < m_objects.size(); ++ idx_print_object)
if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
print_object = m_objects[idx_print_object];
break;
}
assert(print_object != nullptr);
// Find out whether the priority print object is being currently processed.
bool running = false;
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[istep])
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[istep])
// Step was skipped, cancel.
break;
if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
break;
if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
// No step was skipped, and a wanted step is being processed. Don't cancel.
running = true;
break;
}
}
if (! running)
this->call_cancel_callback();
running = true;
break;
}
}
if (! running)
this->call_cancel_callback();
// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
if (params.single_model_instance_only) {
// Suppress all the steps of other instances.
for (SLAPrintObject *po : m_objects)
for (int istep = 0; istep < (int)slaposCount; ++ istep)
po->m_stepmask[istep] = false;
} else if (! running) {
// Swap the print objects, so that the selected print_object is first in the row.
// At this point the background processing must be stopped, so it is safe to shuffle print objects.
if (idx_print_object != 0)
std::swap(m_objects.front(), m_objects[idx_print_object]);
}
// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
if (params.single_model_instance_only) {
// Suppress all the steps of other instances.
for (SLAPrintObject *po : m_objects)
for (int istep = 0; istep < (int)slaposCount; ++ istep)
po->m_stepmask[istep] = false;
} else if (! running) {
// Swap the print objects, so that the selected print_object is first in the row.
// At this point the background processing must be stopped, so it is safe to shuffle print objects.
if (idx_print_object != 0)
std::swap(m_objects.front(), m_objects[idx_print_object]);
}
// and set the steps for the current object.
for (int istep = 0; istep < n_object_steps; ++ istep)
print_object->m_stepmask[istep] = true;
for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
print_object->m_stepmask[istep] = false;
} else {
for (int istep = 0; istep < n_object_steps; ++ istep)
print_object->m_stepmask[istep] = true;
for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
print_object->m_stepmask[istep] = false;
} else {
// Slicing all objects.
bool running = false;
for (SLAPrintObject *print_object : m_objects)
@ -518,9 +525,9 @@ void SLAPrint::set_task(const TaskParams &params)
if (params.to_object_step != -1 || params.to_print_step != -1) {
// Limit the print steps.
size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1;
for (; istep < m_stepmask.size(); ++ istep)
m_stepmask[istep] = false;
size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1;
for (; istep < m_stepmask.size(); ++ istep)
m_stepmask[istep] = false;
}
}
@ -530,7 +537,7 @@ void SLAPrint::finalize()
{
for (SLAPrintObject *po : m_objects)
for (int istep = 0; istep < (int)slaposCount; ++ istep)
po->m_stepmask[istep] = true;
po->m_stepmask[istep] = true;
for (int istep = 0; istep < (int)slapsCount; ++ istep)
m_stepmask[istep] = true;
}
@ -539,7 +546,7 @@ void SLAPrint::finalize()
// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before the output is finalized).
std::string SLAPrint::output_filename() const
{
{
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "sl1", &config);
}
@ -708,10 +715,17 @@ void SLAPrint::process()
[this](){ throw_if_canceled(); });
auto mit = slindex_it;
double doffs = m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = coord_t(doffs / SCALING_FACTOR);
for(size_t id = 0;
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
id++)
{
// We apply the printer correction offset here.
if(clpr_offs != 0)
po.m_model_slices[id] =
offset_ex(po.m_model_slices[id], clpr_offs);
mit->set_model_slice_idx(po, id); ++mit;
}
};
@ -771,7 +785,7 @@ void SLAPrint::process()
po.m_supportdata->emesh,
po.get_model_slices(),
heights,
config,
config,
[this]() { throw_if_canceled(); },
statuscb);
@ -913,10 +927,17 @@ void SLAPrint::process()
heights, float(po.config().slice_closing_radius.value));
}
double doffs = m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = coord_t(doffs / SCALING_FACTOR);
for(size_t i = 0;
i < sd->support_slices.size() && i < po.m_slice_index.size();
++i)
{
// We apply the printer correction offset here.
if(clpr_offs != 0)
sd->support_slices[i] =
offset_ex(sd->support_slices[i], clpr_offs);
po.m_slice_index[i].set_support_slice_idx(po, i);
}
@ -1024,6 +1045,8 @@ void SLAPrint::process()
const double width = m_printer_config.display_width.getFloat() / SCALING_FACTOR;
const double height = m_printer_config.display_height.getFloat() / SCALING_FACTOR;
const double display_area = width*height;
const coord_t clpr_back_offs = - coord_t(m_printer_config.absolute_correction.getFloat() / SCALING_FACTOR);
// get polygons for all instances in the object
auto get_all_polygons =
@ -1107,7 +1130,7 @@ void SLAPrint::process()
auto printlayerfn = [this,
// functions and read only vars
get_all_polygons, polyunion, polydiff, areafn,
area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time,
area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, clpr_back_offs,
// write vars
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
@ -1143,14 +1166,18 @@ void SLAPrint::process()
for(const SliceRecord& record : layer.slices()) {
const SLAPrintObject *po = record.print_obj();
const ExPolygons &modelslices = record.get_slice(soModel);
const ExPolygons &rawmodelslices = record.get_slice(soModel);
const ExPolygons &modelslices = clpr_back_offs != 0 ? offset_ex(rawmodelslices, clpr_back_offs) : rawmodelslices;
bool is_lefth = record.print_obj()->is_left_handed();
if (!modelslices.empty()) {
ClipperPolygons v = get_all_polygons(modelslices, po->instances(), is_lefth);
for(ClipperPolygon& p_tmp : v) model_polygons.emplace_back(std::move(p_tmp));
}
const ExPolygons &supportslices = record.get_slice(soSupport);
const ExPolygons &rawsupportslices = record.get_slice(soSupport);
const ExPolygons &supportslices = clpr_back_offs != 0 ? offset_ex(rawsupportslices, clpr_back_offs) : rawsupportslices;
if (!supportslices.empty()) {
ClipperPolygons v = get_all_polygons(supportslices, po->instances(), is_lefth);
for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp));
@ -1259,12 +1286,16 @@ void SLAPrint::process()
double lh = ocfg.layer_height.getFloat();
double exp_t = matcfg.exposure_time.getFloat();
double iexp_t = matcfg.initial_exposure_time.getFloat();
double gamma = m_printer_config.gamma_correction.getFloat();
if(flpXY) { std::swap(w, h); std::swap(pw, ph); }
m_printer.reset(new SLAPrinter(w, h, pw, ph, lh, exp_t, iexp_t,
flpXY? SLAPrinter::RO_PORTRAIT :
SLAPrinter::RO_LANDSCAPE));
m_printer.reset(
new SLAPrinter(w, h, pw, ph, lh, exp_t, iexp_t,
flpXY? SLAPrinter::RO_PORTRAIT :
SLAPrinter::RO_LANDSCAPE,
gamma));
}
// Allocate space for all the layers
@ -1418,24 +1449,29 @@ void SLAPrint::process()
m_report_status(*this, 100, L("Slicing done"));
}
bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys, bool &invalidate_all_model_objects)
{
if (opt_keys.empty())
return false;
static std::unordered_set<std::string> steps_full = {
"initial_layer_height",
"material_correction",
"relative_correction",
"absolute_correction",
"gamma_correction"
};
// Cache the plenty of parameters, which influence the final rasterization only,
// or they are only notes not influencing the rasterization step.
static std::unordered_set<std::string> steps_rasterize = {
"exposure_time",
"initial_exposure_time",
"material_correction_printing",
"material_correction_curing",
"display_width",
"display_height",
"display_pixels_x",
"display_pixels_y",
"display_orientation",
"printer_correction"
"display_orientation"
};
static std::unordered_set<std::string> steps_ignore = {
@ -1443,8 +1479,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"max_print_height",
"printer_technology",
"output_filename_format",
"fast_tilt_time",
"slow_tilt_time",
"fast_tilt_time",
"slow_tilt_time",
"area_fill"
};
@ -1459,9 +1495,10 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
steps.emplace_back(slapsMergeSlicesAndEval);
} else if (steps_ignore.find(opt_key) != steps_ignore.end()) {
// These steps have no influence on the output. Just ignore them.
} else if (opt_key == "initial_layer_height") {
} else if (steps_full.find(opt_key) != steps_full.end()) {
steps.emplace_back(slapsMergeSlicesAndEval);
osteps.emplace_back(slaposObjectSlice);
invalidate_all_model_objects = true;
} else {
// All values should be covered.
assert(false);
@ -1511,20 +1548,20 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
std::vector<SLAPrintObjectStep> steps;
bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "layer_height"
if ( opt_key == "layer_height"
|| opt_key == "faded_layers"
|| opt_key == "pad_enable"
|| opt_key == "pad_wall_thickness"
|| opt_key == "supports_enable"
|| opt_key == "support_object_elevation"
|| opt_key == "slice_closing_radius") {
steps.emplace_back(slaposObjectSlice);
steps.emplace_back(slaposObjectSlice);
} else if (
opt_key == "support_points_density_relative"
|| opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints);
} else if (
} else if (
opt_key == "support_head_front_diameter"
|| opt_key == "support_head_penetration"
|| opt_key == "support_head_width"
@ -1613,6 +1650,25 @@ double SLAPrintObject::get_current_elevation() const
return get_elevation();
}
Vec3d SLAPrint::relative_correction() const
{
Vec3d corr(1., 1., 1.);
if(printer_config().relative_correction.values.size() == 2) {
corr(X) = printer_config().relative_correction.values[0];
corr(Y) = printer_config().relative_correction.values[0];
corr(Z) = printer_config().relative_correction.values[1];
}
if(material_config().material_correction.values.size() == 2) {
corr(X) *= material_config().material_correction.values[0];
corr(Y) *= material_config().material_correction.values[0];
corr(Z) *= material_config().material_correction.values[1];
}
return corr;
}
namespace { // dummy empty static containers for return values in some methods
const std::vector<ExPolygons> EMPTY_SLICES;
const TriangleMesh EMPTY_MESH;

View file

@ -397,7 +397,10 @@ public:
const SLAMaterialConfig& material_config() const { return m_material_config; }
const SLAPrintObjectConfig& default_object_config() const { return m_default_object_config; }
std::string output_filename() const override;
// Extracted value from the configuration objects
Vec3d relative_correction() const;
std::string output_filename() const override;
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }
@ -452,7 +455,7 @@ private:
bool invalidate_step(SLAPrintStep st);
// Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys, bool &invalidate_all_model_objects);
SLAPrintConfig m_print_config;
SLAPrinterConfig m_printer_config;

View file

@ -18,10 +18,10 @@ wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), -
#ifdef __APPLE__
m_user_drawn_background = false;
#endif /*__APPLE__*/
Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); }));
Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent event) { mouse_event(event); }));
Bind(wxEVT_MOTION, ([this](wxMouseEvent event) { mouse_event(event); }));
Bind(wxEVT_SIZE, ([this](wxSizeEvent e) { Refresh(); }));
Bind(wxEVT_PAINT, ([this](wxPaintEvent &/* e */) { repaint(); }));
Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent &event) { mouse_event(event); }));
Bind(wxEVT_MOTION, ([this](wxMouseEvent &event) { mouse_event(event); }));
Bind(wxEVT_SIZE, ([this](wxSizeEvent & /* e */) { Refresh(); }));
}
void Bed_2D::repaint()
{

View file

@ -227,6 +227,12 @@ const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
const float GLVolume::MODEL_COLOR[4][4] = {
{ 1.0f, 1.0f, 0.0f, 1.f },
{ 1.0f, 0.5f, 0.5f, 1.f },
{ 0.5f, 1.0f, 0.5f, 1.f },
{ 0.5f, 0.5f, 1.0f, 1.f }
};
const float GLVolume::SLA_SUPPORT_COLOR[4] = { 0.75f, 0.75f, 0.75f, 1.0f };
const float GLVolume::SLA_PAD_COLOR[4] = { 0.0f, 0.2f, 0.0f, 1.0f };
@ -568,19 +574,12 @@ int GLVolumeCollection::load_object_volume(
const std::string &color_by,
bool use_VBOs)
{
static float colors[4][4] = {
{ 1.0f, 1.0f, 0.0f, 1.f },
{ 1.0f, 0.5f, 0.5f, 1.f },
{ 0.5f, 1.0f, 0.5f, 1.f },
{ 0.5f, 0.5f, 1.0f, 1.f }
};
const ModelVolume *model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id();
const ModelInstance *instance = model_object->instances[instance_idx];
const TriangleMesh& mesh = model_volume->mesh;
float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
/* if (model_volume->is_support_blocker()) {
color[0] = 1.0f;
color[1] = 0.2f;
@ -595,10 +594,7 @@ int GLVolumeCollection::load_object_volume(
this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back();
v.set_color_from_model_volume(model_volume);
if (use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
v.indexed_vertex_array.load_mesh(mesh, use_VBOs);
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box();
@ -640,14 +636,10 @@ void GLVolumeCollection::load_object_auxiliary(
// Convex hull is required for out of print bed detection.
TriangleMesh convex_hull = mesh.convex_hull_3d();
for (const std::pair<size_t, size_t> &instance_idx : instances) {
const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first];
const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second];
const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first];
this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
GLVolume &v = *this->volumes.back();
if (use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
v.indexed_vertex_array.load_mesh(mesh, use_VBOs);
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs);
@ -718,14 +710,8 @@ int GLVolumeCollection::load_wipe_tower_preview(
this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back();
if (use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
v.indexed_vertex_array.load_mesh(mesh, use_VBOs);
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs);
@ -1856,12 +1842,7 @@ bool GLArrow::on_init(bool useVBOs)
triangles.emplace_back(7, 13, 6);
m_useVBOs = useVBOs;
if (m_useVBOs)
m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles));
else
m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles), useVBOs);
m_volume.finalize_geometry(m_useVBOs);
return true;
}
@ -1976,12 +1957,7 @@ bool GLCurvedArrow::on_init(bool useVBOs)
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
m_useVBOs = useVBOs;
if (m_useVBOs)
m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles));
else
m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles), useVBOs);
m_volume.bounding_box = m_volume.indexed_vertex_array.bounding_box();
m_volume.finalize_geometry(m_useVBOs);
return true;
@ -2016,10 +1992,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs)
TriangleMesh mesh = model.mesh();
mesh.repair();
if (m_useVBOs)
m_volume.indexed_vertex_array.load_mesh_full_shading(mesh);
else
m_volume.indexed_vertex_array.load_mesh_flat_shading(mesh);
m_volume.indexed_vertex_array.load_mesh(mesh, useVBOs);
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
set_color(color, 4);

View file

@ -116,6 +116,7 @@ public:
void load_mesh_flat_shading(const TriangleMesh &mesh);
void load_mesh_full_shading(const TriangleMesh &mesh);
void load_mesh(const TriangleMesh &mesh, bool use_VBOs) { use_VBOs ? this->load_mesh_full_shading(mesh) : this->load_mesh_flat_shading(mesh); }
inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; }
@ -228,6 +229,7 @@ public:
static const float OUTSIDE_COLOR[4];
static const float SELECTED_OUTSIDE_COLOR[4];
static const float DISABLED_COLOR[4];
static const float MODEL_COLOR[4][4];
static const float SLA_SUPPORT_COLOR[4];
static const float SLA_PAD_COLOR[4];

View file

@ -42,7 +42,7 @@ AboutDialog::AboutDialog()
main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20);
// logo
auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192));
auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap(this, "Slic3r_192px.png", 192));
hsizer->Add(logo, 1, wxALIGN_CENTER_VERTICAL);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);

View file

@ -27,16 +27,25 @@ void BitmapCache::clear()
m_map.clear();
}
static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image)
static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image, float scale = 1.0f)
{
#ifdef BROKEN_ALPHA
wxMemoryOutputStream stream;
image.SaveFile(stream, wxBITMAP_TYPE_PNG);
wxStreamBuffer *buf = stream.GetOutputStreamBuffer();
return wxBitmap::NewFromPNGData(buf->GetBufferStart(), buf->GetBufferSize());
#else
#ifdef __APPLE__
// This is a c-tor native to Mac OS. We need to let the Mac OS wxBitmap implementation
// know that the image may already be scaled appropriately for Retina,
// and thereby that it's not supposed to upscale it.
// Contrary to intuition, the `scale` argument isn't "please scale this to such and such"
// but rather "the wxImage is sized for backing scale such and such".
return wxBitmap(std::move(image), -1, scale);
#else
return wxBitmap(std::move(image));
#endif
#endif
}
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height)
@ -165,7 +174,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
#endif
}
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data)
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale /* = 1.0f */)
{
wxImage image(width, height);
image.InitAlpha();
@ -178,7 +187,7 @@ wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned i
*rgb ++ = *raw_data ++;
*alpha ++ = *raw_data ++;
}
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), scale));
}
wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int width, unsigned int height)
@ -186,6 +195,7 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int wid
std::string bitmap_key = bitmap_name + ( height !=0 ?
"-h" + std::to_string(height) :
"-w" + std::to_string(width));
auto it = m_map.find(bitmap_key);
if (it != m_map.end())
return it->second;
@ -206,11 +216,15 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int wid
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
}
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_width, unsigned int target_height)
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height, float scale /* = 1.0f */)
{
std::string bitmap_key = bitmap_name + (target_height != 0 ?
"-h" + std::to_string(target_height) :
"-w" + std::to_string(target_width));
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
"-h" + std::to_string(target_height) :
"-w" + std::to_string(target_width))
+ (scale != 1.0f ? "-s" + std::to_string(scale) : "");
target_height != 0 ? target_height *= scale : target_width *= scale;
auto it = m_map.find(bitmap_key);
if (it != m_map.end())
return it->second;
@ -219,12 +233,12 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int tar
if (image == nullptr)
return nullptr;
float scale = target_height != 0 ?
float svg_scale = target_height != 0 ?
(float)target_height / image->height : target_width != 0 ?
(float)target_width / image->width : 1;
int width = (int)(scale * image->width + 0.5f);
int height = (int)(scale * image->height + 0.5f);
int width = (int)(svg_scale * image->width + 0.5f);
int height = (int)(svg_scale * image->height + 0.5f);
int n_pixels = width * height;
if (n_pixels <= 0) {
::nsvgDelete(image);
@ -238,11 +252,11 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int tar
}
std::vector<unsigned char> data(n_pixels * 4, 0);
::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4);
::nsvgRasterize(rast, image, 0, 0, svg_scale, data.data(), width, height, width * 4);
::nsvgDeleteRasterizer(rast);
::nsvgDelete(image);
return this->insert_raw_rgba(bitmap_key, width, height, data.data());
return this->insert_raw_rgba(bitmap_key, width, height, data.data(), scale);
}
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)

View file

@ -29,12 +29,12 @@ public:
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data);
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale = 1.0f);
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
wxBitmap* load_png(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0);
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
wxBitmap* load_svg(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0);
wxBitmap* load_svg(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0, float scale = 1.0f);
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }

View file

@ -1893,6 +1893,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
size_t idx = 0;
const SLAPrint *sla_print = this->sla_print();
std::vector<double> shift_zs(m_model->objects.size(), 0);
double relative_correction_z = sla_print->relative_correction().z();
if (relative_correction_z <= EPSILON)
relative_correction_z = 1.;
for (const SLAPrintObject *print_object : sla_print->objects()) {
SLASupportState &state = sla_support_state[idx ++];
const ModelObject *model_object = print_object->model_object();
@ -1906,7 +1909,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(it != sla_print->model().objects.end());
object_idx = it - sla_print->model().objects.begin();
// Cache the Z offset to be applied to all volumes with this object_idx.
shift_zs[object_idx] = print_object->get_current_elevation();
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
// pairs of <instance_idx, print_instance_idx>
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
@ -2310,6 +2313,9 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
{
if (!m_initialized)
return;
// Ignore the wheel events if the middle button is pressed.
if (evt.MiddleIsDown())
return;
@ -2563,8 +2569,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_selection.remove(m_hover_volume_id);
else
{
bool add_as_single = !already_selected && !ctrl_down;
m_selection.add(m_hover_volume_id, add_as_single);
m_selection.add(m_hover_volume_id, !ctrl_down);
m_mouse.drag.move_requires_threshold = !already_selected;
if (already_selected)
m_mouse.set_move_start_threshold_position_2D_as_invalid();
@ -3293,8 +3298,9 @@ bool GLCanvas3D::_init_toolbar()
bool GLCanvas3D::_set_current()
{
if ((m_canvas != nullptr) && (m_context != nullptr))
if (_is_shown_on_screen() && (m_context != nullptr)) {
return m_canvas->SetCurrent(*m_context);
}
return false;
}
@ -5038,97 +5044,44 @@ void GLCanvas3D::_load_shells_sla()
// nothing to render, return
return;
auto add_volume = [this](const SLAPrintObject &object, const SLAPrintObject::Instance& instance,
const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) {
m_volumes.volumes.emplace_back(new GLVolume(color));
GLVolume& v = *m_volumes.volumes.back();
v.indexed_vertex_array.load_mesh(mesh, m_use_VBOs);
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
v.composite_id.volume_id = -1;
v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0));
v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation));
v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.);
};
// adds objects' volumes
int obj_idx = 0;
for (const SLAPrintObject* obj : print->objects())
{
if (!obj->is_step_done(slaposSliceSupports))
continue;
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
// selects only instances which were sliced
const ModelObject* model_obj = obj->model_object();
const std::vector<SLAPrintObject::Instance>& sla_instances = obj->instances();
std::vector<int> instances_model_idxs(sla_instances.size());
for (int i = 0; i < (int)sla_instances.size(); ++i)
{
instances_model_idxs[i] = (int)sla_instances[i].instance_id.id;
}
std::vector<int> sliced_instance_idxs;
for (int i = 0; i < (int)model_obj->instances.size(); ++i)
{
if (std::find(instances_model_idxs.begin(), instances_model_idxs.end(), (int)model_obj->instances[i]->id().id) != instances_model_idxs.end())
sliced_instance_idxs.push_back(i);
}
m_volumes.load_object(model_obj, obj_idx, sliced_instance_idxs, "object", m_use_VBOs && m_initialized);
for (const SLAPrintObject::Instance& instance : sla_instances)
{
Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0);
Vec3d rotation(0.0, 0.0, (double)instance.rotation);
unsigned int partial_volumes_count = (unsigned int)m_volumes.volumes.size();
// add supports
if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree))
{
const TriangleMesh& mesh = obj->support_mesh();
m_volumes.volumes.emplace_back(new GLVolume(GLVolume::SLA_SUPPORT_COLOR));
GLVolume& v = *m_volumes.volumes.back();
if (m_use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
v.shader_outside_printer_detection_enabled = true;
v.composite_id.volume_id = -1;
v.set_instance_offset(offset);
v.set_instance_rotation(rotation);
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
if (obj->is_step_done(slaposSliceSupports)) {
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, instance, obj->transformed_mesh(), GLVolume::MODEL_COLOR[0], true);
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call.
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();
m_volumes.volumes.back()->composite_id.volume_id = 0;
if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree))
add_volume(*obj, instance, obj->support_mesh(), GLVolume::SLA_SUPPORT_COLOR, true);
if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool))
add_volume(*obj, instance, obj->pad_mesh(), GLVolume::SLA_PAD_COLOR, true);
}
// add pad
if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool))
{
const TriangleMesh& mesh = obj->pad_mesh();
m_volumes.volumes.emplace_back(new GLVolume(GLVolume::SLA_PAD_COLOR));
GLVolume& v = *m_volumes.volumes.back();
if (m_use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
v.shader_outside_printer_detection_enabled = false;
v.composite_id.volume_id = -1;
v.set_instance_offset(offset);
v.set_instance_rotation(rotation);
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
}
// finalize volumes and sends geometry to gpu
for (unsigned int i = partial_volumes_count; i < m_volumes.volumes.size(); ++i)
{
double shift_z = obj->get_current_elevation();
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
GLVolume& v = *m_volumes.volumes[i];
// finalize volumes and sends geometry to gpu
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(m_use_VBOs);
// apply shift z
v.set_sla_shift_z(shift_z);
}
++obj_idx;
}
// apply shift z
double shift_z = obj->get_current_elevation();
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++i)
{
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
}
}
update_volumes_colors_by_extruder();
#else
this->reload_scene(true, true);

View file

@ -19,6 +19,8 @@
#include <wx/wupdlock.h>
#include <wx/filefn.h>
#include <wx/sysopt.h>
#include <wx/msgdlg.h>
#include <wx/log.h>
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
@ -94,6 +96,34 @@ static void register_dpi_event()
#endif
}
static void generic_exception_handle()
{
// Note: Some wxWidgets APIs use wxLogError() to report errors, eg. wxImage
// - see https://docs.wxwidgets.org/3.1/classwx_image.html#aa249e657259fe6518d68a5208b9043d0
//
// wxLogError typically goes around exception handling and display an error dialog some time
// after an error is logged even if exception handling and OnExceptionInMainLoop() take place.
// This is why we use wxLogError() here as well instead of a custom dialog, because it accumulates
// errors if multiple have been collected and displays just one error message for all of them.
// Otherwise we would get multiple error messages for one missing png, for example.
//
// If a custom error message window (or some other solution) were to be used, it would be necessary
// to turn off wxLogError() usage in wx APIs, most notably in wxImage
// - see https://docs.wxwidgets.org/trunk/classwx_image.html#aa32e5d3507cc0f8c3330135bc0befc6a
try {
throw;
} catch (const std::exception &ex) {
wxLogError("Internal error: %s", ex.what());
BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what();
throw;
} catch (...) {
wxLogError("Unknown internal error");
BOOST_LOG_TRIVIAL(error) << "Uncaught exception: Unknown error";
}
}
IMPLEMENT_APP(GUI_App)
GUI_App::GUI_App()
@ -103,6 +133,16 @@ GUI_App::GUI_App()
{}
bool GUI_App::OnInit()
{
try {
return on_init_inner();
} catch (...) {
generic_exception_handle();
return false;
}
}
bool GUI_App::on_init_inner()
{
// Verify resources path
const wxString resources_dir = from_u8(Slic3r::resources_dir());
@ -132,13 +172,7 @@ bool GUI_App::OnInit()
// just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory
// supplied as argument to --datadir; in that case we should still run the wizard
try {
preset_bundle->setup_directories();
} catch (const std::exception &ex) {
show_error(nullptr, ex.what());
// Exit the application.
return false;
}
preset_bundle->setup_directories();
app_conf_exists = app_config->exists();
// load settings
@ -161,11 +195,11 @@ bool GUI_App::OnInit()
// Suppress the '- default -' presets.
preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1");
try {
preset_bundle->load_presets(*app_config);
} catch (const std::exception &ex) {
show_error(nullptr, ex.what());
}
try {
preset_bundle->load_presets(*app_config);
} catch (const std::exception &ex) {
show_error(nullptr, from_u8(ex.what()));
}
register_dpi_event();
@ -184,8 +218,8 @@ bool GUI_App::OnInit()
Bind(wxEVT_IDLE, [this](wxIdleEvent& event)
{
if (! plater_)
return;
if (! plater_)
return;
if (app_config->dirty() && app_config->get("autosave") == "1")
app_config->save();
@ -207,7 +241,7 @@ bool GUI_App::OnInit()
mainframe->Close();
}
} catch (const std::exception &ex) {
show_error(nullptr, ex.what());
show_error(nullptr, from_u8(ex.what()));
}
CallAfter([this] {
@ -752,18 +786,7 @@ void GUI_App::load_current_presets()
bool GUI_App::OnExceptionInMainLoop()
{
try {
throw;
} catch (const std::exception &ex) {
const std::string error = (boost::format("Uncaught exception: %1%") % ex.what()).str();
BOOST_LOG_TRIVIAL(error) << error;
show_error(nullptr, from_u8(error));
} catch (...) {
const char *error = "Uncaught exception: Unknown error";
BOOST_LOG_TRIVIAL(error) << error;
show_error(nullptr, from_u8(error));
}
generic_exception_handle();
return false;
}

View file

@ -169,6 +169,7 @@ public:
PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); }
private:
bool on_init_inner();
void window_pos_save(wxTopLevelWindow* window, const std::string &name);
void window_pos_restore(wxTopLevelWindow* window, const std::string &name);
void window_pos_sanitize(wxTopLevelWindow* window);

View file

@ -62,18 +62,18 @@ ObjectList::ObjectList(wxWindow* parent) :
// Fill CATEGORY_ICON
{
// ptFFF
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench");
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(this, "layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(this, "infill");
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(this, "support");
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(this, "time");
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(this, "funnel");
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(this, "funnel");
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(this, "skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(this, "time");
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(this, "wrench");
// ptSLA
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("sla_supports");
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("brick.png");
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(this, "sla_supports");
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(this, "brick.png");
}
// create control
@ -88,7 +88,7 @@ ObjectList::ObjectList(wxWindow* parent) :
// before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
// manipulator cache with the following call to selection_changed()
wxGetApp().obj_manipul()->emulate_kill_focus();
#else
// To avoid selection update from SetSelection() and UnselectAll() under osx
if (m_prevent_list_events)
return;
@ -141,6 +141,8 @@ ObjectList::ObjectList(wxWindow* parent) :
#ifdef __WXOSX__
Bind(wxEVT_KEY_DOWN, &ObjectList::OnChar, this);
#endif //__WXOSX__
Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) { this->EnsureVisible(this->GetCurrentItem()); e.Skip(); }));
}
ObjectList::~ObjectList()
@ -390,10 +392,10 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
void ObjectList::init_icons()
{
m_bmp_modifiermesh = create_scaled_bitmap("lambda.png");
m_bmp_solidmesh = create_scaled_bitmap("object.png");
m_bmp_support_enforcer = create_scaled_bitmap("support_enforcer_.png");
m_bmp_support_blocker = create_scaled_bitmap("support_blocker_.png");
m_bmp_modifiermesh = create_scaled_bitmap(this, "lambda.png");
m_bmp_solidmesh = create_scaled_bitmap(this, "object.png");
m_bmp_support_enforcer = create_scaled_bitmap(this, "support_enforcer_.png");
m_bmp_support_blocker = create_scaled_bitmap(this, "support_blocker_.png");
m_bmp_vector.reserve(4); // bitmaps for different types of parts
@ -404,13 +406,13 @@ void ObjectList::init_icons()
m_objects_model->SetVolumeBitmaps(m_bmp_vector);
// init icon for manifold warning
m_bmp_manifold_warning = create_scaled_bitmap("exclamation_mark_.png");
m_bmp_manifold_warning = create_scaled_bitmap(this, "exclamation_mark_.png");
// init bitmap for "Split to sub-objects" context menu
m_bmp_split = create_scaled_bitmap("split_parts");
m_bmp_split = create_scaled_bitmap(this, "split_parts");
// init bitmap for "Add Settings" context menu
m_bmp_cog = create_scaled_bitmap("cog");
m_bmp_cog = create_scaled_bitmap(this, "cog");
}
@ -1977,7 +1979,7 @@ void ObjectList::update_selections()
if (selection.is_single_full_object() &&
m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
return;
if (selection.is_single_volume() || selection.is_modifier()) {
if (selection.is_single_volume() || selection.is_any_modifier()) {
const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin());
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return;
@ -2012,7 +2014,7 @@ void ObjectList::update_selections()
}
}
}
else if (selection.is_single_volume() || selection.is_modifier() || selection.is_multiple_volume())
else if (selection.is_any_volume() || selection.is_any_modifier())
{
for (auto idx : selection.get_volume_idxs()) {
const auto gl_vol = selection.get_volume(idx);
@ -2071,23 +2073,8 @@ void ObjectList::update_selections()
select_items(sels);
/* Because of ScrollLines() and GetItemRect() functions are implemented
* only for GENERIC DataViewCtrl in current version of wxWidgets,
* use this part of code only for MSW
*/
#if defined(wxUSE_GENERICDATAVIEWCTRL)
// Scroll selected Item in the middle of an object list
if (GetSelection()) {
const wxRect& sel_rc = GetItemRect(GetSelection());
const wxRect& main_rc = GetClientRect();
if (sel_rc.GetBottom() <= main_rc.GetTop()+sel_rc.height ||
sel_rc.GetTop() >= main_rc.GetBottom() )
{
const wxRect& top_rc = GetItemRect(GetTopItem());
ScrollLines(int((sel_rc.y - top_rc.y) / top_rc.GetHeight()) - 0.5*GetCountPerPage());
}
}
#endif
this->EnsureVisible(this->GetCurrentItem());
}
void ObjectList::update_selections_on_canvas()
@ -2133,6 +2120,7 @@ void ObjectList::update_selections_on_canvas()
add_to_selection(item, selection, instance_idx, true);
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
wxGetApp().plater()->canvas3D()->render();
return;
}

View file

@ -92,7 +92,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
else if (option_name == "Size") {
line.near_label_widget = [this](wxWindow* parent) {
return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition,
create_scaled_bitmap("one_layer_lock_on.png").GetSize());
create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize());
};
}

View file

@ -77,7 +77,7 @@ void ObjectSettings::update_settings_list()
{
auto opt_key = (line.get_options())[0].opt_id; //we assume that we have one option per line
auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap("colorchange_delete_on.png"),
auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap(m_parent, "cross"/*"colorchange_delete_on.png"*/),
wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
#ifdef __WXMSW__
btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));

View file

@ -96,11 +96,16 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const
void GLGizmoSlaSupports::render_selection_rectangle() const
{
if (!m_selection_rectangle_active)
if (m_selection_rectangle_status == srOff)
return;
glsafe(::glLineWidth(1.5f));
float render_color[3] = {1.f, 0.f, 0.f};
float render_color[3] = {0.f, 1.f, 0.f};
if (m_selection_rectangle_status == srDeselect) {
render_color[0] = 1.f;
render_color[1] = 0.3f;
render_color[2] = 0.3f;
}
glsafe(::glColor3fv(render_color));
glsafe(::glPushAttrib(GL_TRANSFORM_BIT)); // remember current MatrixMode
@ -316,31 +321,35 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is
// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo
// concludes that the event was not intended for it, it should return false.
bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down)
bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
{
if (m_editing_mode) {
// left down - show the selection rectangle:
if (action == SLAGizmoEventType::LeftDown && shift_down) {
// left down with shift - show the selection rectangle:
if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) {
if (m_hover_id == -1) {
m_selection_rectangle_active = true;
m_selection_rectangle_start_corner = mouse_position;
m_selection_rectangle_end_corner = mouse_position;
m_canvas_width = m_parent.get_canvas_size().get_width();
m_canvas_height = m_parent.get_canvas_size().get_height();
if (shift_down || alt_down) {
m_selection_rectangle_status = shift_down ? srSelect : srDeselect;
m_selection_rectangle_start_corner = mouse_position;
m_selection_rectangle_end_corner = mouse_position;
m_canvas_width = m_parent.get_canvas_size().get_width();
m_canvas_height = m_parent.get_canvas_size().get_height();
}
}
else {
if (m_editing_mode_cache[m_hover_id].selected)
unselect_point(m_hover_id);
else
select_point(m_hover_id);
else {
if (!alt_down)
select_point(m_hover_id);
}
}
return true;
}
// left down without selection rectangle - place point on the mesh:
if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle_active && !shift_down) {
if (action == SLAGizmoEventType::LeftDown && m_selection_rectangle_status == srOff && !shift_down) {
// If any point is in hover state, this should initiate its move - return control back to GLCanvas:
if (m_hover_id != -1)
return false;
@ -365,7 +374,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
}
// left up with selection rectangle - select points inside the rectangle:
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp) && m_selection_rectangle_active) {
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle_status != srOff) {
const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix();
const Camera& camera = m_parent.get_camera();
const std::array<int, 4>& viewport = camera.get_viewport();
@ -405,11 +414,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if (hits.size() > 1 || hits.front().t > 0.001f)
is_obscured = true;
if (!is_obscured)
select_point(i);
if (!is_obscured) {
if (m_selection_rectangle_status == srDeselect)
unselect_point(i);
else
select_point(i);
}
}
}
m_selection_rectangle_active = false;
m_selection_rectangle_status = srOff;
return true;
}
@ -427,8 +440,9 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
return true; // point has been placed and the button not released yet
// this prevents GLCanvas from starting scene rotation
if (m_selection_rectangle_active) {
if (m_selection_rectangle_status != srOff) {
m_selection_rectangle_end_corner = mouse_position;
m_selection_rectangle_status = shift_down ? srSelect : srDeselect;
return true;
}

View file

@ -50,7 +50,7 @@ public:
#endif // ENABLE_SVG_ICONS
virtual ~GLGizmoSlaSupports();
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
void delete_selected_points(bool force = false);
std::pair<float, float> get_sla_clipping_plane() const;
@ -75,7 +75,12 @@ private:
mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
float m_clipping_plane_distance = 0.f;
bool m_selection_rectangle_active = false;
enum SelectionRectangleStatus {
srOff = 0,
srSelect = 1,
srDeselect = 2
}m_selection_rectangle_status = srOff;
Vec2d m_selection_rectangle_start_corner;
Vec2d m_selection_rectangle_end_corner;
bool m_wait_for_up_event = false;

View file

@ -10,6 +10,7 @@ enum class SLAGizmoEventType {
Delete,
SelectAll,
ShiftUp,
AltUp,
ApplyChanges,
DiscardChanges,
AutomaticGeneration,

View file

@ -455,14 +455,14 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object, const Sele
}
// Returns true if the gizmo used the event to do something, false otherwise.
bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down)
bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
{
if (!m_enabled)
return false;
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
if (it != m_gizmos.end())
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down);
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
return false;
}
@ -546,7 +546,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
if (evt.LeftDown())
{
if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown()))
if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
// the gizmo got the event and took some action, there is no need to do anything more
processed = true;
else if (!selection.is_empty() && grabber_contains_mouse())
@ -573,7 +573,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
else if (evt.Dragging() && (canvas.get_move_volume_id() != -1) && (m_current == SlaSupports))
// don't allow dragging objects with the Sla gizmo on
processed = true;
else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown()))
else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
{
// the gizmo got the event and took some action, no need to do anything more here
canvas.set_as_dirty();
@ -660,7 +660,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
{
// in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither
// object moving or selecting is suppressed in that case
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown());
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
processed = true;
}
else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_hover_volume_id() != -1) || grabber_contains_mouse()))
@ -801,6 +801,10 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
if ((m_current == SlaSupports) && (keyCode == WXK_SHIFT) && gizmo_event(SLAGizmoEventType::ShiftUp))
// shift has been just released - SLA gizmo might want to close rectangular selection.
processed = true;
if ((m_current == SlaSupports) && (keyCode == WXK_ALT) && gizmo_event(SLAGizmoEventType::AltUp))
// alt has been just released - SLA gizmo might want to close rectangular selection.
processed = true;
}
if (processed)

View file

@ -145,7 +145,8 @@ public:
void set_flattening_data(const ModelObject* model_object);
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false);
void render_current_gizmo(const Selection& selection) const;
void render_current_gizmo_for_picking_pass(const Selection& selection) const;

View file

@ -17,7 +17,7 @@ KBShortcutsDialog::KBShortcutsDialog()
auto main_sizer = new wxBoxSizer(wxVERTICAL);
// logo
const wxBitmap logo_bmp = create_scaled_bitmap("Slic3r_32px.png", 32);
const wxBitmap logo_bmp = create_scaled_bitmap(this, "Slic3r_32px.png", 32);
// fonts
wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
@ -119,7 +119,7 @@ void KBShortcutsDialog::fill_shortcuts()
main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object ")));
main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object")));
main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list")));
main_shortcuts.push_back(Shortcut("Shift+LeftMouse", L("Select multiple object/Move multiple object")));
main_shortcuts.push_back(Shortcut(ctrl+"LeftMouse" ,L("Select multiple object/Move multiple object")));
m_full_shortcuts.push_back(std::make_pair( _(L("Main Shortcuts")), std::make_pair(main_shortcuts, 0) ));

View file

@ -61,7 +61,7 @@ DPIFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAU
/* Load default preset bitmaps before a tabpanel initialization,
* but after filling of an em_unit value
*/
wxGetApp().preset_bundle->load_default_preset_bitmaps();
wxGetApp().preset_bundle->load_default_preset_bitmaps(this);
// initialize tabpanel and menubar
init_tabpanel();
@ -327,9 +327,9 @@ void MainFrame::init_menubar()
wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "brick_add.png");
wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "disk.png");
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "save");
wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "disk.png");
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save");
fileMenu->AppendSeparator();

View file

@ -23,15 +23,11 @@ namespace Slic3r {
namespace GUI {
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) :
MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png", 192), button_id)
{}
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) :
wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)),
content_sizer(new wxBoxSizer(wxVERTICAL)),
btn_sizer(new wxBoxSizer(wxHORIZONTAL))
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id, wxBitmap bitmap)
: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT))
, content_sizer(new wxBoxSizer(wxVERTICAL))
, btn_sizer(new wxBoxSizer(wxHORIZONTAL))
{
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
@ -54,7 +50,11 @@ wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DI
rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT);
auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(bitmap));
if (! bitmap.IsOk()) {
bitmap = create_scaled_bitmap(this, "Slic3r_192px.png", 192);
}
logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
topsizer->Add(logo, 0, wxALL, BORDER);
topsizer->Add(rightsizer, 1, wxALL | wxEXPAND, BORDER);
@ -69,7 +69,6 @@ MsgDialog::~MsgDialog() {}
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
: MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")),
create_scaled_bitmap("Slic3r_192px_grayscale.png"),
wxID_NONE)
, msg(msg)
{
@ -97,6 +96,8 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
btn_ok->SetFocus();
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192));
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
Fit();
}

View file

@ -12,6 +12,7 @@
class wxBoxSizer;
class wxCheckBox;
class wxStaticBitmap;
namespace Slic3r {
@ -40,12 +41,12 @@ protected:
};
// button_id is an id of a button that can be added by default, use wxID_NONE to disable
MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK);
MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id = wxID_OK);
MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK, wxBitmap bitmap = wxNullBitmap);
wxFont boldfont;
wxBoxSizer *content_sizer;
wxBoxSizer *btn_sizer;
wxStaticBitmap *logo;
};

View file

@ -286,7 +286,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 *
#ifdef __WINDOWS__
edit_btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
edit_btn->SetBitmap(create_scaled_bitmap("cog"));
edit_btn->SetBitmap(create_scaled_bitmap(this, "cog"));
edit_btn->SetToolTip(_(L("Click to edit preset")));
edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent)
@ -747,6 +747,7 @@ Sidebar::Sidebar(Plater *parent)
p->plater->export_gcode();
else
p->plater->reslice();
p->plater->select_view_3D("Preview");
});
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
}
@ -2314,20 +2315,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
this->sidebar->show_sliced_info_sizer(false);
// Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
// Otherwise they will be just refreshed.
switch (this->printer_technology) {
case ptFFF:
if (this->preview != nullptr)
// If the preview is not visible, the following line just invalidates the preview,
// but the G-code paths are calculated first once the preview is made visible.
this->preview->reload_print();
// We also need to reload 3D scene because of the wipe tower preview box
if (this->config->opt_bool("wipe_tower"))
return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
break;
case ptSLA:
return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
break;
}
if (this->preview != nullptr)
// If the preview is not visible, the following line just invalidates the preview,
// but the G-code paths or SLA preview are calculated first once the preview is made visible.
this->preview->reload_print();
// In FDM mode, we need to reload the 3D scene because of the wipe tower preview box.
// In SLA mode, we need to reload the 3D scene every time to show the support structures.
if (this->printer_technology == ptSLA || (this->printer_technology == ptFFF && this->config->opt_bool("wipe_tower")))
return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
}
if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! this->background_process.empty()) {

View file

@ -486,7 +486,7 @@ const std::vector<std::string>& Preset::sla_material_options()
s_opts = {
"initial_layer_height",
"exposure_time", "initial_exposure_time",
"material_correction_printing", "material_correction_curing",
"material_correction",
"material_notes",
"default_sla_material_profile",
"compatible_prints", "compatible_prints_condition",
@ -506,7 +506,9 @@ const std::vector<std::string>& Preset::sla_printer_options()
"display_width", "display_height", "display_pixels_x", "display_pixels_y",
"display_orientation",
"fast_tilt_time", "slow_tilt_time", "area_fill",
"printer_correction",
"relative_correction",
"absolute_correction",
"gamma_correction",
"print_host", "printhost_apikey", "printhost_cafile",
"printer_notes",
"inherits"
@ -797,16 +799,14 @@ bool PresetCollection::delete_current_preset()
return true;
}
bool PresetCollection::load_bitmap_default(const std::string &file_name)
void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name)
{
// return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
return load_scaled_bitmap(&m_bitmap_main_frame, file_name);
*m_bitmap_main_frame = create_scaled_bitmap(window, file_name);
}
bool PresetCollection::load_bitmap_add(const std::string &file_name)
void PresetCollection::load_bitmap_add(wxWindow *window, const std::string &file_name)
{
// return m_bitmap_add->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
return load_scaled_bitmap(&m_bitmap_add, file_name);
*m_bitmap_add = create_scaled_bitmap(window, file_name);
}
const Preset* PresetCollection::get_selected_preset_parent() const

View file

@ -15,6 +15,7 @@ class wxBitmapComboBox;
class wxChoice;
class wxItemContainer;
class wxString;
class wxWindow;
namespace Slic3r {
@ -276,10 +277,10 @@ public:
bool delete_current_preset();
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
bool load_bitmap_default(const std::string &file_name);
void load_bitmap_default(wxWindow *window, const std::string &file_name);
// Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
bool load_bitmap_add(const std::string &file_name);
void load_bitmap_add(wxWindow *window, const std::string &file_name);
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }

View file

@ -396,55 +396,36 @@ void PresetBundle::export_selections(AppConfig &config)
config.set("presets", "printer", printers.get_selected_preset_name());
}
bool PresetBundle::load_compatible_bitmaps()
void PresetBundle::load_compatible_bitmaps(wxWindow *window)
{
const std::string path_bitmap_compatible = "flag-green-icon.png";
const std::string path_bitmap_incompatible = "flag-red-icon.png";
const std::string path_bitmap_lock = "sys_lock.png";//"lock.png";
const std::string path_bitmap_lock_open = "sys_unlock.png";//"lock_open.png";
// bool loaded_compatible = m_bitmapCompatible ->LoadFile(
// wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
// bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
// wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG);
// bool loaded_lock = m_bitmapLock->LoadFile(
// wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG);
// bool loaded_lock_open = m_bitmapLockOpen->LoadFile(
// wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG);
*m_bitmapCompatible = create_scaled_bitmap(window, "flag_green");
*m_bitmapIncompatible = create_scaled_bitmap(window, "flag_red");
*m_bitmapLock = create_scaled_bitmap(window, "lock_closed");
*m_bitmapLockOpen = create_scaled_bitmap(window, "sys_unlock.png");
bool loaded_compatible = load_scaled_bitmap(&m_bitmapCompatible, path_bitmap_compatible);
bool loaded_incompatible = load_scaled_bitmap(&m_bitmapIncompatible,path_bitmap_incompatible);
bool loaded_lock = load_scaled_bitmap(&m_bitmapLock, path_bitmap_lock);
bool loaded_lock_open = load_scaled_bitmap(&m_bitmapLockOpen, path_bitmap_lock_open);
prints .set_bitmap_compatible(m_bitmapCompatible);
filaments .set_bitmap_compatible(m_bitmapCompatible);
sla_prints .set_bitmap_compatible(m_bitmapCompatible);
sla_materials.set_bitmap_compatible(m_bitmapCompatible);
printers .set_bitmap_compatible(m_bitmapCompatible);
if (loaded_compatible) {
prints .set_bitmap_compatible(m_bitmapCompatible);
filaments .set_bitmap_compatible(m_bitmapCompatible);
sla_prints .set_bitmap_compatible(m_bitmapCompatible);
sla_materials.set_bitmap_compatible(m_bitmapCompatible);
// printers .set_bitmap_compatible(m_bitmapCompatible);
}
if (loaded_incompatible) {
prints .set_bitmap_incompatible(m_bitmapIncompatible);
filaments .set_bitmap_incompatible(m_bitmapIncompatible);
sla_prints .set_bitmap_incompatible(m_bitmapIncompatible);
sla_materials.set_bitmap_incompatible(m_bitmapIncompatible);
// printers .set_bitmap_incompatible(m_bitmapIncompatible);
}
if (loaded_lock) {
prints .set_bitmap_lock(m_bitmapLock);
filaments .set_bitmap_lock(m_bitmapLock);
sla_prints .set_bitmap_lock(m_bitmapLock);
sla_materials.set_bitmap_lock(m_bitmapLock);
printers .set_bitmap_lock(m_bitmapLock);
}
if (loaded_lock_open) {
prints .set_bitmap_lock_open(m_bitmapLock);
filaments .set_bitmap_lock_open(m_bitmapLock);
sla_prints .set_bitmap_lock_open(m_bitmapLock);
sla_materials.set_bitmap_lock_open(m_bitmapLock);
printers .set_bitmap_lock_open(m_bitmapLock);
}
return loaded_compatible && loaded_incompatible && loaded_lock && loaded_lock_open;
prints .set_bitmap_incompatible(m_bitmapIncompatible);
filaments .set_bitmap_incompatible(m_bitmapIncompatible);
sla_prints .set_bitmap_incompatible(m_bitmapIncompatible);
sla_materials.set_bitmap_incompatible(m_bitmapIncompatible);
printers .set_bitmap_incompatible(m_bitmapIncompatible);
prints .set_bitmap_lock(m_bitmapLock);
filaments .set_bitmap_lock(m_bitmapLock);
sla_prints .set_bitmap_lock(m_bitmapLock);
sla_materials.set_bitmap_lock(m_bitmapLock);
printers .set_bitmap_lock(m_bitmapLock);
prints .set_bitmap_lock_open(m_bitmapLock);
filaments .set_bitmap_lock_open(m_bitmapLock);
sla_prints .set_bitmap_lock_open(m_bitmapLock);
sla_materials.set_bitmap_lock_open(m_bitmapLock);
printers .set_bitmap_lock_open(m_bitmapLock);
}
DynamicPrintConfig PresetBundle::full_config() const
@ -1446,7 +1427,7 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out
return true;
}
void PresetBundle::load_default_preset_bitmaps()
void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
{
// Clear bitmap cache, before load new scaled default preset bitmaps
m_bitmapCache->clear();
@ -1456,13 +1437,13 @@ void PresetBundle::load_default_preset_bitmaps()
this->sla_materials.clear_bitmap_cache();
this->printers.clear_bitmap_cache();
this->prints.load_bitmap_default("cog");
this->sla_prints.load_bitmap_default("cog");
this->filaments.load_bitmap_default("spool.png");
this->sla_materials.load_bitmap_default("package_green.png");
this->printers.load_bitmap_default("printer");
this->printers.load_bitmap_add("add.png");
this->load_compatible_bitmaps();
this->prints.load_bitmap_default(window, "cog");
this->sla_prints.load_bitmap_default(window, "cog");
this->filaments.load_bitmap_default(window, "spool.png");
this->sla_materials.load_bitmap_default(window, "resin");
this->printers.load_bitmap_default(window, "printer");
this->printers.load_bitmap_add(window, "add.png");
this->load_compatible_bitmaps(window);
}
void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)

View file

@ -7,6 +7,8 @@
#include <set>
#include <boost/filesystem/path.hpp>
class wxWindow;
namespace Slic3r {
namespace GUI {
@ -127,7 +129,7 @@ public:
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
void load_default_preset_bitmaps();
void load_default_preset_bitmaps(wxWindow *window);
private:
std::string load_system_presets();
@ -148,7 +150,7 @@ private:
// If it is not an external config, then the config will be stored into the user profile directory.
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
bool load_compatible_bitmaps();
void load_compatible_bitmaps(wxWindow *window);
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;

View file

@ -109,19 +109,20 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection)
if (is_wipe_tower() && volume->is_wipe_tower)
return;
bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance());
bool keep_instance_mode = (m_mode == Instance) && !as_single_selection;
bool already_contained = contains_volume(volume_idx);
// resets the current list if needed
bool needs_reset = as_single_selection;
bool needs_reset = as_single_selection && !already_contained;
needs_reset |= volume->is_wipe_tower;
needs_reset |= is_wipe_tower() && !volume->is_wipe_tower;
needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier;
needs_reset |= is_modifier() && !volume->is_modifier;
needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier;
needs_reset |= is_any_modifier() && !volume->is_modifier;
if (needs_reset)
clear();
if (!contains_volume(volume_idx))
if (!already_contained || needs_reset)
{
if (!keep_instance_mode)
m_mode = volume->is_modifier ? Volume : Instance;
@ -482,30 +483,6 @@ void Selection::translate(const Vec3d& displacement, bool local)
m_bounding_box_dirty = true;
}
static Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
return
// From the current coordinate system to world.
Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) *
// From world to the initial coordinate system.
Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ());
}
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
#ifndef NDEBUG
if (std::abs(angle) > 1e-8) {
assert(std::abs(axis.x()) < 1e-8);
assert(std::abs(axis.y()) < 1e-8);
}
#endif /* NDEBUG */
return (axis.z() < 0) ? -angle : angle;
}
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type)
{
@ -548,7 +525,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
assert(is_approx(rotation.z(), 0.0));
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
const Vec3d &rotation = first_volume.get_instance_rotation();
double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
}
else {
@ -1538,7 +1515,7 @@ void Selection::render_sidebar_size_hint(Axis axis, double length) const
#ifndef NDEBUG
static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
if (std::abs(angle) < 1e-8)
@ -1618,7 +1595,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
break;
case SYNC_ROTATION_GENERAL:
// generic rotation -> update instance z with the delta of the rotation.
double z_diff = rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
break;
}

View file

@ -213,7 +213,7 @@ public:
bool is_empty() const { return m_type == Empty; }
bool is_wipe_tower() const { return m_type == WipeTower; }
bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); }
bool is_any_modifier() const { return is_single_modifier() || is_multiple_modifier(); }
bool is_single_modifier() const { return m_type == SingleModifier; }
bool is_multiple_modifier() const { return m_type == MultipleModifier; }
bool is_single_full_instance() const;
@ -222,6 +222,7 @@ public:
bool is_multiple_full_object() const { return m_type == MultipleFullObject; }
bool is_single_volume() const { return m_type == SingleVolume; }
bool is_multiple_volume() const { return m_type == MultipleVolume; }
bool is_any_volume() const { return is_single_volume() || is_multiple_volume(); }
bool is_mixed() const { return m_type == Mixed; }
bool is_from_single_instance() const { return get_instance_idx() != -1; }
bool is_from_single_object() const;

View file

@ -52,7 +52,7 @@ SysInfoDialog::SysInfoDialog()
main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10);
// logo
auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192));
auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap(this, "Slic3r_192px.png", 192));
hsizer->Add(logo, 0, wxALIGN_CENTER_VERTICAL);
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);

View file

@ -116,16 +116,16 @@ void Tab::create_preset_tab()
//buttons
wxBitmap bmpMenu;
bmpMenu = create_scaled_bitmap("disk.png");
bmpMenu = create_scaled_bitmap(this, "save");
m_btn_save_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
if (wxMSW) m_btn_save_preset->SetBackgroundColour(color);
bmpMenu = create_scaled_bitmap("delete.png");
bmpMenu = create_scaled_bitmap(this, "cross"/*"delete.png"*/);
m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
if (wxMSW) m_btn_delete_preset->SetBackgroundColour(color);
m_show_incompatible_presets = false;
m_bmp_show_incompatible_presets = create_scaled_bitmap("flag-red-icon.png");
m_bmp_hide_incompatible_presets = create_scaled_bitmap("flag-green-icon.png");
m_bmp_show_incompatible_presets = create_scaled_bitmap(this, "flag_red");
m_bmp_hide_incompatible_presets = create_scaled_bitmap(this, "flag_green");
m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
if (wxMSW) m_btn_hide_incompatible_presets->SetBackgroundColour(color);
@ -148,13 +148,13 @@ void Tab::create_preset_tab()
// Determine the theme color of OS (dark or light)
auto luma = wxGetApp().get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
m_bmp_value_lock = create_scaled_bitmap("sys_lock.png");
m_bmp_value_unlock = create_scaled_bitmap(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png");
m_bmp_value_lock = create_scaled_bitmap(this, luma >= 128 ? "lock_closed" : "lock_closed_white");
m_bmp_value_unlock = create_scaled_bitmap(this, "lock_open");
m_bmp_non_system = &m_bmp_white_bullet;
// Bitmaps to be shown on the "Undo user changes" button next to each input field.
m_bmp_value_revert = create_scaled_bitmap(luma >= 128 ? "action_undo.png" : "action_undo_grey.png");
m_bmp_white_bullet = create_scaled_bitmap("bullet_white.png");
m_bmp_question = create_scaled_bitmap("question_mark_01.png");
m_bmp_value_revert = create_scaled_bitmap(this, "undo");
m_bmp_white_bullet = create_scaled_bitmap(this, "bullet_white.png");
m_bmp_question = create_scaled_bitmap(this, "question");
fill_icon_descriptions();
set_tooltips_text();
@ -283,7 +283,7 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
// Add a new icon to the icon list.
// wxIcon img_icon(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG);
// m_icons->Add(img_icon);
m_icons->Add(create_scaled_bitmap(icon));
m_icons->Add(create_scaled_bitmap(this, icon));
icon_idx = ++m_icon_count;
m_icon_index[icon] = icon_idx;
}
@ -1642,7 +1642,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse ")) + dots,
wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->SetBitmap(create_scaled_bitmap("zoom.png"));
btn->SetBitmap(create_scaled_bitmap(this, "zoom.png"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -1661,7 +1661,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),
wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->SetBitmap(create_scaled_bitmap("wrench.png"));
btn->SetBitmap(create_scaled_bitmap(this, "wrench.png"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -1698,7 +1698,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
btn->SetBitmap(create_scaled_bitmap("zoom.png"));
btn->SetBitmap(create_scaled_bitmap(this, "zoom.png"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -1776,7 +1776,7 @@ void TabPrinter::build_fff()
line.widget = [this](wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(wxGetApp().small_font());
btn->SetBitmap(create_scaled_bitmap("printer"));
btn->SetBitmap(create_scaled_bitmap(this, "printer"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -1977,7 +1977,7 @@ void TabPrinter::build_sla()
line.widget = [this](wxWindow* parent) {
auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
btn->SetFont(wxGetApp().small_font());
btn->SetBitmap(create_scaled_bitmap("printer"));
btn->SetBitmap(create_scaled_bitmap(this, "printer"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn);
@ -2016,16 +2016,19 @@ void TabPrinter::build_sla()
optgroup->append_single_option_line("area_fill");
optgroup = page->new_optgroup(_(L("Corrections")));
line = Line{ m_config->def()->get("printer_correction")->full_label, "" };
std::vector<std::string> axes{ "X", "Y", "Z" };
line = Line{ m_config->def()->get("relative_correction")->full_label, "" };
// std::vector<std::string> axes{ "X", "Y", "Z" };
std::vector<std::string> axes{ "XY", "Z" };
int id = 0;
for (auto& axis : axes) {
auto opt = optgroup->get_option("printer_correction", id);
auto opt = optgroup->get_option("relative_correction", id);
opt.opt.label = axis;
line.append_option(opt);
++id;
}
optgroup->append_line(line);
optgroup->append_single_option_line("absolute_correction");
optgroup->append_single_option_line("gamma_correction");
optgroup = page->new_optgroup(_(L("Print Host upload")));
build_printhost(optgroup.get());
@ -2919,7 +2922,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep
deps.btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
deps.btn->SetBitmap(create_scaled_bitmap("printer"));
deps.btn->SetBitmap(create_scaled_bitmap(this, "printer"));
auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL);
@ -3110,7 +3113,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
bmp_name = mode == comExpert ? "mode_expert_.png" :
mode == comAdvanced ? "mode_middle_.png" : "mode_simple_.png";
}
auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(bmp_name));
auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(parent, bmp_name));
bmp->SetBackgroundStyle(wxBG_STYLE_PAINT);
return bmp;
};
@ -3218,7 +3221,7 @@ void TabSLAMaterial::build()
m_presets = &m_preset_bundle->sla_materials;
load_initial_data();
auto page = add_options_page(_(L("Material")), "package_green.png");
auto page = add_options_page(_(L("Material")), "resin");
auto optgroup = page->new_optgroup(_(L("Layers")));
// optgroup->append_single_option_line("layer_height");
@ -3230,7 +3233,7 @@ void TabSLAMaterial::build()
optgroup = page->new_optgroup(_(L("Corrections")));
optgroup->label_width = 19 * m_em_unit;//190;
std::vector<std::string> corrections = { "material_correction_printing", "material_correction_curing" };
std::vector<std::string> corrections = {"material_correction"};
std::vector<std::string> axes{ "X", "Y", "Z" };
for (auto& opt_key : corrections) {
auto line = Line{ m_config->def()->get(opt_key)->full_label, "" };

View file

@ -15,6 +15,7 @@
#include "GUI_App.hpp"
#include "I18N.hpp"
#include "ConfigWizard.hpp"
#include "wxExtensions.hpp"
namespace Slic3r {
namespace GUI {
@ -108,8 +109,10 @@ MsgUpdateConfig::~MsgUpdateConfig() {}
// MsgDataIncompatible
MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, wxString> &incompats) :
MsgDialog(nullptr, _(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG), wxID_NONE)
MsgDialog(nullptr, _(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxID_NONE)
{
logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192));
auto *text = new wxStaticText(this, wxID_ANY, _(L(
"This version of Slic3r PE is not compatible with currently installed configuration bundles.\n"
"This probably happened as a result of running an older Slic3r PE after using a newer one.\n\n"

View file

@ -1,5 +1,7 @@
#include "wxExtensions.hpp"
#include <stdexcept>
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
@ -44,7 +46,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, const std::string& icon, wxEvtHandler* event_handler)
{
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(icon) : wxNullBitmap;
const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(nullptr, icon) : wxNullBitmap; // FIXME: pass window ptr
return append_menu_item(menu, id, string, description, cb, bmp, event_handler);
}
@ -55,7 +57,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
wxMenuItem* item = new wxMenuItem(menu, id, string, description);
if (!icon.empty())
item->SetBitmap(create_scaled_bitmap(icon));
item->SetBitmap(create_scaled_bitmap(nullptr, icon)); // FIXME: pass window ptr
item->SetSubMenu(sub_menu);
menu->Append(item);
@ -420,27 +422,36 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse)
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
bool load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /*= false*/)
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/)
{
static Slic3r::GUI::BitmapCache cache;
#ifdef __APPLE__
const float scale_factor = win != nullptr ? win->GetContentScaleFactor() : 1.0f;
#else
(void)(win);
const float scale_factor = 1.0f;
#endif
unsigned int height, width = height = 0;
unsigned int& scale_base = is_horizontal ? width : height;
scale_base = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * px_cnt * 0.1f + 0.5f);
std::string bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
*bmp = cache.load_svg(bmp_name, width, height);
if (*bmp == nullptr)
*bmp = cache.load_png(bmp_name, width, height);
return *bmp != nullptr;
}
boost::replace_last(bmp_name, ".png", "");
// Try loading an SVG first, then PNG if SVG is not found:
wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor);
if (bmp == nullptr) {
bmp = cache.load_png(bmp_name, width, height);
}
if (bmp == nullptr) {
// Neither SVG nor PNG has been found, raise error
throw std::runtime_error("Could not load bitmap: " + bmp_name);
}
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
wxBitmap create_scaled_bitmap(const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/)
{
wxBitmap *bmp {nullptr};
load_scaled_bitmap(&bmp, bmp_name_in, px_cnt, is_horizontal);
return *bmp;
}
@ -450,10 +461,10 @@ wxBitmap create_scaled_bitmap(const std::string& bmp_name_in, const int px_cnt/*
// ----------------------------------------------------------------------------
void PrusaObjectDataViewModelNode::set_object_action_icon() {
m_action_icon = create_scaled_bitmap("add_object.png");
m_action_icon = create_scaled_bitmap(nullptr, "add_object.png"); // FIXME: pass window ptr
}
void PrusaObjectDataViewModelNode::set_part_action_icon() {
m_action_icon = create_scaled_bitmap(m_type == itVolume ? "cog" : "brick_go.png");
m_action_icon = create_scaled_bitmap(nullptr, m_type == itVolume ? "cog.png" : "brick_go.png"); // FIXME: pass window ptr
}
Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr;
@ -1495,20 +1506,20 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent,
if (!is_osx)
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("right_half_circle.png") : create_scaled_bitmap("up_half_circle.png", 16, true));
m_bmp_thumb_lower = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("left_half_circle.png" ) : create_scaled_bitmap("down_half_circle.png",16, true));
m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap(this, "right_half_circle.png") : create_scaled_bitmap(this, "up_half_circle.png", 16, true));
m_bmp_thumb_lower = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap(this, "left_half_circle.png" ) : create_scaled_bitmap(this, "down_half_circle.png", 16, true));
m_thumb_size = m_bmp_thumb_lower.GetSize();
m_bmp_add_tick_on = create_scaled_bitmap("colorchange_add_on.png");
m_bmp_add_tick_off = create_scaled_bitmap("colorchange_add_off.png");
m_bmp_del_tick_on = create_scaled_bitmap("colorchange_delete_on.png");
m_bmp_del_tick_off = create_scaled_bitmap("colorchange_delete_off.png");
m_bmp_add_tick_on = create_scaled_bitmap(this, "colorchange_add_on.png");
m_bmp_add_tick_off = create_scaled_bitmap(this, "colorchange_add_off.png");
m_bmp_del_tick_on = create_scaled_bitmap(this, "colorchange_delete_on.png");
m_bmp_del_tick_off = create_scaled_bitmap(this, "colorchange_delete_off.png");
m_tick_icon_dim = m_bmp_add_tick_on.GetSize().x;
m_bmp_one_layer_lock_on = create_scaled_bitmap("one_layer_lock_on.png");
m_bmp_one_layer_lock_off = create_scaled_bitmap("one_layer_lock_off.png");
m_bmp_one_layer_unlock_on = create_scaled_bitmap("one_layer_unlock_on.png");
m_bmp_one_layer_unlock_off = create_scaled_bitmap("one_layer_unlock_off.png");
m_bmp_one_layer_lock_on = create_scaled_bitmap(this, "one_layer_lock_on.png");
m_bmp_one_layer_lock_off = create_scaled_bitmap(this, "one_layer_lock_off.png");
m_bmp_one_layer_unlock_on = create_scaled_bitmap(this, "one_layer_unlock_on.png");
m_bmp_one_layer_unlock_off = create_scaled_bitmap(this, "one_layer_unlock_off.png");
m_lock_icon_dim = m_bmp_one_layer_lock_on.GetSize().x;
m_selection = ssUndef;
@ -2332,10 +2343,10 @@ PrusaLockButton::PrusaLockButton( wxWindow *parent,
const wxSize& size /*= wxDefaultSize*/):
wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER)
{
m_bmp_lock_on = create_scaled_bitmap("one_layer_lock_on.png");
m_bmp_lock_off = create_scaled_bitmap("one_layer_lock_off.png");
m_bmp_unlock_on = create_scaled_bitmap("one_layer_unlock_on.png");
m_bmp_unlock_off = create_scaled_bitmap("one_layer_unlock_off.png");
m_bmp_lock_on = create_scaled_bitmap(this, "one_layer_lock_on.png");
m_bmp_lock_off = create_scaled_bitmap(this, "one_layer_lock_off.png");
m_bmp_unlock_on = create_scaled_bitmap(this, "one_layer_unlock_on.png");
m_bmp_unlock_off = create_scaled_bitmap(this, "one_layer_unlock_off.png");
#ifdef __WXMSW__
@ -2393,7 +2404,7 @@ PrusaModeButton::PrusaModeButton( wxWindow *parent,
#ifdef __WXMSW__
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif // __WXMSW__
m_bmp_off = create_scaled_bitmap("mode_off_sq.png");
m_bmp_off = create_scaled_bitmap(this, "mode_off_sq.png");
m_tt_focused = wxString::Format(_(L("Switch to the %s mode")), mode);
m_tt_selected = wxString::Format(_(L("Current mode is %s")), mode);
@ -2447,9 +2458,9 @@ PrusaModeSizer::PrusaModeSizer(wxWindow *parent, int hgap/* = 10*/) :
SetFlexibleDirection(wxHORIZONTAL);
std::vector<std::pair<wxString, wxBitmap>> buttons = {
{_(L("Simple")), create_scaled_bitmap("mode_simple_sq.png")},
{_(L("Advanced")), create_scaled_bitmap("mode_middle_sq.png")},
{_(L("Expert")), create_scaled_bitmap("mode_expert_sq.png")}
{_(L("Simple")), create_scaled_bitmap(parent, "mode_simple_sq.png")},
{_(L("Advanced")), create_scaled_bitmap(parent, "mode_middle_sq.png")},
{_(L("Expert")), create_scaled_bitmap(parent, "mode_expert_sq.png")}
};
mode_btns.reserve(3);

View file

@ -31,8 +31,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
bool load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false);
wxBitmap create_scaled_bitmap(const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false);
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false);
class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup
{