Merge tag 'version_2.3.0'

version_2.3.0
This commit is contained in:
remi durand 2021-02-22 13:28:28 +01:00
commit a50b4cd544
68 changed files with 4903 additions and 3226 deletions

View File

@ -0,0 +1,46 @@
# - Try to find GTK+ 3
# Once done, this will define
#
# GTK3_FOUND - system has GTK+ 3.
# GTK3_INCLUDE_DIRS - the GTK+ 3. include directories
# GTK3_LIBRARIES - link these to use GTK+ 3.
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
# Copyright (C) 2013 Igalia S.L.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
find_package(PkgConfig)
pkg_check_modules(GTK3 QUIET gtk+-3.0)
set(VERSION_OK TRUE)
if (GTK3_VERSION)
if (GTK3_FIND_VERSION_EXACT)
if (NOT("${GTK3_FIND_VERSION}" VERSION_EQUAL "${GTK3_VERSION}"))
set(VERSION_OK FALSE)
endif ()
else ()
if ("${GTK3_VERSION}" VERSION_LESS "${GTK3_FIND_VERSION}")
set(VERSION_OK FALSE)
endif ()
endif ()
endif ()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK3 DEFAULT_MSG GTK3_INCLUDE_DIRS GTK3_LIBRARIES VERSION_OK)

View File

@ -5169,7 +5169,7 @@ msgid "The supplied name is empty. It can't be saved."
msgstr ""
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:547
msgid "You should to change a name of your printer device. It can't be saved."
msgid "You should change the name of your printer device."
msgstr ""
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:555

View File

@ -10482,8 +10482,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "Chcete-li provést změny, musíte restartovat aplikaci %s."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Měli byste změnit název tiskového zařízení. Nemůže být uloženo."
msgid "You should change the name of your printer device."
msgstr "Měli byste změnit název tiskového zařízení."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

View File

@ -10480,8 +10480,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "Sie müssen %s neu starten, damit die Änderungen wirksam werden."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Sie sollten den Namen Ihres Druckers ändern. Er kann nicht gespeichert werden."
msgid "You should change the name of your printer device."
msgstr "Sie sollten den Namen Ihres Druckers ändern."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

View File

@ -10480,8 +10480,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "Es necesario reiniciar %s para hacer los cambios efectivos."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Debería cambiar el nombre de su dispositivo de impresión. No se puede guardar."
msgid "You should change the name of your printer device."
msgstr "Debería cambiar el nombre de su dispositivo de impresión."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

View File

@ -10480,8 +10480,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "Vous devez redémarrer %s afin que les modifications soient appliquées."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Vous devez changer le nom de votre imprimante. Il ne peut pas être enregistré."
msgid "You should change the name of your printer device."
msgstr "Vous devez changer le nom de votre imprimante."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

View File

@ -10480,8 +10480,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "È necessario riavviare %s per rendere effettive le modifiche."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Devi cambiare il nome del dispositivo di stampa. Non può essere salvato."
msgid "You should change the name of your printer device."
msgstr "Devi cambiare il nome del dispositivo di stampa."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

View File

@ -5423,9 +5423,8 @@ msgid "The supplied name is empty. It can't be saved."
msgstr "De ingevoerde naam is leeg. Kan niet opgeslagen worden."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:547
msgid "You should to change a name of your printer device. It can't be saved."
msgstr ""
"Je moet de naam van de printer aanpassen. Het kan niet opgeslagen worden."
msgid "You should change the name of your printer device."
msgstr "Je moet de naam van de printer aanpassen."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:555
msgid "Printer with name \"%1%\" already exists."

View File

@ -10484,8 +10484,8 @@ msgid "You need to restart %s to make the changes effective."
msgstr "Wymagany jest restart %s, aby wprowadzić zmiany."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:468
msgid "You should to change a name of your printer device. It can't be saved."
msgstr "Należy zmienić nazwę drukarki. Nie można jej zapisać."
msgid "You should change the name of your printer device."
msgstr "Należy zmienić nazwę drukarki."
#: src/slic3r/GUI/GUI_ObjectList.cpp:3884
#, possible-c-format

File diff suppressed because it is too large Load Diff

View File

@ -5122,7 +5122,7 @@ msgid "The supplied name is empty. It can't be saved."
msgstr "Имя не задано. Невозможно сохранить."
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:547
msgid "You should to change a name of your printer device. It can't be saved."
msgid "You should change the name of your printer device."
msgstr ""
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:555

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.3.0-rc2
0.0.12 Added Ender-3V2 and filament profiles.
min_slic3r_version = 2.3.0-beta2
0.0.11 Updated machine limits for Ender 5 and Ender 5 Plus.
0.0.10 Parameter consistency improvements. Enabled conservative elephant foot compensation.

View File

@ -5,7 +5,7 @@
name = Creality
# 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 = 0.0.11
config_version = 0.0.12
# Where to get the updates from?
config_update_url =
# https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
@ -28,6 +28,15 @@ bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Creality PLA @CREALITY; Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY
[printer_model:ENDER3V2]
name = Creality Ender-3V2
variants = 0.4
technology = FFF
family = ENDER
bed_model = ender3_bed.stl
bed_texture = ender3.svg
default_materials = Creality PLA @CREALITY; Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY
[printer_model:ENDER3BLTOUCH]
name = Creality Ender-3 BLTouch
variants = 0.4; 0.3; 0.5; 0.6
@ -584,6 +593,26 @@ filament_cost = 19.50
filament_density = 1.24
filament_colour = #FFE200
[filament:Das Filament PLA @CREALITY]
inherits = *PLA*
filament_vendor = Das Filament
temperature = 215
bed_temperature = 50
first_layer_temperature = 215
first_layer_bed_temperature = 50
filament_cost = 20.56
filament_density = 1.24
[filament:Das Filament PETG @CREALITY]
inherits = *PET*
filament_vendor = Das Filament
temperature = 240
bed_temperature = 70
first_layer_temperature = 240
first_layer_bed_temperature = 70
filament_cost = 27.44
filament_density = 1.29
# Common printer preset
[printer:*common*]
printer_technology = FFF
@ -749,6 +778,12 @@ inherits = *Creality Ender-3*; *0.5nozzle*
[printer:Creality Ender-3 0.6mm]
inherits = *Creality Ender-3*; *0.6nozzle*
[printer:Creality Ender-3V2]
inherits = Creality Ender-3
printer_model = ENDER3V2
printer_variant = 0.4
bed_shape = 0x0,220x0,220x220,0x220
[printer:*fastabl*]
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S150 ; set extruder temp for auto bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nG28 ; home all\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S{first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]} ; set extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S{first_layer_temperature[initial_extruder]+extruder_temperature_offset[initial_extruder]} ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0\nG1 Y190 E15 F1500 ; intro line\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E15 F1200 ; intro line\nG92 E0

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.3.0-rc1
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
@ -11,6 +12,7 @@ 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.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.11 SuperSlicer version
1.1.10 Updated firmware version.

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
min_slic3r_version = 2.3.0-alpha3
0.0.6 Added material TPU 93A (SMARTFIL)
0.0.5-susi remove resolution to use default
0.0.5 Removed obsolete host keys.0.0.4-1 remove g92
0.0.5 Removed obsolete host keys.
0.0.4 Added PLA, PETG profiles for 0.8 nozzle, update print materials
0.0.3 Added DeltiQ 2, DeltiQ 2 Plus printers, 0.10mm, 0.20mm FLEX print profiles, updated print materials, flexprint extension support
min_slic3r_version = 2.3.0-alpha0

View File

@ -6,7 +6,7 @@
name = TriLAB
# 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 = 0.0.5-susi
config_version = 0.0.6
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/TriLAB/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -22,7 +22,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ - PLA - Generic; DeltiQ - PETG - Generic; DeltiQ - ABS - Generic; DeltiQ - PLA - ExtraFill (Fillamentum); DeltiQ - PETG (Devil Design); DeltiQ - ABS - ExtraFill (Fillamentum); DeltiQ - ASA - ExtraFill (Fillamentum); DeltiQ - CPE - HG100 (Fillamentum); DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle
default_materials = DeltiQ - PLA - Generic; DeltiQ - PETG - Generic; DeltiQ - ABS - Generic; DeltiQ - PLA - ExtraFill (Fillamentum); DeltiQ - PETG (Devil Design); DeltiQ - ABS - ExtraFill (Fillamentum); DeltiQ - ASA - ExtraFill (Fillamentum); DeltiQ - CPE - HG100 (Fillamentum); DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 93A (SMARTFIL); DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle
[printer_model:DQ2P]
name = DeltiQ 2 Plus
@ -40,7 +40,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum)
default_materials = DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 93A (SMARTFIL)
[printer_model:DQ2P+FP2]
name = DeltiQ 2 Plus + FlexPrint 2
@ -49,7 +49,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum)
default_materials = DeltiQ FP2 - PLA - Generic; DeltiQ FP2 - PETG - Generic; DeltiQ FP2 - ABS - Generic; DeltiQ FP2 - PLA - ExtraFill (Fillamentum); DeltiQ FP2 - PETG (Devil Design); DeltiQ FP2 - ABS - ExtraFill (Fillamentum); DeltiQ FP2 - ASA - ExtraFill (Fillamentum); DeltiQ FP2 - CPE - HG100 (Fillamentum); DeltiQ FP2 - FLEX - Generic; DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum); DeltiQ FP2 - TPU 93A (SMARTFIL)
[printer_model:DQ2+FP]
name = DeltiQ 2 + FlexPrint
@ -375,7 +375,7 @@ temperature = 215
[filament:DeltiQ - PETG - Generic]
inherits = *DeltiQ common*
bed_temperature = 90
bed_temperature = 80
bridge_fan_speed = 50
cooling = 1
fan_always_on = 1
@ -393,7 +393,7 @@ filament_retract_lift = 0.2
filament_retract_speed = 45
filament_type = PET
filament_wipe = 1
first_layer_bed_temperature = 90
first_layer_bed_temperature = 80
first_layer_temperature = 240
max_fan_speed = 50
min_fan_speed = 30
@ -694,6 +694,37 @@ filament_retract_length = 2.5
filament_retract_speed = 20
filament_type = TPU98A
[filament:DeltiQ FP2 - TPU 93A (SMARTFIL)]
inherits = DeltiQ FP2 - FLEX - Generic
bed_temperature = 50
bridge_fan_speed = 80
cooling = 1
disable_fan_first_layers = 3
extrusion_multiplier = 1.00
fan_always_on = 1
fan_below_layer_time = 10
filament_vendor = Smartfil
filament_cost = 1209
filament_density = 1.21
filament_deretract_speed = nil
filament_max_volumetric_speed = 2.5
filament_retract_before_travel = 2
filament_retract_before_wipe = nil
filament_retract_layer_change = 0
filament_retract_length = 2.9
filament_retract_lift = 0.2
filament_retract_restart_extra = nil
filament_retract_speed = 35
filament_type = TPU93A
filament_wipe = 0
first_layer_bed_temperature = 50
first_layer_temperature = 235
max_fan_speed = 70
min_fan_speed = 30
min_print_speed = 10
slowdown_below_layer_time = 4
temperature = 235
# DeltiQ Printer #

