diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm
index 8d2a79f2a..d0696aab0 100644
--- a/lib/Slic3r/Test.pm
+++ b/lib/Slic3r/Test.pm
@@ -139,7 +139,6 @@ sub mesh {
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadFromPerl($vertices, $facets);
- $mesh->repair;
$mesh->scale_xyz(Slic3r::Pointf3->new(@{$params{scale_xyz}})) if $params{scale_xyz};
$mesh->translate(@{$params{translate}}) if $params{translate};
return $mesh;
diff --git a/resources/icons/exclamation_manifold.svg b/resources/icons/exclamation_manifold.svg
new file mode 100644
index 000000000..cd8ba5954
--- /dev/null
+++ b/resources/icons/exclamation_manifold.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/resources/icons/white/exclamation_manifold.svg b/resources/icons/white/exclamation_manifold.svg
new file mode 100644
index 000000000..a18590167
--- /dev/null
+++ b/resources/icons/white/exclamation_manifold.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx
index 8a34a9a11..ee3a57fe8 100644
--- a/resources/profiles/PrusaResearch.idx
+++ b/resources/profiles/PrusaResearch.idx
@@ -1,181 +1,184 @@
-min_slic3r_version = 2.4.0-alpha0
-1.4.0-alpha7 Updated brim_separation value. Updated Prusa MINI end g-code. Added Filamentworld filament profiles.
-1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height).
-1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
-1.4.0-alpha4 Decreased Area Fill (SL1S).
-1.4.0-alpha3 Updated SL1S tilt times.
-1.4.0-alpha2 Updated Prusa MINI machine limits.
-1.4.0-alpha1 Added new SL1S resin profiles.
-1.4.0-alpha0 Bumped up config version.
-1.3.0-alpha2 Added SL1S SPEED profiles.
-1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values.
-1.3.0-alpha0 Disabled thick bridges, updated support settings.
-min_slic3r_version = 2.3.2-alpha0
-1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
-1.3.0 Added SL1S SPEED profiles.
-min_slic3r_version = 2.3.0-rc1
-1.2.8 Added multiple add:north and Extrudr filament profiles.
-1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI.
-1.2.6 Added filament profile for "Prusament PC Blend Carbon Fiber".
-1.2.5 Updated firmware version. Added filament profiles. Various improvements.
-1.2.4 Updated cost/density values in filament settings. Various changes in print settings.
-1.2.3 Updated firmware version. Updated end g-code in MMU2 printer profiles.
-1.2.2 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
-1.2.1 Updated FW version for MK2.5 family printers.
-1.2.0 Added full_fan_speed_layer value for PETG. Increased support interface spacing for 0.6mm nozzle profiles. Updated firmware version.
-min_slic3r_version = 2.3.0-beta2
-1.2.0-beta1 Updated end g-code. Added full_fan_speed_layer values.
-min_slic3r_version = 2.3.0-beta0
-1.2.0-beta0 Adjusted infill anchor limits. Added filament spool weights.
-min_slic3r_version = 2.3.0-alpha4
-1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
-1.2.0-alpha0 Added filament spool weights
-min_slic3r_version = 2.2.0-alpha3
-1.1.14 Updated firmware version.
-1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles.
-1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
-1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
-1.1.10 Updated firmware version.
-1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials.
-1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles.
-1.1.7 Updated end g-code for MMU2 Single printer profiles. Added/updated filament and SLA material profiles.
-1.1.6 Updated firmware version for MK2.5/S and MK3/S.
-1.1.5 Updated MMU1 specific retraction settings for Prusament PC Blend
-1.1.4 Added Prusament PC Blend filament profile.
-1.1.3 Added SLA material and filament profile
-1.1.2 Added renamed_from fields for PETG filaments to indicate that they were renamed from PET.
-1.1.1 Added Verbatim and Fiberlogy PETG filament profiles. Updated auto cooling settings for ABS.
-1.1.1-beta Updated for PrusaSlicer 2.2.0-beta
-1.1.1-alpha4 Extended list of default filaments to be installed, top/bottom_solid_min_thickness defined, infill_acceleration changed etc
-1.1.1-alpha3 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
-# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,
-# so they will see the print bed.
-max_slic3r_version = 2.2.0-alpha2
-min_slic3r_version = 2.2.0-alpha0
-1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
-1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
-min_slic3r_version = 2.1.1-beta0
-1.0.12 Updated firmware version.
-1.0.11 Updated firmware version.
-1.0.10 Updated firmware version for MK2.5/S and MK3/S.
-1.0.9 Updated firmware version for MK2.5/S and MK3/S.
-1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog.
-1.0.7 Updated layer height limits for MINI
-1.0.6 Added Prusa MINI profiles
-min_slic3r_version = 2.1.0-alpha0
-1.0.5 Added SLA materials
-1.0.4 Updated firmware version and 0.25mm nozzle profiles
-1.0.3 Added filament profiles
-1.0.2 Added SLA materials
-1.0.1 Updated MK3 firmware version check to 3.8.0, new soluble support profiles for 0.6mm nozzle diameter MMU2S printers.
-1.0.0 Updated end G-code for the MMU2 profiles to lift the extruder at the end of print. Wipe tower bridging distance was made smaller for soluble supports.
-1.0.0-beta1 Updated color for the ASA filaments to differ from the other filaments. Single extruder printers now have no extruder color assigned, obects and toolpaths will be colored with the color of the active filament.
-1.0.0-beta0 Printer model checks in start G-codes, ASA filament profiles, limits on min / max SL1 exposition times
-1.0.0-alpha2 Printer model and nozzle diameter check
-1.0.0-alpha1 Added Prusament ASA profile
-1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
-min_slic3r_version = 1.42.0-alpha6
-0.8.11 Updated firmware version.
-0.8.10 Updated firmware version.
-0.8.9 Updated firmware version for MK2.5/S and MK3/S.
-0.8.8 Updated firmware version for MK2.5/S and MK3/S.
-0.8.7 Updated firmware version
-0.8.6 Updated firmware version for MK2.5/S and MK3/S
-0.8.5 Updated SL1 printer and material settings
-0.8.4 Added Prusament ASA profile
-0.8.3 FW version and SL1 materials update
-0.8.2 FFF and SL1 settings update
-0.8.1 Output settings and SLA materials update
-0.8.0 Updated for the PrusaSlicer 2.0.0 final release
-0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S
-0.8.0-rc1 Updated SLA profiles
-0.8.0-rc Updated for the PrusaSlicer 2.0.0-rc release
-0.8.0-beta4 Updated SLA profiles
-0.8.0-beta3 Updated SLA profiles
-0.8.0-beta2 Updated SLA profiles
-0.8.0-beta1 Updated SLA profiles
-0.8.0-beta Updated SLA profiles
-0.8.0-alpha9 Updated SLA and FFF profiles
-0.8.0-alpha8 Updated SLA profiles
-0.8.0-alpha7 Updated SLA profiles
-0.8.0-alpha6 Updated SLA profiles
-min_slic3r_version = 1.42.0-alpha
-0.8.0-alpha Updated SLA profiles
-0.4.0-alpha4 Updated SLA profiles
-0.4.0-alpha3 Update of SLA profiles
-0.4.0-alpha2 First SLA profiles
-min_slic3r_version = 1.41.3-alpha
-0.4.12 Updated firmware version for MK2.5/S and MK3/S.
-0.4.11 Updated firmware version for MK2.5/S and MK3/S.
-0.4.10 Updated firmware version
-0.4.9 Updated firmware version for MK2.5/S and MK3/S
-0.4.8 MK2.5/3/S FW update
-0.4.7 MK2/S/MMU FW update
-0.4.6 Updated firmware versions for MK2.5/S and MK3/S
-0.4.5 Enabled remaining time support for MK2/S/MMU1
-0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
-0.4.3 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
-0.4.2 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
-0.4.1 New MK2.5S and MK3S FW versions
-0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
-min_slic3r_version = 1.41.1
-0.3.11 Updated firmware version for MK2.5/S and MK3/S.
-0.3.10 Updated firmware version
-0.3.9 Updated firmware version for MK2.5/S and MK3/S
-0.3.8 MK2.5/3/S FW update
-0.3.7 MK2/S/MMU FW update
-0.3.6 Updated firmware versions for MK2.5 and MK3
-0.3.5 New MK2.5 and MK3 FW versions
-0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
-0.3.3 Prusament PETG released
-0.3.2 New MK2.5 and MK3 FW versions
-0.3.1 New MK2.5 and MK3 FW versions
-0.3.0 New MK2.5 and MK3 FW version
-min_slic3r_version = 1.41.0-alpha
-0.2.9 New MK2.5 and MK3 FW versions
-0.2.8 New MK2.5 and MK3 FW version
-min_slic3r_version = 1.41.1
-0.2.7 New MK2.5 and MK3 FW version
-0.2.6 Added MMU2 MK2.5 settings
-min_slic3r_version = 1.41.0-alpha
-0.2.5 Prusament is out - added prusament settings
-0.2.4 Added soluble support profiles for MMU2
-0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit
-0.2.2 Edited MMU2 Single mode purge line
-0.2.1 Added PET and BVOH settings for MMU2
-0.2.0-beta5 Fixed MMU1 ramming parameters
-0.2.0-beta4 Added filament loading speed at start, increased minimal purge on wipe tower
-0.2.0-beta3 Edited ramming parameters and filament cooling moves for MMU2
-0.2.0-beta2 Edited first layer speed and wipe tower position
-0.2.0-beta Removed limit on the MK3MMU2 height, added legacy M204 S T format to the MK2 profiles
-0.2.0-alpha8 Added filament_load/unload_time for the PLA/ABS MMU2 filament presets.
-0.2.0-alpha7 Vojtech's fix the incorrect *MK3* references
-0.2.0-alpha6 Jindra's way to fix the 0.2.0-alpha5 version
-0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2
-0.2.0-alpha4 Extended the custom start/end G-codes of the MMU2.0 printers for no priming towers.
-0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost
-0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material
-0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
-0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
-min_slic3r_version = 1.40.0
-0.1.18 Updated firmware version
-0.1.17 Updated firmware version for MK2.5/S and MK3/S
-0.1.16 MK2.5/3/S FW update
-0.1.15 MK2/S/MMU FW update
-0.1.14 Updated firmware versions for MK2.5 and MK3
-0.1.13 New MK2.5 and MK3 FW versions
-0.1.12 New MK2.5 and MK3 FW versions
-0.1.11 fw version changed to 3.3.1
-0.1.10 MK3 jerk and acceleration update
-0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles
-0.1.8 extrusion width for 0,25, 0.6 and variable layer height fixes
-0.1.7 Fixed errors in 0.25mm and 0.6mm profiles
-0.1.6 Split the MK2.5 profile from the MK2S
-min_slic3r_version = 1.40.0-beta
-0.1.5 fixed printer_variant fields for the i3 MK3 0.25 and 0.6mm nozzles
-0.1.4 edited fw version, added z-raise after print
-min_slic3r_version = 1.40.0-alpha
-0.1.3 Fixed an incorrect position of the max_print_height parameter
-0.1.2 Wipe tower changes
-0.1.1 Minor print speed adjustments
-0.1.0 Initial
+min_slic3r_version = 2.4.0-alpha0
+1.4.0-alpha8 Added material profiles for Prusament Resin. Detect bridging perimeters enabled by default.
+1.4.0-alpha7 Updated brim_separation value. Updated Prusa MINI end g-code. Added Filamentworld filament profiles.
+1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height).
+1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
+1.4.0-alpha4 Decreased Area Fill (SL1S).
+1.4.0-alpha3 Updated SL1S tilt times.
+1.4.0-alpha2 Updated Prusa MINI machine limits.
+1.4.0-alpha1 Added new SL1S resin profiles.
+1.4.0-alpha0 Bumped up config version.
+1.3.0-alpha2 Added SL1S SPEED profiles.
+1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values.
+1.3.0-alpha0 Disabled thick bridges, updated support settings.
+min_slic3r_version = 2.3.2-alpha0
+1.3.2 Added material profiles for Prusament Resin.
+1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
+1.3.0 Added SL1S SPEED profiles.
+min_slic3r_version = 2.3.0-rc1
+1.2.9 Added material profiles for Prusament Resin.
+1.2.8 Added multiple add:north and Extrudr filament profiles.
+1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI.
+1.2.6 Added filament profile for "Prusament PC Blend Carbon Fiber".
+1.2.5 Updated firmware version. Added filament profiles. Various improvements.
+1.2.4 Updated cost/density values in filament settings. Various changes in print settings.
+1.2.3 Updated firmware version. Updated end g-code in MMU2 printer profiles.
+1.2.2 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
+1.2.1 Updated FW version for MK2.5 family printers.
+1.2.0 Added full_fan_speed_layer value for PETG. Increased support interface spacing for 0.6mm nozzle profiles. Updated firmware version.
+min_slic3r_version = 2.3.0-beta2
+1.2.0-beta1 Updated end g-code. Added full_fan_speed_layer values.
+min_slic3r_version = 2.3.0-beta0
+1.2.0-beta0 Adjusted infill anchor limits. Added filament spool weights.
+min_slic3r_version = 2.3.0-alpha4
+1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
+1.2.0-alpha0 Added filament spool weights
+min_slic3r_version = 2.2.0-alpha3
+1.1.14 Updated firmware version.
+1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles.
+1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
+1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
+1.1.10 Updated firmware version.
+1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials.
+1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles.
+1.1.7 Updated end g-code for MMU2 Single printer profiles. Added/updated filament and SLA material profiles.
+1.1.6 Updated firmware version for MK2.5/S and MK3/S.
+1.1.5 Updated MMU1 specific retraction settings for Prusament PC Blend
+1.1.4 Added Prusament PC Blend filament profile.
+1.1.3 Added SLA material and filament profile
+1.1.2 Added renamed_from fields for PETG filaments to indicate that they were renamed from PET.
+1.1.1 Added Verbatim and Fiberlogy PETG filament profiles. Updated auto cooling settings for ABS.
+1.1.1-beta Updated for PrusaSlicer 2.2.0-beta
+1.1.1-alpha4 Extended list of default filaments to be installed, top/bottom_solid_min_thickness defined, infill_acceleration changed etc
+1.1.1-alpha3 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
+# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,
+# so they will see the print bed.
+max_slic3r_version = 2.2.0-alpha2
+min_slic3r_version = 2.2.0-alpha0
+1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
+1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
+min_slic3r_version = 2.1.1-beta0
+1.0.12 Updated firmware version.
+1.0.11 Updated firmware version.
+1.0.10 Updated firmware version for MK2.5/S and MK3/S.
+1.0.9 Updated firmware version for MK2.5/S and MK3/S.
+1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog.
+1.0.7 Updated layer height limits for MINI
+1.0.6 Added Prusa MINI profiles
+min_slic3r_version = 2.1.0-alpha0
+1.0.5 Added SLA materials
+1.0.4 Updated firmware version and 0.25mm nozzle profiles
+1.0.3 Added filament profiles
+1.0.2 Added SLA materials
+1.0.1 Updated MK3 firmware version check to 3.8.0, new soluble support profiles for 0.6mm nozzle diameter MMU2S printers.
+1.0.0 Updated end G-code for the MMU2 profiles to lift the extruder at the end of print. Wipe tower bridging distance was made smaller for soluble supports.
+1.0.0-beta1 Updated color for the ASA filaments to differ from the other filaments. Single extruder printers now have no extruder color assigned, obects and toolpaths will be colored with the color of the active filament.
+1.0.0-beta0 Printer model checks in start G-codes, ASA filament profiles, limits on min / max SL1 exposition times
+1.0.0-alpha2 Printer model and nozzle diameter check
+1.0.0-alpha1 Added Prusament ASA profile
+1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
+min_slic3r_version = 1.42.0-alpha6
+0.8.11 Updated firmware version.
+0.8.10 Updated firmware version.
+0.8.9 Updated firmware version for MK2.5/S and MK3/S.
+0.8.8 Updated firmware version for MK2.5/S and MK3/S.
+0.8.7 Updated firmware version
+0.8.6 Updated firmware version for MK2.5/S and MK3/S
+0.8.5 Updated SL1 printer and material settings
+0.8.4 Added Prusament ASA profile
+0.8.3 FW version and SL1 materials update
+0.8.2 FFF and SL1 settings update
+0.8.1 Output settings and SLA materials update
+0.8.0 Updated for the PrusaSlicer 2.0.0 final release
+0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S
+0.8.0-rc1 Updated SLA profiles
+0.8.0-rc Updated for the PrusaSlicer 2.0.0-rc release
+0.8.0-beta4 Updated SLA profiles
+0.8.0-beta3 Updated SLA profiles
+0.8.0-beta2 Updated SLA profiles
+0.8.0-beta1 Updated SLA profiles
+0.8.0-beta Updated SLA profiles
+0.8.0-alpha9 Updated SLA and FFF profiles
+0.8.0-alpha8 Updated SLA profiles
+0.8.0-alpha7 Updated SLA profiles
+0.8.0-alpha6 Updated SLA profiles
+min_slic3r_version = 1.42.0-alpha
+0.8.0-alpha Updated SLA profiles
+0.4.0-alpha4 Updated SLA profiles
+0.4.0-alpha3 Update of SLA profiles
+0.4.0-alpha2 First SLA profiles
+min_slic3r_version = 1.41.3-alpha
+0.4.12 Updated firmware version for MK2.5/S and MK3/S.
+0.4.11 Updated firmware version for MK2.5/S and MK3/S.
+0.4.10 Updated firmware version
+0.4.9 Updated firmware version for MK2.5/S and MK3/S
+0.4.8 MK2.5/3/S FW update
+0.4.7 MK2/S/MMU FW update
+0.4.6 Updated firmware versions for MK2.5/S and MK3/S
+0.4.5 Enabled remaining time support for MK2/S/MMU1
+0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
+0.4.3 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
+0.4.2 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
+0.4.1 New MK2.5S and MK3S FW versions
+0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
+min_slic3r_version = 1.41.1
+0.3.11 Updated firmware version for MK2.5/S and MK3/S.
+0.3.10 Updated firmware version
+0.3.9 Updated firmware version for MK2.5/S and MK3/S
+0.3.8 MK2.5/3/S FW update
+0.3.7 MK2/S/MMU FW update
+0.3.6 Updated firmware versions for MK2.5 and MK3
+0.3.5 New MK2.5 and MK3 FW versions
+0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
+0.3.3 Prusament PETG released
+0.3.2 New MK2.5 and MK3 FW versions
+0.3.1 New MK2.5 and MK3 FW versions
+0.3.0 New MK2.5 and MK3 FW version
+min_slic3r_version = 1.41.0-alpha
+0.2.9 New MK2.5 and MK3 FW versions
+0.2.8 New MK2.5 and MK3 FW version
+min_slic3r_version = 1.41.1
+0.2.7 New MK2.5 and MK3 FW version
+0.2.6 Added MMU2 MK2.5 settings
+min_slic3r_version = 1.41.0-alpha
+0.2.5 Prusament is out - added prusament settings
+0.2.4 Added soluble support profiles for MMU2
+0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit
+0.2.2 Edited MMU2 Single mode purge line
+0.2.1 Added PET and BVOH settings for MMU2
+0.2.0-beta5 Fixed MMU1 ramming parameters
+0.2.0-beta4 Added filament loading speed at start, increased minimal purge on wipe tower
+0.2.0-beta3 Edited ramming parameters and filament cooling moves for MMU2
+0.2.0-beta2 Edited first layer speed and wipe tower position
+0.2.0-beta Removed limit on the MK3MMU2 height, added legacy M204 S T format to the MK2 profiles
+0.2.0-alpha8 Added filament_load/unload_time for the PLA/ABS MMU2 filament presets.
+0.2.0-alpha7 Vojtech's fix the incorrect *MK3* references
+0.2.0-alpha6 Jindra's way to fix the 0.2.0-alpha5 version
+0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2
+0.2.0-alpha4 Extended the custom start/end G-codes of the MMU2.0 printers for no priming towers.
+0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost
+0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material
+0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
+0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
+min_slic3r_version = 1.40.0
+0.1.18 Updated firmware version
+0.1.17 Updated firmware version for MK2.5/S and MK3/S
+0.1.16 MK2.5/3/S FW update
+0.1.15 MK2/S/MMU FW update
+0.1.14 Updated firmware versions for MK2.5 and MK3
+0.1.13 New MK2.5 and MK3 FW versions
+0.1.12 New MK2.5 and MK3 FW versions
+0.1.11 fw version changed to 3.3.1
+0.1.10 MK3 jerk and acceleration update
+0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles
+0.1.8 extrusion width for 0,25, 0.6 and variable layer height fixes
+0.1.7 Fixed errors in 0.25mm and 0.6mm profiles
+0.1.6 Split the MK2.5 profile from the MK2S
+min_slic3r_version = 1.40.0-beta
+0.1.5 fixed printer_variant fields for the i3 MK3 0.25 and 0.6mm nozzles
+0.1.4 edited fw version, added z-raise after print
+min_slic3r_version = 1.40.0-alpha
+0.1.3 Fixed an incorrect position of the max_print_height parameter
+0.1.2 Wipe tower changes
+0.1.1 Minor print speed adjustments
+0.1.0 Initial
diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index 47a3883b4..7d4ab7ccb 100644
--- a/resources/profiles/PrusaResearch.ini
+++ b/resources/profiles/PrusaResearch.ini
@@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
-config_version = 1.4.0-alpha7
+config_version = 1.4.0-alpha8
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@@ -120,7 +120,7 @@ technology = SLA
family = SL1
bed_model = sl1_bed.stl
bed_texture = sl1.svg
-default_materials = Prusa Orange Tough @0.05
+default_materials = Prusa Orange Tough @0.05; Prusament Resin Tough Prusa Orange @0.05
[printer_model:SL1S]
name = Original Prusa SL1S SPEED
@@ -129,7 +129,7 @@ technology = SLA
family = SL1
bed_model = sl1s_bed.stl
bed_texture = sl1s.svg
-default_materials = Prusa Orange Tough @0.05 SL1S
+default_materials = Prusa Orange Tough @0.05 SL1S; Prusament Resin Tough Prusa Orange @0.05 SL1S
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
@@ -181,7 +181,7 @@ max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_skirt_length = 4
notes =
-overhangs = 0
+overhangs = 1
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode
@@ -395,6 +395,7 @@ top_solid_min_thickness = 1.2
bottom_solid_min_thickness = 0.8
single_extruder_multi_material_priming = 0
thick_bridges = 1
+overhangs = 0
[print:*soluble_support*]
overhangs = 1
@@ -460,10 +461,10 @@ bridge_flow_ratio = 1
bridge_speed = 20
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
layer_height = 0.1
-perimeter_acceleration = 800
+perimeter_acceleration = 600
top_solid_layers = 9
support_material_contact_distance = 0.17
-raft_contact_distance = 0.17
+raft_contact_distance = 0.15
[print:*0.15mm*]
inherits = *common*
@@ -619,6 +620,7 @@ support_material_contact_distance = 0.1
raft_contact_distance = 0.2
top_solid_infill_speed = 40
thick_bridges = 1
+overhangs = 0
## MMU1 specific
[print:0.15mm OPTIMAL SOLUBLE FULL]
@@ -704,7 +706,7 @@ small_perimeter_speed = 15
solid_infill_speed = 40
top_solid_infill_speed = 30
support_material_contact_distance = 0.08
-raft_contact_distance = 0.08
+raft_contact_distance = 0.07
## MK2 - 0.6mm nozzle
@@ -772,6 +774,7 @@ single_extruder_multi_material_priming = 0
inherits = 0.35mm FAST
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
single_extruder_multi_material_priming = 0
+overhangs = 0
## MK2.5 - MMU2 specific
@@ -1013,7 +1016,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and
fill_pattern = grid
fill_density = 20%
support_material_contact_distance = 0.08
-raft_contact_distance = 0.08
+raft_contact_distance = 0.07
## MK3 - 0.6mm nozzle
@@ -1028,7 +1031,7 @@ perimeter_speed = 45
solid_infill_speed = 70
top_solid_infill_speed = 45
support_material_contact_distance = 0.22
-raft_contact_distance = 0.22
+raft_contact_distance = 0.2
bridge_flow_ratio = 1
[print:0.20mm DETAIL @0.6 nozzle MK3]
@@ -1042,7 +1045,7 @@ perimeter_speed = 45
solid_infill_speed = 70
top_solid_infill_speed = 45
support_material_contact_distance = 0.22
-raft_contact_distance = 0.22
+raft_contact_distance = 0.2
bridge_flow_ratio = 1
[print:0.30mm QUALITY @0.6 nozzle MK3]
@@ -1311,7 +1314,7 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and
fill_pattern = grid
fill_density = 20%
support_material_contact_distance = 0.08
-raft_contact_distance = 0.08
+raft_contact_distance = 0.07
# MINI - 0.6mm nozzle
@@ -4496,7 +4499,31 @@ initial_exposure_time = 35
material_type = Tough
material_vendor = Monocure
-## Prusa
+## Prusa Polymers 0.025
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.025]
+inherits = *common 0.025*
+exposure_time = 5
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.025]
+inherits = *common 0.025*
+exposure_time = 5
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.025]
+inherits = *common 0.025*
+exposure_time = 6
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Prusa 0.025
+
[sla_material:Prusa Orange Tough @0.025]
inherits = *common 0.025*
exposure_time = 6
@@ -5185,7 +5212,30 @@ initial_exposure_time = 35
material_type = Tough
material_vendor = Zortrax
-## Prusa
+## Prusa Polymers 0.05
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 35
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Prusa 0.05
[sla_material:Prusa Beige Tough @0.05]
inherits = *common 0.05*
@@ -5447,7 +5497,30 @@ initial_exposure_time = 50
material_type = Tough
material_vendor = BlueCast
-## Prusa
+## Prusa Polymers 0.1
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.1]
+inherits = *common 0.1*
+exposure_time = 13
+initial_exposure_time = 45
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.1]
+inherits = *common 0.1*
+exposure_time = 13
+initial_exposure_time = 45
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.1]
+inherits = *common 0.1*
+exposure_time = 14
+initial_exposure_time = 45
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Prusa 0.1
[sla_material:Prusa Orange Tough @0.1]
inherits = *common 0.1*
@@ -5530,6 +5603,31 @@ material_vendor = Made for Prusa
## 0.025 SL1S
+## Prusa Polymers 0.025
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.025 SL1S]
+inherits = *0.025_sl1s*
+exposure_time = 1.8
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.025 SL1S]
+inherits = *0.025_sl1s*
+exposure_time = 1.8
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.025 SL1S]
+inherits = *0.025_sl1s*
+exposure_time = 2
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Made for Prusa 0.025
+
[sla_material:Prusa Orange Tough @0.025 SL1S]
inherits = *0.025_sl1s*
exposure_time = 1.8
@@ -5644,6 +5742,31 @@ material_vendor = Peopoly
## 0.05 SL1S
+## Prusa Polymers 0.05
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.05 SL1S]
+inherits = *0.05_sl1s*
+exposure_time = 2
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.05 SL1S]
+inherits = *0.05_sl1s*
+exposure_time = 2
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.05 SL1S]
+inherits = *0.05_sl1s*
+exposure_time = 2.4
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Made for Prusa 0.05
+
[sla_material:Prusa Orange Tough @0.05 SL1S]
inherits = *0.05_sl1s*
exposure_time = 2
@@ -5758,6 +5881,31 @@ material_vendor = Peopoly
## 0.1 SL1S
+## Prusa Polymers 0.1
+
+[sla_material:Prusament Resin Tough Prusa Orange @0.1 SL1S]
+inherits = *0.1_sl1s*
+exposure_time = 2.6
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Rich Black @0.1 SL1S]
+inherits = *0.1_sl1s*
+exposure_time = 2.6
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+[sla_material:Prusament Resin Tough Anthracite Grey @0.1 SL1S]
+inherits = *0.1_sl1s*
+exposure_time = 3
+initial_exposure_time = 25
+material_type = Tough
+material_vendor = Prusa Polymers
+
+## Made for Prusa 0.1
+
[sla_material:Prusa Orange Tough @0.1 SL1S]
inherits = *0.1_sl1s*
exposure_time = 2.6
@@ -6573,7 +6721,7 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
default_print_profile = 0.30mm QUALITY @0.6 nozzle MINI
-retract_length = 3.5
+retract_length = 3.2
retract_before_travel = 1.5
[printer:Original Prusa MINI & MINI+ 0.8 nozzle]
diff --git a/resources/shaders/gouraud_light_instanced.vs b/resources/shaders/gouraud_light_instanced.vs
index 997b6a2bf..a42f8e9a4 100644
--- a/resources/shaders/gouraud_light_instanced.vs
+++ b/resources/shaders/gouraud_light_instanced.vs
@@ -34,9 +34,7 @@ void main()
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
- float width = 1.5 * i_scales.x;
- float height = 1.5 * i_scales.y;
- vec4 world_position = vec4(v_position * vec3(vec2(width), height) + i_offset - vec3(0.0, 0.0, 0.5 * i_scales.y), 1.0);
+ vec4 world_position = vec4(v_position * vec3(vec2(1.5 * i_scales.x), 1.5 * i_scales.y) + i_offset - vec3(0.0, 0.0, 0.5 * i_scales.y), 1.0);
vec3 eye_position = (gl_ModelViewMatrix * world_position).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
diff --git a/sandboxes/aabb-evaluation/aabb-evaluation.cpp b/sandboxes/aabb-evaluation/aabb-evaluation.cpp
index 9ec7451e5..1019ecf28 100644
--- a/sandboxes/aabb-evaluation/aabb-evaluation.cpp
+++ b/sandboxes/aabb-evaluation/aabb-evaluation.cpp
@@ -212,8 +212,7 @@ int main(const int argc, const char *argv[])
return -1;
}
- mesh.repair();
- if (mesh.facets_count() == 0) {
+ if (mesh.empty()) {
std::cerr << "Error loading " << argv[1] << " . It is empty." << std::endl;
return -1;
}
diff --git a/sandboxes/meshboolean/MeshBoolean.cpp b/sandboxes/meshboolean/MeshBoolean.cpp
index 392d90707..c8649888f 100644
--- a/sandboxes/meshboolean/MeshBoolean.cpp
+++ b/sandboxes/meshboolean/MeshBoolean.cpp
@@ -24,7 +24,6 @@ int main(const int argc, const char * argv[])
TriangleMesh input;
input.ReadSTLFile(argv[1]);
- input.repair();
Benchmark bench;
diff --git a/sandboxes/opencsg/Engine.cpp b/sandboxes/opencsg/Engine.cpp
index f110b23c5..d8f1d3464 100644
--- a/sandboxes/opencsg/Engine.cpp
+++ b/sandboxes/opencsg/Engine.cpp
@@ -145,7 +145,7 @@ void IndexedVertexArray::load_mesh(const TriangleMesh &mesh)
this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count());
int vertices_count = 0;
- for (size_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
+ for (size_t i = 0; i < mesh.facets_count(); ++i) {
const stl_facet &facet = mesh.stl.facet_start[i];
for (int j = 0; j < 3; ++j)
this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
@@ -409,7 +409,6 @@ void CSGDisplay::on_scene_updated(const Scene &scene)
interior.transform(po->trafo().inverse());
mshinst.merge(interior);
- mshinst.require_shared_vertices();
mi->transform_mesh(&mshinst);
@@ -417,14 +416,12 @@ void CSGDisplay::on_scene_updated(const Scene &scene)
auto center = bb.center().cast();
mshinst.translate(-center);
- mshinst.require_shared_vertices();
m_scene_cache.add_mesh(mshinst, OpenCSG::Intersection,
m_csgsettings.get_convexity());
}
for (const sla::DrainHole &holept : holedata) {
TriangleMesh holemesh = sla::to_triangle_mesh(holept.to_mesh());
- holemesh.require_shared_vertices();
m_scene_cache.add_mesh(holemesh, OpenCSG::Subtraction, 1);
}
}
diff --git a/sandboxes/opencsg/ShaderCSGDisplay.cpp b/sandboxes/opencsg/ShaderCSGDisplay.cpp
index 8ceb234be..2413bad5b 100644
--- a/sandboxes/opencsg/ShaderCSGDisplay.cpp
+++ b/sandboxes/opencsg/ShaderCSGDisplay.cpp
@@ -43,7 +43,6 @@ void ShaderCSGDisplay::on_scene_updated(const Scene &scene)
interior.transform(po->trafo().inverse());
mshinst.merge(interior);
- mshinst.require_shared_vertices();
mi->transform_mesh(&mshinst);
@@ -51,15 +50,11 @@ void ShaderCSGDisplay::on_scene_updated(const Scene &scene)
auto center = bb.center().cast();
mshinst.translate(-center);
- mshinst.require_shared_vertices();
add_mesh(mshinst);
}
- for (const sla::DrainHole &holept : holedata) {
- TriangleMesh holemesh = sla::to_triangle_mesh(holept.to_mesh());
- holemesh.require_shared_vertices();
- add_mesh(holemesh);
- }
+ for (const sla::DrainHole &holept : holedata)
+ add_mesh(sla::to_triangle_mesh(holept.to_mesh()));
}
repaint();
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 3490b8183..0da5e7380 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -397,7 +397,7 @@ int CLI::run(int argc, char **argv)
TriangleMesh mesh = model.mesh();
mesh.repair();
- TriangleMeshPtrs meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value);
+ std::vector meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value);
size_t i = 0;
for (TriangleMesh* m : meshes) {
Model out;
diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index e5491b1aa..8c3ab154a 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -239,6 +239,7 @@ private:
return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b;
}
+ // Connect edge_a with edge_b, update edge connection statistics.
static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
{
// Facet a's neighbor is facet b
@@ -249,7 +250,7 @@ private:
stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number; /* sets the .neighbor part */
stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
- if (((edge_a.which_edge < 3) && (edge_b.which_edge < 3)) || ((edge_a.which_edge > 2) && (edge_b.which_edge > 2))) {
+ if ((edge_a.which_edge < 3 && edge_b.which_edge < 3) || (edge_a.which_edge > 2 && edge_b.which_edge > 2)) {
// These facets are oriented in opposite directions, their normals are probably messed up.
stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
@@ -479,12 +480,13 @@ void stl_check_facets_exact(stl_file *stl)
void stl_check_facets_nearby(stl_file *stl, float tolerance)
{
- if ( (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
- && (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
- && (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)) {
+ assert(stl->stats.connected_facets_3_edge <= stl->stats.connected_facets_2_edge);
+ assert(stl->stats.connected_facets_2_edge <= stl->stats.connected_facets_1_edge);
+ assert(stl->stats.connected_facets_1_edge <= stl->stats.number_of_facets);
+
+ if (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)
// No need to check any further. All facets are connected.
return;
- }
HashTableEdges hash_table(stl->stats.number_of_facets);
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
@@ -514,22 +516,12 @@ void stl_remove_unconnected_facets(stl_file *stl)
/* Update list of connected edges */
stl_neighbors &neighbors = stl->neighbors_start[facet_number];
// Update statistics on unconnected triangle edges.
- switch ((neighbors.neighbor[0] == -1) + (neighbors.neighbor[1] == -1) + (neighbors.neighbor[2] == -1)) {
- case 0: // Facet has 3 neighbors
- -- stl->stats.connected_facets_3_edge;
- -- stl->stats.connected_facets_2_edge;
- -- stl->stats.connected_facets_1_edge;
- break;
- case 1: // Facet has 2 neighbors
- -- stl->stats.connected_facets_2_edge;
- -- stl->stats.connected_facets_1_edge;
- break;
- case 2: // Facet has 1 neighbor
- -- stl->stats.connected_facets_1_edge;
- case 3: // Facet has 0 neighbors
- break;
- default:
- assert(false);
+ switch (neighbors.num_neighbors()) {
+ case 3: -- stl->stats.connected_facets_3_edge; // fall through
+ case 2: -- stl->stats.connected_facets_2_edge; // fall through
+ case 1: -- stl->stats.connected_facets_1_edge; // fall through
+ case 0: break;
+ default: assert(false);
}
if (facet_number < int(-- stl->stats.number_of_facets)) {
@@ -555,20 +547,14 @@ void stl_remove_unconnected_facets(stl_file *stl)
auto remove_degenerate = [stl, remove_facet](int facet)
{
- // Update statistics on face connectivity.
- auto stl_update_connects_remove_1 = [stl](int facet_num) {
- //FIXME when decreasing 3_edge, should I increase 2_edge etc?
- switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
- case 0: // Facet has 3 neighbors
- -- stl->stats.connected_facets_3_edge; break;
- case 1: // Facet has 2 neighbors
- -- stl->stats.connected_facets_2_edge; break;
- case 2: // Facet has 1 neighbor
- -- stl->stats.connected_facets_1_edge; break;
- case 3: // Facet has 0 neighbors
- break;
- default:
- assert(false);
+ // Update statistics on face connectivity after one edge was disconnected on the facet "facet_num".
+ auto update_connects_remove_1 = [stl](int facet_num) {
+ switch (stl->neighbors_start[facet_num].num_neighbors()) {
+ case 0: assert(false); break;
+ case 1: -- stl->stats.connected_facets_1_edge; break;
+ case 2: -- stl->stats.connected_facets_2_edge; break;
+ case 3: -- stl->stats.connected_facets_3_edge; break;
+ default: assert(false);
}
};
@@ -604,9 +590,9 @@ void stl_remove_unconnected_facets(stl_file *stl)
// Update statistics on edge connectivity.
if ((neighbor[0] == -1) && (neighbor[1] != -1))
- stl_update_connects_remove_1(neighbor[1]);
+ update_connects_remove_1(neighbor[1]);
if ((neighbor[1] == -1) && (neighbor[0] != -1))
- stl_update_connects_remove_1(neighbor[0]);
+ update_connects_remove_1(neighbor[0]);
if (neighbor[0] >= 0) {
if (neighbor[1] >= 0) {
@@ -634,7 +620,7 @@ void stl_remove_unconnected_facets(stl_file *stl)
stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
}
if (neighbor[2] >= 0) {
- stl_update_connects_remove_1(neighbor[2]);
+ update_connects_remove_1(neighbor[2]);
stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
}
@@ -652,11 +638,9 @@ void stl_remove_unconnected_facets(stl_file *stl)
++ i;
if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) {
- // remove completely unconnected facets
+ // There are some faces with no connected edge at all. Remove completely unconnected facets.
for (uint32_t i = 0; i < stl->stats.number_of_facets;)
- if (stl->neighbors_start[i].neighbor[0] == -1 &&
- stl->neighbors_start[i].neighbor[1] == -1 &&
- stl->neighbors_start[i].neighbor[2] == -1) {
+ if (stl->neighbors_start[i].num_neighbors() == 0) {
// This facet is completely unconnected. Remove it.
remove_facet(i);
assert(stl_validate(stl));
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 1ca75c95d..8c30a6ae5 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -79,8 +79,7 @@ struct stl_neighbors {
which_vertex_not[1] = -1;
which_vertex_not[2] = -1;
}
- int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
- int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
+ int num_neighbors() const { return 3 - ((this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1)); }
// Index of a neighbor facet.
int neighbor[3];
@@ -92,28 +91,44 @@ struct stl_stats {
stl_stats() { memset(&header, 0, 81); }
char header[81];
stl_type type = (stl_type)0;
+ // Should always match the number of facets stored inside stl_file::facet_start.
uint32_t number_of_facets = 0;
+ // Bounding box.
stl_vertex max = stl_vertex::Zero();
stl_vertex min = stl_vertex::Zero();
stl_vertex size = stl_vertex::Zero();
float bounding_diameter = 0.f;
float shortest_edge = 0.f;
+ // After repair, the volume shall always be positive.
float volume = -1.f;
+ // Number of face edges connected to another face.
+ // Don't use this statistics after repair, use the connected_facets_1/2/3_edge instead!
int connected_edges = 0;
+ // Faces with >=1, >=2 and 3 edges connected to another face.
int connected_facets_1_edge = 0;
int connected_facets_2_edge = 0;
int connected_facets_3_edge = 0;
+ // Faces with 1, 2 and 3 open edges after exact chaining, but before repair.
int facets_w_1_bad_edge = 0;
int facets_w_2_bad_edge = 0;
int facets_w_3_bad_edge = 0;
+ // Number of faces read form an STL file.
int original_num_facets = 0;
+ // Number of edges connected one to another by snapping their end vertices.
int edges_fixed = 0;
+ // Number of faces removed because they were degenerated.
int degenerate_facets = 0;
+ // Total number of facets removed: Degenerate faces and unconnected faces.
int facets_removed = 0;
+ // Number of faces added by hole filling.
int facets_added = 0;
+ // Number of faces reversed because of negative volume or because one patch was connected to another patch with incompatible normals.
int facets_reversed = 0;
+ // Number of incompatible edges remaining after the patches were connected together and possibly their normals flipped.
int backwards_edges = 0;
+ // Number of triangles, which were flipped during the fixing process.
int normals_fixed = 0;
+ // Number of connected triangle patches.
int number_of_parts = 0;
void clear() { *this = stl_stats(); }
@@ -135,13 +150,11 @@ struct stl_file {
std::vector facet_start;
std::vector neighbors_start;
// Statistics
- stl_stats stats;
+ stl_stats stats;
};
struct indexed_triangle_set
{
- indexed_triangle_set() {}
-
void clear() { indices.clear(); vertices.clear(); }
size_t memsize() const {
@@ -149,9 +162,7 @@ struct indexed_triangle_set
}
std::vector indices;
- std::vector vertices;
- //FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
- //std::vector normals
+ std::vector vertices;
bool empty() const { return indices.empty() || vertices.empty(); }
};
@@ -244,9 +255,15 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix
+inline void its_translate(indexed_triangle_set &its, const V v)
+{
+ for (stl_vertex &v_dst : its.vertices)
+ v_dst += v;
+}
template
-extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
+inline void its_transform(indexed_triangle_set &its, T *trafo3x4)
{
for (stl_vertex &v_dst : its.vertices) {
stl_vertex v_src = v_dst;
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index ddf377c78..26f5dc321 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -205,11 +205,12 @@ bool stl_write_quad_object(stl_file *stl, char *file)
fprintf(fp, "CQUAD\n");
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
- switch (stl->neighbors_start[i].num_neighbors_missing()) {
- case 0: color = connect_color; break;
- case 1: color = uncon_1_color; break;
- case 2: color = uncon_2_color; break;
- default: color = uncon_3_color;
+ switch (stl->neighbors_start[i].num_neighbors()) {
+ case 0:
+ default: color = uncon_3_color; break;
+ case 1: color = uncon_2_color; break;
+ case 2: color = uncon_1_color; break;
+ case 3: color = connect_color; break;
}
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 177d8d708..f3a1d5988 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -139,6 +139,9 @@ void AppConfig::set_defaults()
if (get("default_action_on_select_preset").empty())
set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save"
+ if (get("default_action_on_new_project").empty())
+ set("default_action_on_new_project", "none"); // , "keep(transfer)", "discard" or "save"
+
if (get("color_mapinulation_panel").empty())
set("color_mapinulation_panel", "0");
diff --git a/src/libslic3r/BlacklistedLibraryCheck.cpp b/src/libslic3r/BlacklistedLibraryCheck.cpp
index 76f675c70..938f54249 100644
--- a/src/libslic3r/BlacklistedLibraryCheck.cpp
+++ b/src/libslic3r/BlacklistedLibraryCheck.cpp
@@ -12,7 +12,7 @@ namespace Slic3r {
#ifdef WIN32
//only dll name with .dll suffix - currently case sensitive
-const std::vector BlacklistedLibraryCheck::blacklist({ L"NahimicOSD.dll", L"SS2OSD.dll" });
+const std::vector BlacklistedLibraryCheck::blacklist({ L"NahimicOSD.dll", L"SS2OSD.dll", L"amhook.dll", L"AMHook.dll" });
bool BlacklistedLibraryCheck::get_blacklisted(std::vector& names)
{
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index f9bef903b..d42077b9c 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -78,8 +78,6 @@ add_library(libslic3r STATIC
Format/OBJ.hpp
Format/objparser.cpp
Format/objparser.hpp
- Format/PRUS.cpp
- Format/PRUS.hpp
Format/STL.cpp
Format/STL.hpp
Format/SL1.hpp
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index 8a4dfc03c..e8f87a6e3 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -126,6 +126,45 @@ ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
return PolyTreeToExPolygons(std::move(polytree));
}
+#if 0
+// Global test.
+bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
+{
+ struct Helper {
+ static void collect_points_recursive(const ClipperLib::PolyNode &polynode, ClipperLib::Path &out) {
+ // For each hole of the current expolygon:
+ out.insert(out.end(), polynode.Contour.begin(), polynode.Contour.end());
+ for (int i = 0; i < polynode.ChildCount(); ++ i)
+ collect_points_recursive(*polynode.Childs[i], out);
+ }
+ };
+ ClipperLib::Path pts;
+ for (int i = 0; i < polytree.ChildCount(); ++ i)
+ Helper::collect_points_recursive(*polytree.Childs[i], pts);
+ return has_duplicate_points(std::move(pts));
+}
+#else
+// Local test inside each of the contours.
+bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
+{
+ struct Helper {
+ static bool has_duplicate_points_recursive(const ClipperLib::PolyNode &polynode) {
+ if (has_duplicate_points(polynode.Contour))
+ return true;
+ for (int i = 0; i < polynode.ChildCount(); ++ i)
+ if (has_duplicate_points_recursive(*polynode.Childs[i]))
+ return true;
+ return false;
+ }
+ };
+ ClipperLib::Path pts;
+ for (int i = 0; i < polytree.ChildCount(); ++ i)
+ if (Helper::has_duplicate_points_recursive(*polytree.Childs[i]))
+ return true;
+ return false;
+}
+#endif
+
// Offset outside by 10um, one by one.
template
static ClipperLib::Paths safety_offset(PathsProvider &&paths)
@@ -467,6 +506,8 @@ Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
+Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
+ { return _clipper(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset)
@@ -496,6 +537,8 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfac
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
+Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
+ { return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
@@ -610,12 +653,18 @@ Polylines _clipper_pl_closed(ClipperLib::ClipType clipType, PathProvider1 &&subj
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
+Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip)
+ { return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); }
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip)
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); }
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); }
Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
+Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
+ { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
+Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
+ { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
@@ -637,7 +686,9 @@ Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Pol
// convert Polylines to Lines
Lines retval;
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
- retval.emplace_back(polyline->operator Line());
+ if (polyline->size() >= 2)
+ //FIXME It may happen, that Clipper produced a polyline with more than 2 collinear points by clipping a single line with polygons. It is a very rare issue, but it happens, see GH #6933.
+ retval.push_back({ polyline->front(), polyline->back() });
return retval;
}
diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp
index c4e014a74..f49d922c1 100644
--- a/src/libslic3r/ClipperUtils.hpp
+++ b/src/libslic3r/ClipperUtils.hpp
@@ -303,6 +303,7 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygo
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
+Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
@@ -312,6 +313,7 @@ Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surf
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
+Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
@@ -322,6 +324,7 @@ inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygon
}
// Safety offset is applied to the clipping polygons only.
+Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
@@ -337,6 +340,8 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
+Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
+Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index ab58a43aa..2d4780d0e 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -740,7 +740,11 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
}
// Load the config keys from the given string.
-static inline size_t load_from_gcode_string_legacy(ConfigBase &config, const char *str, ConfigSubstitutionContext &substitutions)
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
+#else
+static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{
if (str == nullptr)
return 0;
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 6439e4632..dd121c90a 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -2015,6 +2015,10 @@ public:
// Set all the nullable values to nils.
void null_nullables();
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions);
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+
private:
// Set a configuration value from a string.
bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append);
diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp
index 506ba8cb6..bfe0479fe 100644
--- a/src/libslic3r/ExPolygon.cpp
+++ b/src/libslic3r/ExPolygon.cpp
@@ -92,7 +92,7 @@ bool ExPolygon::contains(const Line &line) const
bool ExPolygon::contains(const Polyline &polyline) const
{
- return diff_pl((Polylines)polyline, *this).empty();
+ return diff_pl(polyline, *this).empty();
}
bool ExPolygon::contains(const Polylines &polylines) const
@@ -114,10 +114,11 @@ bool ExPolygon::contains(const Polylines &polylines) const
bool ExPolygon::contains(const Point &point) const
{
- if (!this->contour.contains(point)) return false;
- for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
- if (it->contains(point)) return false;
- }
+ if (! this->contour.contains(point))
+ return false;
+ for (const Polygon &hole : this->holes)
+ if (hole.contains(point))
+ return false;
return true;
}
@@ -367,6 +368,57 @@ extern std::vector get_extents_vector(const ExPolygons &polygons)
return out;
}
+bool has_duplicate_points(const ExPolygon &expoly)
+{
+#if 1
+ // Check globally.
+ size_t cnt = expoly.contour.points.size();
+ for (const Polygon &hole : expoly.holes)
+ cnt += hole.points.size();
+ std::vector allpts;
+ allpts.reserve(cnt);
+ allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end());
+ for (const Polygon &hole : expoly.holes)
+ allpts.insert(allpts.end(), hole.points.begin(), hole.points.end());
+ return has_duplicate_points(std::move(allpts));
+#else
+ // Check per contour.
+ if (has_duplicate_points(expoly.contour))
+ return true;
+ for (const Polygon &hole : expoly.holes)
+ if (has_duplicate_points(hole))
+ return true;
+ return false;
+#endif
+}
+
+bool has_duplicate_points(const ExPolygons &expolys)
+{
+#if 1
+ // Check globally.
+ size_t cnt = 0;
+ for (const ExPolygon &expoly : expolys) {
+ cnt += expoly.contour.points.size();
+ for (const Polygon &hole : expoly.holes)
+ cnt += hole.points.size();
+ }
+ std::vector allpts;
+ allpts.reserve(cnt);
+ for (const ExPolygon &expoly : expolys) {
+ allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end());
+ for (const Polygon &hole : expoly.holes)
+ allpts.insert(allpts.end(), hole.points.begin(), hole.points.end());
+ }
+ return has_duplicate_points(std::move(allpts));
+#else
+ // Check per contour.
+ for (const ExPolygon &expoly : expolys)
+ if (has_duplicate_points(expoly))
+ return true;
+ return false;
+#endif
+}
+
bool remove_sticks(ExPolygon &poly)
{
return remove_sticks(poly.contour) || remove_sticks(poly.holes);
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index 464310ac0..6f3884673 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -351,20 +351,24 @@ inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double toleranc
return out;
}
-extern BoundingBox get_extents(const ExPolygon &expolygon);
-extern BoundingBox get_extents(const ExPolygons &expolygons);
-extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);
-extern BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle);
-extern std::vector get_extents_vector(const ExPolygons &polygons);
+BoundingBox get_extents(const ExPolygon &expolygon);
+BoundingBox get_extents(const ExPolygons &expolygons);
+BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);
+BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle);
+std::vector get_extents_vector(const ExPolygons &polygons);
-extern bool remove_sticks(ExPolygon &poly);
-extern void keep_largest_contour_only(ExPolygons &polygons);
+// Test for duplicate points. The points are copied, sorted and checked for duplicates globally.
+bool has_duplicate_points(const ExPolygon &expoly);
+bool has_duplicate_points(const ExPolygons &expolys);
+
+bool remove_sticks(ExPolygon &poly);
+void keep_largest_contour_only(ExPolygons &polygons);
inline double area(const ExPolygon &poly) { return poly.area(); }
inline double area(const ExPolygons &polys) { double s = 0.; for (auto &p : polys) s += p.area(); return s; }
// Removes all expolygons smaller than min_area and also removes all holes smaller than min_area
-extern bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area);
+bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area);
} // namespace Slic3r
diff --git a/src/libslic3r/Fill/FillAdaptive.cpp b/src/libslic3r/Fill/FillAdaptive.cpp
index 3eabc6106..29b343db0 100644
--- a/src/libslic3r/Fill/FillAdaptive.cpp
+++ b/src/libslic3r/Fill/FillAdaptive.cpp
@@ -928,7 +928,9 @@ static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &b
Linef l { { bg::get<0, 0>(seg), bg::get<0, 1>(seg) }, { bg::get<1, 0>(seg), bg::get<1, 1>(seg) } };
assert(line_alg::distance_to_squared(l, Vec2d(pt.cast())) > 1000 * 1000);
#endif // NDEBUG
- } else if (((Line)pl).distance_to_squared(pt) <= 1000 * 1000)
+ } else if (pl.size() >= 2 &&
+ //FIXME Hoping that pl is really a line, trimmed by a polygon using ClipperUtils. Sometimes Clipper leaves some additional collinear points on the polyline, let's hope it is all right.
+ Line{ pl.front(), pl.back() }.distance_to_squared(pt) <= 1000 * 1000)
out = closest.front().second;
}
return out;
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 295c1413d..9f4015913 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
@@ -32,6 +33,8 @@ namespace pt = boost::property_tree;
#include
#include "miniz_extension.hpp"
+#include
+
// Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
// https://github.com/boostorg/spirit/pull/586
// where the exported string is one digit shorter than it should be to guarantee lossless round trip.
@@ -172,14 +175,18 @@ std::string get_attribute_value_string(const char** attributes, unsigned int att
float get_attribute_value_float(const char** attributes, unsigned int attributes_size, const char* attribute_key)
{
- const char* text = get_attribute_value_charptr(attributes, attributes_size, attribute_key);
- return (text != nullptr) ? (float)::atof(text) : 0.0f;
+ float value = 0.0f;
+ if (const char *text = get_attribute_value_charptr(attributes, attributes_size, attribute_key); text != nullptr)
+ fast_float::from_chars(text, text + strlen(text), value);
+ return value;
}
int get_attribute_value_int(const char** attributes, unsigned int attributes_size, const char* attribute_key)
{
- const char* text = get_attribute_value_charptr(attributes, attributes_size, attribute_key);
- return (text != nullptr) ? ::atoi(text) : 0;
+ int value = 0;
+ if (const char *text = get_attribute_value_charptr(attributes, attributes_size, attribute_key); text != nullptr)
+ boost::spirit::qi::parse(text, text + strlen(text), boost::spirit::qi::int_, value);
+ return value;
}
bool get_attribute_value_bool(const char** attributes, unsigned int attributes_size, const char* attribute_key)
@@ -298,8 +305,8 @@ namespace Slic3r {
struct Geometry
{
- std::vector vertices;
- std::vector triangles;
+ std::vector vertices;
+ std::vector triangles;
std::vector custom_supports;
std::vector custom_seam;
std::vector mmu_segmentation;
@@ -713,7 +720,7 @@ namespace Slic3r {
}
// use the geometry to create the volumes in the new model objects
- ObjectMetadata::VolumeMetadataList volumes(1, { 0, (unsigned int)geometry->triangles.size() / 3 - 1 });
+ ObjectMetadata::VolumeMetadataList volumes(1, { 0, (unsigned int)geometry->triangles.size() - 1 });
// for each instance after the 1st, create a new model object containing only that instance
// and copy into it the geometry
@@ -786,7 +793,7 @@ namespace Slic3r {
// config data not found, this model was not saved using slic3r pe
// add the entire geometry as the single volume to generate
- volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() / 3 - 1);
+ volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1);
// select as volumes
volumes_ptr = &volumes;
@@ -1552,9 +1559,10 @@ namespace Slic3r {
{
// appends the vertex coordinates
// missing values are set equal to ZERO
- m_curr_object.geometry.vertices.push_back(m_unit_factor * get_attribute_value_float(attributes, num_attributes, X_ATTR));
- m_curr_object.geometry.vertices.push_back(m_unit_factor * get_attribute_value_float(attributes, num_attributes, Y_ATTR));
- m_curr_object.geometry.vertices.push_back(m_unit_factor * get_attribute_value_float(attributes, num_attributes, Z_ATTR));
+ m_curr_object.geometry.vertices.emplace_back(
+ m_unit_factor * get_attribute_value_float(attributes, num_attributes, X_ATTR),
+ m_unit_factor * get_attribute_value_float(attributes, num_attributes, Y_ATTR),
+ m_unit_factor * get_attribute_value_float(attributes, num_attributes, Z_ATTR));
return true;
}
@@ -1588,9 +1596,10 @@ namespace Slic3r {
// appends the triangle's vertices indices
// missing values are set equal to ZERO
- m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V1_ATTR));
- m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V2_ATTR));
- m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V3_ATTR));
+ m_curr_object.geometry.triangles.emplace_back(
+ get_attribute_value_int(attributes, num_attributes, V1_ATTR),
+ get_attribute_value_int(attributes, num_attributes, V2_ATTR),
+ get_attribute_value_int(attributes, num_attributes, V3_ATTR));
m_curr_object.geometry.custom_supports.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
m_curr_object.geometry.custom_seam.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
@@ -1879,8 +1888,9 @@ namespace Slic3r {
return false;
}
- unsigned int geo_tri_count = (unsigned int)geometry.triangles.size() / 3;
+ unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
unsigned int renamed_volumes_count = 0;
+ int processed_vertices_max_id = 0;
for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) {
if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) {
@@ -1890,77 +1900,68 @@ namespace Slic3r {
Transform3d volume_matrix_to_object = Transform3d::Identity();
bool has_transform = false;
-#if ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
- bool is_left_handed = false;
-#endif // ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
// extract the volume transformation from the volume's metadata, if present
for (const Metadata& metadata : volume_data.metadata) {
if (metadata.key == MATRIX_KEY) {
volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
-#if ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
- is_left_handed = Slic3r::Geometry::Transformation(volume_matrix_to_object).is_left_handed();
-#endif // ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
break;
}
}
// splits volume out of imported geometry
- TriangleMesh triangle_mesh;
- stl_file &stl = triangle_mesh.stl;
- unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1;
- stl.stats.type = inmemory;
- stl.stats.number_of_facets = (uint32_t)triangles_count;
- stl.stats.original_num_facets = (int)stl.stats.number_of_facets;
- stl_allocate(&stl);
+ std::vector faces(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1);
+ const size_t triangles_count = faces.size();
- unsigned int src_start_id = volume_data.first_triangle_id * 3;
-
- for (unsigned int i = 0; i < triangles_count; ++i) {
- unsigned int ii = i * 3;
- stl_facet& facet = stl.facet_start[i];
- for (unsigned int v = 0; v < 3; ++v) {
- unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
- if (tri_id + 2 >= geometry.vertices.size()) {
- add_error("Malformed triangle mesh");
+ int min_id = faces.front()[0];
+ int max_id = faces.front()[0];
+ for (const Vec3i& face : faces) {
+ for (const int tri_id : face) {
+ if (tri_id < 0 || tri_id >= geometry.vertices.size()) {
+ add_error("Found invalid vertex id");
return false;
}
- facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
+ min_id = std::min(min_id, tri_id);
+ max_id = std::max(max_id, tri_id);
}
}
- stl_get_size(&stl);
- triangle_mesh.repair();
+ // rebase indices to the current vertices list
+ for (Vec3i& face : faces) {
+ for (int& tri_id : face) {
+ tri_id -= min_id;
+ }
+ }
-#if ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
- // PrusaSlicer older than 2.4.0 saved mirrored volumes with reversed winding of the triangles
- // This caused the call to TriangleMesh::repair() to reverse all the facets because the calculated volume was negative
- if (is_left_handed && stl.stats.facets_reversed > 0 && stl.stats.facets_reversed == stl.stats.original_num_facets)
- stl.stats.facets_reversed = 0;
-#endif // ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
+ processed_vertices_max_id = 1 + std::max(processed_vertices_max_id, max_id);
+
+ std::vector vertices(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1);
+ TriangleMesh triangle_mesh(std::move(vertices), std::move(faces));
if (m_version == 0) {
// if the 3mf was not produced by PrusaSlicer and there is only one instance,
// bake the transformation into the geometry to allow the reload from disk command
// to work properly
if (object.instances.size() == 1) {
- triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix());
+ triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
+ //FIXME do the mesh fixing?
}
}
+ if (triangle_mesh.volume() < 0)
+ triangle_mesh.flip_triangles();
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
// stores the volume matrix taken from the metadata, if present
if (has_transform)
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
- volume->calculate_convex_hull();
// recreate custom supports, seam and mmu segmentation from previously loaded attribute
volume->supported_facets.reserve(triangles_count);
volume->seam_facets.reserve(triangles_count);
volume->mmu_segmentation_facets.reserve(triangles_count);
- for (unsigned i=0; imesh().repaired)
- throw Slic3r::FileIOError("store_3mf() requires repair()");
- if (!volume->mesh().has_shared_vertices())
- throw Slic3r::FileIOError("store_3mf() requires shared vertices");
-
volumes_offsets.insert({ volume, Offsets(vertices_count) });
const indexed_triangle_set &its = volume->mesh().its;
@@ -2581,10 +2577,7 @@ namespace Slic3r {
if (volume == nullptr)
continue;
-#if ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
bool is_left_handed = volume->is_left_handed();
-#endif // ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
-
VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume);
assert(volume_it != volumes_offsets.end());
@@ -2599,7 +2592,6 @@ namespace Slic3r {
{
const Vec3i &idx = its.indices[i];
char *ptr = buf;
-#if ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << TRIANGLE_TAG <<
" v1=\"" << boost::spirit::int_ <<
"\" v2=\"" << boost::spirit::int_ <<
@@ -2607,15 +2599,6 @@ namespace Slic3r {
idx[is_left_handed ? 2 : 0] + volume_it->second.first_vertex_id,
idx[1] + volume_it->second.first_vertex_id,
idx[is_left_handed ? 0 : 2] + volume_it->second.first_vertex_id);
-#else
- boost::spirit::karma::generate(ptr, boost::spirit::lit(" <") << TRIANGLE_TAG <<
- " v1=\"" << boost::spirit::int_ <<
- "\" v2=\"" << boost::spirit::int_ <<
- "\" v3=\"" << boost::spirit::int_ << "\"",
- idx[0] + volume_it->second.first_vertex_id,
- idx[1] + volume_it->second.first_vertex_id,
- idx[2] + volume_it->second.first_vertex_id);
-#endif // ENABLE_FIX_MIRRORED_VOLUMES_3MF_IMPORT_EXPORT
*ptr = '\0';
output_buffer += buf;
}
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 35b3e0cf4..f0807df51 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -244,11 +244,11 @@ struct AMFParserContext
// Map from obect name to object idx & instances.
std::map m_object_instances_map;
// Vertices parsed for the current m_object.
- std::vector m_object_vertices;
+ std::vector m_object_vertices;
// Current volume allocated for an amf/object/mesh/volume subtree.
ModelVolume *m_volume { nullptr };
// Faces collected for the current m_volume.
- std::vector m_volume_facets;
+ std::vector m_volume_facets;
// Transformation matrix of a volume mesh from its coordinate system to Object's coordinate system.
Transform3d m_volume_transform;
// Current material allocated for an amf/metadata subtree.
@@ -598,9 +598,7 @@ void AMFParserContext::endElement(const char * /* name */)
case NODE_TYPE_VERTEX:
assert(m_object);
// Parse the vertex data
- m_object_vertices.emplace_back((float)atof(m_value[0].c_str()));
- m_object_vertices.emplace_back((float)atof(m_value[1].c_str()));
- m_object_vertices.emplace_back((float)atof(m_value[2].c_str()));
+ m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[2].c_str())));
m_value[0].clear();
m_value[1].clear();
m_value[2].clear();
@@ -609,9 +607,7 @@ void AMFParserContext::endElement(const char * /* name */)
// Faces of the current volume:
case NODE_TYPE_TRIANGLE:
assert(m_object && m_volume);
- m_volume_facets.emplace_back(atoi(m_value[0].c_str()));
- m_volume_facets.emplace_back(atoi(m_value[1].c_str()));
- m_volume_facets.emplace_back(atoi(m_value[2].c_str()));
+ m_volume_facets.emplace_back(atoi(m_value[0].c_str()), atoi(m_value[1].c_str()), atoi(m_value[2].c_str()));
m_value[0].clear();
m_value[1].clear();
m_value[2].clear();
@@ -621,44 +617,36 @@ void AMFParserContext::endElement(const char * /* name */)
case NODE_TYPE_VOLUME:
{
assert(m_object && m_volume);
- TriangleMesh mesh;
- stl_file &stl = mesh.stl;
- stl.stats.type = inmemory;
- stl.stats.number_of_facets = int(m_volume_facets.size() / 3);
- stl.stats.original_num_facets = stl.stats.number_of_facets;
- stl_allocate(&stl);
-
- bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
- for (size_t i = 0; i < m_volume_facets.size();) {
- stl_facet &facet = stl.facet_start[i/3];
- for (unsigned int v = 0; v < 3; ++v)
- {
- unsigned int tri_id = m_volume_facets[i++] * 3;
- if (tri_id < 0 || tri_id + 2 >= m_object_vertices.size()) {
+ // Verify validity of face indices.
+ for (Vec3i face : m_volume_facets)
+ for (unsigned int tri_id : face)
+ if (tri_id < 0 || tri_id >= m_object_vertices.size()) {
this->stop("Malformed triangle mesh");
return;
}
- facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
- }
- }
- stl_get_size(&stl);
- mesh.repair();
- m_volume->set_mesh(std::move(mesh));
- // stores the volume matrix taken from the metadata, if present
- if (has_transform)
- m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
- if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
+
{
+ TriangleMesh triangle_mesh { std::move(m_object_vertices), std::move(m_volume_facets) };
+ if (triangle_mesh.volume() < 0)
+ triangle_mesh.flip_triangles();
+ m_volume->set_mesh(std::move(triangle_mesh));
+ }
+
+ // stores the volume matrix taken from the metadata, if present
+ if (bool has_transform = !m_volume_transform.isApprox(Transform3d::Identity(), 1e-10); has_transform)
+ m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
+
+ if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) {
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
m_volume->source.volume_idx = (int)m_model.objects.back()->volumes.size() - 1;
m_volume->center_geometry_after_creation();
- }
- else
+ } else
// pass false if the mesh offset has been already taken from the data
m_volume->center_geometry_after_creation(m_volume->source.input_file.empty());
m_volume->calculate_convex_hull();
m_volume_facets.clear();
+ m_object_vertices.clear();
m_volume = nullptr;
break;
}
@@ -1187,10 +1175,6 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
int num_vertices = 0;
for (ModelVolume *volume : object->volumes) {
vertices_offsets.push_back(num_vertices);
- if (! volume->mesh().repaired)
- throw Slic3r::FileIOError("store_amf() requires repair()");
- if (! volume->mesh().has_shared_vertices())
- throw Slic3r::FileIOError("store_amf() requires shared vertices");
const indexed_triangle_set &its = volume->mesh().its;
const Transform3d& matrix = volume->get_matrix();
for (size_t i = 0; i < its.vertices.size(); ++i) {
diff --git a/src/libslic3r/Format/OBJ.cpp b/src/libslic3r/Format/OBJ.cpp
index cb7eb4549..54c373ce3 100644
--- a/src/libslic3r/Format/OBJ.cpp
+++ b/src/libslic3r/Format/OBJ.cpp
@@ -19,7 +19,8 @@ namespace Slic3r {
bool load_obj(const char *path, TriangleMesh *meshptr)
{
- if(meshptr == nullptr) return false;
+ if (meshptr == nullptr)
+ return false;
// Parse the OBJ file.
ObjParser::ObjData data;
@@ -31,84 +32,69 @@ bool load_obj(const char *path, TriangleMesh *meshptr)
// Count the faces and verify, that all faces are triangular.
size_t num_faces = 0;
size_t num_quads = 0;
- for (size_t i = 0; i < data.vertices.size(); ) {
+ for (size_t i = 0; i < data.vertices.size(); ++ i) {
+ // Find the end of face.
size_t j = i;
for (; j < data.vertices.size() && data.vertices[j].coordIdx != -1; ++ j) ;
- if (i == j)
- continue;
- size_t face_vertices = j - i;
- if (face_vertices != 3 && face_vertices != 4) {
- // Non-triangular and non-quad faces are not supported as of now.
- return false;
+ if (size_t num_face_vertices = j - i; num_face_vertices > 0) {
+ if (num_face_vertices > 4) {
+ // Non-triangular and non-quad faces are not supported as of now.
+ BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with more than 4 vertices.";
+ return false;
+ } else if (num_face_vertices < 3) {
+ // Non-triangular and non-quad faces are not supported as of now.
+ BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with less than 2 vertices.";
+ return false;
+ }
+ if (num_face_vertices == 4)
+ ++ num_quads;
+ ++ num_faces;
+ i = j;
}
- if (face_vertices == 4)
- ++ num_quads;
- ++ num_faces;
- i = j + 1;
}
- // Convert ObjData into STL.
- TriangleMesh &mesh = *meshptr;
- stl_file &stl = mesh.stl;
- stl.stats.type = inmemory;
- stl.stats.number_of_facets = uint32_t(num_faces + num_quads);
- stl.stats.original_num_facets = int(num_faces + num_quads);
- // stl_allocate clears all the allocated data to zero, all normals are set to zeros as well.
- stl_allocate(&stl);
- size_t i_face = 0;
- for (size_t i = 0; i < data.vertices.size(); ++ i) {
- if (data.vertices[i].coordIdx == -1)
- continue;
- stl_facet &facet = stl.facet_start[i_face ++];
- size_t num_normals = 0;
- stl_normal normal(stl_normal::Zero());
- for (unsigned int v = 0; v < 3; ++ v) {
- const ObjParser::ObjVertex &vertex = data.vertices[i++];
- memcpy(facet.vertex[v].data(), &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
- if (vertex.normalIdx != -1) {
- normal(0) += data.normals[vertex.normalIdx*3];
- normal(1) += data.normals[vertex.normalIdx*3+1];
- normal(2) += data.normals[vertex.normalIdx*3+2];
- ++ num_normals;
- }
- }
- // Result of obj_parseline() call is not checked, thus not all vertices are necessarily finalized with coord_Idx == -1.
- if (i < data.vertices.size() && data.vertices[i].coordIdx != -1) {
- // This is a quad. Produce the other triangle.
- stl_facet &facet2 = stl.facet_start[i_face++];
- facet2.vertex[0] = facet.vertex[0];
- facet2.vertex[1] = facet.vertex[2];
- const ObjParser::ObjVertex &vertex = data.vertices[i++];
- memcpy(facet2.vertex[2].data(), &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
- if (vertex.normalIdx != -1) {
- normal(0) += data.normals[vertex.normalIdx*3];
- normal(1) += data.normals[vertex.normalIdx*3+1];
- normal(2) += data.normals[vertex.normalIdx*3+2];
- ++ num_normals;
- }
- if (num_normals == 4) {
- // Normalize an average normal of a quad.
- float len = facet.normal.norm();
- if (len > EPSILON) {
- normal /= len;
- facet.normal = normal;
- facet2.normal = normal;
- }
- }
- } else if (num_normals == 3) {
- // Normalize an average normal of a triangle.
- float len = facet.normal.norm();
- if (len > EPSILON)
- facet.normal = normal / len;
- }
+ // Convert ObjData into indexed triangle set.
+ indexed_triangle_set its;
+ size_t num_vertices = data.coordinates.size() / 4;
+ its.vertices.reserve(num_vertices);
+ its.indices.reserve(num_faces + num_quads);
+ for (size_t i = 0; i < num_vertices; ++ i) {
+ size_t j = i << 2;
+ its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
}
- stl_get_size(&stl);
- mesh.repair();
- if (mesh.facets_count() == 0) {
+ int indices[4];
+ for (size_t i = 0; i < data.vertices.size();)
+ if (data.vertices[i].coordIdx == -1)
+ ++ i;
+ else {
+ int cnt = 0;
+ while (i < data.vertices.size())
+ if (const ObjParser::ObjVertex &vertex = data.vertices[i ++]; vertex.coordIdx == -1) {
+ break;
+ } else {
+ assert(cnt < 4);
+ if (vertex.coordIdx < 0 || vertex.coordIdx >= its.vertices.size()) {
+ BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index.";
+ return false;
+ }
+ indices[cnt ++] = vertex.coordIdx;
+ }
+ if (cnt) {
+ assert(cnt == 3 || cnt == 4);
+ // Insert one or two faces (triangulate a quad).
+ its.indices.emplace_back(indices[0], indices[1], indices[2]);
+ if (cnt == 4)
+ its.indices.emplace_back(indices[0], indices[2], indices[3]);
+ }
+ }
+
+ *meshptr = TriangleMesh(std::move(its));
+ if (meshptr->empty()) {
BOOST_LOG_TRIVIAL(error) << "load_obj: This OBJ file couldn't be read because it's empty. " << path;
return false;
}
-
+ if (meshptr->volume() < 0)
+ meshptr->flip_triangles();
return true;
}
diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
deleted file mode 100644
index 586fbafb5..000000000
--- a/src/libslic3r/Format/PRUS.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-#include
-#include
-
-#include
-
-#include "miniz_extension.hpp"
-
-#include
-
-#include "../libslic3r.h"
-#include "../Model.hpp"
-
-#include "PRUS.hpp"
-
-#if 0
-// Enable debugging and assert in this file.
-#define DEBUG
-#define _DEBUG
-#undef NDEBUG
-#endif
-
-#include
-
-namespace Slic3r
-{
-
-struct StlHeader
-{
- char comment[80];
- uint32_t nTriangles;
-};
-
-static_assert(sizeof(StlHeader) == 84, "StlHeader size not correct");
-
-// Buffered line reader to a string buffer.
-class LineReader
-{
-public:
- LineReader(std::vector &data) : m_buffer(data), m_pos(0), m_len((int)data.size()) {}
-
- const char* next_line() {
- // Skip empty lines.
- while (m_pos < m_len && (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n'))
- ++ m_pos;
- if (m_pos == m_len) {
- // End of file.
- return nullptr;
- }
- // The buffer is nonempty and it does not start with end of lines. Find the first end of line.
- int end = m_pos + 1;
- while (end < m_len && m_buffer[end] != '\r' && m_buffer[end] != '\n')
- ++ end;
- char *ptr_out = m_buffer.data() + m_pos;
- m_pos = end + 1;
- m_buffer[end] = 0;
- return ptr_out;
- }
-
- int next_line_scanf(const char *format, ...)
- {
- const char *line = next_line();
- if (line == nullptr)
- return -1;
- int result;
- va_list arglist;
- va_start(arglist, format);
- result = vsscanf(line, format, arglist);
- va_end(arglist);
- return result;
- }
-
-private:
- std::vector &m_buffer;
- int m_pos;
- int m_len;
-};
-
-static void extract_model_from_archive(
- // name of the model file
- const char *name,
- // path to the archive
- const char *path,
- // content of scene.xml
- const std::vector &scene_xml_data,
- // loaded data of this STL
- std::vector &data,
- // Model, to which the newly loaded objects will be added
- Model *model,
- // To map multiple STLs into a single model object for multi-material prints.
- std::map &group_to_model_object)
-{
- // Find the model entry in the XML data.
- char model_name_tag[1024];
- sprintf(model_name_tag, "", name);
- const char *model_xml = strstr(scene_xml_data.data(), model_name_tag);
- const char *zero_tag = "";
- const char *zero_xml = strstr(scene_xml_data.data(), zero_tag);
- Vec3d instance_rotation = Vec3d::Zero();
- Vec3d instance_scaling_factor = Vec3d::Ones();
- Vec3d instance_offset = Vec3d::Zero();
- bool trafo_set = false;
- unsigned int group_id = (unsigned int)-1;
- unsigned int extruder_id = (unsigned int)-1;
- ModelObject *model_object = nullptr;
- if (model_xml != nullptr) {
- model_xml += strlen(model_name_tag);
- const char *position_tag = "";
- const char *position_xml = strstr(model_xml, position_tag);
- const char *rotation_tag = "";
- const char *rotation_xml = strstr(model_xml, rotation_tag);
- const char *scale_tag = "";
- const char *scale_xml = strstr(model_xml, scale_tag);
- float position[3], rotation[3], scale[3], zero[3];
- if (position_xml != nullptr && rotation_xml != nullptr && scale_xml != nullptr && zero_xml != nullptr &&
- sscanf(position_xml+strlen(position_tag),
- "[%f, %f, %f]", position, position+1, position+2) == 3 &&
- sscanf(rotation_xml+strlen(rotation_tag),
- "[%f, %f, %f]", rotation, rotation+1, rotation+2) == 3 &&
- sscanf(scale_xml+strlen(scale_tag),
- "[%f, %f, %f]", scale, scale+1, scale+2) == 3 &&
- sscanf(zero_xml+strlen(zero_tag),
- "[%f, %f, %f]", zero, zero+1, zero+2) == 3) {
- instance_scaling_factor = Vec3d((double)scale[0], (double)scale[1], (double)scale[2]);
- instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
- instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
- trafo_set = true;
- }
- const char *group_tag = "";
- const char *group_xml = strstr(model_xml, group_tag);
- const char *extruder_tag = "";
- const char *extruder_xml = strstr(model_xml, extruder_tag);
- if (group_xml != nullptr) {
- int group = atoi(group_xml + strlen(group_tag));
- if (group > 0) {
- group_id = group;
- auto it = group_to_model_object.find(group_id);
- if (it != group_to_model_object.end())
- model_object = it->second;
- }
- }
- if (extruder_xml != nullptr) {
- int e = atoi(extruder_xml + strlen(extruder_tag));
- if (e > 0)
- extruder_id = e;
- }
- }
- if (! trafo_set)
- throw Slic3r::FileIOError(std::string("Archive ") + path + " does not contain a valid entry in scene.xml for " + name);
-
- // Extract the STL.
- StlHeader header;
- TriangleMesh mesh;
- bool mesh_valid = false;
- bool stl_ascii = false;
- if (data.size() > sizeof(StlHeader)) {
- memcpy((char*)&header, data.data(), sizeof(StlHeader));
- if (strncmp(header.comment, "solid ", 6) == 0)
- stl_ascii = true;
- else {
- // Header has been extracted. Now read the faces.
- stl_file &stl = mesh.stl;
- stl.stats.type = inmemory;
- stl.stats.number_of_facets = header.nTriangles;
- stl.stats.original_num_facets = header.nTriangles;
- stl_allocate(&stl);
- if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) {
- memcpy((char*)stl.facet_start.data(), data.data() + sizeof(StlHeader), 50 * header.nTriangles);
- if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
- // The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
- unsigned char *data = (unsigned char*)stl.facet_start.data();
- for (size_t i = header.nTriangles - 1; i > 0; -- i)
- memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
- }
- // All the faces have been read.
- stl_get_size(&stl);
- mesh.repair();
- if (std::abs(stl.stats.min(2)) < EPSILON)
- stl.stats.min(2) = 0.;
- // Add a mesh to a model.
- if (mesh.facets_count() > 0)
- mesh_valid = true;
- }
- }
- } else
- stl_ascii = true;
-
- if (stl_ascii) {
- // Try to parse ASCII STL.
- char normal_buf[3][32];
- stl_facet facet;
- std::vector facets;
- LineReader line_reader(data);
- std::string solid_name;
- facet.extra[0] = facet.extra[1] = 0;
- for (;;) {
- const char *line = line_reader.next_line();
- if (line == nullptr)
- // End of file.
- break;
- if (strncmp(line, "solid", 5) == 0) {
- // Opening the "solid" block.
- if (! solid_name.empty()) {
- // Error, solid block is already open.
- facets.clear();
- break;
- }
- solid_name = line + 5;
- if (solid_name.empty())
- solid_name = "unknown";
- continue;
- }
- if (strncmp(line, "endsolid", 8) == 0) {
- // Closing the "solid" block.
- if (solid_name.empty()) {
- // Error, no solid block is open.
- facets.clear();
- break;
- }
- solid_name.clear();
- continue;
- }
- // Line has to start with the word solid.
- int res_normal = sscanf(line, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
- assert(res_normal == 3);
- int res_outer_loop = line_reader.next_line_scanf(" outer loop");
- assert(res_outer_loop == 0);
- int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
- assert(res_vertex1 == 3);
- int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
- assert(res_vertex2 == 3);
- int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
- assert(res_vertex3 == 3);
- int res_endloop = line_reader.next_line_scanf(" endloop");
- assert(res_endloop == 0);
- int res_endfacet = line_reader.next_line_scanf(" endfacet");
- if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
- // perror("Something is syntactically very wrong with this ASCII STL!");
- facets.clear();
- break;
- }
- // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
- if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
- sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
- sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
- // Normal was mangled. Maybe denormals or "not a number" were stored?
- // Just reset the normal and silently ignore it.
- facet.normal = stl_normal::Zero();
- }
- facets.emplace_back(facet);
- }
- if (! facets.empty() && solid_name.empty()) {
- stl_file &stl = mesh.stl;
- stl.stats.type = inmemory;
- stl.stats.number_of_facets = (uint32_t)facets.size();
- stl.stats.original_num_facets = (int)facets.size();
- stl_allocate(&stl);
- memcpy((void*)stl.facet_start.data(), facets.data(), facets.size() * 50);
- stl_get_size(&stl);
- mesh.repair();
- // Add a mesh to a model.
- if (mesh.facets_count() > 0)
- mesh_valid = true;
- }
- }
-
- if (! mesh_valid)
- throw Slic3r::FileIOError(std::string("Archive ") + path + " does not contain a valid mesh for " + name);
-
- // Add this mesh to the model.
- ModelVolume *volume = nullptr;
- if (model_object == nullptr) {
- // This is a first mesh of a group. Create a new object & volume.
- model_object = model->add_object(name, path, std::move(mesh));
- volume = model_object->volumes.front();
- ModelInstance *instance = model_object->add_instance();
- instance->set_rotation(instance_rotation);
- instance->set_scaling_factor(instance_scaling_factor);
- instance->set_offset(instance_offset);
- if (group_id != (unsigned int)(-1))
- group_to_model_object[group_id] = model_object;
- } else {
- // This is not the 1st mesh of a group. Add it to the ModelObject.
- volume = model_object->add_volume(std::move(mesh));
- volume->name = name;
- }
- // Set the extruder to the volume.
- if (extruder_id != (unsigned int)-1)
- volume->config.set("extruder", int(extruder_id));
-}
-
-// Load a PrusaControl project file into a provided model.
-bool load_prus(const char *path, Model *model)
-{
- mz_zip_archive archive;
- mz_zip_zero_struct(&archive);
-
- size_t n_models_initial = model->objects.size();
- mz_bool res = MZ_FALSE;
- try {
- if (!open_zip_reader(&archive, path))
- throw Slic3r::FileIOError(std::string("Unable to init zip reader for ") + path);
- std::vector scene_xml_data;
- // For grouping multiple STLs into a single ModelObject for multi-material prints.
- std::map group_to_model_object;
- mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
- for (mz_uint i = 0; i < num_entries; ++ i) {
- mz_zip_archive_file_stat stat;
- if (! mz_zip_reader_file_stat(&archive, i, &stat))
- continue;
- std::vector buffer;
- buffer.assign((size_t)stat.m_uncomp_size, 0);
- res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (char*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
- if (res == MZ_FALSE)
- throw Slic3r::FileIOError(std::string("Error while extracting a file from ") + path);
- if (strcmp(stat.m_filename, "scene.xml") == 0) {
- if (! scene_xml_data.empty())
- throw Slic3r::FileIOError(std::string("Multiple scene.xml were found in the archive.") + path);
- scene_xml_data = std::move(buffer);
- } else if (boost::iends_with(stat.m_filename, ".stl")) {
- // May throw std::exception
- extract_model_from_archive(stat.m_filename, path, scene_xml_data, buffer, model, group_to_model_object);
- }
- }
- } catch (std::exception &ex) {
- close_zip_reader(&archive);
- throw ex;
- }
-
- close_zip_reader(&archive);
- return model->objects.size() > n_models_initial;
-}
-
-}; // namespace Slic3r
diff --git a/src/libslic3r/Format/PRUS.hpp b/src/libslic3r/Format/PRUS.hpp
deleted file mode 100644
index be5c5c61a..000000000
--- a/src/libslic3r/Format/PRUS.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#define slic3r_Format_PRUS_hpp_
-
-namespace Slic3r {
-
-class TriangleMesh;
-class Model;
-
-// Load a PrusaControl project file into a provided model.
-extern bool load_prus(const char *path, Model *model);
-
-}; // namespace Slic3r
diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp
index e2ef801f2..4ddc584ba 100644
--- a/src/libslic3r/Format/SL1.cpp
+++ b/src/libslic3r/Format/SL1.cpp
@@ -203,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
!opt_mirror_x || !opt_mirror_y || !opt_orient)
- throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
+ throw MissingProfileError("Invalid SL1 / SL1S file");
RasterParams rstp;
@@ -229,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg)
auto *opt_init_layerh = cfg.option("initial_layer_height");
if (!opt_layerh || !opt_init_layerh)
- throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
+ throw MissingProfileError("Invalid SL1 / SL1S file");
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
}
@@ -293,24 +293,34 @@ ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrint
return out.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
}
+// If the profile is missing from the archive (older PS versions did not have
+// it), profile_out's initial value will be used as fallback. profile_out will be empty on
+// function return if the archive did not contain any profile.
ConfigSubstitutions import_sla_archive(
const std::string & zipfname,
Vec2i windowsize,
indexed_triangle_set & out,
- DynamicPrintConfig & profile,
+ DynamicPrintConfig & profile_out,
std::function progr)
{
// Ensure minimum window size for marching squares
windowsize.x() = std::max(2, windowsize.x());
windowsize.y() = std::max(2, windowsize.y());
- ArchiveData arch = extract_sla_archive(zipfname, "thumbnail");
- ConfigSubstitutions config_substitutions = profile.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
+ std::string exclude_entries{"thumbnail"};
+ ArchiveData arch = extract_sla_archive(zipfname, exclude_entries);
+ DynamicPrintConfig profile_in, profile_use;
+ ConfigSubstitutions config_substitutions = profile_in.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
- RasterParams rstp = get_raster_params(profile);
+ // If the archive contains an empty profile, use the one that was passed as output argument
+ // then replace it with the readed profile to report that it was empty.
+ profile_use = profile_in.empty() ? profile_out : profile_in;
+ profile_out = profile_in;
+
+ RasterParams rstp = get_raster_params(profile_use);
rstp.win = {windowsize.y(), windowsize.x()};
- SliceParams slicp = get_slice_params(profile);
+ SliceParams slicp = get_slice_params(profile_use);
std::vector slices =
extract_slices_from_sla_archive(arch, rstp, progr);
diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp
index 2c7e1edc1..7f4356b12 100644
--- a/src/libslic3r/Format/SL1.hpp
+++ b/src/libslic3r/Format/SL1.hpp
@@ -8,7 +8,7 @@
namespace Slic3r {
-class SL1Archive: public SLAPrinter {
+class SL1Archive: public SLAArchive {
SLAPrinterConfig m_cfg;
protected:
@@ -57,6 +57,8 @@ inline ConfigSubstitutions import_sla_archive(
return import_sla_archive(zipfname, windowsize, out, profile, progr);
}
+class MissingProfileError : public RuntimeError { using RuntimeError::RuntimeError; };
+
} // namespace Slic3r::sla
#endif // ARCHIVETRAITS_HPP
diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp
index 932906fe0..2f2c9ec7f 100644
--- a/src/libslic3r/Format/STL.cpp
+++ b/src/libslic3r/Format/STL.cpp
@@ -21,8 +21,7 @@ bool load_stl(const char *path, Model *model, const char *object_name_in)
// die "Failed to open $file\n" if !-e $path;
return false;
}
- mesh.repair();
- if (mesh.facets_count() == 0) {
+ if (mesh.empty()) {
// die "This STL file couldn't be read because it's empty.\n"
return false;
}
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index cebc9136f..ff0a7c027 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -784,7 +784,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
}
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
- m_processor.finalize();
+ // Post-process the G-code to update time stamps.
+ m_processor.finalize(true);
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
if (result != nullptr) {
@@ -1842,11 +1843,7 @@ namespace ProcessLayer
assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change.
// add tag for processor
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "," + custom_gcode->color + "\n";
-#else
- gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index d16cfb9cf..2397a17ff 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -2,6 +2,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/LocalesUtils.hpp"
+#include "libslic3r/format.hpp"
#include "GCodeProcessor.hpp"
#include
@@ -27,9 +28,7 @@ static const float DEFAULT_TOOLPATH_HEIGHT = 0.2f;
static const float INCHES_TO_MM = 25.4f;
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
-#if ENABLE_RETRACT_ACCELERATION
static const float DEFAULT_RETRACT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
-#endif // ENABLE_RETRACT_ACCELERATION
static const float DEFAULT_TRAVEL_ACCELERATION = 1250.0f;
static const size_t MIN_EXTRUDERS_COUNT = 5;
@@ -184,10 +183,8 @@ void GCodeProcessor::TimeMachine::reset()
enabled = false;
acceleration = 0.0f;
max_acceleration = 0.0f;
-#if ENABLE_RETRACT_ACCELERATION
retract_acceleration = 0.0f;
max_retract_acceleration = 0.0f;
-#endif // ENABLE_RETRACT_ACCELERATION
travel_acceleration = 0.0f;
max_travel_acceleration = 0.0f;
extrude_factor_override_percentage = 1.0f;
@@ -347,18 +344,6 @@ void GCodeProcessor::TimeProcessor::reset()
machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].enabled = true;
}
-struct FilePtr {
- FilePtr(FILE *f) : f(f) {}
- ~FilePtr() { this->close(); }
- void close() {
- if (this->f) {
- ::fclose(this->f);
- this->f = nullptr;
- }
- }
- FILE* f = nullptr;
-};
-
void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector& moves, std::vector& lines_ends)
{
FilePtr in{ boost::nowide::fopen(filename.c_str(), "rb") };
@@ -740,9 +725,7 @@ void GCodeProcessor::Result::reset() {
extruder_colors = std::vector();
filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
custom_gcode_per_print_z = std::vector();
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
time = 0;
}
#else
@@ -756,18 +739,19 @@ void GCodeProcessor::Result::reset() {
extruder_colors = std::vector();
filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
custom_gcode_per_print_z = std::vector();
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
}
#endif // ENABLE_GCODE_VIEWER_STATISTICS
const std::vector> GCodeProcessor::Producers = {
- { EProducer::PrusaSlicer, "PrusaSlicer" },
- { EProducer::Slic3rPE, "Slic3r Prusa Edition" },
- { EProducer::Slic3r, "Slic3r" },
+ { EProducer::PrusaSlicer, "generated by PrusaSlicer" },
+ { EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
+ { EProducer::Slic3r, "generated by Slic3r" },
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ { EProducer::SuperSlicer, "generated by SuperSlicer" },
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
{ EProducer::Cura, "Cura_SteamEngine" },
- { EProducer::Simplify3D, "Simplify3D" },
+ { EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
{ EProducer::CraftWare, "CraftWare" },
{ EProducer::ideaMaker, "ideaMaker" },
{ EProducer::KissSlicer, "KISSlicer" }
@@ -849,26 +833,16 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_result.extruders_count = extruders_count;
m_extruder_offsets.resize(extruders_count);
- for (size_t i = 0; i < extruders_count; ++i) {
- Vec2f offset = config.extruder_offset.get_at(i).cast();
- m_extruder_offsets[i] = { offset(0), offset(1), 0.0f };
- }
-
m_extruder_colors.resize(extruders_count);
- for (size_t i = 0; i < extruders_count; ++i) {
- m_extruder_colors[i] = static_cast(i);
- }
-
+ m_result.filament_diameters.resize(extruders_count);
+ m_result.filament_densities.resize(extruders_count);
m_extruder_temps.resize(extruders_count);
- m_result.filament_diameters.resize(config.filament_diameter.values.size());
- for (size_t i = 0; i < config.filament_diameter.values.size(); ++i) {
- m_result.filament_diameters[i] = static_cast(config.filament_diameter.values[i]);
- }
-
- m_result.filament_densities.resize(config.filament_density.values.size());
- for (size_t i = 0; i < config.filament_density.values.size(); ++i) {
- m_result.filament_densities[i] = static_cast(config.filament_density.values[i]);
+ for (size_t i = 0; i < extruders_count; ++ i) {
+ m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast().eval(), 0.f);
+ m_extruder_colors[i] = static_cast(i);
+ m_result.filament_diameters[i] = static_cast(config.filament_diameter.get_at(i));
+ m_result.filament_densities[i] = static_cast(config.filament_density.get_at(i));
}
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
@@ -895,11 +869,9 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
m_time_processor.machines[i].max_acceleration = max_acceleration;
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
-#if ENABLE_RETRACT_ACCELERATION
float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
-#endif // ENABLE_RETRACT_ACCELERATION
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
@@ -1117,11 +1089,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
m_time_processor.machines[i].max_acceleration = max_acceleration;
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
-#if ENABLE_RETRACT_ACCELERATION
float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
-#endif // ENABLE_RETRACT_ACCELERATION
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
@@ -1200,9 +1170,7 @@ void GCodeProcessor::reset()
m_result.id = ++s_result_id;
m_use_volumetric_e = false;
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
m_last_default_color_id = 0;
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.reset();
@@ -1215,6 +1183,18 @@ void GCodeProcessor::reset()
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
+static inline const char* skip_whitespaces(const char *begin, const char *end) {
+ for (; begin != end && (*begin == ' ' || *begin == '\t'); ++ begin);
+ return begin;
+}
+
+static inline const char* remove_eols(const char *begin, const char *end) {
+ for (; begin != end && (*(end - 1) == '\r' || *(end - 1) == '\n'); -- end);
+ return end;
+}
+
+// Load a G-code into a stand-alone G-code viewer.
+// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
void GCodeProcessor::process_file(const std::string& filename, std::function cancel_callback)
{
CNumericLocalesSetter locales_setter;
@@ -1226,14 +1206,16 @@ void GCodeProcessor::process_file(const std::string& filename, std::function 1 && detect_producer(comment))
+ m_parser.parse_file_raw(filename, [this](GCodeReader& reader, const char *begin, const char *end) {
+ begin = skip_whitespaces(begin, end);
+ if (begin != end && *begin == ';') {
+ // Comment.
+ begin = skip_whitespaces(++ begin, end);
+ end = remove_eols(begin, end);
+ if (begin != end && detect_producer(std::string_view(begin, end - begin)))
m_parser.quit_parsing();
}
- });
+ });
m_parser.reset();
// if the gcode was produced by PrusaSlicer,
@@ -1249,6 +1231,10 @@ void GCodeProcessor::process_file(const std::string& filename, std::functionprocess_gcode_line(line, true);
});
- this->finalize();
+ // Don't post-process the G-code to update time stamps.
+ this->finalize(false);
}
void GCodeProcessor::initialize(const std::string& filename)
@@ -1293,7 +1280,7 @@ void GCodeProcessor::process_buffer(const std::string &buffer)
});
}
-void GCodeProcessor::finalize()
+void GCodeProcessor::finalize(bool post_process)
{
// update width/height of wipe moves
for (MoveVertex& move : m_result.moves) {
@@ -1323,7 +1310,8 @@ void GCodeProcessor::finalize()
m_width_compare.output();
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
- m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends);
+ if (post_process)
+ m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends);
#if ENABLE_GCODE_VIEWER_STATISTICS
m_result.time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@@ -1380,6 +1368,41 @@ std::vector> GCodeProcessor::get_roles_time(Prin
return ret;
}
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
+{
+ // for reference, see: ConfigBase::load_from_gcode_file()
+
+ boost::nowide::ifstream ifs(filename);
+
+ auto header_end_pos = ifs.tellg();
+ ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
+ size_t key_value_pairs = 0;
+
+ ifs.seekg(0, ifs.end);
+ auto file_length = ifs.tellg();
+ auto data_length = std::min(65535, file_length - header_end_pos);
+ ifs.seekg(file_length - data_length, ifs.beg);
+ std::vector data(size_t(data_length) + 1, 0);
+ ifs.read(data.data(), data_length);
+ ifs.close();
+ key_value_pairs = ConfigBase::load_from_gcode_string_legacy(config, data.data(), substitutions_ctxt);
+
+ if (key_value_pairs < 80)
+ throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", filename, key_value_pairs));
+
+ return std::move(substitutions_ctxt.substitutions);
+}
+
+void GCodeProcessor::apply_config_superslicer(const std::string& filename)
+{
+ DynamicPrintConfig config;
+ config.apply(FullPrintConfig::defaults());
+ load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent);
+ apply_config(config);
+}
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+
std::vector GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
{
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ?
@@ -1398,9 +1421,11 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
};
BedSize bed_size;
+ bool producer_detected = false;
- m_parser.parse_file(filename, [this, &bed_size](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
- auto extract_double = [](const std::string& cmt, const std::string& key, double& out) {
+ m_parser.parse_file_raw(filename, [this, &bed_size, &producer_detected](GCodeReader& reader, const char* begin, const char* end) {
+
+ auto extract_double = [](const std::string_view cmt, const std::string& key, double& out) {
size_t pos = cmt.find(key);
if (pos != cmt.npos) {
pos = cmt.find(',', pos);
@@ -1412,12 +1437,12 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
return false;
};
- auto extract_floats = [](const std::string& cmt, const std::string& key, std::vector& out) {
+ auto extract_floats = [](const std::string_view cmt, const std::string& key, std::vector& out) {
size_t pos = cmt.find(key);
if (pos != cmt.npos) {
pos = cmt.find(',', pos);
if (pos != cmt.npos) {
- std::string data_str = cmt.substr(pos + 1);
+ const std::string_view data_str = cmt.substr(pos + 1);
std::vector values_str;
boost::split(values_str, data_str, boost::is_any_of("|,"), boost::token_compress_on);
for (const std::string& s : values_str) {
@@ -1428,28 +1453,39 @@ void GCodeProcessor::apply_config_simplify3d(const std::string& filename)
}
return false;
};
-
- const std::string& comment = line.raw();
- if (comment.length() > 2 && comment.front() == ';') {
- if (bed_size.x == 0.0 && comment.find("strokeXoverride") != comment.npos)
- extract_double(comment, "strokeXoverride", bed_size.x);
- else if (bed_size.y == 0.0 && comment.find("strokeYoverride") != comment.npos)
- extract_double(comment, "strokeYoverride", bed_size.y);
- else if (comment.find("filamentDiameters") != comment.npos) {
- m_result.filament_diameters.clear();
- extract_floats(comment, "filamentDiameters", m_result.filament_diameters);
+
+ begin = skip_whitespaces(begin, end);
+ end = remove_eols(begin, end);
+ if (begin != end)
+ if (*begin == ';') {
+ // Comment.
+ begin = skip_whitespaces(++ begin, end);
+ if (begin != end) {
+ std::string_view comment(begin, end - begin);
+ if (producer_detected) {
+ if (bed_size.x == 0.0 && comment.find("strokeXoverride") != comment.npos)
+ extract_double(comment, "strokeXoverride", bed_size.x);
+ else if (bed_size.y == 0.0 && comment.find("strokeYoverride") != comment.npos)
+ extract_double(comment, "strokeYoverride", bed_size.y);
+ else if (comment.find("filamentDiameters") != comment.npos) {
+ m_result.filament_diameters.clear();
+ extract_floats(comment, "filamentDiameters", m_result.filament_diameters);
+ } else if (comment.find("filamentDensities") != comment.npos) {
+ m_result.filament_densities.clear();
+ extract_floats(comment, "filamentDensities", m_result.filament_densities);
+ } else if (comment.find("extruderDiameter") != comment.npos) {
+ std::vector extruder_diameters;
+ extract_floats(comment, "extruderDiameter", extruder_diameters);
+ m_result.extruders_count = extruder_diameters.size();
+ }
+ } else if (boost::starts_with(comment, "G-Code generated by Simplify3D(R)"))
+ producer_detected = true;
+ }
+ } else {
+ // Some non-empty G-code line detected, stop parsing config comments.
+ reader.quit_parsing();
}
- else if (comment.find("filamentDensities") != comment.npos) {
- m_result.filament_densities.clear();
- extract_floats(comment, "filamentDensities", m_result.filament_densities);
- }
- else if (comment.find("extruderDiameter") != comment.npos) {
- std::vector extruder_diameters;
- extract_floats(comment, "extruderDiameter", extruder_diameters);
- m_result.extruders_count = extruder_diameters.size();
- }
- }
- });
+ });
if (m_result.extruders_count == 0)
m_result.extruders_count = std::max(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size()));
@@ -1741,7 +1777,6 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// color change tag
if (boost::starts_with(comment, reserved_tag(ETags::Color_Change))) {
unsigned char extruder_id = 0;
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
static std::vector Default_Colors = {
"#0B2C7A", // { 0.043f, 0.173f, 0.478f }, // bluish
"#1C8891", // { 0.110f, 0.533f, 0.569f },
@@ -1790,16 +1825,6 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
if (m_last_default_color_id == Default_Colors.size())
m_last_default_color_id = 0;
}
-#else
- if (boost::starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) {
- int eid;
- if (!parse_number(comment.substr(reserved_tag(ETags::Color_Change).size() + 2), eid) || eid < 0 || eid > 255) {
- BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
- return;
- }
- extruder_id = static_cast(eid);
- }
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
if (extruder_id < m_extruder_colors.size())
m_extruder_colors[extruder_id] = static_cast(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview
@@ -1810,7 +1835,6 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
if (m_extruder_id == extruder_id) {
m_cp_color.current = m_extruder_colors[extruder_id];
store_move_vertex(EMoveType::Color_change);
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
@@ -1818,27 +1842,19 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
process_custom_gcode_time(CustomGCode::ColorChange);
process_filaments(CustomGCode::ColorChange);
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
}
-#if !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
- process_custom_gcode_time(CustomGCode::ColorChange);
- process_filaments(CustomGCode::ColorChange);
-#endif // !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
-
return;
}
// pause print tag
if (comment == reserved_tag(ETags::Pause_Print)) {
store_move_vertex(EMoveType::Pause_Print);
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
process_custom_gcode_time(CustomGCode::PausePrint);
return;
}
@@ -1846,13 +1862,11 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// custom code tag
if (comment == reserved_tag(ETags::Custom_Code)) {
store_move_vertex(EMoveType::Custom_GCode);
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" };
m_result.custom_gcode_per_print_z.emplace_back(item);
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
m_options_z_corrector.set();
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
return;
}
@@ -1878,6 +1892,9 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{
case EProducer::Slic3rPE:
case EProducer::Slic3r:
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ case EProducer::SuperSlicer:
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
@@ -2707,15 +2724,15 @@ void GCodeProcessor::process_G28(const GCodeReader::GCodeLine& line)
std::string_view cmd = line.cmd();
std::string new_line_raw = { cmd.data(), cmd.size() };
bool found = false;
- if (line.has_x()) {
+ if (line.has('X')) {
new_line_raw += " X0";
found = true;
}
- if (line.has_y()) {
+ if (line.has('Y')) {
new_line_raw += " Y0";
found = true;
}
- if (line.has_z()) {
+ if (line.has('Z')) {
new_line_raw += " Z0";
found = true;
}
@@ -2851,16 +2868,16 @@ void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line)
// see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md
// Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082
- if (line.has_x())
+ if (line.has('X'))
m_origin[X] = 0.0f;
- if (line.has_y())
+ if (line.has('Y'))
m_origin[Y] = 0.0f;
- if (line.has_z())
+ if (line.has('Z'))
m_origin[Z] = 0.0f;
- if (line.has_e())
+ if (line.has('E'))
m_origin[E] = 0.0f;
}
@@ -2943,22 +2960,14 @@ void GCodeProcessor::process_M204(const GCodeReader::GCodeLine& line)
set_acceleration(static_cast(i), value);
set_travel_acceleration(static_cast(i), value);
if (line.has_value('T', value))
-#if ENABLE_RETRACT_ACCELERATION
set_retract_acceleration(static_cast(i), value);
-#else
- set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
-#endif // ENABLE_RETRACT_ACCELERATION
}
else {
// New acceleration format, compatible with the upstream Marlin.
if (line.has_value('P', value))
set_acceleration(static_cast(i), value);
if (line.has_value('R', value))
-#if ENABLE_RETRACT_ACCELERATION
set_retract_acceleration(static_cast(i), value);
-#else
- set_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i, value);
-#endif // ENABLE_RETRACT_ACCELERATION
if (line.has_value('T', value))
// Interpret the T value as the travel acceleration in the new Marlin format.
set_travel_acceleration(static_cast(i), value);
@@ -3029,7 +3038,7 @@ void GCodeProcessor::process_M402(const GCodeReader::GCodeLine& line)
// https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp
// void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed)
- bool has_xyz = !(line.has_x() || line.has_y() || line.has_z());
+ bool has_xyz = !(line.has('X') || line.has('Y') || line.has('Z'));
float p = FLT_MAX;
for (unsigned char a = X; a <= Z; ++a) {
@@ -3216,20 +3225,12 @@ float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode
}
}
-#if ENABLE_RETRACT_ACCELERATION
float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
{
size_t id = static_cast(mode);
return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
}
-#else
-float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
-{
- return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, static_cast(mode));
-}
-#endif // ENABLE_RETRACT_ACCELERATION
-#if ENABLE_RETRACT_ACCELERATION
void GCodeProcessor::set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value)
{
size_t id = static_cast(mode);
@@ -3239,7 +3240,6 @@ void GCodeProcessor::set_retract_acceleration(PrintEstimatedStatistics::ETimeMod
std::min(value, m_time_processor.machines[id].max_retract_acceleration);
}
}
-#endif // ENABLE_RETRACT_ACCELERATION
float GCodeProcessor::get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
{
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index 040f7432a..fce888233 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -242,11 +242,9 @@ namespace Slic3r {
float acceleration; // mm/s^2
// hard limit for the acceleration, to which the firmware will clamp.
float max_acceleration; // mm/s^2
-#if ENABLE_RETRACT_ACCELERATION
float retract_acceleration; // mm/s^2
// hard limit for the acceleration, to which the firmware will clamp.
float max_retract_acceleration; // mm/s^2
-#endif // ENABLE_RETRACT_ACCELERATION
float travel_acceleration; // mm/s^2
// hard limit for the travel acceleration, to which the firmware will clamp.
float max_travel_acceleration; // mm/s^2
@@ -359,9 +357,7 @@ namespace Slic3r {
std::vector filament_diameters;
std::vector filament_densities;
PrintEstimatedStatistics print_statistics;
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
std::vector custom_gcode_per_print_z;
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
#if ENABLE_GCODE_VIEWER_STATISTICS
int64_t time{ 0 };
@@ -536,9 +532,7 @@ namespace Slic3r {
#if ENABLE_FIX_PREVIEW_OPTIONS_Z
OptionsZCorrector m_options_z_corrector;
#endif // ENABLE_FIX_PREVIEW_OPTIONS_Z
-#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
size_t m_last_default_color_id;
-#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER
#if ENABLE_GCODE_VIEWER_STATISTICS
std::chrono::time_point m_start_time;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@@ -549,6 +543,9 @@ namespace Slic3r {
PrusaSlicer,
Slic3rPE,
Slic3r,
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ SuperSlicer,
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
Cura,
Simplify3D,
CraftWare,
@@ -585,14 +582,14 @@ namespace Slic3r {
const Result& get_result() const { return m_result; }
Result&& extract_result() { return std::move(m_result); }
- // Process the gcode contained in the file with the given filename
+ // Load a G-code into a stand-alone G-code viewer.
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
void process_file(const std::string& filename, std::function cancel_callback = nullptr);
// Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion.
void initialize(const std::string& filename);
void process_buffer(const std::string& buffer);
- void finalize();
+ void finalize(bool post_process);
float get_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
@@ -605,6 +602,9 @@ namespace Slic3r {
private:
void apply_config(const DynamicPrintConfig& config);
void apply_config_simplify3d(const std::string& filename);
+#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
+ void apply_config_superslicer(const std::string& filename);
+#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
// Process tags embedded into comments
@@ -724,9 +724,7 @@ namespace Slic3r {
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
-#if ENABLE_RETRACT_ACCELERATION
void set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value);
-#endif // ENABLE_RETRACT_ACCELERATION
float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
void set_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value);
float get_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp
index 61ab10f22..7b106463a 100644
--- a/src/libslic3r/GCodeReader.cpp
+++ b/src/libslic3r/GCodeReader.cpp
@@ -2,9 +2,11 @@
#include
#include
#include
+#include
#include
#include
#include
+#include "Utils.hpp"
#include "LocalesUtils.hpp"
@@ -126,44 +128,92 @@ void GCodeReader::update_coordinates(GCodeLine &gline, std::pair
+bool GCodeReader::parse_file_raw_internal(const std::string &filename, ParseLineCallback parse_line_callback, LineEndCallback line_end_callback)
{
- boost::nowide::ifstream f(file);
- f.sync_with_stdio(false);
+ FilePtr in{ boost::nowide::fopen(filename.c_str(), "rb") };
+
+ // Read the input stream 64kB at a time, extract lines and process them.
std::vector buffer(65536 * 10, 0);
- std::string line;
+ // Line buffer.
+ std::string gcode_line;
+ size_t file_pos = 0;
m_parsing = true;
- GCodeLine gline;
- while (m_parsing && ! f.eof()) {
- f.read(buffer.data(), buffer.size());
- if (! f.eof() && ! f.good())
- // Reading the input file failed.
+ for (;;) {
+ size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
+ if (::ferror(in.f))
return false;
+ bool eof = cnt_read == 0;
auto it = buffer.begin();
- auto it_bufend = buffer.begin() + f.gcount();
- while (it != it_bufend) {
- bool eol = false;
+ auto it_bufend = buffer.begin() + cnt_read;
+ while (it != it_bufend || (eof && ! gcode_line.empty())) {
+ // Find end of line.
+ bool eol = false;
auto it_end = it;
- for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ;
- eol |= f.eof() && it_end == it_bufend;
+ for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end)
+ if (*it_end == '\n')
+ line_end_callback((it_end - buffer.begin()) + 1);
+ // End of line is indicated also if end of file was reached.
+ eol |= eof && it_end == it_bufend;
if (eol) {
- gline.reset();
- if (line.empty())
- this->parse_line(&(*it), &(*it_end), gline, callback);
+ if (gcode_line.empty())
+ parse_line_callback(&(*it), &(*it_end));
else {
- line.insert(line.end(), it, it_end);
- this->parse_line(line.c_str(), line.c_str() + line.size(), gline, callback);
- line.clear();
+ gcode_line.insert(gcode_line.end(), it, it_end);
+ parse_line_callback(gcode_line.c_str(), gcode_line.c_str() + gcode_line.size());
+ gcode_line.clear();
}
+ if (! m_parsing)
+ // The callback wishes to exit.
+ return true;
} else
- line.insert(line.end(), it, it_end);
- // Skip all the empty lines.
- for (it = it_end; it != it_bufend && (*it == '\r' || *it == '\n'); ++ it) ;
+ gcode_line.insert(gcode_line.end(), it, it_end);
+ // Skip EOL.
+ it = it_end;
+ if (it != it_bufend && *it == '\r')
+ ++ it;
+ if (it != it_bufend && *it == '\n') {
+ line_end_callback((it - buffer.begin()) + 1);
+ ++ it;
+ }
}
+ if (eof)
+ break;
+ file_pos += cnt_read;
}
return true;
}
+template
+bool GCodeReader::parse_file_internal(const std::string &filename, ParseLineCallback parse_line_callback, LineEndCallback line_end_callback)
+{
+ GCodeLine gline;
+ return this->parse_file_raw_internal(filename,
+ [this, &gline, parse_line_callback](const char *begin, const char *end) {
+ gline.reset();
+ this->parse_line(begin, end, gline, parse_line_callback);
+ },
+ line_end_callback);
+}
+
+bool GCodeReader::parse_file(const std::string &file, callback_t callback)
+{
+ return this->parse_file_internal(file, callback, [](size_t){});
+}
+
+bool GCodeReader::parse_file(const std::string &file, callback_t callback, std::vector &lines_ends)
+{
+ lines_ends.clear();
+ return this->parse_file_internal(file, callback, [&lines_ends](size_t file_pos){ lines_ends.emplace_back(file_pos); });
+}
+
+bool GCodeReader::parse_file_raw(const std::string &filename, raw_line_callback_t line_callback)
+{
+ return this->parse_file_raw_internal(filename,
+ [this, line_callback](const char *begin, const char *end) { line_callback(*this, begin, end); },
+ [](size_t){});
+}
+
bool GCodeReader::GCodeLine::has(char axis) const
{
const char *c = m_raw.c_str();
diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp
index 15376c0fc..0ab268139 100644
--- a/src/libslic3r/GCodeReader.hpp
+++ b/src/libslic3r/GCodeReader.hpp
@@ -76,6 +76,7 @@ public:
};
typedef std::function callback_t;
+ typedef std::function raw_line_callback_t;
GCodeReader() : m_verbose(false), m_extrusion_axis('E') { this->reset(); }
void reset() { memset(m_position, 0, sizeof(m_position)); }
@@ -114,6 +115,13 @@ public:
// Returns false if reading the file failed.
bool parse_file(const std::string &file, callback_t callback);
+ // Collect positions of line ends in the binary G-code to be used by the G-code viewer when memory mapping and displaying section of G-code
+ // as an overlay in the 3D scene.
+ bool parse_file(const std::string &file, callback_t callback, std::vector &lines_ends);
+ // Just read the G-code file line by line, calls callback (const char *begin, const char *end). Returns false if reading the file failed.
+ bool parse_file_raw(const std::string &file, raw_line_callback_t callback);
+
+ // To be called by the callback to stop parsing.
void quit_parsing() { m_parsing = false; }
float& x() { return m_position[X]; }
@@ -132,6 +140,11 @@ public:
// void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
private:
+ template
+ bool parse_file_raw_internal(const std::string &filename, ParseLineCallback parse_line_callback, LineEndCallback line_end_callback);
+ template
+ bool parse_file_internal(const std::string &filename, ParseLineCallback parse_line_callback, LineEndCallback line_end_callback);
+
const char* parse_line_internal(const char *ptr, const char *end, GCodeLine &gline, std::pair &command);
void update_coordinates(GCodeLine &gline, std::pair &command);
@@ -154,6 +167,7 @@ private:
char m_extrusion_axis;
float m_position[NUM_AXES];
bool m_verbose;
+ // To be set by the callback to stop parsing.
bool m_parsing{ false };
};
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index eb45e95c1..f57e25406 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -1,7 +1,6 @@
#include "GCodeWriter.hpp"
#include "CustomGCode.hpp"
#include
-#include
#include
#include
#include