View File

@ -145,15 +145,11 @@ int CLI::run(int argc, char **argv)
}
// Read input file(s) if any.
for (const std::string& file : m_input_files) {
std::string ext = boost::filesystem::path(file).extension().string();
if (ext == ".gcode" || ext == ".g") {
if (boost::filesystem::exists(file)) {
for (const std::string& file : m_input_files)
if (is_gcode_file(file) && boost::filesystem::exists(file)) {
start_as_gcodeviewer = true;
break;
}
}
}
if (!start_as_gcodeviewer) {
for (const std::string& file : m_input_files) {
if (!boost::filesystem::exists(file)) {

View File

@ -716,45 +716,33 @@ static void traverse_pt_noholes(const ClipperLib::PolyNodes &nodes, Polygons *ou
});
}
static void traverse_pt_old(ClipperLib::PolyNodes &nodes, Polygons* retval)
static void traverse_pt_outside_in(const ClipperLib::PolyNodes &nodes, Polygons *retval)
{
/* use a nearest neighbor search to order these children
TODO: supply start_near to chained_path() too? */
// collect ordering points
Points ordering_points;
ordering_points.reserve(nodes.size());
for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
Point p((*it)->Contour.front().X, (*it)->Contour.front().Y);
ordering_points.push_back(p);
}
for (const ClipperLib::PolyNode *node : nodes)
ordering_points.emplace_back(node->Contour.front().X, node->Contour.front().Y);
// perform the ordering
ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes);
// push results recursively
for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) {
// Perform the ordering, push results recursively.
//FIXME pass the last point to chain_clipper_polynodes?
for (const ClipperLib::PolyNode *node : chain_clipper_polynodes(ordering_points, nodes)) {
retval->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour));
if (node->IsHole())
// Orient a hole, which is clockwise oriented, to CCW.
retval->back().reverse();
// traverse the next depth
traverse_pt_old((*it)->Childs, retval);
retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour));
if ((*it)->IsHole()) retval->back().reverse(); // ccw
traverse_pt_outside_in(node->Childs, retval);
}
}
Polygons union_pt_chained(const Polygons &subject, bool safety_offset_)
Polygons union_pt_chained_outside_in(const Polygons &subject, bool safety_offset_)
{
ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
Polygons retval;
traverse_pt_old(polytree.Childs, &retval);
traverse_pt_outside_in(polytree.Childs, &retval);
return retval;
// TODO: This needs to be tested:
// ClipperLib::PolyTree polytree = union_pt(subject, safety_offset_);
// Polygons retval;
// traverse_pt_noholes(polytree.Childs, &retval);
// return retval;
}
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)

View File

@ -228,7 +228,7 @@ ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject, bool safety_off
ClipperLib::PolyTree union_pt(Slic3r::Polygons &&subject, bool safety_offset_ = false);
ClipperLib::PolyTree union_pt(Slic3r::ExPolygons &&subject, bool safety_offset_ = false);
Slic3r::Polygons union_pt_chained(const Slic3r::Polygons &subject, bool safety_offset_ = false);
Slic3r::Polygons union_pt_chained_outside_in(const Slic3r::Polygons &subject, bool safety_offset_ = false);
ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes);

View File

@ -680,7 +680,7 @@ void ConfigBase::setenv_() const
void ConfigBase::load(const std::string &file)
{
if (boost::iends_with(file, ".gcode") || boost::iends_with(file, ".g"))
if (is_gcode_file(file))
this->load_from_gcode_file(file);
else
this->load_from_ini(file);

View File

@ -136,7 +136,7 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
#ifdef SLIC3R_DEBUG
printf("Filling bridge with angle %f\n", surface->bridge_angle);
#endif /* SLIC3R_DEBUG */
out_angle = (float)(surface->bridge_angle);
out_angle = float(surface->bridge_angle);
} else if (this->layer_id != size_t(-1)) {
// alternate fill direction
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
@ -1165,15 +1165,15 @@ struct ContourIntersectionPoint {
size_t contour_idx;
size_t point_idx;
// Eucleidean parameter of point_idx along its contour.
float param;
double param;
// Other intersection points along the same contour. If there is only a single T-joint on a contour
// with an intersection line, then the prev_on_contour and next_on_contour remain nulls.
ContourIntersectionPoint* prev_on_contour{ nullptr };
ContourIntersectionPoint* next_on_contour{ nullptr };
// Length of the contour not yet allocated to some extrusion path going back (clockwise), or masked out by some overlapping infill line.
float contour_not_taken_length_prev{ std::numeric_limits<float>::max() };
double contour_not_taken_length_prev { std::numeric_limits<double>::max() };
// Length of the contour not yet allocated to some extrusion path going forward (counter-clockwise), or masked out by some overlapping infill line.
float contour_not_taken_length_next{ std::numeric_limits<float>::max() };
double contour_not_taken_length_next { std::numeric_limits<double>::max() };
// End point is consumed if an infill line connected to this T-joint was already connected left or right along the contour,
// or if the infill line was processed, but it was not possible to connect it left or right along the contour.
bool consumed{ false };
@ -1184,13 +1184,13 @@ struct ContourIntersectionPoint {
void consume_prev() { this->contour_not_taken_length_prev = 0.; this->prev_trimmed = true; this->consumed = true; }
void consume_next() { this->contour_not_taken_length_next = 0.; this->next_trimmed = true; this->consumed = true; }
void trim_prev(const float new_len) {
void trim_prev(const double new_len) {
if (new_len < this->contour_not_taken_length_prev) {
this->contour_not_taken_length_prev = new_len;
this->prev_trimmed = true;
}
}
void trim_next(const float new_len) {
void trim_next(const double new_len) {
if (new_len < this->contour_not_taken_length_next) {
this->contour_not_taken_length_next = new_len;
this->next_trimmed = true;
@ -1211,24 +1211,24 @@ struct ContourIntersectionPoint {
};
// Distance from param1 to param2 when going counter-clockwise.
static inline float closed_contour_distance_ccw(float param1, float param2, float contour_length)
static inline double closed_contour_distance_ccw(double param1, double param2, double contour_length)
{
assert(param1 >= 0.f && param1 <= contour_length);
assert(param2 >= 0.f && param2 <= contour_length);
float d = param2 - param1;
if (d < 0.f)
assert(param1 >= 0. && param1 <= contour_length);
assert(param2 >= 0. && param2 <= contour_length);
double d = param2 - param1;
if (d < 0.)
d += contour_length;
return d;
}
// Distance from param1 to param2 when going clockwise.
static inline float closed_contour_distance_cw(float param1, float param2, float contour_length)
static inline double closed_contour_distance_cw(double param1, double param2, double contour_length)
{
return closed_contour_distance_ccw(param2, param1, contour_length);
}
// Length along the contour from cp1 to cp2 going counter-clockwise.
float path_length_along_contour_ccw(const ContourIntersectionPoint* cp1, const ContourIntersectionPoint* cp2, float contour_length)
double path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
{
assert(cp1 != nullptr);
assert(cp2 != nullptr);
@ -1238,13 +1238,13 @@ float path_length_along_contour_ccw(const ContourIntersectionPoint* cp1, const C
}
// Lengths along the contour from cp1 to cp2 going CCW and going CW.
std::pair<float, float> path_lengths_along_contour(const ContourIntersectionPoint* cp1, const ContourIntersectionPoint* cp2, float contour_length)
std::pair<double, double> path_lengths_along_contour(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
{
// Zero'th param is the length of the contour.
float param_lo = cp1->param;
float param_hi = cp2->param;
assert(param_lo >= 0.f && param_lo <= contour_length);
assert(param_hi >= 0.f && param_hi <= contour_length);
double param_lo = cp1->param;
double param_hi = cp2->param;
assert(param_lo >= 0. && param_lo <= contour_length);
assert(param_hi >= 0. && param_hi <= contour_length);
bool reversed = false;
if (param_lo > param_hi) {
std::swap(param_lo, param_hi);
@ -1271,25 +1271,25 @@ static inline void take_cw_full(Polyline& pl, const Points& contour, size_t idx_
}
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
static inline float take_cw_limited(Polyline& pl, const Points& contour, const std::vector<float>& params, size_t idx_start, size_t idx_end, float length_to_take)
static inline double take_cw_limited(Polyline &pl, const Points &contour, const std::vector<double> &params, size_t idx_start, size_t idx_end, double length_to_take)
{
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
assert(pl.empty() || pl.points.back() == contour[idx_start]);
assert(contour.size() + 1 == params.size());
assert(length_to_take > SCALED_EPSILON);
// Length of the contour.
float length = params.back();
double length = params.back();
// Parameter (length from contour.front()) for the first point.
float p0 = params[idx_start];
double p0 = params[idx_start];
// Current (2nd) point of the contour.
size_t i = (idx_start == 0) ? contour.size() - 1 : idx_start - 1;
// Previous point of the contour.
size_t iprev = idx_start;
// Length of the contour curve taken for iprev.
float lprev = 0.f;
double lprev = 0.;
for (;;) {
float l = closed_contour_distance_cw(p0, params[i], length);
double l = closed_contour_distance_cw(p0, params[i], length);
if (l >= length_to_take) {
// Trim the last segment.
double t = double(length_to_take - lprev) / (l - lprev);
@ -1327,16 +1327,16 @@ static inline void take_ccw_full(Polyline& pl, const Points& contour, size_t idx
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
// Returns length of the contour taken.
static inline float take_ccw_limited(Polyline& pl, const Points& contour, const std::vector<float>& params, size_t idx_start, size_t idx_end, float length_to_take)
static inline double take_ccw_limited(Polyline &pl, const Points &contour, const std::vector<double> &params, size_t idx_start, size_t idx_end, double length_to_take)
{
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
assert(pl.empty() || pl.points.back() == contour[idx_start]);
assert(contour.size() + 1 == params.size());
assert(length_to_take > SCALED_EPSILON);
// Length of the contour.
float length = params.back();
double length = params.back();
// Parameter (length from contour.front()) for the first point.
float p0 = params[idx_start];
double p0 = params[idx_start];
// Current (2nd) point of the contour.
size_t i = idx_start;
if (++i == contour.size())
@ -1344,9 +1344,9 @@ static inline float take_ccw_limited(Polyline& pl, const Points& contour, const
// Previous point of the contour.
size_t iprev = idx_start;
// Length of the contour curve taken at iprev.
float lprev = 0.f;
double lprev = 0;
for (;;) {
float l = closed_contour_distance_ccw(p0, params[i], length);
double l = closed_contour_distance_ccw(p0, params[i], length);
if (l >= length_to_take) {
// Trim the last segment.
double t = double(length_to_take - lprev) / (l - lprev);
@ -1415,8 +1415,8 @@ static void take(Polyline& pl1, const Polyline& pl2, const Points& contour, Cont
}
static void take_limited(
Polyline& pl1, const Points& contour, const std::vector<float>& params,
ContourIntersectionPoint* cp_start, ContourIntersectionPoint* cp_end, bool clockwise, float take_max_length, float line_half_width)
Polyline &pl1, const Points &contour, const std::vector<double> &params,
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
{
#ifndef NDEBUG
// This is a valid case, where a single infill line connect to two different contours (outer contour + hole or two holes).
@ -1449,11 +1449,11 @@ static void take_limited(
pl1.points.reserve(pl1.points.size() + pl_tmp.size() + size_t(new_points));
}
float length = params.back();
float length_to_go = take_max_length;
double length = params.back();
double length_to_go = take_max_length;
cp_start->consumed = true;
if (cp_start == cp_end) {
length_to_go = std::max(0.f, std::min(length_to_go, length - line_half_width));
length_to_go = std::max(0., std::min(length_to_go, length - line_half_width));
length_to_go = std::min(length_to_go, clockwise ? cp_start->contour_not_taken_length_prev : cp_start->contour_not_taken_length_next);
cp_start->consume_prev();
cp_start->consume_next();
@ -1466,11 +1466,11 @@ static void take_limited(
assert(cp_start != cp_end);
for (ContourIntersectionPoint* cp = cp_start; cp != cp_end; cp = cp->prev_on_contour) {
// Length of the segment from cp to cp->prev_on_contour.
float l = closed_contour_distance_cw(cp->param, cp->prev_on_contour->param, length);
double l = closed_contour_distance_cw(cp->param, cp->prev_on_contour->param, length);
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_prev);
//if (cp->prev_on_contour->consumed)
// Don't overlap with an already extruded infill line.
length_to_go = std::max(0.f, std::min(length_to_go, l - line_half_width));
length_to_go = std::max(0., std::min(length_to_go, l - line_half_width));
cp->consume_prev();
if (l >= length_to_go) {
if (length_to_go > SCALED_EPSILON) {
@ -1479,7 +1479,7 @@ static void take_limited(
}
break;
} else {
cp->prev_on_contour->trim_next(0.f);
cp->prev_on_contour->trim_next(0.);
take_cw_full(pl1, contour, cp->point_idx, cp->prev_on_contour->point_idx);
length_to_go -= l;
}
@ -1487,11 +1487,11 @@ static void take_limited(
} else {
assert(cp_start != cp_end);
for (ContourIntersectionPoint* cp = cp_start; cp != cp_end; cp = cp->next_on_contour) {
float l = closed_contour_distance_ccw(cp->param, cp->next_on_contour->param, length);
double l = closed_contour_distance_ccw(cp->param, cp->next_on_contour->param, length);
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_next);
//if (cp->next_on_contour->consumed)
// Don't overlap with an already extruded infill line.
length_to_go = std::max(0.f, std::min(length_to_go, l - line_half_width));
length_to_go = std::max(0., std::min(length_to_go, l - line_half_width));
cp->consume_next();
if (l >= length_to_go) {
if (length_to_go > SCALED_EPSILON) {
@ -1500,7 +1500,7 @@ static void take_limited(
}
break;
} else {
cp->next_on_contour->trim_prev(0.f);
cp->next_on_contour->trim_prev(0.);
take_ccw_full(pl1, contour, cp->point_idx, cp->next_on_contour->point_idx);
length_to_go -= l;
}
@ -1681,19 +1681,19 @@ static inline bool line_rounded_thick_segment_collision(
return intersects;
}
static inline bool inside_interval(float low, float high, float p)
static inline bool inside_interval(double low, double high, double p)
{
return p >= low && p <= high;
}
static inline bool interval_inside_interval(float outer_low, float outer_high, float inner_low, float inner_high, float epsilon)
static inline bool interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double epsilon)
{
outer_low -= epsilon;
outer_high += epsilon;
return inside_interval(outer_low, outer_high, inner_low) && inside_interval(outer_low, outer_high, inner_high);
}
static inline bool cyclic_interval_inside_interval(float outer_low, float outer_high, float inner_low, float inner_high, float length)
static inline bool cyclic_interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double length)
{
if (outer_low > outer_high)
outer_high += length;
@ -1703,7 +1703,7 @@ static inline bool cyclic_interval_inside_interval(float outer_low, float outer_
inner_low += length;
inner_high += length;
}
return interval_inside_interval(outer_low, outer_high, inner_low, inner_high, float(SCALED_EPSILON));
return interval_inside_interval(outer_low, outer_high, inner_low, inner_high, double(SCALED_EPSILON));
}
// #define INFILL_DEBUG_OUTPUT
@ -1713,7 +1713,7 @@ static void export_infill_to_svg(
// Boundary contour, along which the perimeter extrusions will be drawn.
const std::vector<Points>& boundary,
// Parametrization of boundary with Euclidian length.
const std::vector<std::vector<float>>& boundary_parameters,
const std::vector<std::vector<double>> &boundary_parameters,
// Intersections (T-joints) of the infill lines with the boundary.
std::vector<std::vector<ContourIntersectionPoint*>>& boundary_intersections,
// Infill lines, either completely inside the boundary, or touching the boundary.
@ -1739,11 +1739,11 @@ static void export_infill_to_svg(
const std::string color_boundary_not_trimmed = "yellow";
const coordf_t boundary_line_width = scaled_spacing;
svg.draw_outline(polygons, "red", boundary_line_width);
for (const std::vector<ContourIntersectionPoint*>& intersections : boundary_intersections) {
for (const std::vector<ContourIntersectionPoint*> &intersections : boundary_intersections) {
const size_t boundary_idx = &intersections - boundary_intersections.data();
const Points& contour = boundary[boundary_idx];
const std::vector<float>& contour_param = boundary_parameters[boundary_idx];
for (const ContourIntersectionPoint* ip : intersections) {
const Points &contour = boundary[boundary_idx];
const std::vector<double> &contour_param = boundary_parameters[boundary_idx];
for (const ContourIntersectionPoint *ip : intersections) {
assert(ip->next_trimmed == ip->next_on_contour->prev_trimmed);
assert(ip->prev_trimmed == ip->prev_on_contour->next_trimmed);
{
@ -1837,7 +1837,7 @@ void mark_boundary_segments_touching_infill(
// Boundary contour, along which the perimeter extrusions will be drawn.
const std::vector<Points>& boundary,
// Parametrization of boundary with Euclidian length.
const std::vector<std::vector<float>>& boundary_parameters,
const std::vector<std::vector<double>> &boundary_parameters,
// Intersections (T-joints) of the infill lines with the boundary.
std::vector<std::vector<ContourIntersectionPoint*>>& boundary_intersections,
// Bounding box around the boundary.
@ -1868,12 +1868,12 @@ void mark_boundary_segments_touching_infill(
// Make sure that the the grid is big enough for queries against the thick segment.
grid.set_bbox(boundary_bbox.inflated(distance_colliding * 1.43));
// Inflate the bounding box by a thick line width.
grid.create(boundary, std::max(clip_distance, distance_colliding) + scale_(10.));
grid.create(boundary, coord_t(std::max(clip_distance, distance_colliding) + scale_(10.)));
// Visitor for the EdgeGrid to trim boundary_intersections with existing infill lines.
struct Visitor {
Visitor(const EdgeGrid::Grid& grid,
const std::vector<Points>& boundary, const std::vector<std::vector<float>>& boundary_parameters, std::vector<std::vector<ContourIntersectionPoint*>>& boundary_intersections,
Visitor(const EdgeGrid::Grid &grid,
const std::vector<Points> &boundary, const std::vector<std::vector<double>> &boundary_parameters, std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
const double radius) :
grid(grid), boundary(boundary), boundary_parameters(boundary_parameters), boundary_intersections(boundary_intersections), radius(radius), trim_l_threshold(0.5 * radius) {}
@ -1910,10 +1910,10 @@ void mark_boundary_segments_touching_infill(
// The boundary segment intersects with the infill segment thickened by radius.
// Interval is specified in Euclidian length from seg_pt1 to seg_pt2.
// 1) Find the Euclidian parameters of seg_pt1 and seg_pt2 on its boundary contour.
const std::vector<float>& contour_parameters = boundary_parameters[it_contour_and_segment->first];
const float contour_length = contour_parameters.back();
const float param_seg_pt1 = contour_parameters[it_contour_and_segment->second];
const float param_seg_pt2 = contour_parameters[it_contour_and_segment->second + 1];
const std::vector<double> &contour_parameters = boundary_parameters[it_contour_and_segment->first];
const double contour_length = contour_parameters.back();
const double param_seg_pt1 = contour_parameters[it_contour_and_segment->second];
const double param_seg_pt2 = contour_parameters[it_contour_and_segment->second + 1];
#ifdef INFILL_DEBUG_OUTPUT
this->perimeter_overlaps.push_back({ Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.first).cast<coord_t>()),
Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.second).cast<coord_t>()) });
@ -1921,8 +1921,8 @@ void mark_boundary_segments_touching_infill(
assert(interval.first >= 0.);
assert(interval.second >= 0.);
assert(interval.first <= interval.second);
const auto param_overlap1 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.first));
const auto param_overlap2 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.second));
const auto param_overlap1 = std::min(param_seg_pt2, param_seg_pt1 + interval.first);
const auto param_overlap2 = std::min(param_seg_pt2, param_seg_pt1 + interval.second);
// 2) Find the ContourIntersectionPoints before param_overlap1 and after param_overlap2.
// Find the span of ContourIntersectionPoints, that is trimmed by the interval (param_overlap1, param_overlap2).
ContourIntersectionPoint* ip_low, * ip_high;
@ -1949,7 +1949,7 @@ void mark_boundary_segments_touching_infill(
ip->consume_next();
}
// Subtract the interval from the first and last segments.
float trim_l = closed_contour_distance_ccw(ip_low->param, param_overlap1, contour_length);
double trim_l = closed_contour_distance_ccw(ip_low->param, param_overlap1, contour_length);
//if (trim_l > trim_l_threshold)
ip_low->trim_next(trim_l);
trim_l = closed_contour_distance_ccw(param_overlap2, ip_high->param, contour_length);
@ -1979,14 +1979,14 @@ void mark_boundary_segments_touching_infill(
return true;
}
const EdgeGrid::Grid& grid;
const std::vector<Points>& boundary;
const std::vector<std::vector<float>>& boundary_parameters;
std::vector<std::vector<ContourIntersectionPoint*>>& boundary_intersections;
const EdgeGrid::Grid &grid;
const std::vector<Points> &boundary;
const std::vector<std::vector<double>> &boundary_parameters;
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections;
// Maximum distance between the boundary and the infill line allowed to consider the boundary not touching the infill line.
const double radius;
// Region around the contour / infill line intersection point, where the intersections are ignored.
const float trim_l_threshold;
const double trim_l_threshold;
const Vec2d* infill_pt1;
const Vec2d* infill_pt2;
@ -2106,11 +2106,11 @@ void connect_infill(Polylines&& infill_ordered, const Polygons& boundary_src, co
void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*>& boundary_src, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params)
{
assert(!infill_ordered.empty());
assert(params.anchor_length >= 0.f);
assert(params.anchor_length >= 0.);
assert(params.anchor_length_max >= 0.01f);
assert(params.anchor_length_max >= params.anchor_length);
const auto anchor_length = float(scale_(params.anchor_length));
const auto anchor_length_max = float(scale_(params.anchor_length_max));
const double anchor_length = scale_(params.anchor_length);
const double anchor_length_max = scale_(params.anchor_length_max);
#if 0
append(polylines_out, infill_ordered);
@ -2119,9 +2119,9 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
// 1) Add the end points of infill_ordered to boundary_src.
std::vector<Points> boundary;
std::vector<std::vector<float>> boundary_params;
std::vector<std::vector<double>> boundary_params;
boundary.assign(boundary_src.size(), Points());
boundary_params.assign(boundary_src.size(), std::vector<float>());
boundary_params.assign(boundary_src.size(), std::vector<double>());
// Mapping the infill_ordered end point to a (contour, point) of boundary.
static constexpr auto boundary_idx_unconnected = std::numeric_limits<size_t>::max();
std::vector<ContourIntersectionPoint> map_infill_end_point_to_boundary(infill_ordered.size() * 2, ContourIntersectionPoint{ boundary_idx_unconnected, boundary_idx_unconnected });
@ -2131,10 +2131,10 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
{
EdgeGrid::Grid grid;
grid.set_bbox(bbox.inflated(SCALED_EPSILON));
grid.create(boundary_src, scale_(10.));
grid.create(boundary_src, coord_t(scale_(10.)));
intersection_points.reserve(infill_ordered.size() * 2);
for (const Polyline& pl : infill_ordered)
for (const Point* pt : { &pl.points.front(), &pl.points.back() }) {
for (const Polyline &pl : infill_ordered)
for (const Point *pt : { &pl.points.front(), &pl.points.back() }) {
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, SCALED_EPSILON);
if (cp.valid()) {
// The infill end point shall lie on the contour.
@ -2168,23 +2168,31 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
++n_intersection_points;
contour_intersection_points.reserve(n_intersection_points);
}
for (size_t idx_point = 0; idx_point < contour_src.points.size(); ++idx_point) {
contour_dst.emplace_back(contour_src.points[idx_point]);
for (; it != it_end && it->first.contour_idx == idx_contour && it->first.start_point_idx == idx_point; ++it) {
for (size_t idx_point = 0; idx_point < contour_src.points.size(); ++ idx_point) {
const Point &ipt = contour_src.points[idx_point];
if (contour_dst.empty() || contour_dst.back() != ipt)
contour_dst.emplace_back(ipt);
for (; it != it_end && it->first.contour_idx == idx_contour && it->first.start_point_idx == idx_point; ++ it) {
// Add these points to the destination contour.
const Polyline& infill_line = infill_ordered[it->second / 2];
const Point& pt = (it->second & 1) ? infill_line.points.back() : infill_line.points.front();
const Polyline &infill_line = infill_ordered[it->second / 2];
const Point &pt = (it->second & 1) ? infill_line.points.back() : infill_line.points.front();
#ifndef NDEBUG
{
const Vec2d pt1 = contour_src[idx_point].cast<double>();
const Vec2d pt1 = ipt.cast<double>();
const Vec2d pt2 = (idx_point + 1 == contour_src.size() ? contour_src.points.front() : contour_src.points[idx_point + 1]).cast<double>();
const Vec2d ptx = lerp(pt1, pt2, it->first.t);
assert(std::abs(pt.x() - pt.x()) < SCALED_EPSILON);
assert(std::abs(pt.y() - pt.y()) < SCALED_EPSILON);
}
#endif // NDEBUG
map_infill_end_point_to_boundary[it->second] = ContourIntersectionPoint{ idx_contour, contour_dst.size() };
ContourIntersectionPoint* pthis = &map_infill_end_point_to_boundary[it->second];
size_t idx_tjoint_pt = 0;
if (idx_point + 1 < contour_src.size() || pt != contour_dst.front()) {
if (pt != contour_dst.back())
contour_dst.emplace_back(pt);
idx_tjoint_pt = contour_dst.size() - 1;
}
map_infill_end_point_to_boundary[it->second] = ContourIntersectionPoint{ idx_contour, idx_tjoint_pt };
ContourIntersectionPoint *pthis = &map_infill_end_point_to_boundary[it->second];
if (pprev) {
pprev->next_on_contour = pthis;
pthis->prev_on_contour = pprev;
@ -2192,8 +2200,6 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
pfirst = pthis;
contour_intersection_points.emplace_back(pthis);
pprev = pthis;
//add new point here
contour_dst.emplace_back(pt);
}
if (pfirst) {
pprev->next_on_contour = pfirst;
@ -2201,16 +2207,19 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
}
}
// Parametrize the new boundary with the intersection points inserted.
std::vector<float>& contour_params = boundary_params[idx_contour];
contour_params.assign(contour_dst.size() + 1, 0.f);
for (size_t i = 1; i < contour_dst.size(); ++i)
contour_params[i] = contour_params[i - 1] + (contour_dst[i].cast<float>() - contour_dst[i - 1].cast<float>()).norm();
contour_params.back() = contour_params[contour_params.size() - 2] + (contour_dst.back().cast<float>() - contour_dst.front().cast<float>()).norm();
std::vector<double> &contour_params = boundary_params[idx_contour];
contour_params.assign(contour_dst.size() + 1, 0.);
for (size_t i = 1; i < contour_dst.size(); ++i) {
contour_params[i] = contour_params[i - 1] + (contour_dst[i].cast<double>() - contour_dst[i - 1].cast<double>()).norm();
assert(contour_params[i] > contour_params[i - 1]);
}
contour_params.back() = contour_params[contour_params.size() - 2] + (contour_dst.back().cast<double>() - contour_dst.front().cast<double>()).norm();
assert(contour_params.back() > contour_params[contour_params.size() - 2]);
// Map parameters from contour_params to boundary_intersection_points.
for (ContourIntersectionPoint* ip : contour_intersection_points)
ip->param = contour_params[ip->point_idx];
// and measure distance to the previous and next intersection point.
const float contour_length = contour_params.back();
const double contour_length = contour_params.back();
for (ContourIntersectionPoint *ip : contour_intersection_points)
if (ip->next_on_contour == ip) {
assert(ip->prev_on_contour == ip);
@ -2244,9 +2253,9 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
}
// Connection from end of one infill line to the start of another infill line.
//const float length_max = scale_(spacing);
// const auto length_max = float(scale_((2. / params.density) * spacing));
const auto length_max = float(scale_((1000. / params.density) * spacing));
//const double length_max = scale_(spacing);
// const auto length_max = double(scale_((2. / params.density) * spacing));
const auto length_max = double(scale_((1000. / params.density) * spacing));
std::vector<size_t> merged_with(infill_ordered.size());
std::iota(merged_with.begin(), merged_with.end(), 0);
struct ConnectionCost {
@ -2264,7 +2273,7 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
const ContourIntersectionPoint* cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
if (cp1->contour_idx != boundary_idx_unconnected && cp1->contour_idx == cp2->contour_idx) {
// End points on the same contour. Try to connect them.
std::pair<float, float> len = path_lengths_along_contour(cp1, cp2, boundary_params[cp1->contour_idx].back());
std::pair<double, double> len = path_lengths_along_contour(cp1, cp2, boundary_params[cp1->contour_idx].back());
if (len.first < length_max)
connections_sorted.emplace_back(idx_chain - 1, len.first, false);
if (len.second < length_max)
@ -2301,7 +2310,7 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
return std::numeric_limits<size_t>::max();
};
const float line_half_width = 0.5f * scale_(spacing);
const double line_half_width = 0.5 * scale_(spacing);
#if 0
for (ConnectionCost& connection_cost : connections_sorted) {
@ -2311,7 +2320,7 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
assert(cp1->contour_idx == cp2->contour_idx && cp1->contour_idx != boundary_idx_unconnected);
if (cp1->consumed || cp2->consumed)
continue;
const float length = connection_cost.cost;
const double length = connection_cost.cost;
bool could_connect;
{
// cp1, cp2 sorted CCW.
@ -2354,7 +2363,7 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
struct Arc {
ContourIntersectionPoint* intersection;
float arc_length;
double arc_length;
};
std::vector<Arc> arches;
arches.reserve(map_infill_end_point_to_boundary.size());
@ -2367,12 +2376,12 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
for (Arc& arc : arches)
if (!arc.intersection->consumed && !arc.intersection->next_on_contour->consumed) {
// Indices of the polylines to be connected by a perimeter segment.
ContourIntersectionPoint* cp1 = arc.intersection;
ContourIntersectionPoint* cp2 = arc.intersection->next_on_contour;
ContourIntersectionPoint *cp1 = arc.intersection;
ContourIntersectionPoint *cp2 = arc.intersection->next_on_contour;
size_t polyline_idx1 = get_and_update_merged_with(((cp1 - map_infill_end_point_to_boundary.data()) / 2));
size_t polyline_idx2 = get_and_update_merged_with(((cp2 - map_infill_end_point_to_boundary.data()) / 2));
const Points& contour = boundary[cp1->contour_idx];
const std::vector<float>& contour_params = boundary_params[cp1->contour_idx];
const Points &contour = boundary[cp1->contour_idx];
const std::vector<double> &contour_params = boundary_params[cp1->contour_idx];
if (polyline_idx1 != polyline_idx2) {
Polyline& polyline1 = infill_ordered[polyline_idx1];
Polyline& polyline2 = infill_ordered[polyline_idx2];
@ -2403,25 +2412,25 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
}
// Connect the remaining open infill lines to the perimeter lines if possible.
for (ContourIntersectionPoint& contour_point : map_infill_end_point_to_boundary)
if (!contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
const Points& contour = boundary[contour_point.contour_idx];
const std::vector<float>& contour_params = boundary_params[contour_point.contour_idx];
for (ContourIntersectionPoint &contour_point : map_infill_end_point_to_boundary)
if (! contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
const Points &contour = boundary[contour_point.contour_idx];
const std::vector<double> &contour_params = boundary_params[contour_point.contour_idx];
const size_t contour_pt_idx = contour_point.point_idx;
float lprev = contour_point.could_connect_prev() ?
double lprev = contour_point.could_connect_prev() ?
path_length_along_contour_ccw(contour_point.prev_on_contour, &contour_point, contour_params.back()) :
std::numeric_limits<float>::max();
float lnext = contour_point.could_connect_next() ?
std::numeric_limits<double>::max();
double lnext = contour_point.could_connect_next() ?
path_length_along_contour_ccw(&contour_point, contour_point.next_on_contour, contour_params.back()) :
std::numeric_limits<float>::max();
std::numeric_limits<double>::max();
size_t polyline_idx = get_and_update_merged_with(((&contour_point - map_infill_end_point_to_boundary.data()) / 2));
Polyline& polyline = infill_ordered[polyline_idx];
assert(!polyline.empty());
assert(contour[contour_point.point_idx] == polyline.points.front() || contour[contour_point.point_idx] == polyline.points.back());
bool connected = false;
for (float l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
if (l == std::numeric_limits<float>::max() || l > anchor_length_max)
for (double l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
if (l == std::numeric_limits<double>::max() || l > anchor_length_max)
break;
// Take the complete contour.
bool reversed = l == lprev;
@ -2459,7 +2468,7 @@ void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*
// 2) Hook length
// ...
// Let's take the longer now, as this improves the chance of another hook to be placed on the other side of this contour point.
float l = std::max(contour_point.contour_not_taken_length_prev, contour_point.contour_not_taken_length_next);
double l = std::max(contour_point.contour_not_taken_length_prev, contour_point.contour_not_taken_length_next);
if (l > SCALED_EPSILON) {
if (contour_point.contour_not_taken_length_prev > contour_point.contour_not_taken_length_next)
take_limited(polyline, contour, contour_params, &contour_point, contour_point.prev_on_contour, true, anchor_length, line_half_width);

View File

@ -35,22 +35,22 @@ FillConcentric::_fill_surface_single(
distance = scale_(this->get_spacing());
}
Polygons loops = (Polygons)expolygon;
Polygons loops = to_polygons(std::move(expolygon));
Polygons last = loops;
while (! last.empty()) {
last = offset2(last, -double(distance + scale_(this->get_spacing()) /2), +double(scale_(this->get_spacing()) /2));
loops.insert(loops.end(), last.begin(), last.end());
append(loops, last);
}
// generate paths from the outermost to the innermost, to avoid
// adhesion problems of the first central tiny loops
loops = union_pt_chained(loops, false);
loops = union_pt_chained_outside_in(loops, false);
// split paths using a nearest neighbor search
size_t iPathFirst = polylines_out.size();
Point last_pos(0, 0);
for (const Polygon &loop : loops) {
polylines_out.push_back(loop.split_at_index(last_pos.nearest_point_index(loop.points)));
polylines_out.emplace_back(loop.split_at_index(last_pos.nearest_point_index(loop.points)));
last_pos = polylines_out.back().last_point();
}

View File

@ -8,7 +8,7 @@ namespace Slic3r {
class FillConcentric : public Fill
{
public:
~FillConcentric() override {}
~FillConcentric() override = default;
protected:
Fill* clone() const override { return new FillConcentric(*this); };

View File

@ -38,7 +38,7 @@ protected:
bool _can_connect(coord_t dist_X, coord_t dist_Y) const
{
coord_t TOLERANCE = 10 * SCALED_EPSILON;
const auto TOLERANCE = coord_t(10 * SCALED_EPSILON);
return (dist_X >= (this->_line_spacing - this->_line_oscillation) - TOLERANCE)
&& (dist_X <= (this->_line_spacing + this->_line_oscillation) + TOLERANCE)
&& (dist_Y <= this->_diagonal_distance);

View File

@ -58,59 +58,59 @@ const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_poin
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml";
static constexpr char* MODEL_TAG = "model";
static constexpr char* RESOURCES_TAG = "resources";
static constexpr char* OBJECT_TAG = "object";
static constexpr char* MESH_TAG = "mesh";
static constexpr char* VERTICES_TAG = "vertices";
static constexpr char* VERTEX_TAG = "vertex";
static constexpr char* TRIANGLES_TAG = "triangles";
static constexpr char* TRIANGLE_TAG = "triangle";
static constexpr char* COMPONENTS_TAG = "components";
static constexpr char* COMPONENT_TAG = "component";
static constexpr char* BUILD_TAG = "build";
static constexpr char* ITEM_TAG = "item";
static constexpr char* METADATA_TAG = "metadata";
static constexpr const char* MODEL_TAG = "model";
static constexpr const char* RESOURCES_TAG = "resources";
static constexpr const char* OBJECT_TAG = "object";
static constexpr const char* MESH_TAG = "mesh";
static constexpr const char* VERTICES_TAG = "vertices";
static constexpr const char* VERTEX_TAG = "vertex";
static constexpr const char* TRIANGLES_TAG = "triangles";
static constexpr const char* TRIANGLE_TAG = "triangle";
static constexpr const char* COMPONENTS_TAG = "components";
static constexpr const char* COMPONENT_TAG = "component";
static constexpr const char* BUILD_TAG = "build";
static constexpr const char* ITEM_TAG = "item";
static constexpr const char* METADATA_TAG = "metadata";
static constexpr char* CONFIG_TAG = "config";
static constexpr char* VOLUME_TAG = "volume";
static constexpr const char* CONFIG_TAG = "config";
static constexpr const char* VOLUME_TAG = "volume";
static constexpr char* UNIT_ATTR = "unit";
static constexpr char* NAME_ATTR = "name";
static constexpr char* TYPE_ATTR = "type";
static constexpr char* ID_ATTR = "id";
static constexpr char* X_ATTR = "x";
static constexpr char* Y_ATTR = "y";
static constexpr char* Z_ATTR = "z";
static constexpr char* V1_ATTR = "v1";
static constexpr char* V2_ATTR = "v2";
static constexpr char* V3_ATTR = "v3";
static constexpr char* OBJECTID_ATTR = "objectid";
static constexpr char* TRANSFORM_ATTR = "transform";
static constexpr char* PRINTABLE_ATTR = "printable";
static constexpr char* INSTANCESCOUNT_ATTR = "instances_count";
static constexpr char* CUSTOM_SUPPORTS_ATTR = "slic3rpe:custom_supports";
static constexpr char* CUSTOM_SEAM_ATTR = "slic3rpe:custom_seam";
static constexpr const char* UNIT_ATTR = "unit";
static constexpr const char* NAME_ATTR = "name";
static constexpr const char* TYPE_ATTR = "type";
static constexpr const char* ID_ATTR = "id";
static constexpr const char* X_ATTR = "x";
static constexpr const char* Y_ATTR = "y";
static constexpr const char* Z_ATTR = "z";
static constexpr const char* V1_ATTR = "v1";
static constexpr const char* V2_ATTR = "v2";
static constexpr const char* V3_ATTR = "v3";
static constexpr const char* OBJECTID_ATTR = "objectid";
static constexpr const char* TRANSFORM_ATTR = "transform";
static constexpr const char* PRINTABLE_ATTR = "printable";
static constexpr const char* INSTANCESCOUNT_ATTR = "instances_count";
static constexpr const char* CUSTOM_SUPPORTS_ATTR = "slic3rpe:custom_supports";
static constexpr const char* CUSTOM_SEAM_ATTR = "slic3rpe:custom_seam";
static constexpr char* KEY_ATTR = "key";
static constexpr char* VALUE_ATTR = "value";
static constexpr char* FIRST_TRIANGLE_ID_ATTR = "firstid";
static constexpr char* LAST_TRIANGLE_ID_ATTR = "lastid";
static constexpr const char* KEY_ATTR = "key";
static constexpr const char* VALUE_ATTR = "value";
static constexpr const char* FIRST_TRIANGLE_ID_ATTR = "firstid";
static constexpr const char* LAST_TRIANGLE_ID_ATTR = "lastid";
static constexpr char* OBJECT_TYPE = "object";
static constexpr char* VOLUME_TYPE = "volume";
static constexpr const char* OBJECT_TYPE = "object";
static constexpr const char* VOLUME_TYPE = "volume";
static constexpr char* NAME_KEY = "name";
static constexpr char* MODIFIER_KEY = "modifier";
static constexpr char* VOLUME_TYPE_KEY = "volume_type";
static constexpr char* MATRIX_KEY = "matrix";
static constexpr char* SOURCE_FILE_KEY = "source_file";
static constexpr char* SOURCE_OBJECT_ID_KEY = "source_object_id";
static constexpr char* SOURCE_VOLUME_ID_KEY = "source_volume_id";
static constexpr char* SOURCE_OFFSET_X_KEY = "source_offset_x";
static constexpr char* SOURCE_OFFSET_Y_KEY = "source_offset_y";
static constexpr char* SOURCE_OFFSET_Z_KEY = "source_offset_z";
static constexpr char* SOURCE_IN_INCHES = "source_in_inches";
static constexpr const char* NAME_KEY = "name";
static constexpr const char* MODIFIER_KEY = "modifier";
static constexpr const char* VOLUME_TYPE_KEY = "volume_type";
static constexpr const char* MATRIX_KEY = "matrix";
static constexpr const char* SOURCE_FILE_KEY = "source_file";
static constexpr const char* SOURCE_OBJECT_ID_KEY = "source_object_id";
static constexpr const char* SOURCE_VOLUME_ID_KEY = "source_volume_id";
static constexpr const char* SOURCE_OFFSET_X_KEY = "source_offset_x";
static constexpr const char* SOURCE_OFFSET_Y_KEY = "source_offset_y";
static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z";
static constexpr const char* SOURCE_IN_INCHES = "source_in_inches";
const unsigned int VALID_OBJECT_TYPES_COUNT = 1;
const char* VALID_OBJECT_TYPES[] =

View File

@ -2478,6 +2478,8 @@ void GCode::process_layer(
instance_to_print.object_by_extruder.support->chained_path_from(m_last_pos, instance_to_print.object_by_extruder.support_extrusion_role));
m_layer = layers[instance_to_print.layer_id].layer();
}
//FIXME order islands?
// Sequential tool path ordering of multiple parts within the same object, aka. perimeter tracking (#5511)
for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) {
const std::vector<ObjectByExtruder::Island::Region>& by_region_specific =
is_anything_overridden ?

View File

@ -134,7 +134,7 @@ GCodeSender::set_baud_rate(unsigned int baud_rate)
speed_t newSpeed = baud_rate;
ioctl(handle, IOSSIOSPEED, &newSpeed);
::tcsetattr(handle, TCSANOW, &ios);
#elif __linux
#elif __linux__
termios2 ios;
if (ioctl(handle, TCGETS2, &ios))
printf("Error in TCGETS2: %s\n", strerror(errno));

View File

@ -668,7 +668,7 @@ DynamicPrintConfig PresetBundle::full_sla_config() const
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
void PresetBundle::load_config_file(const std::string &path)
{
if (boost::iends_with(path, ".gcode") || boost::iends_with(path, ".g")) {
if (is_gcode_file(path)) {
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
config.load_from_gcode_file(path);

View File

@ -2379,7 +2379,7 @@ void Print::_make_brim_ears(const Flow &flow, const PrintObjectPtrs &objects, Ex
}
}
//order path with least travel possible
loops = union_pt_chained(loops, false);
loops = union_pt_chained_outside_in(loops, false);
//create ear pattern
coord_t size_ear = (scale_((brim_config.brim_width.value - brim_config.brim_offset.value)) - flow.scaled_spacing());
@ -2518,6 +2518,7 @@ void Print::_make_brim_interior(const Flow &flow, const PrintObjectPtrs &objects
for (Polygon& poly : offset(islands_to_loops, 0.5f * double(flow.scaled_spacing())))
loops[i].emplace_back(poly);
}
//loops = union_pt_chained_outside_in(loops, false);
std::reverse(loops.begin(), loops.end());
//intersection

View File

@ -2610,7 +2610,7 @@ namespace Slic3r {
layer->make_slices();
//FIXME: can't make it work in multi-region object, it seems useful to avoid bridge on top of first layer compensation
//so it's disable, if you want an offset, use the offset field.
//if (layer->regions().size() == 1 && layer_id == 0 && first_layer_compensation < 0 && m_config.raft_layers == 0) {
//if (layer->regions().size() == 1 && ! m_layers.empty() && layer_id == 0 && first_layer_compensation < 0 && m_config.raft_layers == 0) {
// // The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value.
// // Store the uncompensated value there.
// assert(! m_layers.empty());

View File

@ -45,9 +45,11 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
m_cursor = Cursor(hit, source, radius, cursor_type, trafo);
// In case user changed cursor size since last time, update triangle edge limit.
if (m_old_cursor_radius != radius) {
set_edge_limit(radius / 5.f);
m_old_cursor_radius = radius;
// It is necessary to compare the internal radius in m_cursor! radius is in
// world coords and does not change after scaling.
if (m_old_cursor_radius_sqr != m_cursor.radius_sqr) {
set_edge_limit(std::sqrt(m_cursor.radius_sqr) / 5.f);
m_old_cursor_radius_sqr = m_cursor.radius_sqr;
}
// Now start with the facet the pointer points to and check all adjacent facets.

View File

@ -146,7 +146,7 @@ protected:
};
Cursor m_cursor;
float m_old_cursor_radius;
float m_old_cursor_radius_sqr;
// Private functions:
bool select_triangle(int facet_idx, EnforcerBlockerType type,

View File

@ -90,6 +90,7 @@ extern CopyFileResult check_copy(const std::string& origin, const std::string& c
extern bool is_plain_file(const boost::filesystem::directory_entry &path);
extern bool is_ini_file(const boost::filesystem::directory_entry &path);
extern bool is_idx_file(const boost::filesystem::directory_entry &path);
extern bool is_gcode_file(const std::string &path);
// File path / name / extension splitting utilities, working with UTF-8,
// to be published to Perl.
@ -358,8 +359,12 @@ inline std::string get_time_dhm(float time_in_secs)
#if WIN32
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE)
//FIXME this is an inprecise hack. Add the hash table size and possibly some estimate of the linked list at each of the used bin.
#define SLIC3R_STDUNORDEREDSET_MEMSIZE(NAME, TYPE) NAME.size() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE)
#else
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + alignof(TYPE) - 1) / alignof(TYPE)) * alignof(TYPE)
//FIXME this is an inprecise hack. Add the hash table size and possibly some estimate of the linked list at each of the used bin.
#define SLIC3R_STDUNORDEREDSET_MEMSIZE(NAME, TYPE) NAME.size() * ((sizeof(TYPE) + alignof(TYPE) - 1) / alignof(TYPE)) * alignof(TYPE)
#endif
#endif // slic3r_Utils_hpp_

View File

@ -39,9 +39,9 @@
#include <tbb/task_scheduler_init.h>
#if defined(__linux) || defined(__GNUC__ )
#if defined(__linux__) || defined(__GNUC__ )
#include <strings.h>
#endif /* __linux */
#endif /* __linux__ */
#ifdef _MSC_VER
#define strcasecmp _stricmp
@ -522,6 +522,12 @@ bool is_idx_file(const boost::filesystem::directory_entry &dir_entry)
return is_plain_file(dir_entry) && strcasecmp(dir_entry.path().extension().string().c_str(), ".idx") == 0;
}
bool is_gcode_file(const std::string &path)
{
return boost::iends_with(path, ".gcode") || boost::iends_with(path, ".gco") ||
boost::iends_with(path, ".g") || boost::iends_with(path, ".ngc");
}
} // namespace Slic3r
#ifdef WIN32

View File

@ -273,3 +273,12 @@ endif ()
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
endif ()
# We need to implement some hacks for wxWidgets and touch the underlying GTK
# layer and sub-libraries. This forces us to use the include locations and
# link these libraries.
if (UNIX AND NOT APPLE)
find_package(GTK${SLIC3R_GTK} REQUIRED)
target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS})
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES})
endif ()

View File

@ -612,7 +612,7 @@ struct _3DScene
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
};
static constexpr float BedEpsilon = float(EPSILON);
static constexpr float BedEpsilon = 3.f * float(EPSILON);
class ExtrusionToVert : public ExtrusionVisitorConst {
float print_z;

View File

@ -151,9 +151,9 @@ void GCodeViewer::TBuffer::reset()
}
// release cpu memory
indices = std::vector<IBuffer>();
paths = std::vector<Path>();
render_paths = std::vector<RenderPath>();
indices.clear();
paths.clear();
render_paths.clear();
}
void GCodeViewer::TBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id)
@ -798,9 +798,9 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
unsigned int start_vertex_offset = buffer.start_segment_vertex_offset();
unsigned int end_vertex_offset = buffer.end_segment_vertex_offset();
for (size_t i = 0; i < buffer.render_paths.size(); ++i) {
size_t i = 0;
for (const RenderPath& render_path : buffer.render_paths) {
// get paths segments from buffer paths
const RenderPath& render_path = buffer.render_paths[i];
const IndexBuffer& ibuffer = indices[render_path.index_buffer_id];
const Path& path = buffer.paths[render_path.path_id];
float half_width = 0.5f * path.width;
@ -965,6 +965,8 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
for (const Triangle& t : out_triangles) {
fprintf(fp, "f %zu//%zu %zu//%zu %zu//%zu\n", t[0], t[0], t[1], t[1], t[2], t[2]);
}
++ i;
}
fclose(fp);
@ -1978,6 +1980,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
// second pass: filter paths by sequential data and collect them by color
RenderPath *render_path = nullptr;
for (const auto& [buffer, index_buffer_id, path_id] : paths) {
const Path& path = buffer->paths[path_id];
if (m_sequential_view.current.last <= path.first.s_id || path.last.s_id <= m_sequential_view.current.first)
@ -2008,16 +2011,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
default: { color = { 0.0f, 0.0f, 0.0f }; break; }
}
unsigned int ibuffer_id = index_buffer_id;
auto it = std::find_if(buffer->render_paths.begin(), buffer->render_paths.end(),
[color, ibuffer_id](const RenderPath& path) { return path.index_buffer_id == ibuffer_id && path.color == color; });
if (it == buffer->render_paths.end()) {
it = buffer->render_paths.insert(buffer->render_paths.end(), RenderPath());
it->color = color;
it->path_id = path_id;
it->index_buffer_id = index_buffer_id;
}
RenderPath key{ color, static_cast<unsigned int>(index_buffer_id), path_id };
if (render_path == nullptr || ! RenderPathPropertyEqual()(*render_path, key))
render_path = const_cast<RenderPath*>(&(*buffer->render_paths.emplace(key).first));
unsigned int segments_count = std::min(m_sequential_view.current.last, path.last.s_id) - std::max(m_sequential_view.current.first, path.first.s_id) + 1;
unsigned int size_in_indices = 0;
switch (buffer->render_primitive_type)
@ -2026,7 +2022,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
case TBuffer::ERenderPrimitiveType::Line:
case TBuffer::ERenderPrimitiveType::Triangle: { size_in_indices = buffer->indices_per_segment() * (segments_count - 1); break; }
}
it->sizes.push_back(size_in_indices);
render_path->sizes.push_back(size_in_indices);
unsigned int delta_1st = 0;
if (path.first.s_id < m_sequential_view.current.first && m_sequential_view.current.first <= path.last.s_id)
@ -2035,7 +2031,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (buffer->render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle)
delta_1st *= buffer->indices_per_segment();
it->offsets.push_back(static_cast<size_t>((path.first.i_id + delta_1st) * sizeof(unsigned int)));
render_path->offsets.push_back(static_cast<size_t>((path.first.i_id + delta_1st) * sizeof(unsigned int)));
}
// set sequential data to their final value
@ -3054,7 +3050,7 @@ void GCodeViewer::log_memory_used(const std::string& label, int64_t additional)
int64_t render_paths_size = 0;
for (const TBuffer& buffer : m_buffers) {
paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.paths, Path);
render_paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.render_paths, RenderPath);
render_paths_size += SLIC3R_STDUNORDEREDSET_MEMSIZE(buffer.render_paths, RenderPath);
for (const RenderPath& path : buffer.render_paths) {
render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.sizes, unsigned int);
render_paths_size += SLIC3R_STDVEC_MEMSIZE(path.offsets, size_t);

View File

@ -7,6 +7,8 @@
#include <cstdint>
#include <float.h>
#include <set>
#include <unordered_set>
namespace Slic3r {
@ -149,12 +151,36 @@ class GCodeViewer
// Used to batch the indices needed to render paths
struct RenderPath
{
// Render path property
Color color;
unsigned int path_id;
unsigned int index_buffer_id;
// Render path content
unsigned int path_id;
std::vector<unsigned int> sizes;
std::vector<size_t> offsets; // use size_t because we need an unsigned int whose size matches pointer's size (used in the call glMultiDrawElements())
};
struct RenderPathPropertyHash {
size_t operator() (const RenderPath &p) const {
// Conver the RGB value to an integer hash.
// return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.index_buffer_id);
return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.index_buffer_id);
}
};
struct RenderPathPropertyLower {
bool operator() (const RenderPath &l, const RenderPath &r) const {
for (int i = 0; i < 3; ++ i)
if (l.color[i] < r.color[i])
return true;
else if (l.color[i] > r.color[i])
return false;
return l.index_buffer_id < r.index_buffer_id;
}
};
struct RenderPathPropertyEqual {
bool operator() (const RenderPath &l, const RenderPath &r) const {
return l.color == r.color && l.index_buffer_id == r.index_buffer_id;
}
};
// buffer containing data for rendering a specific toolpath type
struct TBuffer
@ -172,7 +198,9 @@ class GCodeViewer
std::string shader;
std::vector<Path> paths;
std::vector<RenderPath> render_paths;
// std::set seems to perform singificantly better, at least on Windows.
// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
std::set<RenderPath, RenderPathPropertyLower> render_paths;
bool visible{ false };
void reset();

View File

@ -3004,6 +3004,7 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt)
}
//render();
m_dirty = true;
wxWakeUpIdle();
}
void GLCanvas3D::request_extra_frame_delayed(int miliseconds)
@ -4175,7 +4176,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
custom_color[1] = clr.Green() / 255.f;
custom_color[2] = clr.Blue() / 255.f;
}
for (const GLVolume* vol : visible_volumes)
for (GLVolume* vol : visible_volumes)
{
if (vol->printable && !vol->is_outside) {
if (custom_color[0] < 0) {
@ -4187,7 +4188,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
} else {
shader->set_uniform("uniform_color", gray);
}
// the volume may have been deactivated by an active gizmo
bool is_active = vol->is_active;
vol->is_active = true;
vol->render();
vol->is_active = is_active;
}
shader->stop_using();

View File

@ -652,7 +652,6 @@ public:
void set_toolpath_view_type(GCodeViewer::EViewType type);
void set_volumes_z_range(const std::array<double, 2>& range);
void set_toolpaths_z_range(const std::array<unsigned int, 2>& range);
void set_toolpaths_range(double low, double high);
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
std::vector<int> load_object(const Model& model, int obj_idx);

View File

@ -139,7 +139,7 @@ public:
memDC.SetFont(m_action_font);
memDC.SetTextForeground(wxColour(0, 102, 255));
memDC.DrawText(text, int(m_scale * 60), int(m_scale * 275));
memDC.DrawText(text, int(m_scale * 60), m_action_line_y_position);
memDC.SelectObject(wxNullBitmap);
set_bitmap(bitmap);
@ -214,14 +214,22 @@ public:
memDc.SetFont(m_constant_text.version_font);
memDc.DrawLabel(m_constant_text.version, banner_rect, wxALIGN_TOP | wxALIGN_LEFT);
int version_height = memDc.GetTextExtent(m_constant_text.version).GetY();
memDc.SetFont(m_constant_text.credits_font);
memDc.DrawLabel(m_constant_text.credits, banner_rect, wxALIGN_BOTTOM | wxALIGN_LEFT);
int credits_height = memDc.GetMultiLineTextExtent(m_constant_text.credits).GetY();
int text_height = memDc.GetTextExtent("text").GetY();
// calculate position for the dynamic text
int logo_and_header_height = margin + logo_size + title_height + version_height;
m_action_line_y_position = logo_and_header_height + 0.5 * (bmp.GetHeight() - margin - credits_height - logo_and_header_height - text_height);
}
private:
wxBitmap m_main_bitmap;
wxFont m_action_font;
int m_action_line_y_position;
float m_scale {1.0};
struct ConstantText
@ -265,7 +273,8 @@ private:
float title_font_scale = (float)text_banner_width / GetTextExtent(m_constant_text.title).GetX();
scale_font(m_constant_text.title_font, title_font_scale > 3.5f ? 3.5f : title_font_scale);
scale_font(m_constant_text.version_font, 2.f);
float version_font_scale = (float)text_banner_width / GetTextExtent(m_constant_text.version).GetX();
scale_font(m_constant_text.version_font, version_font_scale > 2.f ? 2.f : version_font_scale);
// The width of the credits information string doesn't respect to the banner width some times.
// So, scale credits_font in the respect to the longest string width
@ -1945,11 +1954,9 @@ bool GUI_App::OnExceptionInMainLoop()
void GUI_App::OSXStoreOpenFiles(const wxArrayString &fileNames)
{
size_t num_gcodes = 0;
for (const wxString &filename : fileNames) {
wxString fn = filename.Upper();
if (fn.EndsWith(".G") || fn.EndsWith(".GCODE"))
for (const wxString &filename : fileNames)
if (is_gcode_file(into_u8(filename)))
++ num_gcodes;
}
if (fileNames.size() == num_gcodes) {
// Opening PrusaSlicer by drag & dropping a G-Code onto PrusaSlicer icon in Finder,
// just G-codes were passed. Switch to G-code viewer mode.
@ -1969,8 +1976,7 @@ void GUI_App::MacOpenFiles(const wxArrayString &fileNames)
std::vector<wxString> gcode_files;
std::vector<wxString> non_gcode_files;
for (const auto& filename : fileNames) {
wxString fn = filename.Upper();
if (fn.EndsWith(".G") || fn.EndsWith(".GCODE"))
if (is_gcode_file(into_u8(filename)))
gcode_files.emplace_back(filename);
else {
files.emplace_back(into_u8(filename));

View File

@ -16,11 +16,26 @@
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/convert.hpp>
#if __APPLE__
#include <signal.h>
#endif // __APPLE__
namespace Slic3r {
namespace GUI {
int GUI_Run(GUI_InitParams &params)
{
#if __APPLE__
// On OSX, we use boost::process::spawn() to launch new instances of PrusaSlicer from another PrusaSlicer.
// boost::process::spawn() sets SIGCHLD to SIGIGN for the child process, thus if a child PrusaSlicer spawns another
// subprocess and the subrocess dies, the child PrusaSlicer will not receive information on end of subprocess
// (posix waitpid() call will always fail).
// https://jmmv.dev/2008/10/boostprocess-and-sigchld.html
// The child instance of PrusaSlicer has to reset SIGCHLD to its default, so that posix waitpid() and similar continue to work.
// See GH issue #5507
signal(SIGCHLD, SIG_DFL);
#endif // __APPLE__
try {
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {

View File

@ -1194,7 +1194,7 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
**/
m_prevent_list_events = true;//it's needed for GTK
/* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid value,
/* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid vaSome textlue,
* so set some nonempty string
*/
wxTextDataObject* obj = new wxTextDataObject;
@ -1226,8 +1226,10 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event)
{
const wxDataViewItem& item = event.GetItem();
if (!can_drop(item))
if (!can_drop(item)) {
event.Veto();
m_prevent_list_events = false;
}
}
void ObjectList::OnDrop(wxDataViewEvent &event)
@ -1252,7 +1254,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
// It looks like a fixed in current version of the wxWidgets
// #ifdef __WXGTK__
// /* Under GTK, DnD moves an item between another two items.
// * And event.GetItem() return item, which is under "insertion line"
// * And event.GetItem() return item, which is under "insertion line"Some text
// * So, if we move item down we should to decrease the to_volume_id value
// **/
// if (to_volume_id > from_volume_id) to_volume_id--;

View File

@ -401,7 +401,7 @@ void Preview::reload_print(bool keep_volumes)
m_volumes_cleanup_required = !keep_volumes;
return;
}
#endif /* __linux __ */
#endif /* __linux__ */
if (
#ifdef __linux__
m_volumes_cleanup_required ||

View File

@ -252,14 +252,31 @@ namespace instance_check_internal
bool instance_check(int argc, char** argv, bool app_config_single_instance)
{
#ifndef _WIN32
boost::system::error_code ec;
#endif
std::size_t hashed_path =
std::size_t hashed_path;
#ifdef _WIN32
std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
#else
std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]), ec).string());
boost::system::error_code ec;
#ifdef __linux__
// If executed by an AppImage, start the AppImage, not the main process.
// see https://docs.appimage.org/packaging-guide/environment-variables.html#id2
const char *appimage_env = std::getenv("APPIMAGE");
bool appimage_env_valid = false;
if (appimage_env) {
try {
auto appimage_path = boost::filesystem::canonical(boost::filesystem::path(appimage_env));
if (boost::filesystem::exists(appimage_path)) {
hashed_path = std::hash<std::string>{}(appimage_path.string());
appimage_env_valid = true;
}
} catch (std::exception &) {
}
if (! appimage_env_valid)
BOOST_LOG_TRIVIAL(error) << "APPIMAGE environment variable was set, but it does not point to a valid file: " << appimage_env;
}
if (! appimage_env_valid)
#endif // __linux__
hashed_path = std::hash<std::string>{}(boost::filesystem::canonical(boost::filesystem::system_complete(argv[0]), ec).string());
if (ec.value() > 0) { // canonical was not able to find the executable (can happen with appimage on some systems. Does it fail on Fuse file systems?)
ec.clear();
// Compose path with boost canonical of folder and filename
@ -269,7 +286,7 @@ bool instance_check(int argc, char** argv, bool app_config_single_instance)
hashed_path = std::hash<std::string>{}(boost::filesystem::system_complete(argv[0]).string());
}
}
#endif // win32
#endif // _WIN32
std::string lock_name = std::to_string(hashed_path);
GUI::wxGetApp().set_instance_hash(hashed_path);

View File

@ -73,9 +73,14 @@ void FillBedJob::prepare()
// This is the maximum number of items, the real number will always be close but less.
int needed_items = (bed_area - fixed_area) / poly_area;
ModelInstance *mi = model_object->instances[0];
int sel_id = m_plater->get_selection().get_instance_idx();
// if the selection is not a single instance, choose the first as template
sel_id = std::max(sel_id, 0);
ModelInstance *mi = model_object->instances[sel_id];
ArrangePolygon template_ap = get_arrange_poly(PtrWrapper{mi}, m_plater);
for (int i = 0; i < needed_items; ++i) {
ArrangePolygon ap;
ArrangePolygon ap = template_ap;
ap.poly = m_selected.front().poly;
ap.bed_idx = arrangement::UNARRANGED;
ap.setter = [this, mi](const ArrangePolygon &p) {

View File

@ -1235,11 +1235,11 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
if (this->activate_existing(notification.get())) {
m_pop_notifications.back()->update(notification->get_data());
canvas.request_extra_frame();
canvas.request_extra_frame_delayed(33);
return false;
} else {
m_pop_notifications.emplace_back(std::move(notification));
canvas.request_extra_frame();
canvas.request_extra_frame_delayed(33);
return true;
}
}
@ -1389,15 +1389,19 @@ void NotificationManager::update_notifications()
if (!top_level_wnd->IsActive())
return;
static size_t last_size = m_pop_notifications.size();
//static size_t last_size = m_pop_notifications.size();
//request frames
int64_t next_render = std::numeric_limits<int64_t>::max();
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
std::unique_ptr<PopNotification>& notification = *it;
notification->set_paused(m_hovered);
notification->update_state();
next_render = std::min<int64_t>(next_render, notification->next_render());
if (notification->get_state() == PopNotification::EState::Finished)
it = m_pop_notifications.erase(it);
else {
notification->set_paused(m_hovered);
notification->update_state();
++it;
}
}
@ -1438,16 +1442,11 @@ void NotificationManager::update_notifications()
if (m_requires_render)
m_requires_update = true;
*/
//request frames
int64_t next_render = std::numeric_limits<int64_t>::max();
const int64_t max = std::numeric_limits<int64_t>::max();
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
next_render = std::min<int64_t>(next_render, notification->next_render());
}
if (next_render == 0)
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
else if (next_render < max)
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(33); //few milliseconds to get from GLCanvas::render
else if (next_render < std::numeric_limits<int64_t>::max())
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render));
/*

View File

@ -585,7 +585,7 @@ void PhysicalPrinterDialog::OnOK(wxEvent& event)
return;
}
if (printer_name == m_default_name) {
warning_catcher(this, _L("You should to change a name of your printer device. It can't be saved."));
warning_catcher(this, _L("You should change the name of your printer device."));
return;
}

View File

@ -3596,6 +3596,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
*/
wxGetApp().obj_list()->update_object_list_by_printer_technology();
}
#ifdef __WXMSW__
// From the Win 2004 preset combobox lose a focus after change the preset selection
// and that is why the up/down arrow doesn't work properly
// (see https://github.com/prusa3d/PrusaSlicer/issues/5531 ).
// So, set the focus to the combobox explicitly
combo->SetFocus();
#endif
}
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
@ -4885,9 +4893,7 @@ void Plater::load_gcode()
void Plater::load_gcode(const wxString& filename)
{
if (filename.empty() ||
(!filename.Lower().EndsWith(".gcode") && !filename.Lower().EndsWith(".g")) ||
m_last_loaded_gcode == filename)
if (! is_gcode_file(into_u8(filename)) || m_last_loaded_gcode == filename)
return;
m_last_loaded_gcode = filename;

View File

@ -32,6 +32,14 @@
#include "PhysicalPrinterDialog.hpp"
#include "SavePresetDialog.hpp"
// A workaround for a set of issues related to text fitting into gtk widgets:
// See e.g.: https://github.com/prusa3d/PrusaSlicer/issues/4584
#if defined(__WXGTK20__) || defined(__WXGTK3__)
#include <glib-2.0/glib-object.h>
#include <pango-1.0/pango/pango-layout.h>
#include <gtk/gtk.h>
#endif
using Slic3r::GUI::format_wxstr;
namespace Slic3r {
@ -179,6 +187,25 @@ void PresetComboBox::update_selection()
SetSelection(m_last_selected);
SetToolTip(GetString(m_last_selected));
// A workaround for a set of issues related to text fitting into gtk widgets:
// See e.g.: https://github.com/prusa3d/PrusaSlicer/issues/4584
#if defined(__WXGTK20__) || defined(__WXGTK3__)
GList* cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(m_widget));
// 'cells' contains the GtkCellRendererPixBuf for the icon,
// 'cells->next' contains GtkCellRendererText for the text we need to ellipsize
if (!cells || !cells->next) return;
auto cell = static_cast<GtkCellRendererText *>(cells->next->data);
if (!cell) return;
g_object_set(G_OBJECT(cell), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
// Only the list of cells must be freed, the renderer isn't ours to free
g_list_free(cells);
#endif
}
void PresetComboBox::update(std::string select_preset_name)
@ -905,6 +932,13 @@ TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type)
}
evt.StopPropagation();
#ifdef __WXMSW__
// From the Win 2004 preset combobox lose a focus after change the preset selection
// and that is why the up/down arrow doesn't work properly
// (see https://github.com/prusa3d/PrusaSlicer/issues/5531 ).
// So, set the focus to the combobox explicitly
this->SetFocus();
#endif
});
}

View File

@ -82,6 +82,17 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
Fit();
CenterOnParent();
#ifdef __linux__
// On Linux with GTK2 when text control lose the focus then selection (colored background) disappears but text color stay white
// and as a result the text is invisible with light mode
// see https://github.com/prusa3d/PrusaSlicer/issues/4532
// Workaround: Unselect text selection explicitly on kill focus
txt_filename->Bind(wxEVT_KILL_FOCUS, [this](wxEvent& e) {
e.Skip();
txt_filename->SetInsertionPoint(txt_filename->GetLastPosition());
}, txt_filename->GetId());
#endif /* __linux__ */
Bind(wxEVT_SHOW, [=](const wxShowEvent &) {
// Another similar case where the function only works with EVT_SHOW + CallAfter,
// this time on Mac.

View File

@ -261,19 +261,31 @@ void RemovableDriveManager::eject_drive()
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
this->update();
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
#if __APPLE__
// If eject is still pending on the eject thread, wait until it finishes.
//FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
// to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
// finishes quickly.
this->eject_thread_finish();
#endif
BOOST_LOG_TRIVIAL(info) << "Ejecting started";
DriveData drive_data;
{
tbb::mutex::scoped_lock lock(m_drives_mutex);
auto it_drive_data = this->find_last_save_path_drive_data();
if (it_drive_data != m_current_drives.end()) {
std::string correct_path(m_last_save_path);
#ifndef __APPLE__
for (size_t i = 0; i < correct_path.size(); ++i)
if (correct_path[i]==' ') {
correct_path = correct_path.insert(i,1,'\\');
++ i;
if (it_drive_data == m_current_drives.end())
return;
drive_data = *it_drive_data;
}
std::string correct_path(m_last_save_path);
#if __APPLE__
// On Apple, run the eject asynchronously on a worker thread, see the discussion at GH issue #4844.
m_eject_thread = new boost::thread([this, correct_path, drive_data]()
#endif
{
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
// there is no usable command in c++ so terminal command is used instead
// but neither triggers "succesful safe removal messege"
@ -296,31 +308,36 @@ void RemovableDriveManager::eject_drive()
// wait for command to finnish (blocks ui thread)
std::error_code ec;
child.wait(ec);
bool success = false;
if (ec) {
// The wait call can fail, as it did in https://github.com/prusa3d/PrusaSlicer/issues/5507
// It can happen even in cases where the eject is sucessful, but better report it as failed.
// We did not find a way to reliably retrieve the exit code of the process.
BOOST_LOG_TRIVIAL(error) << "boost::process::child::wait() failed during Ejection. State of Ejection is unknown. Error code: " << ec.value();
assert(m_callback_evt_handler);
if (m_callback_evt_handler)
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
return;
}
} else {
int err = child.exit_code();
if (err) {
BOOST_LOG_TRIVIAL(error) << "Ejecting failed. Exit code: " << err;
assert(m_callback_evt_handler);
if (m_callback_evt_handler)
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
return;
}
} else {
BOOST_LOG_TRIVIAL(info) << "Ejecting finished";
success = true;
}
}
assert(m_callback_evt_handler);
if (m_callback_evt_handler)
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(std::move(*it_drive_data), true)));
m_current_drives.erase(it_drive_data);
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(drive_data, success)));
if (success) {
// Remove the drive_data from m_current drives, searching by value, not by pointer, as m_current_drives may get modified during
// asynchronous execution on m_eject_thread.
tbb::mutex::scoped_lock lock(m_drives_mutex);
auto it = std::find(m_current_drives.begin(), m_current_drives.end(), drive_data);
if (it != m_current_drives.end())
m_current_drives.erase(it);
}
}
#if __APPLE__
);
#endif // __APPLE__
}
std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
@ -382,7 +399,11 @@ void RemovableDriveManager::init(wxEvtHandler *callback_evt_handler)
void RemovableDriveManager::shutdown()
{
#if __APPLE__
this->unregister_window_osx();
// If eject is still pending on the eject thread, wait until it finishes.
//FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
// to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
// finishes quickly.
this->eject_thread_finish();
#endif
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
@ -493,4 +514,15 @@ std::vector<DriveData>::const_iterator RemovableDriveManager::find_last_save_pat
[this](const DriveData &data){ return data.path == m_last_save_path; });
}
#if __APPLE__
void RemovableDriveManager::eject_thread_finish()
{
if (m_eject_thread) {
m_eject_thread->join();
delete m_eject_thread;
m_eject_thread = nullptr;
}
}
#endif // __APPLE__
}} // namespace Slic3r::GUI

View File

@ -132,6 +132,8 @@ private:
void eject_device(const std::string &path);
// Opaque pointer to RemovableDriveManagerMM
void *m_impl_osx;
boost::thread *m_eject_thread { nullptr };
void eject_thread_finish();
#endif
};

View File

@ -316,6 +316,13 @@ void Tab::create_preset_tab()
// This helps to process all the cursor key events on Windows in the tree control,
// so that the cursor jumps to the last item.
m_treectrl->Bind(wxEVT_TREE_SEL_CHANGED, [this](wxTreeEvent&) {
#ifdef __linux__
// Events queue is opposite On Linux. wxEVT_SET_FOCUS invokes after wxEVT_TREE_SEL_CHANGED,
// and a result wxEVT_KILL_FOCUS doesn't invoke for the TextCtrls.
// see https://github.com/prusa3d/PrusaSlicer/issues/5720
// So, call SetFocus explicitly for this control before changing of the selection
m_treectrl->SetFocus();
#endif
if (!m_disable_tree_sel_changed_event && !m_pages.empty()) {
if (m_page_switch_running)
m_page_switch_planned = true;
@ -508,7 +515,7 @@ void Tab::update_labels_colour()
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
opt.first == "compatible_prints" || opt.first == "compatible_printers" ) {
if (m_colored_Label_colors.find(opt.first) != m_colored_Label_colors.end())
*m_colored_Label_colors.at(opt.first) = *color;
m_colored_Label_colors.at(opt.first) = *color;
continue;
}
@ -547,7 +554,7 @@ void Tab::decorate()
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
opt.first == "compatible_prints" || opt.first == "compatible_printers")
colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : m_colored_Label_colors.at(opt.first);
colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : &m_colored_Label_colors.at(opt.first);
if (!colored_label_clr) {
field = get_field(opt.first);
@ -3622,8 +3629,8 @@ void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::strin
line.widget = widget;
line.label_path = path;
m_colored_Label_colors[opt_key] = &m_default_text_clr;
line.full_Label_color = m_colored_Label_colors[opt_key];
m_colored_Label_colors[opt_key] = m_default_text_clr;
line.full_Label_color = &m_colored_Label_colors[opt_key];
optgroup->append_line(line);
}

View File

@ -247,7 +247,7 @@ public:
// map of option name -> wxColour (color of the colored label, associated with option)
// Used for options which don't have corresponded field
std::map<std::string, wxColour*> m_colored_Label_colors;
std::map<std::string, wxColour> m_colored_Label_colors;
// Counter for the updating (because of an update() function can have a recursive behavior):
// 1. increase value from the very beginning of an update() function

View File

@ -78,6 +78,12 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
args.emplace_back("--single-instance");
boost::process::spawn(bin_path, args);
// boost::process::spawn() sets SIGCHLD to SIGIGN for the child process, thus if a child PrusaSlicer spawns another
// subprocess and the subrocess dies, the child PrusaSlicer will not receive information on end of subprocess
// (posix waitpid() call will always fail).
// https://jmmv.dev/2008/10/boostprocess-and-sigchld.html
// The child instance of PrusaSlicer has to reset SIGCHLD to its default, so that posix waitpid() and similar continue to work.
// See GH issue #5507
}
catch (const std::exception& ex) {
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
@ -87,7 +93,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
{
std::vector<const char*> args;
args.reserve(3);
#ifdef __linux
#ifdef __linux__
static const char* gcodeviewer_param = "--gcodeviewer";
{
// If executed by an AppImage, start the AppImage, not the main process.
@ -99,7 +105,7 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
args.emplace_back(gcodeviewer_param);
}
}
#endif // __linux
#endif // __linux__
std::string my_path;
if (args.empty()) {
// Binary path was not set to the AppImage in the Linux specific block above, call the application directly.

View File

@ -313,7 +313,7 @@ void Serial::set_baud_rate(unsigned baud_rate)
speed_t newSpeed = baud_rate;
handle_errno(::ioctl(handle, IOSSIOSPEED, &newSpeed));
handle_errno(::tcsetattr(handle, TCSANOW, &ios));
#elif __linux
#elif __linux__
/* The following definitions are kindly borrowed from:
/usr/include/asm-generic/termbits.h

View File

@ -4,7 +4,7 @@
set(SLIC3R_APP_NAME "SuperSlicer")
set(SLIC3R_APP_KEY "SuperSlicer")
set(SLIC3R_VERSION "2.3.55")
set(SLIC3R_VERSION_FULL "2.3.55.4")
set(SLIC3R_VERSION_FULL "2.3.55.5")
set(SLIC3R_BUILD_ID "SuperSlicer_${SLIC3R_VERSION_FULL}")
set(SLIC3R_RC_VERSION "2,3,55,4")
set(SLIC3R_RC_VERSION "2,3,55,5")
set(SLIC3R_RC_VERSION_DOTS "${SLIC3R_VERSION_FULL}")