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

# Conflicts:
#	src/libslic3r/MotionPlanner.cpp
#	src/libslic3r/libslic3r.h
This commit is contained in:
Lukáš Hejl 2020-11-29 17:27:23 +01:00
commit 87879034f6
175 changed files with 34821 additions and 26174 deletions

BIN
PrusaSlicer.mo Normal file

Binary file not shown.

View file

@ -80,7 +80,6 @@ ExternalProject_Add(dep_libcurl
--disable-smb --disable-smb
--disable-smtp --disable-smtp
--disable-gopher --disable-gopher
--disable-crypto-auth
--without-gssapi --without-gssapi
--without-libpsl --without-libpsl
--without-libidn2 --without-libidn2

View file

@ -67,7 +67,6 @@ ExternalProject_Add(dep_libcurl
--disable-smb --disable-smb
--disable-smtp --disable-smtp
--disable-gopher --disable-gopher
--disable-crypto-auth
--without-gssapi --without-gssapi
--without-libpsl --without-libpsl
--without-libidn2 --without-libidn2

File diff suppressed because it is too large Load diff

View file

@ -5,21 +5,13 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Poedit 2.4.1\n" "X-Generator: Poedit 2.4.2\n"
"Project-Id-Version: \n" "Project-Id-Version: \n"
"POT-Creation-Date: \n" "POT-Creation-Date: \n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
"Last-Translator: Oleksandra Iushchenko <yusanka@gmail.com>\n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
#: src/slic3r/GUI/MainFrame.cpp:166
msgid " - Remember to check for updates at https://github.com/prusa3d/PrusaSlicer/releases"
msgstr "- Nezapomeňte zkontrolovat aktualizace na https://github.com/prusa3d/PrusaSlicer/releases"
#: src/slic3r/GUI/MainFrame.cpp:1573
msgid " was successfully sliced."
msgstr " byl úspěšně slicován."
#: src/slic3r/GUI/Tab.cpp:4124 #: src/slic3r/GUI/Tab.cpp:4124
msgid "" msgid ""
"\"%1%\" is disabled because \"%2%\" is on in \"%3%\" category.\n" "\"%1%\" is disabled because \"%2%\" is on in \"%3%\" category.\n"
@ -50,6 +42,10 @@ msgstr "%1% Přednastavení"
msgid "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets." msgid "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."
msgstr "%1% tiskárna byla aktivní v době, kdy byly pořízeny kroky Zpět / Vpřed. Přepnutí na tiskárnu %1% vyžaduje opětovné načtení předvoleb %1%." msgstr "%1% tiskárna byla aktivní v době, kdy byly pořízeny kroky Zpět / Vpřed. Přepnutí na tiskárnu %1% vyžaduje opětovné načtení předvoleb %1%."
#: src/slic3r/GUI/MainFrame.cpp:1585
msgid "%1% was successfully sliced."
msgstr "%1% byl úspěšně naslicován."
#: src/libslic3r/Print.cpp:1400 #: src/libslic3r/Print.cpp:1400
msgid "%1%=%2% mm is too low to be printable at a layer height %3% mm" msgid "%1%=%2% mm is too low to be printable at a layer height %3% mm"
msgstr "%1%=%2% mm je příliš nízké na to, aby bylo možné tisknout ve výšce vrstvy %3% mm" msgstr "%1%=%2% mm je příliš nízké na to, aby bylo možné tisknout ve výšce vrstvy %3% mm"
@ -98,6 +94,11 @@ msgstr "%s &Webová stránka"
msgid "%s - BREAKING CHANGE" msgid "%s - BREAKING CHANGE"
msgstr "%s - ZLOMOVÁ ZMĚNA" msgstr "%s - ZLOMOVÁ ZMĚNA"
#: src/slic3r/GUI/Plater.cpp:1410
#, c-format
msgid "%s - Drop project file"
msgstr "%s - Otevírání projektu"
#: src/slic3r/GUI/UpdateDialogs.cpp:211 #: src/slic3r/GUI/UpdateDialogs.cpp:211
#, c-format #, c-format
msgid "%s configuration is incompatible" msgid "%s configuration is incompatible"
@ -395,7 +396,7 @@ msgstr "Obecným pravidlem je 60 °C pro PLA a 110 °C pro ABS. Zadejte nula, po
#: src/slic3r/GUI/GLCanvas3D.cpp:634 #: src/slic3r/GUI/GLCanvas3D.cpp:634
msgid "A toolpath outside the print area was detected." msgid "A toolpath outside the print area was detected."
msgstr "Byla detekována cesta mimo tiskovou oblast" msgstr "Byla detekována cesta mimo tiskovou oblast."
#: src/slic3r/GUI/AboutDialog.cpp:212 src/slic3r/GUI/AboutDialog.cpp:215 #: src/slic3r/GUI/AboutDialog.cpp:212 src/slic3r/GUI/AboutDialog.cpp:215
#, c-format #, c-format
@ -428,6 +429,10 @@ msgstr "Přesnost"
msgid "Accurate" msgid "Accurate"
msgstr "Přesné" msgstr "Přesné"
#: src/slic3r/GUI/Plater.cpp:1423
msgid "Action"
msgstr "Akce"
#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:78 #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:78
msgid "Activate" msgid "Activate"
msgstr "Aktivovat" msgstr "Aktivovat"
@ -728,10 +733,6 @@ msgstr "Všechna gizma: Rotace - levé talčítko myši; Posun - pravé tlačít
msgid "All installed printers are compatible with the selected filament." msgid "All installed printers are compatible with the selected filament."
msgstr "Všechny instalované tiskárny jsou kompatibilní s vybraným filamentem." msgstr "Všechny instalované tiskárny jsou kompatibilní s vybraným filamentem."
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:737
msgid "All modified options will be reverted."
msgstr "Všechny upravené možnosti budou vráceny."
#: src/libslic3r/Print.cpp:1245 #: src/libslic3r/Print.cpp:1245
msgid "All objects are outside of the print volume." msgid "All objects are outside of the print volume."
msgstr "Všechny objekty jsou mimo tiskový prostor." msgstr "Všechny objekty jsou mimo tiskový prostor."
@ -740,6 +741,10 @@ msgstr "Všechny objekty jsou mimo tiskový prostor."
msgid "All objects will be removed, continue?" msgid "All objects will be removed, continue?"
msgstr "Všechny objekty budou odebrány, pokračovat?" msgstr "Všechny objekty budou odebrány, pokračovat?"
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:737
msgid "All settings changes will be discarded."
msgstr "Všechny změny v nastavení budou zahozeny."
#: src/slic3r/GUI/ConfigWizard.cpp:307 #: src/slic3r/GUI/ConfigWizard.cpp:307
msgid "All standard" msgid "All standard"
msgstr "Všechny běžné" msgstr "Všechny běžné"
@ -987,6 +992,10 @@ msgstr "Automatické aktualizace"
msgid "Automatically repair an STL file" msgid "Automatically repair an STL file"
msgstr "Automaticky opravit STL soubor" msgstr "Automaticky opravit STL soubor"
#: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:129
msgid "Autoset by angle"
msgstr "Automaticky podle úhlu"
#: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:233 #: src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp:233
msgid "Autoset custom supports" msgid "Autoset custom supports"
msgstr "Automatické nastavení podpěr" msgstr "Automatické nastavení podpěr"
@ -1749,7 +1758,9 @@ msgstr "Kopírování dočasného G-codu do výstupního G-codu selhalo"
msgid "" msgid ""
"Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\n" "Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\n"
"Error message: %1%" "Error message: %1%"
msgstr "Kopírování dočasného G-codu do výstupního G-codu se nezdařilo. Není SD karta chráněná proti zápisu?" msgstr ""
"Kopírování dočasného G-codu do výstupního G-codu se nezdařilo. Není SD karta chráněná proti zápisu?\n"
"Chybová hláška: %1%"
#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:147 #: src/slic3r/GUI/BackgroundSlicingProcess.cpp:147
msgid "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp." msgid "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."
@ -2394,6 +2405,10 @@ msgstr "Neuspořádávat"
msgid "Don't notify about new releases any more" msgid "Don't notify about new releases any more"
msgstr "Neupozorňovat na nové verze" msgstr "Neupozorňovat na nové verze"
#: src/slic3r/GUI/Plater.cpp:1431
msgid "Don't show again"
msgstr "Znovu nezobrazovat"
#: src/libslic3r/PrintConfig.cpp:403 #: src/libslic3r/PrintConfig.cpp:403
msgid "Don't support bridges" msgid "Don't support bridges"
msgstr "Nevytvářet podpěry pod mosty" msgstr "Nevytvářet podpěry pod mosty"
@ -2534,6 +2549,10 @@ msgstr "Nadzvednutí objektu je příliš malé. Pomocí funkce „Podložka oko
msgid "Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute intervals into the G-code to let the firmware show accurate remaining time. As of now only the Prusa i3 MK3 firmware recognizes M73. Also the i3 MK3 firmware supports M73 Qxx Sxx for the silent mode." msgid "Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute intervals into the G-code to let the firmware show accurate remaining time. As of now only the Prusa i3 MK3 firmware recognizes M73. Also the i3 MK3 firmware supports M73 Qxx Sxx for the silent mode."
msgstr "Vkládání M73 P[počet vytištěných procent] R[zbývající čas v minutách] v 1 minutových intervalech do G-codu, aby firmware ukázal přesný zbývající čas. M73 nyní rozpoznává pouze firmware tiskárny Prusa i3 MK3. Firmware i3 MK3 také podporuje M73 Qxx Sxx pro tichý režim." msgstr "Vkládání M73 P[počet vytištěných procent] R[zbývající čas v minutách] v 1 minutových intervalech do G-codu, aby firmware ukázal přesný zbývající čas. M73 nyní rozpoznává pouze firmware tiskárny Prusa i3 MK3. Firmware i3 MK3 také podporuje M73 Qxx Sxx pro tichý režim."
#: src/libslic3r/PrintConfig.cpp:1217
msgid "Emit to G-code"
msgstr "Emitivat do G-codu"
#: src/libslic3r/GCode.cpp:622 #: src/libslic3r/GCode.cpp:622
msgid "Empty layers detected, the output would not be printable." msgid "Empty layers detected, the output would not be printable."
msgstr "Byly detekovány prázdné vrstvy, model by nebylo možné vytisknout." msgstr "Byly detekovány prázdné vrstvy, model by nebylo možné vytisknout."
@ -2565,7 +2584,7 @@ msgstr "Zapnout ironing"
#: src/libslic3r/PrintConfig.cpp:1125 #: src/libslic3r/PrintConfig.cpp:1125
msgid "Enable ironing of the top layers with the hot print head for smooth surface" msgid "Enable ironing of the top layers with the hot print head for smooth surface"
msgstr "Pro hladké vrchní vrstvy povolte ironing pomocí ohřáté tiskové hlavy." msgstr "Pro hladké vrchní vrstvy povolte ironing pomocí ohřáté tiskové hlavy"
#: src/libslic3r/PrintConfig.cpp:2009 #: src/libslic3r/PrintConfig.cpp:2009
msgid "Enable support material generation." msgid "Enable support material generation."
@ -2975,10 +2994,6 @@ msgstr "Exportovat vybrané objekty jako STL soubor"
msgid "Export to SD card / Flash drive" msgid "Export to SD card / Flash drive"
msgstr "Export na SD kartu / Flash disk" msgstr "Export na SD kartu / Flash disk"
#: src/slic3r/GUI/Plater.cpp:755
msgid "Export to SD card / Flash drive "
msgstr "Export na SD kartu / Flash disk"
#: src/slic3r/GUI/MainFrame.cpp:1090 src/slic3r/GUI/MainFrame.cpp:1395 #: src/slic3r/GUI/MainFrame.cpp:1090 src/slic3r/GUI/MainFrame.cpp:1395
msgid "Export toolpaths as OBJ" msgid "Export toolpaths as OBJ"
msgstr "Exportovat trasy extruderu jako OBJ" msgstr "Exportovat trasy extruderu jako OBJ"
@ -3188,7 +3203,7 @@ msgstr "Typ"
#: src/slic3r/GUI/GUI_Preview.cpp:293 src/slic3r/GUI/GUI_Preview.cpp:295 #: src/slic3r/GUI/GUI_Preview.cpp:293 src/slic3r/GUI/GUI_Preview.cpp:295
#: src/slic3r/GUI/GUI_Preview.cpp:316 #: src/slic3r/GUI/GUI_Preview.cpp:316
msgid "Feature types" msgid "Feature types"
msgstr "Typy extruzí" msgstr "Typy extrudování"
#: src/slic3r/GUI/ConfigWizard.cpp:1926 #: src/slic3r/GUI/ConfigWizard.cpp:1926
msgid "FFF Technology Printers" msgid "FFF Technology Printers"
@ -3983,7 +3998,7 @@ msgstr "Pokud je tato volba povolena, bude 3D scéna vykreslena v rozlišení Re
#: src/slic3r/GUI/Preferences.cpp:215 #: src/slic3r/GUI/Preferences.cpp:215
msgid "If enabled, the button for the collapse sidebar will be appeared in top right corner of the 3D Scene" msgid "If enabled, the button for the collapse sidebar will be appeared in top right corner of the 3D Scene"
msgstr "Pokud je povoleno, bude v pravém horním rohu 3D scény zobrazeno tlačítko pro ovládání bočního panelu." msgstr "Pokud je povoleno, bude v pravém horním rohu 3D scény zobrazeno tlačítko pro ovládání bočního panelu"
#: src/libslic3r/PrintConfig.cpp:3698 #: src/libslic3r/PrintConfig.cpp:3698
msgid "If enabled, the command line arguments are sent to an existing instance of GUI PrusaSlicer, or an existing PrusaSlicer window is activated. Overrides the \"single_instance\" configuration value from application preferences." msgid "If enabled, the command line arguments are sent to an existing instance of GUI PrusaSlicer, or an existing PrusaSlicer window is activated. Overrides the \"single_instance\" configuration value from application preferences."
@ -4073,6 +4088,10 @@ msgstr "Pokud firmware nezpracovává umístění extruderu správně, potřebuj
msgid "If your firmware requires relative E values, check this, otherwise leave it unchecked. Most firmwares use absolute values." msgid "If your firmware requires relative E values, check this, otherwise leave it unchecked. Most firmwares use absolute values."
msgstr "Pokud váš firmware vyžaduje relativní hodnoty E, zaškrtněte toto, jinak nechte nezaškrtnuté. Většina firmwarů používá absolutní hodnoty." msgstr "Pokud váš firmware vyžaduje relativní hodnoty E, zaškrtněte toto, jinak nechte nezaškrtnuté. Většina firmwarů používá absolutní hodnoty."
#: src/libslic3r/PrintConfig.cpp:1219
msgid "Ignore"
msgstr "Ignorovat"
#: src/libslic3r/PrintConfig.cpp:3684 #: src/libslic3r/PrintConfig.cpp:3684
msgid "Ignore non-existent config files" msgid "Ignore non-existent config files"
msgstr "Ignorovat neexistující konfigurační soubory" msgstr "Ignorovat neexistující konfigurační soubory"
@ -4098,9 +4117,17 @@ msgstr "Načíst konfiguraci z &projektu"
msgid "Import Config from ini/amf/3mf/gcode" msgid "Import Config from ini/amf/3mf/gcode"
msgstr "Načíst konfiguraci ze souboru ini/amf/3mf/gcode" msgstr "Načíst konfiguraci ze souboru ini/amf/3mf/gcode"
#: src/slic3r/GUI/Plater.cpp:1419
msgid "Import config only"
msgstr "Importovat pouze konfiguraci"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:39 #: src/slic3r/GUI/Jobs/SLAImportJob.cpp:39
msgid "Import file: " msgid "Import file"
msgstr "Importovat soubor:" msgstr "Importovat soubor"
#: src/slic3r/GUI/Plater.cpp:1418
msgid "Import geometry only"
msgstr "Importovat pouze modely"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:46 #: src/slic3r/GUI/Jobs/SLAImportJob.cpp:46
msgid "Import model and profile" msgid "Import model and profile"
@ -4566,10 +4593,6 @@ msgstr "Vrchních"
msgid "Layout Options" msgid "Layout Options"
msgstr "Možnosti rozložení" msgstr "Možnosti rozložení"
#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:233
msgid "Least supports"
msgstr "Nejméně podpěr"
#: src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp:48 #: src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp:48
msgid "Leaving Paint-on supports" msgid "Leaving Paint-on supports"
msgstr "Opuštění Malování podpěr" msgstr "Opuštění Malování podpěr"
@ -4670,14 +4693,6 @@ msgstr "Načíst konfiguraci ze zadaného souboru. Může být použito vícekr
msgid "Load exported configuration file" msgid "Load exported configuration file"
msgstr "Načíst exportovaný konfigurační soubor" msgstr "Načíst exportovaný konfigurační soubor"
#: src/slic3r/GUI/Plater.cpp:1436
msgid "Load File"
msgstr "Načtení souboru"
#: src/slic3r/GUI/Plater.cpp:1440
msgid "Load Files"
msgstr "Naštení souborů"
#: src/slic3r/GUI/GUI_ObjectList.cpp:2038 #: src/slic3r/GUI/GUI_ObjectList.cpp:2038
msgid "Load Part" msgid "Load Part"
msgstr "Přidání části" msgstr "Přidání části"
@ -4710,9 +4725,9 @@ msgstr "Načteno"
msgid "Loading" msgid "Loading"
msgstr "Načítání" msgstr "Načítání"
#: src/slic3r/GUI/GUI_App.cpp:759 #: src/slic3r/GUI/GUI_App.cpp:797
msgid "Loading configuration..." msgid "Loading configuration"
msgstr "Načítání konfigurace ..." msgstr "Načítání konfigurace"
#: src/slic3r/GUI/Plater.cpp:2226 #: src/slic3r/GUI/Plater.cpp:2226
msgid "Loading file" msgid "Loading file"
@ -5690,7 +5705,7 @@ msgstr "Teplota trysky"
#: src/libslic3r/PrintConfig.cpp:2198 #: src/libslic3r/PrintConfig.cpp:2198
msgid "Nozzle temperature for layers after the first one. Set this to zero to disable temperature control commands in the output G-code." msgid "Nozzle temperature for layers after the first one. Set this to zero to disable temperature control commands in the output G-code."
msgstr "Teplota trysky pro od druhé vrstvy dále. Nastavte tuto hodnotu na nulu, abyste zakázali příkazy pro řízení teploty ve výstupním G-codu." msgstr "Teplota trysky od druhé vrstvy dále. Nastavte tuto hodnotu na nulu, abyste zakázali příkazy pro řízení teploty ve výstupním G-codu."
#: src/libslic3r/PrintConfig.cpp:961 #: src/libslic3r/PrintConfig.cpp:961
msgid "Nozzle temperature for the first layer. If you want to control temperature manually during print, set this to zero to disable temperature control commands in the output G-code." msgid "Nozzle temperature for the first layer. If you want to control temperature manually during print, set this to zero to disable temperature control commands in the output G-code."
@ -5882,6 +5897,10 @@ msgstr "Otevře novou instanci PrusaSliceru"
msgid "Open a project file" msgid "Open a project file"
msgstr "Otevřít soubor s projektem" msgstr "Otevřít soubor s projektem"
#: src/slic3r/GUI/Plater.cpp:1417
msgid "Open as project"
msgstr "Otevřít jako projekt"
#: src/slic3r/GUI/PhysicalPrinterDialog.cpp:330 #: src/slic3r/GUI/PhysicalPrinterDialog.cpp:330
msgid "Open CA certificate file" msgid "Open CA certificate file"
msgstr "Otevřít soubor s certifikátem CA" msgstr "Otevřít soubor s certifikátem CA"
@ -6338,9 +6357,9 @@ msgstr "Preferovaný směr švu - rozkmit"
msgid "Preparing infill" msgid "Preparing infill"
msgstr "Příprava výplně" msgstr "Příprava výplně"
#: src/slic3r/GUI/GUI_App.cpp:895 #: src/slic3r/GUI/GUI_App.cpp:855
msgid "Preparing settings tabs..." msgid "Preparing settings tabs"
msgstr "Příprava karet s nastavením..." msgstr "Příprava karet s nastavením"
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:1009 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:1009
msgid "Preset \"%1%\" has the following unsaved changes:" msgid "Preset \"%1%\" has the following unsaved changes:"
@ -6662,10 +6681,6 @@ msgstr "Kvalita (pomalejší slicing)"
msgid "Quality / Speed" msgid "Quality / Speed"
msgstr "Kvalita / Rychlost" msgstr "Kvalita / Rychlost"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:56
msgid "Quality: "
msgstr "Kvalita:"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:61 #: src/slic3r/GUI/Jobs/SLAImportJob.cpp:61
msgid "Quick" msgid "Quick"
msgstr "Rychlé" msgstr "Rychlé"
@ -6693,7 +6708,7 @@ msgstr "Ukončit %s"
#: src/slic3r/GUI/GUI_App.cpp:396 #: src/slic3r/GUI/GUI_App.cpp:396
msgid "Quit, I will move my data now" msgid "Quit, I will move my data now"
msgstr "Zavřít aplikaci, přesunu si svá data." msgstr "Zavřít aplikaci, přesunu si svá data"
#: src/slic3r/GUI/GLCanvas3D.cpp:280 src/libslic3r/PrintConfig.cpp:547 #: src/slic3r/GUI/GLCanvas3D.cpp:280 src/libslic3r/PrintConfig.cpp:547
msgid "Radius" msgid "Radius"
@ -6880,6 +6895,10 @@ msgstr "Zapamatovat moji volbu"
msgid "Remember output directory" msgid "Remember output directory"
msgstr "Pamatovat si výstupní složku" msgstr "Pamatovat si výstupní složku"
#: src/slic3r/GUI/MainFrame.cpp:166
msgid "Remember to check for updates at https://github.com/prusa3d/PrusaSlicer/releases"
msgstr "Nezapomeňte zkontrolovat aktualizace na https://github.com/prusa3d/PrusaSlicer/releases"
#: src/slic3r/GUI/Tab.cpp:3386 #: src/slic3r/GUI/Tab.cpp:3386
msgid "remove" msgid "remove"
msgstr "odebrat" msgstr "odebrat"
@ -7345,7 +7364,7 @@ msgstr "Uložit SL1 soubor jako:"
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:744 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:744
msgid "Save the selected options to preset \"%1%\"." msgid "Save the selected options to preset \"%1%\"."
msgstr "Uložte vybraná nastaneví do přednastavení \"%1%\"." msgstr "Uloží vybraná nastaneví do přednastavení \"%1%\"."
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:740 #: src/slic3r/GUI/UnsavedChangesDialog.cpp:740
msgid "Save the selected options." msgid "Save the selected options."
@ -7470,6 +7489,10 @@ msgstr "Vybrat všechny body"
msgid "Select all standard printers" msgid "Select all standard printers"
msgstr "Vybrat všechny standardní tiskárny" msgstr "Vybrat všechny standardní tiskárny"
#: src/slic3r/GUI/Plater.cpp:1422
msgid "Select an action to apply to the file"
msgstr "Vyberte jak chcete na soubor otevřít"
#: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1215 #: src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp:1215
msgid "Select by rectangle" msgid "Select by rectangle"
msgstr "Označit obdélníkovým výběrem myši" msgstr "Označit obdélníkovým výběrem myši"
@ -7616,10 +7639,6 @@ msgstr "Odeslat k tisku stávající plochu jako G-code"
msgid "Send to printer" msgid "Send to printer"
msgstr "Odeslat do tiskárny" msgstr "Odeslat do tiskárny"
#: src/slic3r/GUI/Plater.cpp:753
msgid "Send to printer "
msgstr "Odeslat do tiskárny"
#: src/slic3r/GUI/GLCanvas3D.cpp:1312 #: src/slic3r/GUI/GLCanvas3D.cpp:1312
msgid "Seq." msgid "Seq."
msgstr "Sekv." msgstr "Sekv."
@ -7861,6 +7880,10 @@ msgstr "Zobrazit okno o Slic3ru"
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Zobrazit rozšířená nastavení" msgstr "Zobrazit rozšířená nastavení"
#: src/slic3r/GUI/Preferences.cpp:120
msgid "Show drop project dialog"
msgstr "Zobrazit dialogové okno při přetažení projektu"
#: src/slic3r/GUI/PrintHostDialogs.cpp:157 #: src/slic3r/GUI/PrintHostDialogs.cpp:157
msgid "Show error message" msgid "Show error message"
msgstr "Zobrazit chybovou hlášku" msgstr "Zobrazit chybovou hlášku"
@ -8522,10 +8545,6 @@ msgstr "Úspěch!"
msgid "Successfully unmounted. The device %s(%s) can now be safely removed from the computer." msgid "Successfully unmounted. The device %s(%s) can now be safely removed from the computer."
msgstr "Odpojení proběhlo úspěšné. Zařízení %s(%s) lze nyní bezpečně odebrat z počítače." msgstr "Odpojení proběhlo úspěšné. Zařízení %s(%s) lze nyní bezpečně odebrat z počítače."
#: src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp:234
msgid "Suface quality"
msgstr "Kvalita povrchu"
#: src/slic3r/GUI/PresetHints.cpp:202 #: src/slic3r/GUI/PresetHints.cpp:202
msgid "support" msgid "support"
msgstr "podpěry" msgstr "podpěry"
@ -9159,9 +9178,9 @@ msgstr "Čistící věž je podporována pouze v případě, že všechny extrud
msgid "The Wipe tower is only supported if all objects have the same variable layer height" msgid "The Wipe tower is only supported if all objects have the same variable layer height"
msgstr "Čistící věž je podporována pouze v případě, že všechny objekty mají stejnou variabilní výšku vrstvy" msgstr "Čistící věž je podporována pouze v případě, že všechny objekty mají stejnou variabilní výšku vrstvy"
#: src/slic3r/GUI/Plater.cpp:3543 #: src/slic3r/GUI/Plater.cpp:3563
msgid "There are active warnings concerning sliced models:\n" msgid "There are active warnings concerning sliced models:"
msgstr "Varování týkající se slicovaných modelů:\n" msgstr "Varování týkající se slicovaných modelů:"
#: src/libslic3r/SLAPrintSteps.cpp:619 #: src/libslic3r/SLAPrintSteps.cpp:619
msgid "There are unprintable objects. Try to adjust support settings to make the objects printable." msgid "There are unprintable objects. Try to adjust support settings to make the objects printable."
@ -9246,7 +9265,7 @@ msgstr "Toto experimentální nastavení používá příkazy G10 a G11, aby si
#: src/libslic3r/PrintConfig.cpp:2319 #: src/libslic3r/PrintConfig.cpp:2319
msgid "This experimental setting uses outputs the E values in cubic millimeters instead of linear millimeters. If your firmware doesn't already know filament diameter(s), you can put commands like 'M200 D[filament_diameter_0] T0' in your start G-code in order to turn volumetric mode on and use the filament diameter associated to the filament selected in Slic3r. This is only supported in recent Marlin." msgid "This experimental setting uses outputs the E values in cubic millimeters instead of linear millimeters. If your firmware doesn't already know filament diameter(s), you can put commands like 'M200 D[filament_diameter_0] T0' in your start G-code in order to turn volumetric mode on and use the filament diameter associated to the filament selected in Slic3r. This is only supported in recent Marlin."
msgstr "Toto experimentální nastavení používá výstupní hodnoty E v kubických milimetrech místo lineárních milimetrů. Pokud firmware dosud nezná průměr (průměry) filamentu, můžete v počátečním G-code zadat příkazy jako “M200 D [filament_diameter_0] T0”, pro zapnutí volumetrického režimu a použití průměru filamentu přidruženého k vybranému filamentu ve Slic3ru. Toto je podporováno pouze v posledních verzích firmwaru Marlin.\n" msgstr "Toto experimentální nastavení používá výstupní hodnoty E v kubických milimetrech místo lineárních milimetrů. Pokud firmware dosud nezná průměr (průměry) filamentu, můžete v počátečním G-code zadat příkazy jako “M200 D [filament_diameter_0] T0”, pro zapnutí volumetrického režimu a použití průměru filamentu přidruženého k vybranému filamentu ve Slic3ru. Toto je podporováno pouze v posledních verzích firmwaru Marlin."
#: src/slic3r/GUI/GUI_ObjectList.cpp:4459 #: src/slic3r/GUI/GUI_ObjectList.cpp:4459
msgid "This extruder will be set for selected items" msgid "This extruder will be set for selected items"
@ -9324,7 +9343,7 @@ msgstr "Toto nastavení přemístí trysku při retrakci, aby se minimalizovalo
#: src/libslic3r/PrintConfig.cpp:1961 #: src/libslic3r/PrintConfig.cpp:1961
msgid "This G-code will be used as a code for the color change" msgid "This G-code will be used as a code for the color change"
msgstr "Tento G-code bude použit jako kód pro změnu barvy." msgstr "Tento G-code bude použit jako kód pro změnu barvy"
#: src/libslic3r/PrintConfig.cpp:1970 #: src/libslic3r/PrintConfig.cpp:1970
msgid "This G-code will be used as a code for the pause print" msgid "This G-code will be used as a code for the pause print"
@ -9888,6 +9907,10 @@ msgstr "Použít retrakce z firmwaru"
msgid "Use for search" msgid "Use for search"
msgstr "Použit pro vyhledávání" msgstr "Použit pro vyhledávání"
#: src/libslic3r/PrintConfig.cpp:1218
msgid "Use for time estimate"
msgstr "Použít pro odhad času"
#: src/slic3r/GUI/PrintHostDialogs.cpp:42 #: src/slic3r/GUI/PrintHostDialogs.cpp:42
msgid "Use forward slashes ( / ) as a directory separator if needed." msgid "Use forward slashes ( / ) as a directory separator if needed."
msgstr "Pokud je to nutné, použijte pro oddělení složek lomítko ( / )." msgstr "Pokud je to nutné, použijte pro oddělení složek lomítko ( / )."
@ -10133,6 +10156,10 @@ msgstr "Co chcete udělat s přednastavením „% 1%“ po uložení?"
msgid "When checked, the print and filament presets are shown in the preset editor even if they are marked as incompatible with the active printer" msgid "When checked, the print and filament presets are shown in the preset editor even if they are marked as incompatible with the active printer"
msgstr "Pokud je zaškrtnuto, přednastavení tisku a filamentu se zobrazují v editoru přednastavení, i když jsou označeny jako nekompatibilní s aktivní tiskárnou" msgstr "Pokud je zaškrtnuto, přednastavení tisku a filamentu se zobrazují v editoru přednastavení, i když jsou označeny jako nekompatibilní s aktivní tiskárnou"
#: src/slic3r/GUI/Preferences.cpp:122
msgid "When checked, whenever dragging and dropping a project file on the application, shows a dialog asking to select the action to take on the file to load."
msgstr "Je-li zaškrtnuto, při každém přetažení souboru s projektem do aplikace se zobrazí dialogové okno s výzvou k výběru akce, kterou se má soubor načíst."
#: src/slic3r/GUI/Preferences.cpp:156 #: src/slic3r/GUI/Preferences.cpp:156
msgid "When closing the application, always ask for unsaved changes" msgid "When closing the application, always ask for unsaved changes"
msgstr "Při zavírání aplikace vždy ptát na neuložené změny" msgstr "Při zavírání aplikace vždy ptát na neuložené změny"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
min_slic3r_version = 2.3.0-alpha2 min_slic3r_version = 2.3.0-alpha2
0.0.7 Updated start g-code for Creality printers
0.0.6 Added filament profiles, adjusted temperatures, updated start g-code for some models. 0.0.6 Added filament profiles, adjusted temperatures, updated start g-code for some models.
0.0.5 Added 0.08mm SUPERDETAIL and 0.28mm SUPERDRAFT print profiles. Updated OPTIMAL print profile. 0.0.5 Added 0.08mm SUPERDETAIL and 0.28mm SUPERDRAFT print profiles. Updated OPTIMAL print profile.
0.0.4 Added initial CR-10 profile, end g-code improvements. 0.0.4 Added initial CR-10 profile, end g-code improvements.

View file

@ -5,7 +5,7 @@
name = Creality name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.6 config_version = 0.0.7
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -666,14 +666,14 @@ deretract_speed = 40
retract_before_wipe = 70% retract_before_wipe = 70%
default_print_profile = 0.16mm OPTIMAL @CREALITY default_print_profile = 0.16mm OPTIMAL @CREALITY
default_filament_profile = Creality PLA @CREALITY default_filament_profile = Creality PLA @CREALITY
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG1 Z2 F240\nG1 X2 Y10 F3000\nG1 Z0.28 F240\nG92 E0.0\nG1 Y190 E15.0 F1500.0 ; intro line\nG1 X2.3 F5000\nG1 Y10 E15.0 F1200.0 ; intro line\nG92 E0.0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG1 Z2 F240\nG1 X2 Y10 F3000\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
end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y170 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+min(layer_z+70, max_print_height-10)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y170 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+min(layer_z+70, max_print_height-10)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors
[printer:*fastabl*] [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] ; set extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0.0\nG1 Y190 E15.0 F1500.0 ; intro line\nG1 X2.3 F5000\nG1 Y10 E15.0 F1200.0 ; intro line\nG92 E0.0 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] ; set extruder temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; 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
[printer:*slowabl*] [printer:*slowabl*]
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\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG28 ; home all\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set extruder temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG1 Z0.28 F240\nG92 E0.0\nG1 Y190 E15.0 F1500.0 ; intro line\nG1 X2.3 F5000\nG1 Y10 E15.0 F1200.0 ; intro line\nG92 E0.0 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\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nG28 ; home all\nG29 ; auto bed levelling\nG1 Z50 F240\nG1 X2 Y10 F3000\nM104 S[first_layer_temperature] ; set extruder temp\nM109 S[first_layer_temperature] ; 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
[printer:*invertedz*] [printer:*invertedz*]
end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print bed down\nG1 X50 Y50 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+max_print_height-10} F600{endif} ; Move print bed down\nM84 X Y E ; disable motors end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print bed down\nG1 X50 Y50 F3000 ; present print\n{if layer_z < max_print_height-10}G1 Z{z_offset+max_print_height-10} F600{endif} ; Move print bed down\nM84 X Y E ; disable motors
@ -706,7 +706,7 @@ bed_shape = 0x0,150x0,150x150,0x150
printer_model = ENDER2 printer_model = ENDER2
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER2\nPRINTER_HAS_BOWDEN printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER2\nPRINTER_HAS_BOWDEN
max_print_height = 200 max_print_height = 200
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG1 Z2 F240\nG1 X2 Y10 F3000\nG1 Z0.28 F240\nG92 E0.0\nG1 X15 Y135 E15.0 F1500.0 ; intro line\nG1 X2.3 F5000\nG1 Y10 E15.0 F1200.0 ; intro line\nG92 E0.0 start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all\nG1 Z2 F240\nG1 X2 Y10 F3000\nG1 Z0.28 F240\nG92 E0\nG1 X15 Y135 E15 F1500 ; intro line\nG1 X2.3 F5000\nG92 E0\nG1 Y10 E15 F1200 ; intro line\nG92 E0
end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y140 F3000 ; present print\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors end_gcode = M104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+5, max_print_height)} F600{endif} ; Move print head up\nG1 X5 Y140 F3000 ; present print\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)} F600{endif} ; Move print head up\nM84 X Y E ; disable motors
[printer:Creality CR-10 Mini] [printer:Creality CR-10 Mini]

View file

@ -1,4 +1,10 @@
min_slic3r_version = 2.3.0-beta0
1.2.0-beta0 Adjusted infill anchor limits. Added filament spool weights.
min_slic3r_version = 2.3.0-alpha4
1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.2.0-alpha0 Added filament spool weights
min_slic3r_version = 2.2.0-alpha3 min_slic3r_version = 2.2.0-alpha3
1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.1.10 Updated firmware version. 1.1.10 Updated firmware version.
1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials. 1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials.
1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles. 1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles.

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
min_slic3r_version = 2.3.0-alpha3 min_slic3r_version = 2.3.0-alpha3
0.0.3 Added DeltiQ 2, DeltiQ 2 Plus printers, 0.10mm, 0.20mm FLEX print profiles, updated print materials, flexprint extension support 0.0.4 Added PLA, PETG profiles for 0.8 nozzle, update print materials
min_slic3r_version = 2.3.0-alpha0 0.0.3 Added DeltiQ 2, DeltiQ 2 Plus printers, 0.10mm, 0.20mm FLEX print profiles, updated print materials, flexprint extension support
0.0.2 Added 0.15mm print profile min_slic3r_version = 2.3.0-alpha0
0.0.1 Initial TriLAB bundle 0.0.2 Added 0.15mm print profile
0.0.1 Initial TriLAB bundle

View file

@ -6,7 +6,7 @@
name = TriLAB name = TriLAB
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.3 config_version = 0.0.4
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/TriLAB/ 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% # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -17,21 +17,21 @@ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/Prus
[printer_model:DQ2] [printer_model:DQ2]
name = DeltiQ 2 name = DeltiQ 2
variants = 0.4 variants = 0.4; 0.8
technology = FFF technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ PLA; DeltiQ ASA; DeltiQ PET; DeltiQ ABS; DeltiQ CPE 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
[printer_model:DQ2P] [printer_model:DQ2P]
name = DeltiQ 2 Plus name = DeltiQ 2 Plus
variants = 0.4 variants = 0.4; 0.8
technology = FFF technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ PLA; DeltiQ ASA; DeltiQ PET; DeltiQ ABS; DeltiQ CPE 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 - PLA - ExtraFill (Fillamentum) @0.8 nozzle
[printer_model:DQ2+FP2] [printer_model:DQ2+FP2]
name = DeltiQ 2 + FlexPrint 2 name = DeltiQ 2 + FlexPrint 2
@ -40,7 +40,7 @@ technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FlexPrint 2 FLEX; DeltiQ FlexPrint 2 FLEX Smartfil; DeltiQ FlexPrint 2 PLA; DeltiQ FlexPrint 2 ASA; DeltiQ FlexPrint 2 PET; DeltiQ FlexPrint 2 ABS; DeltiQ FlexPrint 2 CPE 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)
[printer_model:DQ2P+FP2] [printer_model:DQ2P+FP2]
name = DeltiQ 2 Plus + FlexPrint 2 name = DeltiQ 2 Plus + FlexPrint 2
@ -49,7 +49,7 @@ technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FlexPrint 2 FLEX; DeltiQ FlexPrint 2 FLEX Smartfil; DeltiQ FlexPrint 2 PLA; DeltiQ FlexPrint 2 ASA; DeltiQ FlexPrint 2 PET; DeltiQ FlexPrint 2 ABS; DeltiQ FlexPrint 2 CPE 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)
[printer_model:DQ2+FP] [printer_model:DQ2+FP]
name = DeltiQ 2 + FlexPrint name = DeltiQ 2 + FlexPrint
@ -58,7 +58,7 @@ technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FlexPrint FLEX; DeltiQ FlexPrint PLA; DeltiQ FlexPrint ASA; DeltiQ FlexPrint PET; DeltiQ FlexPrint ABS; DeltiQ FlexPrint CPE default_materials = DeltiQ FP - PLA - Generic; DeltiQ FP - PETG - Generic; DeltiQ FP - ABS - Generic; DeltiQ FP - PLA - ExtraFill (Fillamentum); DeltiQ FP - PETG (Devil Design); DeltiQ FP - ABS - ExtraFill (Fillamentum); DeltiQ FP - ASA - ExtraFill (Fillamentum); DeltiQ FP - CPE - HG100 (Fillamentum); DeltiQ FP - FLEX - Generic;
[printer_model:DQ2P+FP] [printer_model:DQ2P+FP]
name = DeltiQ 2 Plus + FlexPrint name = DeltiQ 2 Plus + FlexPrint
@ -67,7 +67,7 @@ technology = FFF
family = DeltiQ 2 family = DeltiQ 2
bed_model = dq2_bed.stl bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ FlexPrint FLEX; DeltiQ FlexPrint PLA; DeltiQ FlexPrint ASA; DeltiQ FlexPrint PET; DeltiQ FlexPrint ABS; DeltiQ FlexPrint CPE default_materials = DeltiQ FP - PLA - Generic; DeltiQ FP - PETG - Generic; DeltiQ FP - ABS - Generic; DeltiQ FP - PLA - ExtraFill (Fillamentum); DeltiQ FP - PETG (Devil Design); DeltiQ FP - ABS - ExtraFill (Fillamentum); DeltiQ FP - ASA - ExtraFill (Fillamentum); DeltiQ FP - CPE - HG100 (Fillamentum); DeltiQ FP - FLEX - Generic
[printer_model:DQM] [printer_model:DQM]
name = DeltiQ M name = DeltiQ M
@ -105,7 +105,7 @@ bridge_speed = 30
brim_width = 0 brim_width = 0
clip_multipart_objects = 1 clip_multipart_objects = 1
compatible_printers = compatible_printers =
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and nozzle_diameter[0]==0.4
complete_objects = 0 complete_objects = 0
default_acceleration = 2000 default_acceleration = 2000
dont_support_bridges = 0 dont_support_bridges = 0
@ -176,7 +176,7 @@ solid_infill_speed = 60
spiral_vase = 0 spiral_vase = 0
standby_temperature_delta = -5 standby_temperature_delta = -5
support_material = 0 support_material = 0
support_material_angle = 40 support_material_angle = 30
support_material_auto = 1 support_material_auto = 1
support_material_buildplate_only = 0 support_material_buildplate_only = 0
support_material_contact_distance = 0.1 support_material_contact_distance = 0.1
@ -192,7 +192,7 @@ support_material_pattern = rectilinear
support_material_spacing = 2 support_material_spacing = 2
support_material_speed = 50 support_material_speed = 50
support_material_synchronize_layers = 0 support_material_synchronize_layers = 0
support_material_threshold = 55 support_material_threshold = 40
support_material_with_sheath = 0 support_material_with_sheath = 0
support_material_xy_spacing = 0.6 support_material_xy_spacing = 0.6
thin_walls = 0 thin_walls = 0
@ -254,9 +254,11 @@ thin_walls = 0
[print:DeltiQ 0.20mm FLEX] [print:DeltiQ 0.20mm FLEX]
inherits = DeltiQ 0.20mm Normal inherits = DeltiQ 0.20mm Normal
avoid_crossing_perimeters = 0 avoid_crossing_perimeters = 0
bridge_flow_ratio = 0.90 bridge_flow_ratio = 0.80
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*FLEXPRINT.*/ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*FLEXPRINT.*/ and nozzle_diameter[0]==0.4
extra_perimeters = 1
only_retract_when_crossing_perimeters = 1 only_retract_when_crossing_perimeters = 1
extrusion_width = 0.40
overhangs = 0 overhangs = 0
seam_position = nearest seam_position = nearest
thin_walls = 0 thin_walls = 0
@ -264,23 +266,71 @@ bridge_speed = 20
external_perimeter_speed = 20 external_perimeter_speed = 20
first_layer_speed = 20 first_layer_speed = 20
gap_fill_speed = 25 gap_fill_speed = 25
infill_speed = 30 infill_extrusion_width = 0.55
infill_speed = 40
infill_overlap = 27%
perimeter_speed = 25 perimeter_speed = 25
small_perimeter_speed = 20 small_perimeter_speed = 20
solid_infill_speed = 30 solid_infill_speed = 30
solid_infill_extrusion_width = 0.45
support_material_contact_distance = 0.3 support_material_contact_distance = 0.3
support_material_speed = 30
top_solid_infill_speed = 20 top_solid_infill_speed = 20
top_fill_pattern = rectilinear top_fill_pattern = rectilinear
fill_pattern = grid fill_pattern = grid
fill_density = 25% fill_density = 25%
travel_speed = 200 travel_speed = 200
max_print_speed = 30 max_print_speed = 40
complete_objects = 1 complete_objects = 1
[print:DeltiQ 0.40mm Normal @0.8 nozzle]
inherits = DeltiQ 0.20mm Normal
bottom_solid_layers = 3
bottom_solid_min_thickness = 1.2
bridge_flow_ratio = 0.90
bridge_speed = 20
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and nozzle_diameter[0]==0.8
elefant_foot_compensation = 0.2
external_perimeter_extrusion_width = 0.80
external_perimeter_speed = 30
extrusion_width = 0.80
first_layer_extrusion_width = 0.80
first_layer_height = 0.4
first_layer_speed = 20
gap_fill_speed = 40
infill_extrusion_width = 0.9
infill_overlap = 28%
infill_speed = 60
layer_height = 0.4
max_print_speed = 80
max_volumetric_speed = 40
overhangs = 1
perimeter_extrusion_width = 0.80
perimeter_speed = 45
perimeters = 2
small_perimeter_speed = 20
solid_infill_extrusion_width = 0.8
solid_infill_speed = 60
top_infill_extrusion_width = 0.8
top_solid_infill_speed = 40
top_solid_layers = 4
top_solid_min_thickness = 1.2
[print:DeltiQ 0.40mm Vase @0.8 nozzle]
inherits = DeltiQ 0.40mm Normal @0.8 nozzle
bottom_solid_layers = 4
perimeters = 1
top_solid_layers = 0
fill_density = 0
support_material = 0
spiral_vase = 1
ensure_vertical_shell_thickness = 1
thin_walls = 0
[filament:*DeltiQ common*] [filament:*DeltiQ common*]
compatible_printers = compatible_printers =
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.4
disable_fan_first_layers = 3 disable_fan_first_layers = 3
extrusion_multiplier = 1 extrusion_multiplier = 1
filament_colour = #FF0000 filament_colour = #FF0000
@ -294,7 +344,37 @@ filament_toolchange_delay = 0
start_filament_gcode = "; FILAMENT_START_GCODE" start_filament_gcode = "; FILAMENT_START_GCODE"
end_filament_gcode = "; FILAMENT_END_GCODE" end_filament_gcode = "; FILAMENT_END_GCODE"
[filament:DeltiQ PET]
# DeltiQ Filaments #
[filament:DeltiQ - PLA - Generic]
inherits = *DeltiQ common*
bed_temperature = 55
bridge_fan_speed = 100
cooling = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_vendor = Fillamentum
filament_cost = 767
filament_density = 1.24
filament_max_volumetric_speed = 8
filament_retract_before_travel = 2
filament_retract_before_wipe = 90%
filament_retract_layer_change = 1
filament_retract_length = 4.0
filament_retract_lift = 0.2
filament_retract_speed = 30
filament_type = PLA
filament_wipe = 1
first_layer_bed_temperature = 55
first_layer_temperature = 220
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 10
slowdown_below_layer_time = 4
temperature = 215
[filament:DeltiQ - PETG - Generic]
inherits = *DeltiQ common* inherits = *DeltiQ common*
bed_temperature = 90 bed_temperature = 90
bridge_fan_speed = 50 bridge_fan_speed = 50
@ -322,34 +402,7 @@ min_print_speed = 10
slowdown_below_layer_time = 5 slowdown_below_layer_time = 5
temperature = 245 temperature = 245
[filament:DeltiQ PLA] [filament:DeltiQ - ABS - Generic]
inherits = *DeltiQ common*
bed_temperature = 55
bridge_fan_speed = 100
cooling = 1
fan_always_on = 1
fan_below_layer_time = 100
filament_vendor = Fillamentum
filament_cost = 767
filament_density = 1.24
filament_max_volumetric_speed = 8
filament_retract_before_travel = 2
filament_retract_before_wipe = 90%
filament_retract_layer_change = 1
filament_retract_length = 4.0
filament_retract_lift = 0.2
filament_retract_speed = 30
filament_type = PLA
filament_wipe = 1
first_layer_bed_temperature = 55
first_layer_temperature = 220
max_fan_speed = 100
min_fan_speed = 100
min_print_speed = 10
slowdown_below_layer_time = 4
temperature = 215
[filament:DeltiQ ABS]
inherits = *DeltiQ common* inherits = *DeltiQ common*
bed_temperature = 100 bed_temperature = 100
bridge_fan_speed = 25 bridge_fan_speed = 25
@ -376,14 +429,24 @@ min_print_speed = 10
slowdown_below_layer_time = 15 slowdown_below_layer_time = 15
temperature = 255 temperature = 255
[filament:DeltiQ ASA] [filament:DeltiQ - PLA - ExtraFill (Fillamentum)]
inherits = DeltiQ ABS inherits = DeltiQ - PLA - Generic
[filament:DeltiQ - PETG (Devil Design)]
inherits = DeltiQ - PETG - Generic
[filament:DeltiQ - ABS - ExtraFill (Fillamentum)]
inherits = DeltiQ - ABS - Generic
[filament:DeltiQ - ASA - ExtraFill (Fillamentum)]
inherits = DeltiQ - ABS - Generic
filament_density = 1.07 filament_density = 1.07
filament_type = ASA filament_type = ASA
filament_vendor = Fillamentum
first_layer_temperature = 265 first_layer_temperature = 265
temperature = 265 temperature = 265
[filament:DeltiQ CPE] [filament:DeltiQ - CPE - HG100 (Fillamentum)]
inherits = *DeltiQ common* inherits = *DeltiQ common*
bed_temperature = 90 bed_temperature = 90
bridge_fan_speed = 50 bridge_fan_speed = 50
@ -411,41 +474,155 @@ min_print_speed = 10
slowdown_below_layer_time = 5 slowdown_below_layer_time = 5
temperature = 260 temperature = 260
[filament:DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle]
inherits = DeltiQ - PLA - ExtraFill (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.8
disable_fan_first_layers = 1
filament_max_volumetric_speed = 40
first_layer_temperature = 230
slowdown_below_layer_time = 8
temperature = 230
filament_retract_layer_change = 0
filament_retract_length = 4.1
filament_retract_speed = 45
filament_deretract_speed = 25
[filament:DeltiQ FlexPrint 2 PET] [filament:DeltiQ - PETG (Devil Design) @0.8 nozzle]
inherits = DeltiQ PET inherits = DeltiQ - PETG (Devil Design)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and !(printer_notes=~/.*FLEXPRINT.*/) and nozzle_diameter[0]==0.8
filament_max_volumetric_speed = 40
first_layer_temperature = 240
slowdown_below_layer_time = 8
temperature = 240
filament_retract_layer_change = 0
filament_retract_length = 4.3
filament_retract_speed = 45
filament_deretract_speed = 25
filament_retract_before_wipe = 80%
filament_wipe = 1
# DeltiQ FlexPrint Filaments #
[filament:DeltiQ FP - PLA - Generic]
inherits = DeltiQ - PLA - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.7
filament_retract_speed = 28
[filament:DeltiQ FP - PETG - Generic]
inherits = DeltiQ - PETG - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FP - ABS - Generic]
inherits = DeltiQ - ABS - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FP - FLEX - Generic]
inherits = *DeltiQ common*
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
bed_temperature = 50
bridge_fan_speed = 80
cooling = 1
disable_fan_first_layers = 1
extrusion_multiplier = 1.07
fan_always_on = 1
fan_below_layer_time = 20
filament_vendor = Generic
filament_cost = 1870
filament_density = 1.22
filament_deretract_speed = nil
filament_max_volumetric_speed = 0.7
filament_retract_before_travel = 2
filament_retract_before_wipe = 70%
filament_retract_layer_change = 0
filament_retract_length = 2.5
filament_retract_lift = 0.2
filament_retract_restart_extra = nil
filament_retract_speed = 20
filament_type = FLEX
filament_wipe = 1
first_layer_bed_temperature = 50
first_layer_temperature = 240
max_fan_speed = 50
min_fan_speed = 30
min_print_speed = 5
slowdown_below_layer_time = 4
temperature = 240
[filament:DeltiQ FP - PLA - ExtraFill (Fillamentum)]
inherits = DeltiQ FP - PLA - Generic
[filament:DeltiQ FP - PETG (Devil Design)]
inherits = DeltiQ FP - PETG - Generic
[filament:DeltiQ FP - ABS - ExtraFill (Fillamentum)]
inherits = DeltiQ FP - ABS - Generic
[filament:DeltiQ FP - ASA - ExtraFill (Fillamentum)]
inherits = DeltiQ - ASA - ExtraFill (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FP - CPE - HG100 (Fillamentum)]
inherits = DeltiQ - CPE - HG100 (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.7
filament_retract_speed = 25
filament_deretract_speed = 0
filament_retract_before_wipe = 0%
# DeltiQ FlexPrint 2 Filaments #
[filament:DeltiQ FP2 - PLA - Generic]
inherits = DeltiQ FP - PLA - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 1.2
filament_retract_speed = 28
[filament:DeltiQ FP2 - PETG - Generic]
inherits = DeltiQ FP - PETG - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 1.4 filament_retract_length = 1.4
filament_retract_speed = 35 filament_retract_speed = 35
filament_retract_before_wipe = 0% filament_retract_before_wipe = 0%
[filament:DeltiQ FlexPrint 2 PLA] [filament:DeltiQ FP2 - ABS - Generic]
inherits = DeltiQ PLA inherits = DeltiQ FP - ABS - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 1.2
filament_retract_speed = 28
[filament:DeltiQ FlexPrint 2 ABS]
inherits = DeltiQ ABS
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
filament_retract_length = 0.8 filament_retract_length = 0.8
filament_retract_speed = 25 filament_retract_speed = 25
[filament:DeltiQ FlexPrint 2 ASA] [filament:DeltiQ FP2 - PLA - ExtraFill (Fillamentum)]
inherits = DeltiQ ASA inherits = DeltiQ FP2 - PLA - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FlexPrint 2 CPE] [filament:DeltiQ FP2 - PETG (Devil Design)]
inherits = DeltiQ CPE inherits = DeltiQ FP2 - PETG - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FP2 - ABS - ExtraFill (Fillamentum)]
inherits = DeltiQ FP2 - ABS - Generic
[filament:DeltiQ FP2 - ASA - ExtraFill (Fillamentum)]
inherits = DeltiQ FP - ASA - ExtraFill (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
[filament:DeltiQ FP2 - CPE - HG100 (Fillamentum)]
inherits = DeltiQ FP - CPE - HG100 (Fillamentum)
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
filament_retract_length = 0.8 filament_retract_length = 0.8
filament_retract_speed = 35 filament_retract_speed = 35
filament_deretract_speed = 0 filament_deretract_speed = 0
filament_retract_before_wipe = 0% filament_retract_before_wipe = 0%
[filament:DeltiQ FlexPrint 2 FLEX] [filament:DeltiQ FP2 - FLEX - Generic]
inherits = *DeltiQ common* inherits = DeltiQ FP - FLEX - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/ and nozzle_diameter[0]==0.4
bed_temperature = 50 bed_temperature = 50
bridge_fan_speed = 80 bridge_fan_speed = 80
cooling = 1 cooling = 1
@ -456,12 +633,12 @@ fan_below_layer_time = 20
filament_vendor = Fillamentum filament_vendor = Fillamentum
filament_cost = 1870 filament_cost = 1870
filament_density = 1.22 filament_density = 1.22
filament_deretract_speed = 0 filament_deretract_speed = nil
filament_max_volumetric_speed = 2.9 filament_max_volumetric_speed = 2.9
filament_retract_before_travel = 1 filament_retract_before_travel = 2
filament_retract_before_wipe = 70% filament_retract_before_wipe = 70%
filament_retract_layer_change = 0 filament_retract_layer_change = 0
filament_retract_length = 1.6 filament_retract_length = 2.5
filament_retract_lift = 0.2 filament_retract_lift = 0.2
filament_retract_restart_extra = nil filament_retract_restart_extra = nil
filament_retract_speed = 20 filament_retract_speed = 20
@ -475,72 +652,52 @@ min_print_speed = 5
slowdown_below_layer_time = 4 slowdown_below_layer_time = 4
temperature = 225 temperature = 225
[filament:DeltiQ FlexPrint 2 FLEX Smartfil] [filament:DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum)]
inherits = *DeltiQ common* inherits = DeltiQ FP2 - FLEX - Generic
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
bed_temperature = 50 bed_temperature = 50
bridge_fan_speed = 80 bridge_fan_speed = 80
cooling = 0 cooling = 1
disable_fan_first_layers = 3 disable_fan_first_layers = 1
extrusion_multiplier = 1.07 extrusion_multiplier = 1.10
fan_always_on = 1 fan_always_on = 1
fan_below_layer_time = 20 fan_below_layer_time = 20
filament_vendor = Smart Materials 3D filament_vendor = Fillamentum
filament_cost = 1209 filament_cost = 1870
filament_density = 1.21 filament_density = 1.22
filament_deretract_speed = 0 filament_deretract_speed = nil
filament_max_volumetric_speed = 2.5 filament_max_volumetric_speed = 2.9
filament_retract_before_travel = 1 filament_retract_before_travel = 2
filament_retract_before_wipe = nil filament_retract_before_wipe = 70%
filament_retract_layer_change = 0 filament_retract_layer_change = 0
filament_retract_length = 1.2 filament_retract_length = 2.5
filament_retract_lift = 0.2 filament_retract_lift = 0.2
filament_retract_restart_extra = nil filament_retract_restart_extra = nil
filament_retract_speed = 20 filament_retract_speed = 20
filament_type = FLEX filament_type = TPU92A
filament_wipe = 0 filament_wipe = 1
first_layer_bed_temperature = 50 first_layer_bed_temperature = 50
first_layer_temperature = 240 first_layer_temperature = 230
max_fan_speed = 50 max_fan_speed = 70
min_fan_speed = 50 min_fan_speed = 50
min_print_speed = 10 min_print_speed = 5
slowdown_below_layer_time = 4 slowdown_below_layer_time = 4
temperature = 240 temperature = 230
[filament:DeltiQ FP2 - TPU 98A - FlexFill (Fillamentum)]
inherits = DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum)
extrusion_multiplier = 1.10
filament_cost = 1870
filament_density = 1.23
filament_deretract_speed = nil
filament_max_volumetric_speed = 2.9
filament_retract_before_wipe = 70%
filament_retract_length = 2.5
filament_retract_speed = 20
filament_type = TPU98A
[filament:DeltiQ FlexPrint PET]
inherits = DeltiQ PET # DeltiQ Printer #
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FlexPrint PLA]
inherits = DeltiQ PLA
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/
filament_retract_length = 0.7
filament_retract_speed = 28
[filament:DeltiQ FlexPrint ABS]
inherits = DeltiQ ABS
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FlexPrint ASA]
inherits = DeltiQ ASA
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/
filament_retract_length = 0.7
filament_retract_speed = 25
[filament:DeltiQ FlexPrint CPE]
inherits = DeltiQ CPE
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT1.*/
filament_retract_length = 0.7
filament_retract_speed = 25
filament_deretract_speed = 0
filament_retract_before_wipe = 0%
[printer:*DeltiQ*] [printer:*DeltiQ*]
inherits = inherits =
bed_shape = 124.315x13.0661,122.268x25.989,118.882x38.6271,114.193x50.8421,108.253x62.5,101.127x73.4732,92.8931x83.6413,83.6413x92.8931,73.4732x101.127,62.5x108.253,50.8421x114.193,38.6271x118.882,25.989x122.268,13.0661x124.315,3.54096e-014x125,-13.0661x124.315,-25.989x122.268,-38.6271x118.882,-50.8421x114.193,-62.5x108.253,-73.4732x101.127,-83.6413x92.8931,-92.8931x83.6413,-101.127x73.4732,-108.253x62.5,-114.193x50.8421,-118.882x38.6271,-122.268x25.989,-124.315x13.0661,-125x7.08192e-014,-124.315x-13.0661,-122.268x-25.989,-118.882x-38.6271,-114.193x-50.8421,-108.253x-62.5,-101.127x-73.4732,-92.8931x-83.6413,-83.6413x-92.8931,-73.4732x-101.127,-62.5x-108.253,-50.8421x-114.193,-38.6271x-118.882,-25.989x-122.268,-13.0661x-124.315,-2.29621e-014x-125,13.0661x-124.315,25.989x-122.268,38.6271x-118.882,50.8421x-114.193,62.5x-108.253,73.4732x-101.127,83.6413x-92.8931,92.8931x-83.6413,101.127x-73.4732,108.253x-62.5,114.193x-50.8421,118.882x-38.6271,122.268x-25.989,124.315x-13.0661,125x-1.41638e-013 bed_shape = 124.315x13.0661,122.268x25.989,118.882x38.6271,114.193x50.8421,108.253x62.5,101.127x73.4732,92.8931x83.6413,83.6413x92.8931,73.4732x101.127,62.5x108.253,50.8421x114.193,38.6271x118.882,25.989x122.268,13.0661x124.315,3.54096e-014x125,-13.0661x124.315,-25.989x122.268,-38.6271x118.882,-50.8421x114.193,-62.5x108.253,-73.4732x101.127,-83.6413x92.8931,-92.8931x83.6413,-101.127x73.4732,-108.253x62.5,-114.193x50.8421,-118.882x38.6271,-122.268x25.989,-124.315x13.0661,-125x7.08192e-014,-124.315x-13.0661,-122.268x-25.989,-118.882x-38.6271,-114.193x-50.8421,-108.253x-62.5,-101.127x-73.4732,-92.8931x-83.6413,-83.6413x-92.8931,-73.4732x-101.127,-62.5x-108.253,-50.8421x-114.193,-38.6271x-118.882,-25.989x-122.268,-13.0661x-124.315,-2.29621e-014x-125,13.0661x-124.315,25.989x-122.268,38.6271x-118.882,50.8421x-114.193,62.5x-108.253,73.4732x-101.127,83.6413x-92.8931,92.8931x-83.6413,101.127x-73.4732,108.253x-62.5,114.193x-50.8421,118.882x-38.6271,122.268x-25.989,124.315x-13.0661,125x-1.41638e-013
@ -597,68 +754,6 @@ variable_layer_height = 0
wipe = 1 wipe = 1
z_offset = 0 z_offset = 0
[printer:*DeltiQ 2*]
inherits = *DeltiQ*
before_layer_gcode = ; BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n
end_gcode = ; END_GCODE\n\nM140 S0 ; Turn off bed\n\nG28 ; Home\n\nM104 S0 ; Turn off extruder\nM107 ; Turn off fan\n\nG90 ; Absolute positioning\nM220 S100 ; Feedmultiply back to 100percent\n\nM84 S5; Disable motors
gcode_flavor = reprap
layer_gcode = ; AFTER_LAYER_CHANGE\n;[layer_z]
pause_print_gcode = M0
start_gcode = ; START_GCODE\n\nM220 S100 ; Set feedmultiply back to 100percent\n\nT0 ; Select Titan extruder\n\nG90 ; Absolute positioning\nM83; Relative Extruder\n\nM190 S[first_layer_bed_temperature] ; Set and wait - bed temperature\nM104 S[first_layer_temperature]\n\nG28 ; Home all axes\nG32 ; Probe Z and calculate Z plane\n\nG29 ; Mesh bed probe\n\nG1009 ; Go ARC to purge end\n\nG92 E0 ; Zero extruder
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2
[printer:*DeltiQ 2 FlexPrint*]
inherits = *DeltiQ 2*
start_gcode = ; START_GCODE\n\nM220 S100 ; Set feedmultiply back to 100percent\n\nT1 ; Select FlexPrint extruder\n\nG90 ; Absolute positioning\nM83; Relative Extruder\n\nM190 S[first_layer_bed_temperature] ; Set and wait - bed temperature\nM104 S[first_layer_temperature]\n\nG28 ; Home all axes\nG32 ; Probe Z and calculate Z plane\n\nG29 ; Mesh bed probe\n\nG1009 ; Go ARC to purge end\n\nG92 E0 ; Zero extruder
default_print_profile = DeltiQ 0.20mm FLEX
default_filament_profile = "DeltiQ FlexPrint 2 FLEX"
retract_length = 0.7
retract_speed = 25
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2+FP\nFLEXPRINT1
[printer:*DeltiQ 2 FlexPrint 2*]
inherits = *DeltiQ 2 FlexPrint*
default_filament_profile = "DeltiQ FlexPrint 2 FLEX"
retract_length = 0.8
retract_speed = 25
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2+FP\nFLEXPRINT2
[printer:DeltiQ 2]
inherits = *DeltiQ 2*
printer_model = DQ2
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 Plus]
inherits = *DeltiQ 2*
printer_model = DQ2P
printer_variant = 0.4
max_print_height = 500
[printer:DeltiQ 2 + FlexPrint 2]
inherits = *DeltiQ 2 FlexPrint 2*
printer_model = DQ2+FP2
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 Plus + FlexPrint 2]
inherits = *DeltiQ 2 FlexPrint 2*
printer_model = DQ2P+FP2
printer_variant = 0.4
max_print_height = 500
[printer:DeltiQ 2 + FlexPrint]
inherits = *DeltiQ 2 FlexPrint*
printer_model = DQ2+FP
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 Plus + FlexPrint]
inherits = *DeltiQ 2 FlexPrint*
printer_model = DQ2P+FP
printer_variant = 0.4
max_print_height = 500
[printer:DeltiQ L] [printer:DeltiQ L]
inherits = *DeltiQ* inherits = *DeltiQ*
printer_model = DQL printer_model = DQL
@ -686,7 +781,88 @@ max_print_height = 500
retract_length = 4.5 retract_length = 4.5
retract_speed = 35 retract_speed = 35
[printer:*DeltiQ 2*]
inherits = *DeltiQ*
before_layer_gcode = ; BEFORE_LAYER_CHANGE\n;[layer_z]\nG92 E0\n
end_gcode = ; END_GCODE\n\nM140 S0 ; Turn off bed\n\nG28 ; Home\n\nM104 S0 ; Turn off extruder\nM107 ; Turn off fan\n\nG90 ; Absolute positioning\nM220 S100 ; Feedmultiply back to 100percent\n\nM84 S5; Disable motors
gcode_flavor = reprap
layer_gcode = ; AFTER_LAYER_CHANGE\n;[layer_z]
pause_print_gcode = M0
start_gcode = ; START_GCODE\n\nM220 S100 ; Set feedmultiply back to 100percent\n\nT0 ; Select Titan extruder\n\nG90 ; Absolute positioning\nM83; Relative Extruder\n\nM190 S[first_layer_bed_temperature] ; Set and wait - bed temperature\nM104 S[first_layer_temperature]\n\nG28 ; Home all axes\nG32 ; Probe Z and calculate Z plane\n\nG29 ; Mesh bed probe\n\nG1009 ; Go ARC to purge end\n\nG92 E0 ; Zero extruder
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2
[printer:DeltiQ 2]
inherits = *DeltiQ 2*
printer_model = DQ2
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 - 0.8 nozzle]
inherits = DeltiQ 2
printer_variant = 0.8
max_layer_height = 0.4
min_layer_height = 0.4
nozzle_diameter = 0.8
default_filament_profile = "DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle"
default_print_profile = DeltiQ 0.40mm Normal @0.8 nozzle
[printer:DeltiQ 2 Plus]
inherits = *DeltiQ 2*
printer_model = DQ2P
printer_variant = 0.4
max_print_height = 500
[printer:DeltiQ 2 Plus - 0.8 nozzle]
inherits = DeltiQ 2 Plus
printer_variant = 0.8
max_layer_height = 0.4
min_layer_height = 0.4
nozzle_diameter = 0.8
default_filament_profile = "DeltiQ - PLA - ExtraFill (Fillamentum) @0.8 nozzle"
default_print_profile = DeltiQ 0.40mm Normal @0.8 nozzle
[printer:*DeltiQ 2 FlexPrint*]
inherits = *DeltiQ 2*
start_gcode = ; START_GCODE\n\nM220 S100 ; Set feedmultiply back to 100percent\n\nT1 ; Select FlexPrint extruder\n\nG90 ; Absolute positioning\nM83; Relative Extruder\n\nM190 S[first_layer_bed_temperature] ; Set and wait - bed temperature\nM104 S[first_layer_temperature]\n\nG28 ; Home all axes\nG32 ; Probe Z and calculate Z plane\n\nG29 ; Mesh bed probe\n\nG1009 ; Go ARC to purge end\n\nG92 E0 ; Zero extruder
default_print_profile = DeltiQ 0.20mm FLEX
default_filament_profile = "DeltiQ FP2 - FLEX - Generic"
retract_length = 0.7
retract_speed = 25
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2+FP\nFLEXPRINT1
[printer:DeltiQ 2 + FlexPrint]
inherits = *DeltiQ 2 FlexPrint*
printer_model = DQ2+FP
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 Plus + FlexPrint]
inherits = *DeltiQ 2 FlexPrint*
printer_model = DQ2P+FP
printer_variant = 0.4
max_print_height = 500
[printer:*DeltiQ 2 FlexPrint 2*]
inherits = *DeltiQ 2 FlexPrint*
default_filament_profile = "DeltiQ FP2 - FLEX - Generic"
retract_length = 0.8
retract_speed = 25
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_TRILAB\nPRINTER_FAMILY_DQ\nPRINTER_MODEL_DQ2+FP\nFLEXPRINT2
[printer:DeltiQ 2 + FlexPrint 2]
inherits = *DeltiQ 2 FlexPrint 2*
printer_model = DQ2+FP2
printer_variant = 0.4
max_print_height = 320
[printer:DeltiQ 2 Plus + FlexPrint 2]
inherits = *DeltiQ 2 FlexPrint 2*
printer_model = DQ2P+FP2
printer_variant = 0.4
max_print_height = 500
[presets] [presets]
print = DeltiQ 0.20mm Normal print = DeltiQ 0.20mm Normal
printer = DeltiQ 2 printer = DeltiQ 2
filament = DeltiQ PLA filament = DeltiQ - PLA - Generic

View file

@ -249,5 +249,5 @@ else ()
install(TARGETS PrusaSlicer RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") install(TARGETS PrusaSlicer RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
# Install the symlink for gcodeviewer # Install the symlink for gcodeviewer
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink prusa-slicer prusa-gcodeviewer WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})") install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink prusa-slicer prusa-gcodeviewer WORKING_DIRECTORY \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})")
endif () endif ()

View file

@ -741,6 +741,10 @@ public:
return impl_.getResult(); return impl_.getResult();
} }
inline int lastPackedBinId() const {
return impl_.lastPackedBinId();
}
void clear() { impl_.clear(); } void clear() { impl_.clear(); }
}; };
@ -862,6 +866,10 @@ public:
{ {
return selector_.getResult(); return selector_.getResult();
} }
inline int lastPackedBinId() const {
return selector_.lastPackedBinId();
}
}; };
} }

View file

@ -479,13 +479,18 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin
using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>; using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
// Norming factor for the optimization function
const double norm_;
public: public:
using Pile = nfp::Shapes<RawShape>; using Pile = nfp::Shapes<RawShape>;
private:
// Norming factor for the optimization function
const double norm_;
Pile merged_pile_;
public:
inline explicit _NofitPolyPlacer(const BinType& bin): inline explicit _NofitPolyPlacer(const BinType& bin):
Base(bin), Base(bin),
norm_(std::sqrt(sl::area(bin))) norm_(std::sqrt(sl::area(bin)))
@ -616,135 +621,9 @@ private:
template<class Level> template<class Level>
Shapes calcnfp(const Item &trsh, Level) Shapes calcnfp(const Item &trsh, Level)
{ // Function for arbitrary level of nfp implementation { // Function for arbitrary level of nfp implementation
using namespace nfp;
Shapes nfps; // TODO: implement
return {};
auto& orb = trsh.transformedShape();
bool orbconvex = trsh.isContourConvex();
for(Item& sh : items_) {
nfp::NfpResult<RawShape> subnfp;
auto& stat = sh.transformedShape();
if(sh.isContourConvex() && orbconvex)
subnfp = nfp::noFitPolygon<NfpLevel::CONVEX_ONLY>(stat, orb);
else if(orbconvex)
subnfp = nfp::noFitPolygon<NfpLevel::ONE_CONVEX>(stat, orb);
else
subnfp = nfp::noFitPolygon<Level::value>(stat, orb);
correctNfpPosition(subnfp, sh, trsh);
nfps = nfp::merge(nfps, subnfp.first);
}
return nfps;
}
// Very much experimental
void repack(Item& item, PackResult& result) {
if((sl::area(bin_) - this->filledArea()) >= item.area()) {
auto prev_func = config_.object_function;
unsigned iter = 0;
ItemGroup backup_rf = items_;
std::vector<Item> backup_cpy;
for(Item& itm : items_) backup_cpy.emplace_back(itm);
auto ofn = [this, &item, &result, &iter, &backup_cpy, &backup_rf]
(double ratio)
{
auto& bin = bin_;
iter++;
config_.object_function = [bin, ratio](
nfp::Shapes<RawShape>& pile,
const Item& item,
const ItemGroup& /*remaining*/)
{
pile.emplace_back(item.transformedShape());
auto ch = sl::convexHull(pile);
auto pbb = sl::boundingBox(pile);
pile.pop_back();
double parea = 0.5*(sl::area(ch) + sl::area(pbb));
double pile_area = std::accumulate(
pile.begin(), pile.end(), item.area(),
[](double sum, const RawShape& sh){
return sum + sl::area(sh);
});
// The pack ratio -- how much is the convex hull occupied
double pack_rate = (pile_area)/parea;
// ratio of waste
double waste = 1.0 - pack_rate;
// Score is the square root of waste. This will extend the
// range of good (lower) values and shrink the range of bad
// (larger) values.
auto wscore = std::sqrt(waste);
auto ibb = item.boundingBox();
auto bbb = sl::boundingBox(bin);
auto c = ibb.center();
double norm = 0.5*pl::distance(bbb.minCorner(),
bbb.maxCorner());
double dscore = pl::distance(c, pbb.center()) / norm;
return ratio*wscore + (1.0 - ratio) * dscore;
};
auto bb = sl::boundingBox(bin);
double norm = bb.width() + bb.height();
auto items = items_;
clearItems();
auto it = items.begin();
while(auto pr = _trypack(*it++)) {
this->accept(pr); if(it == items.end()) break;
}
auto count_diff = items.size() - items_.size();
double score = count_diff;
if(count_diff == 0) {
result = _trypack(item);
if(result) {
std::cout << "Success" << std::endl;
score = 0.0;
} else {
score += result.overfit() / norm;
}
} else {
result = PackResult();
items_ = backup_rf;
for(unsigned i = 0; i < items_.size(); i++) {
items_[i].get() = backup_cpy[i];
}
}
std::cout << iter << " repack result: " << score << " "
<< ratio << " " << count_diff << std::endl;
return score;
};
opt::StopCriteria stopcr;
stopcr.max_iterations = 30;
stopcr.stop_score = 1e-20;
opt::TOptimizer<opt::Method::L_SUBPLEX> solver(stopcr);
solver.optimize_min(ofn, opt::initvals(0.5),
opt::bound(0.0, 1.0));
// optimize
config_.object_function = prev_func;
}
} }
struct Optimum { struct Optimum {
@ -798,6 +677,50 @@ private:
Radians final_rot = initial_rot; Radians final_rot = initial_rot;
Shapes nfps; Shapes nfps;
auto& bin = bin_;
double norm = norm_;
auto pbb = sl::boundingBox(merged_pile_);
auto binbb = sl::boundingBox(bin);
// This is the kernel part of the object function that is
// customizable by the library client
std::function<double(const Item&)> _objfunc;
if(config_.object_function) _objfunc = config_.object_function;
else {
// Inside check has to be strict if no alignment was enabled
std::function<double(const Box&)> ins_check;
if(config_.alignment == Config::Alignment::DONT_ALIGN)
ins_check = [&binbb, norm](const Box& fullbb) {
double ret = 0;
if(!sl::isInside(fullbb, binbb))
ret += norm;
return ret;
};
else
ins_check = [&bin](const Box& fullbb) {
double miss = overfit(fullbb, bin);
miss = miss > 0? miss : 0;
return std::pow(miss, 2);
};
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
{
auto ibb = item.boundingBox();
auto fullbb = sl::boundingBox(pbb, ibb);
double score = pl::distance(ibb.center(),
binbb.center());
score /= norm;
score += ins_check(fullbb);
return score;
};
}
Pile merged_pile = merged_pile_;
for(auto rot : config_.rotations) { for(auto rot : config_.rotations) {
item.translation(initial_tr); item.translation(initial_tr);
@ -822,57 +745,6 @@ private:
ecache.back().accuracy(config_.accuracy); ecache.back().accuracy(config_.accuracy);
} }
Shapes pile;
pile.reserve(items_.size()+1);
// double pile_area = 0;
for(Item& mitem : items_) {
pile.emplace_back(mitem.transformedShape());
// pile_area += mitem.area();
}
auto merged_pile = nfp::merge(pile);
auto& bin = bin_;
double norm = norm_;
auto pbb = sl::boundingBox(merged_pile);
auto binbb = sl::boundingBox(bin);
// This is the kernel part of the object function that is
// customizable by the library client
std::function<double(const Item&)> _objfunc;
if(config_.object_function) _objfunc = config_.object_function;
else {
// Inside check has to be strict if no alignment was enabled
std::function<double(const Box&)> ins_check;
if(config_.alignment == Config::Alignment::DONT_ALIGN)
ins_check = [&binbb, norm](const Box& fullbb) {
double ret = 0;
if(!sl::isInside(fullbb, binbb))
ret += norm;
return ret;
};
else
ins_check = [&bin](const Box& fullbb) {
double miss = overfit(fullbb, bin);
miss = miss > 0? miss : 0;
return std::pow(miss, 2);
};
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
{
auto ibb = item.boundingBox();
auto fullbb = sl::boundingBox(pbb, ibb);
double score = pl::distance(ibb.center(),
binbb.center());
score /= norm;
score += ins_check(fullbb);
return score;
};
}
// Our object function for placement // Our object function for placement
auto rawobjfunc = [_objfunc, iv, startpos] auto rawobjfunc = [_objfunc, iv, startpos]
(Vertex v, Item& itm) (Vertex v, Item& itm)
@ -1045,6 +917,7 @@ private:
if(can_pack) { if(can_pack) {
ret = PackResult(item); ret = PackResult(item);
merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
} else { } else {
ret = PackResult(best_overfit); ret = PackResult(best_overfit);
} }

View file

@ -71,8 +71,9 @@ public:
std::sort(store_.begin(), store_.end(), sortfunc); std::sort(store_.begin(), store_.end(), sortfunc);
auto total = last-first; auto total = last-first;
auto makeProgress = [this, &total](Placer& placer, size_t idx) { auto makeProgress = [this, &total](Placer& placer, size_t bin_idx) {
packed_bins_[idx] = placer.getItems(); packed_bins_[bin_idx] = placer.getItems();
this->last_packed_bin_id_ = int(bin_idx);
this->progress_(static_cast<unsigned>(--total)); this->progress_(static_cast<unsigned>(--total));
}; };

View file

@ -18,6 +18,8 @@ public:
return packed_bins_; return packed_bins_;
} }
inline int lastPackedBinId() const { return last_packed_bin_id_; }
inline void progressIndicator(ProgressFunction fn) { progress_ = fn; } inline void progressIndicator(ProgressFunction fn) { progress_ = fn; }
inline void stopCondition(StopCondition cond) { stopcond_ = cond; } inline void stopCondition(StopCondition cond) { stopcond_ = cond; }
@ -54,6 +56,7 @@ protected:
PackGroup packed_bins_; PackGroup packed_bins_;
ProgressFunction progress_ = [](unsigned){}; ProgressFunction progress_ = [](unsigned){};
StopCondition stopcond_ = [](){ return false; }; StopCondition stopcond_ = [](){ return false; };
int last_packed_bin_id_ = -1;
}; };
} }

View file

@ -726,6 +726,36 @@ inline bool is_any_triangle_in_radius(
return hit_point.allFinite(); return hit_point.allFinite();
} }
// Traverse the tree and return the index of an entity whose bounding box
// contains a given point. Returns size_t(-1) when the point is outside.
template<typename TreeType, typename VectorType>
size_t get_candidate_idx(const TreeType& tree, const VectorType& v)
{
if (tree.empty() || ! tree.node(0).bbox.contains(v))
return size_t(-1);
size_t node_idx = 0;
while (true) {
decltype(tree.node(node_idx)) node = tree.node(node_idx);
static_assert(std::is_reference<decltype(node)>::value,
"Nodes shall be addressed by reference.");
assert(node.is_valid());
assert(node.bbox.contains(v));
if (! node.is_leaf()) {
if (tree.left_child(node_idx).bbox.contains(v))
node_idx = tree.left_child_idx(node_idx);
else if (tree.right_child(node_idx).bbox.contains(v))
node_idx = tree.right_child_idx(node_idx);
else
return size_t(-1);
} else
return node.idx;
}
}
} // namespace AABBTreeIndirect } // namespace AABBTreeIndirect
} // namespace Slic3r } // namespace Slic3r

View file

@ -68,6 +68,15 @@ void AppConfig::set_defaults()
if (get("export_sources_full_pathnames").empty()) if (get("export_sources_full_pathnames").empty())
set("export_sources_full_pathnames", "0"); set("export_sources_full_pathnames", "0");
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
#ifdef _WIN32
if (get("associate_3mf").empty())
set("associate_3mf", "0");
if (get("associate_stl").empty())
set("associate_stl", "0");
#endif // _WIN32
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
// remove old 'use_legacy_opengl' parameter from this config, if present // remove old 'use_legacy_opengl' parameter from this config, if present
if (!get("use_legacy_opengl").empty()) if (!get("use_legacy_opengl").empty())
erase("", "use_legacy_opengl"); erase("", "use_legacy_opengl");
@ -108,7 +117,21 @@ void AppConfig::set_defaults()
if (get("use_inches").empty()) if (get("use_inches").empty())
set("use_inches", "0"); set("use_inches", "0");
if (get("default_action_on_close_application").empty())
set("default_action_on_close_application", "none"); // , "discard" or "save"
if (get("default_action_on_select_preset").empty())
set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save"
} }
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
else {
#ifdef _WIN32
if (get("associate_gcode").empty())
set("associate_gcode", "0");
#endif // _WIN32
}
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
if (get("seq_top_layer_only").empty()) if (get("seq_top_layer_only").empty())
set("seq_top_layer_only", "1"); set("seq_top_layer_only", "1");
@ -125,11 +148,12 @@ void AppConfig::set_defaults()
if (get("show_splash_screen").empty()) if (get("show_splash_screen").empty())
set("show_splash_screen", "1"); set("show_splash_screen", "1");
if (get("default_action_on_close_application").empty()) #if ENABLE_CTRL_M_ON_WINDOWS
set("default_action_on_close_application", "none"); // , "discard" or "save" #ifdef _WIN32
if (get("use_legacy_3DConnexion").empty())
if (get("default_action_on_select_preset").empty()) set("use_legacy_3DConnexion", "0");
set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save" #endif // _WIN32
#endif // ENABLE_CTRL_M_ON_WINDOWS
// Remove legacy window positions/sizes // Remove legacy window positions/sizes
erase("", "main_frame_maximized"); erase("", "main_frame_maximized");

View file

@ -7,6 +7,7 @@
#include <libnest2d/optimizers/nlopt/subplex.hpp> #include <libnest2d/optimizers/nlopt/subplex.hpp>
#include <libnest2d/placers/nfpplacer.hpp> #include <libnest2d/placers/nfpplacer.hpp>
#include <libnest2d/selections/firstfit.hpp> #include <libnest2d/selections/firstfit.hpp>
#include <libnest2d/utils/rotcalipers.hpp>
#include <numeric> #include <numeric>
#include <ClipperUtils.hpp> #include <ClipperUtils.hpp>
@ -83,7 +84,7 @@ const double BIG_ITEM_TRESHOLD = 0.02;
// Fill in the placer algorithm configuration with values carefully chosen for // Fill in the placer algorithm configuration with values carefully chosen for
// Slic3r. // Slic3r.
template<class PConf> template<class PConf>
void fill_config(PConf& pcfg) { void fill_config(PConf& pcfg, const ArrangeParams &params) {
// Align the arranged pile into the center of the bin // Align the arranged pile into the center of the bin
pcfg.alignment = PConf::Alignment::CENTER; pcfg.alignment = PConf::Alignment::CENTER;
@ -93,14 +94,17 @@ void fill_config(PConf& pcfg) {
// TODO cannot use rotations until multiple objects of same geometry can // TODO cannot use rotations until multiple objects of same geometry can
// handle different rotations. // handle different rotations.
pcfg.rotations = { 0.0 }; if (params.allow_rotations)
pcfg.rotations = {0., PI / 2., PI, 3. * PI / 2. };
else
pcfg.rotations = {0.};
// The accuracy of optimization. // The accuracy of optimization.
// Goes from 0.0 to 1.0 and scales performance as well // Goes from 0.0 to 1.0 and scales performance as well
pcfg.accuracy = 0.65f; pcfg.accuracy = params.accuracy;
// Allow parallel execution. // Allow parallel execution.
pcfg.parallel = true; pcfg.parallel = params.parallel;
} }
// Apply penalty to object function result. This is used only when alignment // Apply penalty to object function result. This is used only when alignment
@ -277,10 +281,10 @@ protected:
if (result.empty()) if (result.empty())
score = 0.50 * dist + 0.50 * density; score = 0.50 * dist + 0.50 * density;
else else
score = R * 0.60 * dist + // Let the density matter more when fewer objects remain
(1.0 - R) * 0.20 * density + score = 0.50 * dist + (1.0 - R) * 0.20 * density +
0.20 * alignment_score; 0.30 * alignment_score;
break; break;
} }
case LAST_BIG_ITEM: { case LAST_BIG_ITEM: {
@ -304,15 +308,15 @@ protected:
public: public:
AutoArranger(const TBin & bin, AutoArranger(const TBin & bin,
Distance dist, const ArrangeParams &params,
std::function<void(unsigned)> progressind, std::function<void(unsigned)> progressind,
std::function<bool(void)> stopcond) std::function<bool(void)> stopcond)
: m_pck(bin, dist) : m_pck(bin, params.min_obj_distance)
, m_bin(bin) , m_bin(bin)
, m_bin_area(sl::area(bin)) , m_bin_area(sl::area(bin))
, m_norm(std::sqrt(m_bin_area)) , m_norm(std::sqrt(m_bin_area))
{ {
fill_config(m_pconf); fill_config(m_pconf, params);
// Set up a callback that is called just before arranging starts // Set up a callback that is called just before arranging starts
// This functionality is provided by the Nester class (m_pack). // This functionality is provided by the Nester class (m_pack).
@ -343,18 +347,31 @@ public:
}; };
m_pconf.object_function = get_objfn(); m_pconf.object_function = get_objfn();
auto on_packed = params.on_packed;
if (progressind) m_pck.progressIndicator(progressind); if (progressind || on_packed)
m_pck.progressIndicator([this, progressind, on_packed](unsigned rem) {
if (progressind)
progressind(rem);
if (on_packed) {
int last_bed = m_pck.lastPackedBinId();
if (last_bed >= 0) {
Item &last_packed = m_pck.lastResult()[last_bed].back();
ArrangePolygon ap;
ap.bed_idx = last_packed.binId();
ap.priority = last_packed.priority();
on_packed(ap);
}
}
});
if (stopcond) m_pck.stopCondition(stopcond); if (stopcond) m_pck.stopCondition(stopcond);
m_pck.configure(m_pconf); m_pck.configure(m_pconf);
} }
AutoArranger(const TBin & bin,
std::function<void(unsigned)> progressind,
std::function<bool(void)> stopcond)
: AutoArranger{bin, 0 /* no min distance */, progressind, stopcond}
{}
template<class It> inline void operator()(It from, It to) { template<class It> inline void operator()(It from, It to) {
m_rtree.clear(); m_rtree.clear();
@ -452,12 +469,18 @@ template<class Bin> void remove_large_items(std::vector<Item> &items, Bin &&bin)
++it : it = items.erase(it); ++it : it = items.erase(it);
} }
template<class S> Radians min_area_boundingbox_rotation(const S &sh)
{
return minAreaBoundingBox<S, TCompute<S>, boost::rational<LargeInt>>(sh)
.angleToX();
}
template<class BinT> // Arrange for arbitrary bin type template<class BinT> // Arrange for arbitrary bin type
void _arrange( void _arrange(
std::vector<Item> & shapes, std::vector<Item> & shapes,
std::vector<Item> & excludes, std::vector<Item> & excludes,
const BinT & bin, const BinT & bin,
const ArrangeParams & params, const ArrangeParams &params,
std::function<void(unsigned)> progressfn, std::function<void(unsigned)> progressfn,
std::function<bool()> stopfn) std::function<bool()> stopfn)
{ {
@ -467,11 +490,10 @@ void _arrange(
auto corrected_bin = bin; auto corrected_bin = bin;
sl::offset(corrected_bin, md); sl::offset(corrected_bin, md);
ArrangeParams mod_params = params;
AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn}; mod_params.min_obj_distance = 0;
arranger.config().accuracy = params.accuracy; AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn};
arranger.config().parallel = params.parallel;
auto infl = coord_t(std::ceil(params.min_obj_distance / 2.0)); auto infl = coord_t(std::ceil(params.min_obj_distance / 2.0));
for (Item& itm : shapes) itm.inflate(infl); for (Item& itm : shapes) itm.inflate(infl);
@ -487,6 +509,13 @@ void _arrange(
for (auto &itm : shapes ) inp.emplace_back(itm); for (auto &itm : shapes ) inp.emplace_back(itm);
for (auto &itm : excludes) inp.emplace_back(itm); for (auto &itm : excludes) inp.emplace_back(itm);
// Use the minimum bounding box rotation as a starting point.
// TODO: This only works for convex hull. If we ever switch to concave
// polygon nesting, a convex hull needs to be calculated.
if (params.allow_rotations)
for (auto &itm : shapes)
itm.rotation(min_area_boundingbox_rotation(itm.rawShape()));
arranger(inp.begin(), inp.end()); arranger(inp.begin(), inp.end());
for (Item &itm : inp) itm.inflate(-infl); for (Item &itm : inp) itm.inflate(-infl);
} }
@ -556,28 +585,35 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
outp.back().priority(arrpoly.priority); outp.back().priority(arrpoly.priority);
} }
template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn)
{
if (bed.empty())
return fn(InfiniteBed{});
else if (bed.size() == 1)
return fn(InfiniteBed{bed.front()});
else {
auto bb = BoundingBox(bed);
CircleBed circ = to_circle(bb.center(), bed);
auto parea = poly_area(bed);
if ((1.0 - parea / area(bb)) < 1e-3)
return fn(bb);
else if (!std::isnan(circ.radius()))
return fn(circ);
else
return fn(Polygon(bed));
}
}
template<> template<>
void arrange(ArrangePolygons & items, void arrange(ArrangePolygons & items,
const ArrangePolygons &excludes, const ArrangePolygons &excludes,
const Points & bed, const Points & bed,
const ArrangeParams & params) const ArrangeParams & params)
{ {
if (bed.empty()) call_with_bed(bed, [&](const auto &bin) {
arrange(items, excludes, InfiniteBed{}, params); arrange(items, excludes, bin, params);
else if (bed.size() == 1) });
arrange(items, excludes, InfiniteBed{bed.front()}, params);
else {
auto bb = BoundingBox(bed);
CircleBed circ = to_circle(bb.center(), bed);
auto parea = poly_area(bed);
if ((1.0 - parea / area(bb)) < 1e-3)
arrange(items, excludes, bb, params);
else if (!std::isnan(circ.radius()))
arrange(items, excludes, circ, params);
else
arrange(items, excludes, Polygon(bed), params);
}
} }
template<class BedT> template<class BedT>

View file

@ -74,14 +74,18 @@ struct ArrangeParams {
/// The accuracy of optimization. /// The accuracy of optimization.
/// Goes from 0.0 to 1.0 and scales performance as well /// Goes from 0.0 to 1.0 and scales performance as well
float accuracy = 0.65f; float accuracy = 1.f;
/// Allow parallel execution. /// Allow parallel execution.
bool parallel = true; bool parallel = true;
bool allow_rotations = false;
/// Progress indicator callback called when an object gets packed. /// Progress indicator callback called when an object gets packed.
/// The unsigned argument is the number of items remaining to pack. /// The unsigned argument is the number of items remaining to pack.
std::function<void(unsigned)> progressind; std::function<void(unsigned)> progressind;
std::function<void(const ArrangePolygon &)> on_packed;
/// A predicate returning true if abort is needed. /// A predicate returning true if abort is needed.
std::function<bool(void)> stopcondition; std::function<bool(void)> stopcondition;

View file

@ -47,6 +47,7 @@ public:
void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; } void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
void translate(const Vec2d &v) { this->min += v; this->max += v; } void translate(const Vec2d &v) { this->min += v; this->max += v; }
void offset(coordf_t delta); void offset(coordf_t delta);
BoundingBoxBase<PointClass> inflated(coordf_t delta) const throw() { BoundingBoxBase<PointClass> out(*this); out.offset(delta); return out; }
PointClass center() const; PointClass center() const;
bool contains(const PointClass &point) const { bool contains(const PointClass &point) const {
return point(0) >= this->min(0) && point(0) <= this->max(0) return point(0) >= this->min(0) && point(0) <= this->max(0)
@ -91,6 +92,7 @@ public:
void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; } void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; }
void translate(const Vec3d &v) { this->min += v; this->max += v; } void translate(const Vec3d &v) { this->min += v; this->max += v; }
void offset(coordf_t delta); void offset(coordf_t delta);
BoundingBoxBase<PointClass> inflated(coordf_t delta) const throw() { BoundingBoxBase<PointClass> out(*this); out.offset(delta); return out; }
PointClass center() const; PointClass center() const;
coordf_t max_size() const; coordf_t max_size() const;
@ -159,6 +161,8 @@ public:
BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {} BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {}
BoundingBox(const Points &points) : BoundingBoxBase<Point>(points) {} BoundingBox(const Points &points) : BoundingBoxBase<Point>(points) {}
BoundingBox inflated(coordf_t delta) const throw() { BoundingBox out(*this); out.offset(delta); return out; }
friend BoundingBox get_extents_rotated(const Points &points, double angle); friend BoundingBox get_extents_rotated(const Points &points, double angle);
}; };

View file

@ -58,10 +58,10 @@ add_library(libslic3r STATIC
Fill/FillGyroid.hpp Fill/FillGyroid.hpp
Fill/FillPlanePath.cpp Fill/FillPlanePath.cpp
Fill/FillPlanePath.hpp Fill/FillPlanePath.hpp
Fill/FillLine.cpp
Fill/FillLine.hpp
Fill/FillRectilinear.cpp Fill/FillRectilinear.cpp
Fill/FillRectilinear.hpp Fill/FillRectilinear.hpp
Fill/FillRectilinear2.cpp
Fill/FillRectilinear2.hpp
Flow.cpp Flow.cpp
Flow.hpp Flow.hpp
format.hpp format.hpp
@ -159,8 +159,8 @@ add_library(libslic3r STATIC
PrintConfig.hpp PrintConfig.hpp
PrintObject.cpp PrintObject.cpp
PrintRegion.cpp PrintRegion.cpp
PNGRead.hpp PNGReadWrite.hpp
PNGRead.cpp PNGReadWrite.cpp
Semver.cpp Semver.cpp
ShortestPath.cpp ShortestPath.cpp
ShortestPath.hpp ShortestPath.hpp

View file

@ -1069,7 +1069,7 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
ClipperLib::Paths holes; ClipperLib::Paths holes;
holes.reserve(expoly.holes.size()); holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes) for (const Polygon& hole : expoly.holes)
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false)); append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
#ifndef NDEBUG #ifndef NDEBUG
for (auto &c : holes) for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.); assert(ClipperLib::Area(c) > 0.);
@ -1113,7 +1113,7 @@ for (const std::vector<float>& ds : deltas)
ClipperLib::Paths holes; ClipperLib::Paths holes;
holes.reserve(expoly.holes.size()); holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes) for (const Polygon& hole : expoly.holes)
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
#ifndef NDEBUG #ifndef NDEBUG
for (auto &c : holes) for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.); assert(ClipperLib::Area(c) > 0.);
@ -1157,7 +1157,7 @@ for (const std::vector<float>& ds : deltas)
ClipperLib::Paths holes; ClipperLib::Paths holes;
holes.reserve(expoly.holes.size()); holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes) for (const Polygon& hole : expoly.holes)
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
#ifndef NDEBUG #ifndef NDEBUG
for (auto &c : holes) for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.); assert(ClipperLib::Area(c) > 0.);
@ -1205,7 +1205,7 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
ClipperLib::Paths holes; ClipperLib::Paths holes;
holes.reserve(expoly.holes.size()); holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes) for (const Polygon& hole : expoly.holes)
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false)); append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole.points, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
#ifndef NDEBUG #ifndef NDEBUG
for (auto &c : holes) for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.); assert(ClipperLib::Area(c) > 0.);

View file

@ -3,16 +3,16 @@
#include <float.h> #include <float.h>
#include <unordered_map> #include <unordered_map>
#if 0 #include <png.h>
// #ifdef SLIC3R_GUI
#include <wx/image.h>
#endif /* SLIC3R_GUI */
#include "libslic3r.h" #include "libslic3r.h"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "EdgeGrid.hpp" #include "EdgeGrid.hpp"
#include "Geometry.hpp" #include "Geometry.hpp"
#include "SVG.hpp" #include "SVG.hpp"
#include "PNGReadWrite.hpp"
// #define EDGE_GRID_DEBUG_OUTPUT
#if 0 #if 0
// Enable debugging and assert in this file. // Enable debugging and assert in this file.
@ -55,6 +55,24 @@ void EdgeGrid::Grid::create(const Polygons &polygons, coord_t resolution)
create_from_m_contours(resolution); create_from_m_contours(resolution);
} }
void EdgeGrid::Grid::create(const std::vector<const Polygon*> &polygons, coord_t resolution)
{
// Count the contours.
size_t ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j]->points.empty())
++ ncontours;
// Collect the contours.
m_contours.assign(ncontours, nullptr);
ncontours = 0;
for (size_t j = 0; j < polygons.size(); ++ j)
if (! polygons[j]->points.empty())
m_contours[ncontours ++] = &polygons[j]->points;
create_from_m_contours(resolution);
}
void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution) void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution)
{ {
// Count the contours. // Count the contours.
@ -659,6 +677,11 @@ struct PropagateDanielssonSingleVStep3 {
void EdgeGrid::Grid::calculate_sdf() void EdgeGrid::Grid::calculate_sdf()
{ {
#ifdef EDGE_GRID_DEBUG_OUTPUT
static int iRun = 0;
++ iRun;
#endif
// 1) Initialize a signum and an unsigned vector to a zero iso surface. // 1) Initialize a signum and an unsigned vector to a zero iso surface.
size_t nrows = m_rows + 1; size_t nrows = m_rows + 1;
size_t ncols = m_cols + 1; size_t ncols = m_cols + 1;
@ -756,19 +779,12 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
#if 0 #ifdef EDGE_GRID_DEBUG_OUTPUT
static int iRun = 0;
++ iRun;
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler);
//#ifdef SLIC3R_GUI
{ {
wxImage img(ncols, nrows); std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
unsigned char *data = img.GetData(); for (coord_t r = 0; r < nrows; ++ r) {
memset(data, 0, ncols * nrows * 3); for (coord_t c = 0; c < ncols; ++ c) {
for (coord_t r = 0; r < nrows; ++r) { uint8_t *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3;
float d = m_signed_distance_field[r * ncols + c]; float d = m_signed_distance_field[r * ncols + c];
if (d != search_radius) { if (d != search_radius) {
float s = 255 * d / search_radius; float s = 255 * d / search_radius;
@ -784,15 +800,13 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
} }
img.SaveFile(debug_out_path("unsigned_df-%d.png", iRun), wxBITMAP_TYPE_PNG); png::write_rgb_to_file_scaled(debug_out_path("unsigned_df-%d.png", iRun), ncols, nrows, pixels, 10);
} }
{ {
wxImage img(ncols, nrows); std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
unsigned char *data = img.GetData(); for (coord_t r = 0; r < nrows; ++ r) {
memset(data, 0, ncols * nrows * 3); for (coord_t c = 0; c < ncols; ++ c) {
for (coord_t r = 0; r < nrows; ++r) { unsigned char *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3;
float d = m_signed_distance_field[r * ncols + c]; float d = m_signed_distance_field[r * ncols + c];
if (d != search_radius) { if (d != search_radius) {
float s = 255 * d / search_radius; float s = 255 * d / search_radius;
@ -817,9 +831,9 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
} }
img.SaveFile(debug_out_path("signed_df-%d.png", iRun), wxBITMAP_TYPE_PNG); png::write_rgb_to_file_scaled(debug_out_path("signed_df-%d.png", iRun), ncols, nrows, pixels, 10);
} }
#endif /* SLIC3R_GUI */ #endif // EDGE_GRID_DEBUG_OUTPUT
// 2) Propagate the signum. // 2) Propagate the signum.
#define PROPAGATE_SIGNUM_SINGLE_STEP(DELTA) do { \ #define PROPAGATE_SIGNUM_SINGLE_STEP(DELTA) do { \
@ -891,17 +905,14 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
#if 0 #ifdef EDGE_GRID_DEBUG_OUTPUT
//#ifdef SLIC3R_GUI
{ {
wxImage img(ncols, nrows); std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
float search_radius = float(m_resolution * 5); float search_radius = float(m_resolution * 5);
for (coord_t r = 0; r < nrows; ++r) { for (coord_t r = 0; r < nrows; ++r) {
for (coord_t c = 0; c < ncols; ++c) { for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3; uint8_t *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
unsigned char sign = signs[r * ncols + c]; uint8_t sign = signs[r * ncols + c];
switch (sign) { switch (sign) {
case 0: case 0:
// Positive, outside of a narrow band. // Positive, outside of a narrow band.
@ -942,20 +953,17 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
} }
img.SaveFile(debug_out_path("signed_df-signs-%d.png", iRun), wxBITMAP_TYPE_PNG); png::write_rgb_to_file_scaled(debug_out_path("signed_df-signs-%d.png", iRun), ncols, nrows, pixels, 10);
} }
#endif /* SLIC3R_GUI */ #endif // EDGE_GRID_DEBUG_OUTPUT
#if 0 #ifdef EDGE_GRID_DEBUG_OUTPUT
//#ifdef SLIC3R_GUI
{ {
wxImage img(ncols, nrows); std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
float search_radius = float(m_resolution * 5); float search_radius = float(m_resolution * 5);
for (coord_t r = 0; r < nrows; ++r) { for (coord_t r = 0; r < nrows; ++r) {
for (coord_t c = 0; c < ncols; ++c) { for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3; uint8_t *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
float d = m_signed_distance_field[r * ncols + c]; float d = m_signed_distance_field[r * ncols + c];
float s = 255.f * fabs(d) / search_radius; float s = 255.f * fabs(d) / search_radius;
int is = std::max(0, std::min(255, int(floor(s + 0.5f)))); int is = std::max(0, std::min(255, int(floor(s + 0.5f))));
@ -971,9 +979,9 @@ void EdgeGrid::Grid::calculate_sdf()
} }
} }
} }
img.SaveFile(debug_out_path("signed_df2-%d.png", iRun), wxBITMAP_TYPE_PNG); png::write_rgb_to_file_scaled(debug_out_path("signed_df2-%d.png", iRun), ncols, nrows, pixels, 10);
} }
#endif /* SLIC3R_GUI */ #endif // EDGE_GRID_DEBUG_OUTPUT
} }
float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
@ -1150,7 +1158,7 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
if (result.contour_idx != size_t(-1) && d_min <= double(search_radius)) { if (result.contour_idx != size_t(-1) && d_min <= double(search_radius)) {
result.distance = d_min * sign_min; result.distance = d_min * sign_min;
result.t /= l2_seg_min; result.t /= l2_seg_min;
assert(result.t >= 0. && result.t < 1.); assert(result.t >= 0. && result.t <= 1.);
#ifndef NDEBUG #ifndef NDEBUG
{ {
const Slic3r::Points &pts = *m_contours[result.contour_idx]; const Slic3r::Points &pts = *m_contours[result.contour_idx];
@ -1473,26 +1481,18 @@ bool EdgeGrid::Grid::has_intersecting_edges() const
return false; return false;
} }
#if 0 void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path, size_t scale)
void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path)
{ {
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler);
unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution; unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution;
unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution; unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution;
wxImage img(w, h);
unsigned char *data = img.GetData();
memset(data, 0, w * h * 3);
static int iRun = 0; std::vector<uint8_t> pixels(w * h * 3, 0);
++iRun;
const coord_t search_radius = grid.resolution() * 2; const coord_t search_radius = grid.resolution() * 2;
const coord_t display_blend_radius = grid.resolution() * 2; const coord_t display_blend_radius = grid.resolution() * 2;
for (coord_t r = 0; r < h; ++r) { for (coord_t r = 0; r < h; ++r) {
for (coord_t c = 0; c < w; ++ c) { for (coord_t c = 0; c < w; ++ c) {
unsigned char *pxl = data + (((h - r - 1) * w) + c) * 3; unsigned char *pxl = pixels.data() + (((h - r - 1) * w) + c) * 3;
Point pt(c * resolution + bbox.min(0), r * resolution + bbox.min(1)); Point pt(c * resolution + bbox.min(0), r * resolution + bbox.min(1));
coordf_t min_dist; coordf_t min_dist;
bool on_segment = true; bool on_segment = true;
@ -1566,9 +1566,8 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
} }
} }
img.SaveFile(path, wxBITMAP_TYPE_PNG); png::write_rgb_to_file_scaled(path, w, h, pixels, scale);
} }
#endif /* SLIC3R_GUI */
// Find all pairs of intersectiong edges from the set of polygons. // Find all pairs of intersectiong edges from the set of polygons.
std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> intersecting_edges(const Polygons &polygons) std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> intersecting_edges(const Polygons &polygons)

View file

@ -21,6 +21,7 @@ public:
void set_bbox(const BoundingBox &bbox) { m_bbox = bbox; } void set_bbox(const BoundingBox &bbox) { m_bbox = bbox; }
void create(const Polygons &polygons, coord_t resolution); void create(const Polygons &polygons, coord_t resolution);
void create(const std::vector<const Polygon*> &polygons, coord_t resolution);
void create(const std::vector<Points> &polygons, coord_t resolution); void create(const std::vector<Points> &polygons, coord_t resolution);
void create(const ExPolygon &expoly, coord_t resolution); void create(const ExPolygon &expoly, coord_t resolution);
void create(const ExPolygons &expolygons, coord_t resolution); void create(const ExPolygons &expolygons, coord_t resolution);
@ -83,10 +84,14 @@ public:
template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const
{ {
// End points of the line segment. // End points of the line segment.
p1(0) -= m_bbox.min(0); assert(m_bbox.contains(p1));
p1(1) -= m_bbox.min(1); assert(m_bbox.contains(p2));
p2(0) -= m_bbox.min(0); p1 -= m_bbox.min;
p2(1) -= m_bbox.min(1); p2 -= m_bbox.min;
assert(p1.x() >= 0 && p1.x() < m_cols * m_resolution);
assert(p1.y() >= 0 && p1.y() < m_rows * m_resolution);
assert(p2.x() >= 0 && p2.x() < m_cols * m_resolution);
assert(p2.y() >= 0 && p2.y() < m_rows * m_resolution);
// Get the cells of the end points. // Get the cells of the end points.
coord_t ix = p1(0) / m_resolution; coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution; coord_t iy = p1(1) / m_resolution;
@ -114,18 +119,22 @@ public:
ey -= ex; ey -= ex;
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix += 1; ix += 1;
assert(ix <= ixb);
} }
else if (ex == ey) { else if (ex == ey) {
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
ix += 1; ix += 1;
iy += 1; iy += 1;
assert(ix <= ixb);
assert(iy <= iyb);
} }
else { else {
assert(ex > ey); assert(ex > ey);
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy += 1; iy += 1;
assert(iy <= iyb);
} }
if (! visitor(iy, ix)) if (! visitor(iy, ix))
return; return;
@ -140,11 +149,13 @@ public:
ey -= ex; ey -= ex;
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix += 1; ix += 1;
assert(ix <= ixb);
} }
else { else {
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy -= 1; iy -= 1;
assert(iy >= iyb);
} }
if (! visitor(iy, ix)) if (! visitor(iy, ix))
return; return;
@ -162,12 +173,14 @@ public:
ey -= ex; ey -= ex;
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix -= 1; ix -= 1;
assert(ix >= ixb);
} }
else { else {
assert(ex >= ey); assert(ex >= ey);
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy += 1; iy += 1;
assert(iy <= iyb);
} }
if (! visitor(iy, ix)) if (! visitor(iy, ix))
return; return;
@ -182,6 +195,7 @@ public:
ey -= ex; ey -= ex;
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix -= 1; ix -= 1;
assert(ix >= ixb);
} }
else if (ex == ey) { else if (ex == ey) {
// The lower edge of a grid cell belongs to the cell. // The lower edge of a grid cell belongs to the cell.
@ -190,10 +204,12 @@ public:
if (dx > 0) { if (dx > 0) {
ex = int64_t(dy) * m_resolution; ex = int64_t(dy) * m_resolution;
ix -= 1; ix -= 1;
assert(ix >= ixb);
} }
if (dy > 0) { if (dy > 0) {
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy -= 1; iy -= 1;
assert(iy >= iyb);
} }
} }
else { else {
@ -201,6 +217,7 @@ public:
ex -= ey; ex -= ey;
ey = int64_t(dx) * m_resolution; ey = int64_t(dx) * m_resolution;
iy -= 1; iy -= 1;
assert(iy >= iyb);
} }
if (! visitor(iy, ix)) if (! visitor(iy, ix))
return; return;
@ -230,6 +247,10 @@ public:
std::pair<std::vector<std::pair<size_t, size_t>>::const_iterator, std::vector<std::pair<size_t, size_t>>::const_iterator> cell_data_range(coord_t row, coord_t col) const std::pair<std::vector<std::pair<size_t, size_t>>::const_iterator, std::vector<std::pair<size_t, size_t>>::const_iterator> cell_data_range(coord_t row, coord_t col) const
{ {
assert(row >= 0);
assert(row < m_rows);
assert(col >= 0);
assert(col < m_cols);
const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col]; const EdgeGrid::Grid::Cell &cell = m_cells[row * m_cols + col];
return std::make_pair(m_cell_data.begin() + cell.begin, m_cell_data.begin() + cell.end); return std::make_pair(m_cell_data.begin() + cell.begin, m_cell_data.begin() + cell.end);
} }
@ -295,10 +316,8 @@ protected:
std::vector<float> m_signed_distance_field; std::vector<float> m_signed_distance_field;
}; };
#if 0
// Debugging utility. Save the signed distance field. // Debugging utility. Save the signed distance field.
extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path); extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path, size_t scale = 1);
#endif /* SLIC3R_GUI */
} // namespace EdgeGrid } // namespace EdgeGrid

View file

@ -350,23 +350,10 @@ void ExPolygon::get_trapezoids2(Polygons* polygons) const
// find trapezoids by looping from first to next-to-last coordinate // find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) { for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1); coord_t next_x = *(x + 1);
if (*x == next_x) continue; if (*x != next_x)
// intersect with rectangle
// build rectangle // append results to return value
Polygon poly; polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, to_polygons(*this)));
poly.points.resize(4);
poly[0](0) = *x;
poly[0](1) = bb.min(1);
poly[1](0) = next_x;
poly[1](1) = bb.min(1);
poly[2](0) = next_x;
poly[2](1) = bb.max(1);
poly[3](0) = *x;
poly[3](1) = bb.max(1);
// intersect with this expolygon
// append results to return value
polygons_append(*polygons, intersection(poly, to_polygons(*this)));
} }
} }

View file

@ -17,9 +17,9 @@ typedef std::vector<ExPolygon> ExPolygons;
class ExPolygon class ExPolygon
{ {
public: public:
ExPolygon() {} ExPolygon() = default;
ExPolygon(const ExPolygon &other) : contour(other.contour), holes(other.holes) {} ExPolygon(const ExPolygon &other) = default;
ExPolygon(ExPolygon &&other) noexcept : contour(std::move(other.contour)), holes(std::move(other.holes)) {} ExPolygon(ExPolygon &&other) = default;
explicit ExPolygon(const Polygon &contour) : contour(contour) {} explicit ExPolygon(const Polygon &contour) : contour(contour) {}
explicit ExPolygon(Polygon &&contour) : contour(std::move(contour)) {} explicit ExPolygon(Polygon &&contour) : contour(std::move(contour)) {}
explicit ExPolygon(const Points &contour) : contour(contour) {} explicit ExPolygon(const Points &contour) : contour(contour) {}
@ -31,10 +31,10 @@ public:
ExPolygon(std::initializer_list<Point> contour) : contour(contour) {} ExPolygon(std::initializer_list<Point> contour) : contour(contour) {}
ExPolygon(std::initializer_list<Point> contour, std::initializer_list<Point> hole) : contour(contour), holes({ hole }) {} ExPolygon(std::initializer_list<Point> contour, std::initializer_list<Point> hole) : contour(contour), holes({ hole }) {}
ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; } ExPolygon& operator=(const ExPolygon &other) = default;
ExPolygon& operator=(ExPolygon &&other) noexcept { contour = std::move(other.contour); holes = std::move(other.holes); return *this; } ExPolygon& operator=(ExPolygon &&other) = default;
Polygon contour; Polygon contour;
Polygons holes; Polygons holes;
operator Points() const; operator Points() const;

View file

@ -14,12 +14,12 @@ namespace Slic3r {
void ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const void ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
{ {
this->_inflate_collection(intersection_pl(this->polyline, (Polygons)collection), retval); this->_inflate_collection(intersection_pl((Polylines)polyline, to_polygons(collection.expolygons)), retval);
} }
void ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const void ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
{ {
this->_inflate_collection(diff_pl(this->polyline, (Polygons)collection), retval); this->_inflate_collection(diff_pl((Polylines)this->polyline, to_polygons(collection.expolygons)), retval);
} }
void ExtrusionPath::clip_end(double distance) void ExtrusionPath::clip_end(double distance)

View file

@ -10,7 +10,7 @@
#include "../Surface.hpp" #include "../Surface.hpp"
#include "FillBase.hpp" #include "FillBase.hpp"
#include "FillRectilinear2.hpp" #include "FillRectilinear.hpp"
namespace Slic3r { namespace Slic3r {
@ -33,10 +33,12 @@ struct SurfaceFillParams
// FillParams // FillParams
float density = 0.f; float density = 0.f;
// Don't connect the fill lines around the inner perimeter.
bool dont_connect = false;
// Don't adjust spacing to fill the space evenly. // Don't adjust spacing to fill the space evenly.
bool dont_adjust = false; bool dont_adjust = false;
// Length of the infill anchor along the perimeter line.
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length = 1000.f;
float anchor_length_max = 1000.f;
// width, height of extrusion, nozzle diameter, is bridge // width, height of extrusion, nozzle diameter, is bridge
// For the output, for fill generator. // For the output, for fill generator.
@ -65,8 +67,9 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(overlap); RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle); RETURN_COMPARE_NON_EQUAL(angle);
RETURN_COMPARE_NON_EQUAL(density); RETURN_COMPARE_NON_EQUAL(density);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_connect);
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust); RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
RETURN_COMPARE_NON_EQUAL(anchor_length);
RETURN_COMPARE_NON_EQUAL(anchor_length_max);
RETURN_COMPARE_NON_EQUAL(flow.width); RETURN_COMPARE_NON_EQUAL(flow.width);
RETURN_COMPARE_NON_EQUAL(flow.height); RETURN_COMPARE_NON_EQUAL(flow.height);
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter); RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
@ -83,8 +86,9 @@ struct SurfaceFillParams
this->overlap == rhs.overlap && this->overlap == rhs.overlap &&
this->angle == rhs.angle && this->angle == rhs.angle &&
this->density == rhs.density && this->density == rhs.density &&
this->dont_connect == rhs.dont_connect &&
this->dont_adjust == rhs.dont_adjust && this->dont_adjust == rhs.dont_adjust &&
this->anchor_length == rhs.anchor_length &&
this->anchor_length_max == rhs.anchor_length_max &&
this->flow == rhs.flow && this->flow == rhs.flow &&
this->extrusion_role == rhs.extrusion_role; this->extrusion_role == rhs.extrusion_role;
} }
@ -115,16 +119,17 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
if (surface.surface_type == stInternalVoid) if (surface.surface_type == stInternalVoid)
has_internal_voids = true; has_internal_voids = true;
else { else {
const PrintRegionConfig &region_config = layerm.region()->config();
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill); FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
bool is_bridge = layer.id() > 0 && surface.is_bridge(); bool is_bridge = layer.id() > 0 && surface.is_bridge();
params.extruder = layerm.region()->extruder(extrusion_role); params.extruder = layerm.region()->extruder(extrusion_role);
params.pattern = layerm.region()->config().fill_pattern.value; params.pattern = region_config.fill_pattern.value;
params.density = float(layerm.region()->config().fill_density); params.density = float(region_config.fill_density);
if (surface.is_solid()) { if (surface.is_solid()) {
params.density = 100.f; params.density = 100.f;
params.pattern = (surface.is_external() && ! is_bridge) ? params.pattern = (surface.is_external() && ! is_bridge) ?
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) : (surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) :
ipRectilinear; ipRectilinear;
} else if (params.density <= 0) } else if (params.density <= 0)
continue; continue;
@ -136,7 +141,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
(surface.is_top() ? erTopSolidInfill : erSolidInfill) : (surface.is_top() ? erTopSolidInfill : erSolidInfill) :
erInternalInfill); erInternalInfill);
params.bridge_angle = float(surface.bridge_angle); params.bridge_angle = float(surface.bridge_angle);
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value)); params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
// calculate the actual flow we'll be using for this infill // calculate the actual flow we'll be using for this infill
params.flow = layerm.region()->flow( params.flow = layerm.region()->flow(
@ -149,7 +154,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
); );
// Calculate flow spacing for infill pattern generation. // Calculate flow spacing for infill pattern generation.
if (! surface.is_solid() && ! is_bridge) { if (surface.is_solid() || is_bridge) {
params.spacing = params.flow.spacing();
// Don't limit anchor length for solid or bridging infill.
params.anchor_length = 1000.f;
} else {
// it's internal infill, so we can calculate a generic flow spacing // it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of // for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and // misaligned infill on first layer because of different extrusion width and
@ -162,8 +171,15 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
-1, // auto width -1, // auto width
*layer.object() *layer.object()
).spacing(); ).spacing();
} else // Anchor a sparse infill to inner perimeters with the following anchor length:
params.spacing = params.flow.spacing(); params.anchor_length = float(region_config.infill_anchor);
if (region_config.infill_anchor.percent)
params.anchor_length = float(params.anchor_length * 0.01 * params.spacing);
params.anchor_length_max = float(region_config.infill_anchor_max);
if (region_config.infill_anchor_max.percent)
params.anchor_length_max = float(params.anchor_length_max * 0.01 * params.spacing);
}
params.anchor_length = std::min(params.anchor_length, params.anchor_length_max);
auto it_params = set_surface_params.find(params); auto it_params = set_surface_params.find(params);
if (it_params == set_surface_params.end()) if (it_params == set_surface_params.end())
@ -367,8 +383,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
// apply half spacing using this flow's own spacing and generate infill // apply half spacing using this flow's own spacing and generate infill
FillParams params; FillParams params;
params.density = float(0.01 * surface_fill.params.density); params.density = float(0.01 * surface_fill.params.density);
params.dont_adjust = surface_fill.params.dont_adjust; // false params.dont_adjust = surface_fill.params.dont_adjust; // false
params.anchor_length = surface_fill.params.anchor_length;
params.anchor_length_max = surface_fill.params.anchor_length_max;
for (ExPolygon &expoly : surface_fill.expolygons) { for (ExPolygon &expoly : surface_fill.expolygons) {
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
@ -526,15 +544,13 @@ void Layer::make_ironing()
} }
std::sort(by_extruder.begin(), by_extruder.end()); std::sort(by_extruder.begin(), by_extruder.end());
FillRectilinear2 fill; FillRectilinear fill;
FillParams fill_params; FillParams fill_params;
fill.set_bounding_box(this->object()->bounding_box()); fill.set_bounding_box(this->object()->bounding_box());
fill.layer_id = this->id(); fill.layer_id = this->id();
fill.z = this->print_z; fill.z = this->print_z;
fill.overlap = 0; fill.overlap = 0;
fill_params.density = 1.; fill_params.density = 1.;
// fill_params.dont_connect = true;
fill_params.dont_connect = false;
fill_params.monotonic = true; fill_params.monotonic = true;
for (size_t i = 0; i < by_extruder.size(); ++ i) { for (size_t i = 0; i < by_extruder.size(); ++ i) {

View file

@ -19,10 +19,10 @@ class LayerRegion;
class Filler class Filler
{ {
public: public:
Filler() : fill(NULL) {} Filler() : fill(nullptr) {}
~Filler() { ~Filler() {
delete fill; delete fill;
fill = NULL; fill = nullptr;
} }
Fill *fill; Fill *fill;
FillParams params; FillParams params;

View file

@ -137,7 +137,7 @@ void Fill3DHoneycomb::_fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
// no rotation is supported for this infill pattern // no rotation is supported for this infill pattern
@ -162,15 +162,13 @@ void Fill3DHoneycomb::_fill_surface_single(
pl.translate(bb.min); pl.translate(bb.min);
// clip pattern to boundaries, chain the clipped polylines // clip pattern to boundaries, chain the clipped polylines
Polylines polylines_chained = chain_polylines(intersection_pl(polylines, to_polygons(expolygon))); polylines = intersection_pl(polylines, to_polygons(expolygon));
// connect lines if needed // connect lines if needed
if (! polylines_chained.empty()) { if (params.dont_connect() || polylines.size() <= 1)
if (params.dont_connect) append(polylines_out, chain_polylines(std::move(polylines)));
append(polylines_out, std::move(polylines_chained)); else
else this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
this->connect_infill(std::move(polylines_chained), expolygon, polylines_out, this->spacing, params);
}
} }
} // namespace Slic3r } // namespace Slic3r

View file

@ -12,19 +12,19 @@ namespace Slic3r {
class Fill3DHoneycomb : public Fill class Fill3DHoneycomb : public Fill
{ {
public: public:
virtual Fill* clone() const { return new Fill3DHoneycomb(*this); }; Fill* clone() const override { return new Fill3DHoneycomb(*this); };
virtual ~Fill3DHoneycomb() {} ~Fill3DHoneycomb() override {}
// require bridge flow since most of this pattern hangs in air // require bridge flow since most of this pattern hangs in air
virtual bool use_bridge_flow() const { return true; } bool use_bridge_flow() const override { return true; }
protected: protected:
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
}; };
} // namespace Slic3r } // namespace Slic3r

View file

@ -14,11 +14,18 @@
#include <cstdlib> #include <cstdlib>
#include <cmath> #include <cmath>
#include <algorithm> #include <algorithm>
#include <numeric>
// Boost pool: Don't use mutexes to synchronize memory allocation. // Boost pool: Don't use mutexes to synchronize memory allocation.
#define BOOST_POOL_NO_MT #define BOOST_POOL_NO_MT
#include <boost/pool/object_pool.hpp> #include <boost/pool/object_pool.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/index/rtree.hpp>
namespace Slic3r { namespace Slic3r {
namespace FillAdaptive { namespace FillAdaptive {
@ -288,7 +295,7 @@ std::pair<double, double> adaptive_fill_line_spacing(const PrintObject &print_ob
bool build_octree = false; bool build_octree = false;
const std::vector<double> &nozzle_diameters = print_object.print()->config().nozzle_diameter.values; const std::vector<double> &nozzle_diameters = print_object.print()->config().nozzle_diameter.values;
double max_nozzle_diameter = *std::max_element(nozzle_diameters.begin(), nozzle_diameters.end()); double max_nozzle_diameter = *std::max_element(nozzle_diameters.begin(), nozzle_diameters.end());
double default_infill_extrusion_width = Flow::auto_extrusion_width(FlowRole::frInfill, max_nozzle_diameter); double default_infill_extrusion_width = Flow::auto_extrusion_width(FlowRole::frInfill, float(max_nozzle_diameter));
for (const PrintRegion *region : print_object.print()->regions()) { for (const PrintRegion *region : print_object.print()->regions()) {
const PrintRegionConfig &config = region->config(); const PrintRegionConfig &config = region->config();
bool nonempty = config.fill_density > 0; bool nonempty = config.fill_density > 0;
@ -475,7 +482,7 @@ static void generate_infill_lines_recursive(
Line new_line(Point::new_scale(from), Point::new_scale(to)); Line new_line(Point::new_scale(from), Point::new_scale(to));
if (last_line.a.x() == std::numeric_limits<coord_t>::max()) { if (last_line.a.x() == std::numeric_limits<coord_t>::max()) {
last_line.a = new_line.a; last_line.a = new_line.a;
} else if ((new_line.a - last_line.b).cwiseAbs().maxCoeff() > 300) { // SCALED_EPSILON is 100 and it is not enough } else if ((new_line.a - last_line.b).cwiseAbs().maxCoeff() > 1000) { // SCALED_EPSILON is 100 and it is not enough
context.output_lines.emplace_back(last_line); context.output_lines.emplace_back(last_line);
last_line.a = new_line.a; last_line.a = new_line.a;
} }
@ -501,7 +508,7 @@ static void generate_infill_lines_recursive(
#endif #endif
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
static void export_infill_lines_to_svg(const ExPolygon &expoly, const Polylines &polylines, const std::string &path) static void export_infill_lines_to_svg(const ExPolygon &expoly, const Polylines &polylines, const std::string &path, const Points &pts = Points())
{ {
BoundingBox bbox = get_extents(expoly); BoundingBox bbox = get_extents(expoly);
bbox.offset(scale_(3.)); bbox.offset(scale_(3.));
@ -511,46 +518,805 @@ static void export_infill_lines_to_svg(const ExPolygon &expoly, const Polylines
svg.draw_outline(expoly, "green"); svg.draw_outline(expoly, "green");
svg.draw(polylines, "red"); svg.draw(polylines, "red");
static constexpr double trim_length = scale_(0.4); static constexpr double trim_length = scale_(0.4);
for (Polyline polyline : polylines) { for (Polyline polyline : polylines)
Vec2d a = polyline.points.front().cast<double>(); if (! polyline.empty()) {
Vec2d d = polyline.points.back().cast<double>(); Vec2d a = polyline.points.front().cast<double>();
if (polyline.size() == 2) { Vec2d d = polyline.points.back().cast<double>();
Vec2d v = d - a; if (polyline.size() == 2) {
double l = v.norm(); Vec2d v = d - a;
if (l > 2. * trim_length) { double l = v.norm();
a += v * trim_length / l; if (l > 2. * trim_length) {
d -= v * trim_length / l; a += v * trim_length / l;
polyline.points.front() = a.cast<coord_t>(); d -= v * trim_length / l;
polyline.points.back() = d.cast<coord_t>(); polyline.points.front() = a.cast<coord_t>();
} else polyline.points.back() = d.cast<coord_t>();
polyline.points.clear(); } else
} else if (polyline.size() > 2) { polyline.points.clear();
Vec2d b = polyline.points[1].cast<double>(); } else if (polyline.size() > 2) {
Vec2d c = polyline.points[polyline.points.size() - 2].cast<double>(); Vec2d b = polyline.points[1].cast<double>();
Vec2d v = b - a; Vec2d c = polyline.points[polyline.points.size() - 2].cast<double>();
double l = v.norm(); Vec2d v = b - a;
if (l > trim_length) { double l = v.norm();
a += v * trim_length / l; if (l > trim_length) {
polyline.points.front() = a.cast<coord_t>(); a += v * trim_length / l;
} else polyline.points.front() = a.cast<coord_t>();
polyline.points.erase(polyline.points.begin()); } else
v = d - c; polyline.points.erase(polyline.points.begin());
l = v.norm(); v = d - c;
if (l > trim_length) l = v.norm();
polyline.points.back() = (d - v * trim_length / l).cast<coord_t>(); if (l > trim_length)
else polyline.points.back() = (d - v * trim_length / l).cast<coord_t>();
polyline.points.pop_back(); else
polyline.points.pop_back();
}
svg.draw(polyline, "black");
} }
svg.draw(polyline, "black"); svg.draw(pts, "magenta");
}
} }
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */ #endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
// Representing a T-joint (in general case) between two infill lines
// (between one end point of intersect_pl/intersect_line and
struct Intersection
{
// Closest line to intersect_point.
const Line *closest_line;
// The line for which is computed closest line from intersect_point to closest_line
const Line *intersect_line;
// Pointer to the polyline from which is computed closest_line
Polyline *intersect_pl;
// Point for which is computed closest line (closest_line)
Point intersect_point;
// Indicate if intersect_point is the first or the last point of intersect_pl
bool front;
// Signum of intersect_line_dir.cross(closest_line.dir()):
bool left;
// Indication if this intersection has been proceed
bool used = false;
bool fresh() const throw() { return ! used && ! intersect_pl->empty(); }
Intersection(const Line &closest_line, const Line &intersect_line, Polyline *intersect_pl, const Point &intersect_point, bool front) :
closest_line(&closest_line), intersect_line(&intersect_line), intersect_pl(intersect_pl), intersect_point(intersect_point), front(front)
{
// Calculate side of this intersection line of the closest line.
Vec2d v1((this->closest_line->b - this->closest_line->a).cast<double>());
Vec2d v2(this->intersect_line_dir());
#ifndef NDEBUG
{
Vec2d v1n = v1.normalized();
Vec2d v2n = v2.normalized();
double c = cross2(v1n, v2n);
assert(std::abs(c) > sin(M_PI / 12.));
}
#endif // NDEBUG
this->left = cross2(v1, v2) > 0.;
}
std::optional<Line> other_hook() const {
std::optional<Line> out;
const Points &pts = intersect_pl->points;
if (pts.size() >= 3)
out = this->front ? Line(pts[1], pts[2]) : Line(pts[pts.size() - 2], pts[pts.size() - 3]);
return out;
}
bool other_hook_intersects(const Line &l, Point &pt) {
std::optional<Line> h = other_hook();
return h && h->intersection(l, &pt);
}
bool other_hook_intersects(const Line &l) { Point pt; return this->other_hook_intersects(l, pt); }
// Direction to intersect_point.
Vec2d intersect_line_dir() const throw() {
return (this->intersect_point == intersect_line->a ? intersect_line->b - intersect_line->a : intersect_line->a - intersect_line->b).cast<double>();
}
};
static inline Intersection* get_nearest_intersection(std::vector<std::pair<Intersection*, double>>& intersect_line, const size_t first_idx)
{
assert(intersect_line.size() >= 2);
bool take_next = false;
if (first_idx == 0)
take_next = true;
else if (first_idx + 1 == intersect_line.size())
take_next = false;
else {
// Has both prev and next.
const std::pair<Intersection*, double> &ithis = intersect_line[first_idx];
const std::pair<Intersection*, double> &iprev = intersect_line[first_idx - 1];
const std::pair<Intersection*, double> &inext = intersect_line[first_idx + 1];
take_next = iprev.first->fresh() && inext.first->fresh() ?
inext.second - ithis.second < ithis.second - iprev.second :
inext.first->fresh();
}
return intersect_line[take_next ? first_idx + 1 : first_idx - 1].first;
}
// Create a line representing the anchor aka hook extrusion based on line_to_offset
// translated in the direction of the intersection line (intersection.intersect_line).
static Line create_offset_line(Line offset_line, const Intersection &intersection, const double scaled_offset)
{
offset_line.translate((perp(intersection.closest_line->vector().cast<double>().normalized()) * (intersection.left ? scaled_offset : - scaled_offset)).cast<coord_t>());
// Extend the line by a small value to guarantee a collision with adjacent lines
offset_line.extend(coord_t(scaled_offset * 1.16)); // / cos(PI/6)
return offset_line;
}
namespace bg = boost::geometry;
namespace bgm = boost::geometry::model;
namespace bgi = boost::geometry::index;
// float is needed because for coord_t bgi::intersects throws "bad numeric conversion: positive overflow"
using rtree_point_t = bgm::point<float, 2, boost::geometry::cs::cartesian>;
using rtree_segment_t = bgm::segment<rtree_point_t>;
using rtree_t = bgi::rtree<std::pair<rtree_segment_t, size_t>, bgi::rstar<16, 4>>;
static inline rtree_point_t mk_rtree_point(const Point &pt) {
return rtree_point_t(float(pt.x()), float(pt.y()));
}
static inline rtree_segment_t mk_rtree_seg(const Point &a, const Point &b) {
return { mk_rtree_point(a), mk_rtree_point(b) };
}
static inline rtree_segment_t mk_rtree_seg(const Line &l) {
return mk_rtree_seg(l.a, l.b);
}
// Create a hook based on hook_line and append it to the begin or end of the polyline in the intersection
static void add_hook(
const Intersection &intersection, const double scaled_offset,
const coordf_t hook_length, double scaled_trim_distance,
const rtree_t &rtree, const Lines &lines_src)
{
if (hook_length < SCALED_EPSILON)
// Ignore open hooks.
return;
#ifndef NDEBUG
{
const Vec2d v = (intersection.closest_line->b - intersection.closest_line->a).cast<double>();
const Vec2d va = (intersection.intersect_point - intersection.closest_line->a).cast<double>();
const double l2 = v.squaredNorm(); // avoid a sqrt
assert(l2 > 0.);
const double t = va.dot(v) / l2;
assert(t > 0. && t < 1.);
const double d = (t * v - va).norm();
assert(d < 1000.);
}
#endif // NDEBUG
// Trim the hook start by the infill line it will connect to.
Point hook_start;
bool intersection_found = intersection.intersect_line->intersection(
create_offset_line(*intersection.closest_line, intersection, scaled_offset),
&hook_start);
assert(intersection_found);
std::optional<Line> other_hook = intersection.other_hook();
Vec2d hook_vector_norm = intersection.closest_line->vector().cast<double>().normalized();
// hook_vector is extended by the thickness of the infill line, so that a collision is found against
// the infill centerline to be later trimmed by the thickened line.
Vector hook_vector = ((hook_length + 1.16 * scaled_trim_distance) * hook_vector_norm).cast<coord_t>();
Line hook_forward(hook_start, hook_start + hook_vector);
auto filter_itself = [&intersection, &lines_src](const auto &item) { return item.second != intersection.intersect_line - lines_src.data(); };
std::vector<std::pair<rtree_segment_t, size_t>> hook_intersections;
rtree.query(bgi::intersects(mk_rtree_seg(hook_forward)) && bgi::satisfies(filter_itself), std::back_inserter(hook_intersections));
Point self_intersection_point;
bool self_intersection = other_hook && other_hook->intersection(hook_forward, &self_intersection_point);
// Find closest intersection of a line segment starting with pt pointing in dir
// with any of the hook_intersections, returns Euclidian distance.
// dir is normalized.
auto max_hook_length = [hook_length, scaled_trim_distance, &lines_src](
const Vec2d &pt, const Vec2d &dir,
const std::vector<std::pair<rtree_segment_t, size_t>> &hook_intersections,
bool self_intersection, const std::optional<Line> &self_intersection_line, const Point &self_intersection_point) {
// No hook is longer than hook_length, there shouldn't be any intersection closer than that.
auto max_length = hook_length;
auto update_max_length = [&max_length](double d) {
if (d < max_length)
max_length = d;
};
// Shift the trimming point away from the colliding thick line.
auto shift_from_thick_line = [&dir, scaled_trim_distance](const Vec2d& dir2) {
return scaled_trim_distance * std::abs(cross2(dir, dir2.normalized()));
};
for (const auto &hook_intersection : hook_intersections) {
const rtree_segment_t &segment = hook_intersection.first;
// Segment start and end points, segment vector.
Vec2d pt2(bg::get<0, 0>(segment), bg::get<0, 1>(segment));
Vec2d dir2 = Vec2d(bg::get<1, 0>(segment), bg::get<1, 1>(segment)) - pt2;
// Find intersection of (pt, dir) with (pt2, dir2), where dir is normalized.
double denom = cross2(dir, dir2);
assert(std::abs(denom) > EPSILON);
double t = cross2(pt2 - pt, dir2) / denom;
if (hook_intersection.second < lines_src.size())
// Trimming by another infill line. Reduce overlap.
t -= shift_from_thick_line(dir2);
update_max_length(t);
}
if (self_intersection) {
double t = (self_intersection_point.cast<double>() - pt).dot(dir) - shift_from_thick_line((*self_intersection_line).vector().cast<double>());
max_length = std::min(max_length, t);
}
return std::max(0., max_length);
};
Vec2d hook_startf = hook_start.cast<double>();
double hook_forward_max_length = max_hook_length(hook_startf, hook_vector_norm, hook_intersections, self_intersection, other_hook, self_intersection_point);
double hook_backward_max_length = 0.;
if (hook_forward_max_length < hook_length - SCALED_EPSILON) {
// Try the other side.
hook_intersections.clear();
Line hook_backward(hook_start, hook_start - hook_vector);
rtree.query(bgi::intersects(mk_rtree_seg(hook_backward)) && bgi::satisfies(filter_itself), std::back_inserter(hook_intersections));
self_intersection = other_hook && other_hook->intersection(hook_backward, &self_intersection_point);
hook_backward_max_length = max_hook_length(hook_startf, - hook_vector_norm, hook_intersections, self_intersection, other_hook, self_intersection_point);
}
// Take the longer hook.
Vec2d hook_dir = (hook_forward_max_length > hook_backward_max_length ? hook_forward_max_length : - hook_backward_max_length) * hook_vector_norm;
Point hook_end = hook_start + hook_dir.cast<coord_t>();
Points &pl = intersection.intersect_pl->points;
if (intersection.front) {
pl.front() = hook_start;
pl.emplace(pl.begin(), hook_end);
} else {
pl.back() = hook_start;
pl.emplace_back(hook_end);
}
}
#ifndef NDEBUG
bool validate_intersection_t_joint(const Intersection &intersection)
{
const Vec2d v = (intersection.closest_line->b - intersection.closest_line->a).cast<double>();
const Vec2d va = (intersection.intersect_point - intersection.closest_line->a).cast<double>();
const double l2 = v.squaredNorm(); // avoid a sqrt
assert(l2 > 0.);
const double t = va.dot(v);
assert(t > SCALED_EPSILON && t < l2 - SCALED_EPSILON);
const double d = ((t / l2) * v - va).norm();
assert(d < 1000.);
return true;
}
bool validate_intersections(const std::vector<Intersection> &intersections)
{
for (const Intersection& intersection : intersections)
assert(validate_intersection_t_joint(intersection));
return true;
}
#endif // NDEBUG
static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &boundary, const double spacing, const coordf_t hook_length, const coordf_t hook_length_max)
{
rtree_t rtree;
size_t poly_idx = 0;
// 19% overlap, slightly lower than the allowed overlap in Fill::connect_infill()
const float scaled_offset = float(scale_(spacing) * 0.81);
// 25% overlap
const float scaled_trim_distance = float(scale_(spacing) * 0.5 * 0.75);
// Keeping the vector of closest points outside the loop, so the vector does not need to be reallocated.
std::vector<std::pair<rtree_segment_t, size_t>> closest;
// Pairs of lines touching at one end point. The pair is sorted to make the end point connection test symmetric.
std::vector<std::pair<const Polyline*, const Polyline*>> lines_touching_at_endpoints;
{
// Insert infill lines into rtree, merge close collinear segments split by the infill boundary,
// collect lines_touching_at_endpoints.
double r2_close = Slic3r::sqr(1200.);
for (Polyline &poly : lines) {
assert(poly.points.size() == 2);
if (&poly != lines.data()) {
// Join collinear segments separated by a tiny gap. These gaps were likely created by clipping the infill lines with a concave dent in an infill boundary.
auto collinear_segment = [&rtree, &closest, &lines, &lines_touching_at_endpoints, r2_close](const Point& pt, const Point& pt_other, const Polyline* polyline) -> std::pair<Polyline*, bool> {
closest.clear();
rtree.query(bgi::nearest(mk_rtree_point(pt), 1), std::back_inserter(closest));
const Polyline *other = &lines[closest.front().second];
double dist2_front = (other->points.front() - pt).cast<double>().squaredNorm();
double dist2_back = (other->points.back() - pt).cast<double>().squaredNorm();
double dist2_min = std::min(dist2_front, dist2_back);
if (dist2_min < r2_close) {
// Don't connect the segments in an opposite direction.
double dist2_min_other = std::min((other->points.front() - pt_other).cast<double>().squaredNorm(), (other->points.back() - pt_other).cast<double>().squaredNorm());
if (dist2_min_other > dist2_min) {
// End points of the two lines are very close, they should have been merged together if they are collinear.
Vec2d v1 = (pt_other - pt).cast<double>();
Vec2d v2 = (other->points.back() - other->points.front()).cast<double>();
Vec2d v1n = v1.normalized();
Vec2d v2n = v2.normalized();
// The vectors must not be collinear.
double d = v1n.dot(v2n);
if (std::abs(d) > 0.99f) {
// Lines are collinear, merge them.
rtree.remove(closest.front());
return std::make_pair(const_cast<Polyline*>(other), dist2_min == dist2_front);
} else {
if (polyline > other)
std::swap(polyline, other);
lines_touching_at_endpoints.emplace_back(polyline, other);
}
}
}
return std::make_pair(static_cast<Polyline*>(nullptr), false);
};
auto collinear_front = collinear_segment(poly.points.front(), poly.points.back(), &poly);
auto collinear_back = collinear_segment(poly.points.back(), poly.points.front(), &poly);
assert(! collinear_front.first || ! collinear_back.first || collinear_front.first != collinear_back.first);
if (collinear_front.first) {
Polyline &other = *collinear_front.first;
assert(&other != &poly);
poly.points.front() = collinear_front.second ? other.points.back() : other.points.front();
other.points.clear();
}
if (collinear_back.first) {
Polyline &other = *collinear_back.first;
assert(&other != &poly);
poly.points.back() = collinear_back.second ? other.points.back() : other.points.front();
other.points.clear();
}
}
rtree.insert(std::make_pair(mk_rtree_seg(poly.points.front(), poly.points.back()), poly_idx++));
}
}
// Convert input polylines to lines_src after the colinear segments were merged.
Lines lines_src;
lines_src.reserve(lines.size());
std::transform(lines.begin(), lines.end(), std::back_inserter(lines_src), [](const Polyline &pl) {
return pl.empty() ? Line(Point(0, 0), Point(0, 0)) : Line(pl.points.front(), pl.points.back()); });
sort_remove_duplicates(lines_touching_at_endpoints);
std::vector<Intersection> intersections;
{
// Minimum lenght of an infill line to anchor. Very short lines cannot be trimmed from both sides,
// it does not help to anchor extremely short infill lines, it consumes too much plastic while not adding
// to the object rigidity.
assert(scaled_offset > scaled_trim_distance);
const double line_len_threshold_drop_both_sides = scaled_offset * (2. / cos(PI / 6.) + 0.5) + SCALED_EPSILON;
const double line_len_threshold_anchor_both_sides = line_len_threshold_drop_both_sides + scaled_offset;
const double line_len_threshold_drop_single_side = scaled_offset * (1. / cos(PI / 6.) + 1.5) + SCALED_EPSILON;
const double line_len_threshold_anchor_single_side = line_len_threshold_drop_single_side + scaled_offset;
for (size_t line_idx = 0; line_idx < lines.size(); ++ line_idx) {
Polyline &line = lines[line_idx];
if (line.points.empty())
continue;
Point &front_point = line.points.front();
Point &back_point = line.points.back();
// Find the nearest line from the start point of the line.
std::optional<size_t> tjoint_front, tjoint_back;
{
auto has_tjoint = [&closest, line_idx, &rtree, &lines, &lines_src](const Point &pt) {
auto filter_t_joint = [line_idx, &lines_src, pt](const auto &item) {
if (item.second != line_idx) {
// Verify that the point projects onto the line.
const Line &line = lines_src[item.second];
const Vec2d v = (line.b - line.a).cast<double>();
const Vec2d va = (pt - line.a).cast<double>();
const double l2 = v.squaredNorm(); // avoid a sqrt
if (l2 > 0.) {
const double t = va.dot(v);
return t > SCALED_EPSILON && t < l2 - SCALED_EPSILON;
}
}
return false;
};
closest.clear();
rtree.query(bgi::nearest(mk_rtree_point(pt), 1) && bgi::satisfies(filter_t_joint), std::back_inserter(closest));
std::optional<size_t> out;
if (! closest.empty()) {
const Polyline &pl = lines[closest.front().second];
if (pl.points.empty()) {
// The closest infill line was already dropped as it was too short.
// Such an infill line should not make a T-joint anyways.
#if 0 // #ifndef NDEBUG
const auto &seg = closest.front().first;
struct Linef { Vec2d a; Vec2d b; };
Linef l { { bg::get<0, 0>(seg), bg::get<0, 1>(seg) }, { bg::get<1, 0>(seg), bg::get<1, 1>(seg) } };
assert(line_alg::distance_to_squared(l, Vec2d(pt.cast<double>())) > 1000 * 1000);
#endif // NDEBUG
} else if (((Line)pl).distance_to_squared(pt) <= 1000 * 1000)
out = closest.front().second;
}
return out;
};
// Refuse to create a T-joint if the infill lines touch at their ends.
auto filter_end_point_connections = [&lines_touching_at_endpoints, &lines, &line](std::optional<size_t> in) {
std::optional<size_t> out;
if (in) {
const Polyline *lo = &line;
const Polyline *hi = &lines[*in];
if (lo > hi)
std::swap(lo, hi);
if (! std::binary_search(lines_touching_at_endpoints.begin(), lines_touching_at_endpoints.end(), std::make_pair(lo, hi)))
// Not an end-point connection, it is a valid T-joint.
out = in;
}
return out;
};
tjoint_front = filter_end_point_connections(has_tjoint(front_point));
tjoint_back = filter_end_point_connections(has_tjoint(back_point));
}
int num_tjoints = int(tjoint_front.has_value()) + int(tjoint_back.has_value());
if (num_tjoints > 0) {
double line_len = line.length();
bool drop = false;
bool anchor = false;
if (num_tjoints == 1) {
// Connected to perimeters on a single side only, connected to another infill line on the other side.
drop = line_len < line_len_threshold_drop_single_side;
anchor = line_len > line_len_threshold_anchor_single_side;
} else {
// Not connected to perimeters at all, connected to two infill lines.
assert(num_tjoints == 2);
drop = line_len < line_len_threshold_drop_both_sides;
anchor = line_len > line_len_threshold_anchor_both_sides;
}
if (drop) {
// Drop a very short line if connected to another infill line.
// Lines shorter than spacing are skipped because it is needed to shrink a line by the value of spacing.
// A shorter line than spacing could produce a degenerate polyline.
line.points.clear();
} else if (anchor) {
if (tjoint_front) {
// T-joint of line's front point with the 'closest' line.
intersections.emplace_back(lines_src[*tjoint_front], lines_src[line_idx], &line, front_point, true);
assert(validate_intersection_t_joint(intersections.back()));
}
if (tjoint_back) {
// T-joint of line's back point with the 'closest' line.
intersections.emplace_back(lines_src[*tjoint_back], lines_src[line_idx], &line, back_point, false);
assert(validate_intersection_t_joint(intersections.back()));
}
} else {
if (tjoint_front)
// T joint at the front at a 60 degree angle, the line is very short.
// Trim the front side.
front_point += ((scaled_trim_distance * 1.155) * (back_point - front_point).cast<double>().normalized()).cast<coord_t>();
if (tjoint_back)
// T joint at the front at a 60 degree angle, the line is very short.
// Trim the front side.
back_point += ((scaled_trim_distance * 1.155) * (front_point - back_point).cast<double>().normalized()).cast<coord_t>();
}
}
}
// Remove those intersections, that point to a dropped line.
for (auto it = intersections.begin(); it != intersections.end(); ) {
assert(! lines[it->intersect_line - lines_src.data()].points.empty());
if (lines[it->closest_line - lines_src.data()].points.empty()) {
*it = intersections.back();
intersections.pop_back();
} else
++ it;
}
}
assert(validate_intersections(intersections));
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
static int iRun = 0;
int iStep = 0;
{
Points pts;
for (const Intersection &i : intersections)
pts.emplace_back(i.intersect_point);
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-Tjoints-%d.svg", iRun++), pts);
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
// Sort lexicographically by closest_line_idx and left/right orientation.
std::sort(intersections.begin(), intersections.end(),
[](const Intersection &i1, const Intersection &i2) {
return (i1.closest_line == i2.closest_line) ?
int(i1.left) < int(i2.left) :
i1.closest_line < i2.closest_line;
});
std::vector<size_t> merged_with(lines.size());
std::iota(merged_with.begin(), merged_with.end(), 0);
// Appends the boundary polygon with all holes to rtree for detection to check whether hooks are not crossing the boundary
{
Point prev = boundary.contour.points.back();
for (const Point &point : boundary.contour.points) {
rtree.insert(std::make_pair(mk_rtree_seg(prev, point), poly_idx++));
prev = point;
}
for (const Polygon &polygon : boundary.holes) {
Point prev = polygon.points.back();
for (const Point &point : polygon.points) {
rtree.insert(std::make_pair(mk_rtree_seg(prev, point), poly_idx++));
prev = point;
}
}
}
auto update_merged_polyline_idx = [&merged_with](size_t pl_idx) {
// Update the polyline index to index which is merged
for (size_t last = pl_idx;;) {
size_t lower = merged_with[last];
if (lower == last) {
merged_with[pl_idx] = lower;
return lower;
}
last = lower;
}
assert(false);
return size_t(0);
};
auto update_merged_polyline = [&lines, update_merged_polyline_idx](Intersection& intersection) {
// Update the polyline index to index which is merged
size_t intersect_pl_idx = update_merged_polyline_idx(intersection.intersect_pl - lines.data());
intersection.intersect_pl = &lines[intersect_pl_idx];
// After polylines are merged, it is necessary to update "forward" based on if intersect_point is the first or the last point of intersect_pl.
if (intersection.fresh()) {
assert(intersection.intersect_pl->points.front() == intersection.intersect_point ||
intersection.intersect_pl->points.back() == intersection.intersect_point);
intersection.front = intersection.intersect_pl->points.front() == intersection.intersect_point;
}
};
// Merge polylines touching at their ends. This should be a very rare case, but it happens surprisingly often.
for (auto it = lines_touching_at_endpoints.rbegin(); it != lines_touching_at_endpoints.rend(); ++ it) {
Polyline *pl1 = const_cast<Polyline*>(it->first);
Polyline *pl2 = const_cast<Polyline*>(it->second);
assert(pl1 < pl2);
// pl1 was visited for the 1st time.
// pl2 may have alread been merged with another polyline, even with this one.
pl2 = &lines[update_merged_polyline_idx(pl2 - lines.data())];
assert(pl1 <= pl2);
// Avoid closing a loop, ignore dropped infill lines.
if (pl1 != pl2 && ! pl1->points.empty() && ! pl2->points.empty()) {
// Merge the polylines.
assert(pl1 < pl2);
assert(pl1->points.size() >= 2);
assert(pl2->points.size() >= 2);
double d11 = (pl1->points.front() - pl2->points.front()).cast<double>().squaredNorm();
double d12 = (pl1->points.front() - pl2->points.back()) .cast<double>().squaredNorm();
double d21 = (pl1->points.back() - pl2->points.front()).cast<double>().squaredNorm();
double d22 = (pl1->points.back() - pl2->points.back()) .cast<double>().squaredNorm();
double d1min = std::min(d11, d12);
double d2min = std::min(d21, d22);
if (d1min < d2min) {
pl1->reverse();
if (d12 == d1min)
pl2->reverse();
} else if (d22 == d2min)
pl2->reverse();
pl1->points.back() = (pl1->points.back() + pl2->points.front()) / 2;
pl1->append(pl2->points.begin() + 1, pl2->points.end());
pl2->points.clear();
merged_with[pl2 - lines.data()] = pl1 - lines.data();
}
}
// Keep intersect_line outside the loop, so it does not get reallocated.
std::vector<std::pair<Intersection*, double>> intersect_line;
for (size_t min_idx = 0; min_idx < intersections.size();) {
intersect_line.clear();
// All the nearest points (T-joints) ending at the same line are projected onto this line. Because of it, it can easily find the nearest point.
{
const Vec2d line_dir = intersections[min_idx].closest_line->vector().cast<double>();
size_t max_idx = min_idx;
for (; max_idx < intersections.size() &&
intersections[min_idx].closest_line == intersections[max_idx].closest_line &&
intersections[min_idx].left == intersections[max_idx].left;
++ max_idx)
intersect_line.emplace_back(&intersections[max_idx], line_dir.dot(intersections[max_idx].intersect_point.cast<double>()));
min_idx = max_idx;
assert(intersect_line.size() > 0);
// Sort the intersections along line_dir.
std::sort(intersect_line.begin(), intersect_line.end(), [](const auto &i1, const auto &i2) { return i1.second < i2.second; });
}
if (intersect_line.size() == 1) {
// Simple case: The current intersection is the only one touching its adjacent line.
Intersection &first_i = *intersect_line.front().first;
update_merged_polyline(first_i);
if (first_i.fresh()) {
// Try to connect left or right. If not enough space for hook_length, take the longer side.
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-add_hook0-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
add_hook(first_i, scaled_offset, hook_length, scaled_trim_distance, rtree, lines_src);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-add_hook0-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
++ iStep;
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
first_i.used = true;
}
continue;
}
for (size_t first_idx = 0; first_idx < intersect_line.size(); ++ first_idx) {
Intersection &first_i = *intersect_line[first_idx].first;
update_merged_polyline(first_i);
if (! first_i.fresh())
// The intersection has been processed, or the polyline has been merged to another polyline.
continue;
// Get the previous or next intersection on the same line, pick the closer one.
if (first_idx > 0)
update_merged_polyline(*intersect_line[first_idx - 1].first);
if (first_idx + 1 < intersect_line.size())
update_merged_polyline(*intersect_line[first_idx + 1].first);
Intersection &nearest_i = *get_nearest_intersection(intersect_line, first_idx);
assert(first_i.closest_line == nearest_i.closest_line);
assert(first_i.intersect_line != nearest_i.intersect_line);
assert(first_i.intersect_line != first_i.closest_line);
assert(nearest_i.intersect_line != first_i.closest_line);
// A line between two intersections points
Line offset_line = create_offset_line(Line(first_i.intersect_point, nearest_i.intersect_point), first_i, scaled_offset);
// Check if both intersections lie on the offset_line and simultaneously get their points of intersecting.
// These points are used as start and end of the hook
Point first_i_point, nearest_i_point;
bool could_connect = false;
if (nearest_i.fresh()) {
could_connect = first_i.intersect_line->intersection(offset_line, &first_i_point) &&
nearest_i.intersect_line->intersection(offset_line, &nearest_i_point);
assert(could_connect);
}
Points &first_points = first_i.intersect_pl->points;
Points &second_points = nearest_i.intersect_pl->points;
could_connect &= (nearest_i_point - first_i_point).cast<double>().squaredNorm() <= Slic3r::sqr(hook_length_max);
if (could_connect) {
// Both intersections are so close that their polylines can be connected.
// Verify that no other infill line intersects this anchor line.
closest.clear();
rtree.query(
bgi::intersects(mk_rtree_seg(first_i_point, nearest_i_point)) &&
bgi::satisfies([&first_i, &nearest_i, &lines_src](const auto &item)
{ return item.second != first_i.intersect_line - lines_src.data() && item.second != nearest_i.intersect_line - lines_src.data(); }),
std::back_inserter(closest));
could_connect = closest.empty();
#if 0
// Avoid self intersections. Maybe it is better to trim the self intersection after the connection?
if (could_connect && first_i.intersect_pl != nearest_i.intersect_pl) {
Line l(first_i_point, nearest_i_point);
could_connect = ! first_i.other_hook_intersects(l) && ! nearest_i.other_hook_intersects(l);
}
#endif
}
bool connected = false;
if (could_connect) {
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-connecting-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point, nearest_i.intersect_point });
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
// No other infill line intersects this anchor line. Extrude it as a whole.
if (first_i.intersect_pl == nearest_i.intersect_pl) {
// Both intersections are on the same polyline, that means a loop is being closed.
assert(first_i.front != nearest_i.front);
if (! first_i.front)
std::swap(first_i_point, nearest_i_point);
first_points.front() = first_i_point;
first_points.back() = nearest_i_point;
//FIXME trim the end of a closed loop a bit?
first_points.emplace(first_points.begin(), nearest_i_point);
} else {
// Both intersections are on different polylines
Line l(first_i_point, nearest_i_point);
l.translate((perp(first_i.closest_line->vector().cast<double>().normalized()) * (first_i.left ? scaled_trim_distance : - scaled_trim_distance)).cast<coord_t>());
Point pt_start, pt_end;
bool trim_start = first_i .intersect_pl->points.size() == 3 && first_i .other_hook_intersects(l, pt_start);
bool trim_end = nearest_i.intersect_pl->points.size() == 3 && nearest_i.other_hook_intersects(l, pt_end);
first_points.reserve(first_points.size() + second_points.size());
if (first_i.front)
std::reverse(first_points.begin(), first_points.end());
if (trim_start)
first_points.front() = pt_start;
first_points.back() = first_i_point;
first_points.emplace_back(nearest_i_point);
if (nearest_i.front)
first_points.insert(first_points.end(), second_points.begin() + 1, second_points.end());
else
first_points.insert(first_points.end(), second_points.rbegin() + 1, second_points.rend());
if (trim_end)
first_points.back() = pt_end;
// Keep the polyline at the lower index slot.
if (first_i.intersect_pl < nearest_i.intersect_pl) {
second_points.clear();
merged_with[nearest_i.intersect_pl - lines.data()] = first_i.intersect_pl - lines.data();
} else {
second_points = std::move(first_points);
first_points.clear();
merged_with[first_i.intersect_pl - lines.data()] = nearest_i.intersect_pl - lines.data();
}
}
nearest_i.used = true;
connected = true;
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-connecting-post-%d-%d.svg", iRun, iStep), { first_i.intersect_point, nearest_i.intersect_point });
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
}
if (! connected) {
// Try to connect left or right. If not enough space for hook_length, take the longer side.
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-add_hook-pre-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
add_hook(first_i, scaled_offset, hook_length, scaled_trim_distance, rtree, lines_src);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
export_infill_lines_to_svg(boundary, lines, debug_out_path("FillAdaptive-add_hook-post-%d-%d.svg", iRun, iStep), { first_i.intersect_point });
#endif // ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
}
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
++ iStep;
#endif ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
first_i.used = true;
}
}
Polylines polylines_out;
polylines_out.reserve(polylines_out.size() + std::count_if(lines.begin(), lines.end(), [](const Polyline &pl) { return !pl.empty(); }));
for (Polyline &pl : lines)
if (!pl.empty()) polylines_out.emplace_back(std::move(pl));
return polylines_out;
}
#ifndef NDEBUG
bool has_no_collinear_lines(const Polylines &polylines)
{
// Create line end point lookup.
struct LineEnd {
LineEnd(const Polyline *line, bool start) : line(line), start(start) {}
const Polyline *line;
// Is it the start or end point?
bool start;
const Point& point() const { return start ? line->points.front() : line->points.back(); }
const Point& other_point() const { return start ? line->points.back() : line->points.front(); }
LineEnd other_end() const { return LineEnd(line, !start); }
Vec2d vec() const { return Vec2d((this->other_point() - this->point()).cast<double>()); }
bool operator==(const LineEnd &rhs) const { return this->line == rhs.line && this->start == rhs.start; }
};
struct LineEndAccessor {
const Point* operator()(const LineEnd &pt) const { return &pt.point(); }
};
typedef ClosestPointInRadiusLookup<LineEnd, LineEndAccessor> ClosestPointLookupType;
ClosestPointLookupType closest_end_point_lookup(coord_t(1001. * sqrt(2.)));
for (const Polyline& pl : polylines) {
// assert(pl.points.size() == 2);
auto line_start = LineEnd(&pl, true);
auto line_end = LineEnd(&pl, false);
auto assert_not_collinear = [&closest_end_point_lookup](const LineEnd &line_start) {
std::vector<std::pair<const LineEnd*, double>> hits = closest_end_point_lookup.find_all(line_start.point());
for (const std::pair<const LineEnd*, double> &hit : hits)
if ((line_start.point() - hit.first->point()).cwiseAbs().maxCoeff() <= 1000) {
// End points of the two lines are very close, they should have been merged together if they are collinear.
Vec2d v1 = line_start.vec();
Vec2d v2 = hit.first->vec();
Vec2d v1n = v1.normalized();
Vec2d v2n = v2.normalized();
// The vectors must not be collinear.
assert(std::abs(v1n.dot(v2n)) < cos(M_PI / 12.));
}
};
assert_not_collinear(line_start);
assert_not_collinear(line_end);
closest_end_point_lookup.insert(line_start);
closest_end_point_lookup.insert(line_end);
}
return true;
}
#endif
void Filler::_fill_surface_single( void Filler::_fill_surface_single(
const FillParams & params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
assert (this->adapt_fill_octree); assert (this->adapt_fill_octree);
@ -569,6 +1335,23 @@ void Filler::_fill_surface_single(
generate_infill_lines_recursive(context, adapt_fill_octree->root_cube, 0, int(adapt_fill_octree->cubes_properties.size()) - 1); generate_infill_lines_recursive(context, adapt_fill_octree->root_cube, 0, int(adapt_fill_octree->cubes_properties.size()) - 1);
num_lines += context.output_lines.size() + context.temp_lines.size(); num_lines += context.output_lines.size() + context.temp_lines.size();
} }
#if 0
// Collect the lines, trim them by the expolygon.
all_polylines.reserve(num_lines);
auto boundary = to_polygons(expolygon);
for (auto &context : contexts) {
Polylines lines;
lines.reserve(context.output_lines.size() + context.temp_lines.size());
std::transform(context.output_lines.begin(), context.output_lines.end(), std::back_inserter(lines), [](const Line& l) { return Polyline{ l.a, l.b }; });
for (const Line &l : context.temp_lines)
if (l.a.x() != std::numeric_limits<coord_t>::max())
lines.push_back({ l.a, l.b });
// Crop all polylines
append(all_polylines, intersection_pl(std::move(lines), boundary));
}
// assert(has_no_collinear_lines(all_polylines));
#else
// Collect the lines. // Collect the lines.
std::vector<Line> lines; std::vector<Line> lines;
lines.reserve(num_lines); lines.reserve(num_lines);
@ -578,18 +1361,21 @@ void Filler::_fill_surface_single(
if (line.a.x() != std::numeric_limits<coord_t>::max()) if (line.a.x() != std::numeric_limits<coord_t>::max())
lines.emplace_back(line); lines.emplace_back(line);
} }
#if 0
// Chain touching line segments, convert lines to polylines.
//all_polylines = chain_lines(lines, 300.); // SCALED_EPSILON is 100 and it is not enough
#else
// Convert lines to polylines. // Convert lines to polylines.
all_polylines.reserve(lines.size()); all_polylines.reserve(lines.size());
std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; }); std::transform(lines.begin(), lines.end(), std::back_inserter(all_polylines), [](const Line& l) { return Polyline{ l.a, l.b }; });
// Crop all polylines
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
#endif #endif
} }
// Crop all polylines // After intersection_pl some polylines with only one line are split into more lines
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon)); for (Polyline &polyline : all_polylines) {
//FIXME assert that all the points are collinear and in between the start and end point.
if (polyline.points.size() > 2)
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
}
// assert(has_no_collinear_lines(all_polylines));
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{ {
@ -598,10 +1384,22 @@ void Filler::_fill_surface_single(
} }
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */ #endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
if (params.dont_connect || all_polylines.size() <= 1) const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
append(polylines_out, std::move(all_polylines)); const auto hook_length_max = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length_max)));
Polylines all_polylines_with_hooks = all_polylines.size() > 1 ? connect_lines_using_hooks(std::move(all_polylines), expolygon, this->spacing, hook_length, hook_length_max) : std::move(all_polylines);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{
static int iRun = 0;
export_infill_lines_to_svg(expolygon, all_polylines_with_hooks, debug_out_path("FillAdaptive-hooks-%d.svg", iRun++));
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
if (params.dont_connect() || all_polylines_with_hooks.size() <= 1)
append(polylines_out, chain_polylines(std::move(all_polylines_with_hooks)));
else else
connect_infill(chain_polylines(std::move(all_polylines)), expolygon, polylines_out, this->spacing, params); connect_infill(std::move(all_polylines_with_hooks), expolygon, polylines_out, this->spacing, params);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{ {

View file

@ -56,17 +56,17 @@ FillAdaptive::OctreePtr build_octree(
class Filler : public Slic3r::Fill class Filler : public Slic3r::Fill
{ {
public: public:
virtual ~Filler() {} ~Filler() override {}
protected: protected:
virtual Fill* clone() const { return new Filler(*this); }; Fill* clone() const override { return new Filler(*this); };
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
virtual bool no_sort() const { return true; } bool no_sort() const override { return true; }
}; };
}; // namespace FillAdaptive }; // namespace FillAdaptive

File diff suppressed because it is too large Load diff

View file

@ -33,12 +33,16 @@ public:
struct FillParams struct FillParams
{ {
bool full_infill() const { return density > 0.9999f; } bool full_infill() const { return density > 0.9999f; }
// Don't connect the fill lines around the inner perimeter.
bool dont_connect() const { return anchor_length_max < 0.05f; }
// Fill density, fraction in <0, 1> // Fill density, fraction in <0, 1>
float density { 0.f }; float density { 0.f };
// Don't connect the fill lines around the inner perimeter. // Length of an infill anchor along the perimeter.
bool dont_connect { false }; // 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length { 1000.f };
float anchor_length_max { 1000.f };
// Don't adjust spacing to fill the space evenly. // Don't adjust spacing to fill the space evenly.
bool dont_adjust { true }; bool dont_adjust { true };
@ -80,6 +84,7 @@ public:
public: public:
virtual ~Fill() {} virtual ~Fill() {}
virtual Fill* clone() const = 0;
static Fill* new_from_type(const InfillPattern type); static Fill* new_from_type(const InfillPattern type);
static Fill* new_from_type(const std::string &type); static Fill* new_from_type(const std::string &type);
@ -116,7 +121,7 @@ protected:
const FillParams & /* params */, const FillParams & /* params */,
unsigned int /* thickness_layers */, unsigned int /* thickness_layers */,
const std::pair<float, Point> & /* direction */, const std::pair<float, Point> & /* direction */,
ExPolygon & /* expolygon */, ExPolygon /* expolygon */,
Polylines & /* polylines_out */) {}; Polylines & /* polylines_out */) {};
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; } virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
@ -124,7 +129,9 @@ protected:
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const; virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
public: public:
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, double spacing, const FillParams &params); static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params);
static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams &params);
static void connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams &params);
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance); static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance);

View file

@ -10,7 +10,7 @@ void FillConcentric::_fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
// no rotation is supported for this infill pattern // no rotation is supported for this infill pattern
@ -39,7 +39,7 @@ void FillConcentric::_fill_surface_single(
size_t iPathFirst = polylines_out.size(); size_t iPathFirst = polylines_out.size();
Point last_pos(0, 0); Point last_pos(0, 0);
for (const Polygon &loop : loops) { for (const Polygon &loop : loops) {
polylines_out.push_back(loop.split_at_index(last_pos.nearest_point_index(loop))); polylines_out.push_back(loop.split_at_index(last_pos.nearest_point_index(loop.points)));
last_pos = polylines_out.back().last_point(); last_pos = polylines_out.back().last_point();
} }

View file

@ -8,18 +8,18 @@ namespace Slic3r {
class FillConcentric : public Fill class FillConcentric : public Fill
{ {
public: public:
virtual ~FillConcentric() {} ~FillConcentric() override {}
protected: protected:
virtual Fill* clone() const { return new FillConcentric(*this); }; Fill* clone() const override { return new FillConcentric(*this); };
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
virtual bool no_sort() const { return true; } bool no_sort() const override { return true; }
}; };
} // namespace Slic3r } // namespace Slic3r

View file

@ -37,12 +37,12 @@ static inline Polyline make_wave(
double period = points.back()(0); double period = points.back()(0);
if (width != period) // do not extend if already truncated if (width != period) // do not extend if already truncated
{ {
points.reserve(one_period.size() * floor(width / period)); points.reserve(one_period.size() * size_t(floor(width / period)));
points.pop_back(); points.pop_back();
int n = points.size(); size_t n = points.size();
do { do {
points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1))); points.emplace_back(points[points.size()-n].x() + period, points[points.size()-n].y());
} while (points.back()(0) < width - EPSILON); } while (points.back()(0) < width - EPSILON);
points.emplace_back(Vec2d(width, f(width, z_sin, z_cos, vertical, flip))); points.emplace_back(Vec2d(width, f(width, z_sin, z_cos, vertical, flip)));
@ -67,7 +67,7 @@ static std::vector<Vec2d> make_one_period(double width, double scaleFactor, doub
std::vector<Vec2d> points; std::vector<Vec2d> points;
double dx = M_PI_2; // exact coordinates on main inflexion lobes double dx = M_PI_2; // exact coordinates on main inflexion lobes
double limit = std::min(2*M_PI, width); double limit = std::min(2*M_PI, width);
points.reserve(ceil(limit / tolerance / 3)); points.reserve(coord_t(ceil(limit / tolerance / 3)));
for (double x = 0.; x < limit - EPSILON; x += dx) { for (double x = 0.; x < limit - EPSILON; x += dx) {
points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
@ -152,10 +152,10 @@ void FillGyroid::_fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
float infill_angle = this->angle + (CorrectionAngle * 2*M_PI) / 360.; auto infill_angle = float(this->angle + (CorrectionAngle * 2*M_PI) / 360.);
if(std::abs(infill_angle) >= EPSILON) if(std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle); expolygon.rotate(-infill_angle);
@ -182,19 +182,20 @@ void FillGyroid::_fill_surface_single(
polylines = intersection_pl(polylines, to_polygons(expolygon)); polylines = intersection_pl(polylines, to_polygons(expolygon));
if (! polylines.empty()) if (! polylines.empty()) {
// remove too small bits (larger than longer) // Remove very small bits, but be careful to not remove infill lines connecting thin walls!
// The infill perimeter lines should be separated by around a single infill line width.
const double minlength = scale_(0.8 * this->spacing);
polylines.erase( polylines.erase(
//FIXME what is the small size? Removing tiny extrusions disconnects walls! std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) { return pl.length() < minlength; }),
std::remove_if(polylines.begin(), polylines.end(), [this](const Polyline &pl) { return pl.length() < scale_(this->spacing * 3); }),
polylines.end()); polylines.end());
}
if (! polylines.empty()) { if (! polylines.empty()) {
polylines = chain_polylines(polylines);
// connect lines // connect lines
size_t polylines_out_first_idx = polylines_out.size(); size_t polylines_out_first_idx = polylines_out.size();
if (params.dont_connect) if (params.dont_connect())
append(polylines_out, std::move(polylines)); append(polylines_out, chain_polylines(polylines));
else else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params); this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);

View file

@ -11,10 +11,10 @@ class FillGyroid : public Fill
{ {
public: public:
FillGyroid() {} FillGyroid() {}
virtual Fill* clone() const { return new FillGyroid(*this); } Fill* clone() const override { return new FillGyroid(*this); }
// require bridge flow since most of this pattern hangs in air // require bridge flow since most of this pattern hangs in air
virtual bool use_bridge_flow() const { return false; } bool use_bridge_flow() const override { return false; }
// Correction applied to regular infill angle to maximize printing // Correction applied to regular infill angle to maximize printing
// speed in default configuration (degrees) // speed in default configuration (degrees)
@ -28,12 +28,12 @@ public:
protected: protected:
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
}; };
} // namespace Slic3r } // namespace Slic3r

View file

@ -10,7 +10,7 @@ void FillHoneycomb::_fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
// cache hexagons math // cache hexagons math
@ -18,21 +18,21 @@ void FillHoneycomb::_fill_surface_single(
Cache::iterator it_m = this->cache.find(cache_id); Cache::iterator it_m = this->cache.find(cache_id);
if (it_m == this->cache.end()) { if (it_m == this->cache.end()) {
it_m = this->cache.insert(it_m, std::pair<CacheID, CacheData>(cache_id, CacheData())); it_m = this->cache.insert(it_m, std::pair<CacheID, CacheData>(cache_id, CacheData()));
CacheData &m = it_m->second; CacheData &m = it_m->second;
coord_t min_spacing = scale_(this->spacing); coord_t min_spacing = coord_t(scale_(this->spacing));
m.distance = min_spacing / params.density; m.distance = coord_t(min_spacing / params.density);
m.hex_side = m.distance / (sqrt(3)/2); m.hex_side = coord_t(m.distance / (sqrt(3)/2));
m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3); m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3);
coord_t hex_height = m.hex_side * 2; coord_t hex_height = m.hex_side * 2;
m.pattern_height = hex_height + m.hex_side; m.pattern_height = hex_height + m.hex_side;
m.y_short = m.distance * sqrt(3)/3; m.y_short = coord_t(m.distance * sqrt(3)/3);
m.x_offset = min_spacing / 2; m.x_offset = min_spacing / 2;
m.y_offset = m.x_offset * sqrt(3)/3; m.y_offset = coord_t(m.x_offset * sqrt(3)/3);
m.hex_center = Point(m.hex_width/2, m.hex_side); m.hex_center = Point(m.hex_width/2, m.hex_side);
} }
CacheData &m = it_m->second; CacheData &m = it_m->second;
Polygons polygons; Polylines all_polylines;
{ {
// adjust actual bounding box to the nearest multiple of our hex pattern // adjust actual bounding box to the nearest multiple of our hex pattern
// and align it so that it matches across layers // and align it so that it matches across layers
@ -52,7 +52,7 @@ void FillHoneycomb::_fill_surface_single(
coord_t x = bounding_box.min(0); coord_t x = bounding_box.min(0);
while (x <= bounding_box.max(0)) { while (x <= bounding_box.max(0)) {
Polygon p; Polyline p;
coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset }; coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset };
for (size_t i = 0; i < 2; ++ i) { for (size_t i = 0; i < 2; ++ i) {
std::reverse(p.points.begin(), p.points.end()); // turn first half upside down std::reverse(p.points.begin(), p.points.end()); // turn first half upside down
@ -69,55 +69,15 @@ void FillHoneycomb::_fill_surface_single(
x += m.distance; x += m.distance;
} }
p.rotate(-direction.first, m.hex_center); p.rotate(-direction.first, m.hex_center);
polygons.push_back(p); all_polylines.push_back(p);
} }
} }
if (params.complete || true) { all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
// we were requested to complete each loop; if (params.dont_connect() || all_polylines.size() <= 1)
// in this case we don't try to make more continuous paths append(polylines_out, chain_polylines(std::move(all_polylines)));
Polygons polygons_trimmed = intersection((Polygons)expolygon, polygons); else
for (Polygons::iterator it = polygons_trimmed.begin(); it != polygons_trimmed.end(); ++ it) connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);
polylines_out.push_back(it->split_at_first_point());
} else {
// consider polygons as polylines without re-appending the initial point:
// this cuts the last segment on purpose, so that the jump to the next
// path is more straight
Polylines paths;
{
Polylines p;
for (Polygon &poly : polygons)
p.emplace_back(poly.points);
paths = intersection_pl(p, to_polygons(expolygon));
}
// connect paths
if (! paths.empty()) { // prevent calling leftmost_point() on empty collections
Polylines chained = chain_polylines(std::move(paths));
assert(paths.empty());
paths.clear();
for (Polyline &path : chained) {
if (! paths.empty()) {
// distance between first point of this path and last point of last path
double distance = (path.first_point() - paths.back().last_point()).cast<double>().norm();
if (distance <= m.hex_width) {
paths.back().points.insert(paths.back().points.end(), path.points.begin(), path.points.end());
continue;
}
}
// Don't connect the paths.
paths.push_back(std::move(path));
}
}
// clip paths again to prevent connection segments from crossing the expolygon boundaries
paths = intersection_pl(paths, to_polygons(offset_ex(expolygon, SCALED_EPSILON)));
// Move the polylines to the output, avoid a deep copy.
size_t j = polylines_out.size();
polylines_out.resize(j + paths.size(), Polyline());
for (size_t i = 0; i < paths.size(); ++ i)
std::swap(polylines_out[j ++], paths[i]);
}
} }
} // namespace Slic3r } // namespace Slic3r

View file

@ -12,16 +12,16 @@ namespace Slic3r {
class FillHoneycomb : public Fill class FillHoneycomb : public Fill
{ {
public: public:
virtual ~FillHoneycomb() {} ~FillHoneycomb() override {}
protected: protected:
virtual Fill* clone() const { return new FillHoneycomb(*this); }; Fill* clone() const override { return new FillHoneycomb(*this); };
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
// Caching the // Caching the
struct CacheID struct CacheID
@ -49,7 +49,7 @@ protected:
typedef std::map<CacheID, CacheData> Cache; typedef std::map<CacheID, CacheData> Cache;
Cache cache; Cache cache;
virtual float _layer_angle(size_t idx) const { return float(M_PI/3.) * (idx % 3); } float _layer_angle(size_t idx) const override { return float(M_PI/3.) * (idx % 3); }
}; };
} // namespace Slic3r } // namespace Slic3r

View file

@ -0,0 +1,122 @@
#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../ShortestPath.hpp"
#include "../Surface.hpp"
#include "FillLine.hpp"
namespace Slic3r {
void FillLine::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out)
{
// rotate polygons so that we can work with vertical lines here
expolygon.rotate(- direction.first);
this->_min_spacing = scale_(this->spacing);
assert(params.density > 0.0001f && params.density <= 1.f);
this->_line_spacing = coord_t(coordf_t(this->_min_spacing) / params.density);
this->_diagonal_distance = this->_line_spacing * 2;
this->_line_oscillation = this->_line_spacing - this->_min_spacing; // only for Line infill
BoundingBox bounding_box = expolygon.contour.bounding_box();
// define flow spacing according to requested density
if (params.density > 0.9999f && !params.dont_adjust) {
this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing);
this->spacing = unscale<double>(this->_line_spacing);
} else {
// extend bounding box so that our pattern will be aligned with other layers
// Transform the reference point to the rotated coordinate system.
bounding_box.merge(_align_to_grid(
bounding_box.min,
Point(this->_line_spacing, this->_line_spacing),
direction.second.rotated(- direction.first)));
}
// generate the basic pattern
coord_t x_max = bounding_box.max(0) + SCALED_EPSILON;
Lines lines;
for (coord_t x = bounding_box.min(0); x <= x_max; x += this->_line_spacing)
lines.push_back(this->_line(lines.size(), x, bounding_box.min(1), bounding_box.max(1)));
// clip paths against a slightly larger expolygon, so that the first and last paths
// are kept even if the expolygon has vertical sides
// the minimum offset for preventing edge lines from being clipped is SCALED_EPSILON;
// however we use a larger offset to support expolygons with slightly skewed sides and
// not perfectly straight
//FIXME Vojtech: Update the intersecton function to work directly with lines.
Polylines polylines_src;
polylines_src.reserve(lines.size());
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++ it) {
polylines_src.push_back(Polyline());
Points &pts = polylines_src.back().points;
pts.reserve(2);
pts.push_back(it->a);
pts.push_back(it->b);
}
Polylines polylines = intersection_pl(polylines_src, offset(to_polygons(expolygon), scale_(0.02)), false);
// FIXME Vojtech: This is only performed for horizontal lines, not for the vertical lines!
const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
// How much to extend an infill path from expolygon outside?
coord_t extra = coord_t(floor(this->_min_spacing * INFILL_OVERLAP_OVER_SPACING + 0.5f));
for (Polylines::iterator it_polyline = polylines.begin(); it_polyline != polylines.end(); ++ it_polyline) {
Point *first_point = &it_polyline->points.front();
Point *last_point = &it_polyline->points.back();
if (first_point->y() > last_point->y())
std::swap(first_point, last_point);
first_point->y() -= extra;
last_point->y() += extra;
}
size_t n_polylines_out_old = polylines_out.size();
// connect lines
if (! params.dont_connect() && ! polylines.empty()) { // prevent calling leftmost_point() on empty collections
// offset the expolygon by max(min_spacing/2, extra)
ExPolygon expolygon_off;
{
ExPolygons expolygons_off = offset_ex(expolygon, this->_min_spacing/2);
if (! expolygons_off.empty()) {
// When expanding a polygon, the number of islands could only shrink. Therefore the offset_ex shall generate exactly one expanded island for one input island.
assert(expolygons_off.size() == 1);
std::swap(expolygon_off, expolygons_off.front());
}
}
bool first = true;
for (Polyline &polyline : chain_polylines(std::move(polylines))) {
if (! first) {
// Try to connect the lines.
Points &pts_end = polylines_out.back().points;
const Point &first_point = polyline.points.front();
const Point &last_point = pts_end.back();
// Distance in X, Y.
const Vector distance = last_point - first_point;
// TODO: we should also check that both points are on a fill_boundary to avoid
// connecting paths on the boundaries of internal regions
if (this->_can_connect(std::abs(distance(0)), std::abs(distance(1))) &&
expolygon_off.contains(Line(last_point, first_point))) {
// Append the polyline.
pts_end.insert(pts_end.end(), polyline.points.begin(), polyline.points.end());
continue;
}
}
// The lines cannot be connected.
polylines_out.emplace_back(std::move(polyline));
first = false;
}
}
// paths must be rotated back
for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_old; it != polylines_out.end(); ++ it) {
// No need to translate, the absolute position is irrelevant.
// it->translate(- direction.second(0), - direction.second(1));
it->rotate(direction.first);
}
}
} // namespace Slic3r

View file

@ -0,0 +1,49 @@
#ifndef slic3r_FillLine_hpp_
#define slic3r_FillLine_hpp_
#include "../libslic3r.h"
#include "FillBase.hpp"
namespace Slic3r {
class Surface;
class FillLine : public Fill
{
public:
Fill* clone() const override { return new FillLine(*this); };
~FillLine() override = default;
protected:
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out) override;
coord_t _min_spacing;
coord_t _line_spacing;
// distance threshold for allowing the horizontal infill lines to be connected into a continuous path
coord_t _diagonal_distance;
// only for line infill
coord_t _line_oscillation;
Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const {
coord_t osc = (i & 1) ? this->_line_oscillation : 0;
return Line(Point(x - osc, y_min), Point(x + osc, y_max));
}
bool _can_connect(coord_t dist_X, coord_t dist_Y)
{
coord_t TOLERANCE = 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);
}
};
}; // namespace Slic3r
#endif // slic3r_FillLine_hpp_

View file

@ -1,4 +1,5 @@
#include "../ClipperUtils.hpp" #include "../ClipperUtils.hpp"
#include "../ShortestPath.hpp"
#include "../Surface.hpp" #include "../Surface.hpp"
#include "FillPlanePath.hpp" #include "FillPlanePath.hpp"
@ -9,7 +10,7 @@ void FillPlanePath::_fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out) Polylines &polylines_out)
{ {
expolygon.rotate(- direction.first); expolygon.rotate(- direction.first);
@ -23,14 +24,14 @@ void FillPlanePath::_fill_surface_single(
Point shift = this->_centered() ? Point shift = this->_centered() ?
bounding_box.center() : bounding_box.center() :
bounding_box.min; bounding_box.min;
expolygon.translate(-shift(0), -shift(1)); expolygon.translate(-shift.x(), -shift.y());
bounding_box.translate(-shift(0), -shift(1)); bounding_box.translate(-shift.x(), -shift.y());
Pointfs pts = _generate( Pointfs pts = _generate(
coord_t(ceil(coordf_t(bounding_box.min(0)) / distance_between_lines)), coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.min(1)) / distance_between_lines)), coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.max(0)) / distance_between_lines)), coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)),
coord_t(ceil(coordf_t(bounding_box.max(1)) / distance_between_lines))); coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)));
Polylines polylines; Polylines polylines;
if (pts.size() >= 2) { if (pts.size() >= 2) {
@ -38,39 +39,24 @@ void FillPlanePath::_fill_surface_single(
polylines.push_back(Polyline()); polylines.push_back(Polyline());
Polyline &polyline = polylines.back(); Polyline &polyline = polylines.back();
polyline.points.reserve(pts.size()); polyline.points.reserve(pts.size());
for (Pointfs::iterator it = pts.begin(); it != pts.end(); ++ it) for (const Vec2d &pt : pts)
polyline.points.push_back(Point( polyline.points.push_back(Point(
coord_t(floor((*it)(0) * distance_between_lines + 0.5)), coord_t(floor(pt.x() * distance_between_lines + 0.5)),
coord_t(floor((*it)(1) * distance_between_lines + 0.5)))); coord_t(floor(pt.y() * distance_between_lines + 0.5))));
// intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines); // intersection(polylines_src, offset((Polygons)expolygon, scale_(0.02)), &polylines);
polylines = intersection_pl(polylines, to_polygons(expolygon)); polylines = intersection_pl(std::move(polylines), to_polygons(expolygon));
Polylines chained;
/* if (params.dont_connect() || params.density > 0.5 || polylines.size() <= 1)
if (1) { chained = chain_polylines(std::move(polylines));
require "Slic3r/SVG.pm"; else
print "Writing fill.svg\n"; connect_infill(std::move(polylines), expolygon, chained, this->spacing, params);
Slic3r::SVG::output("fill.svg",
no_arrows => 1,
polygons => \@$expolygon,
green_polygons => [ $bounding_box->polygon ],
polylines => [ $polyline ],
red_polylines => \@paths,
);
}
*/
// paths must be repositioned and rotated back // paths must be repositioned and rotated back
for (Polylines::iterator it = polylines.begin(); it != polylines.end(); ++ it) { for (Polyline &pl : chained) {
it->translate(shift(0), shift(1)); pl.translate(shift.x(), shift.y());
it->rotate(direction.first); pl.rotate(direction.first);
} }
append(polylines_out, std::move(chained));
} }
// Move the polylines to the output, avoid a deep copy.
size_t j = polylines_out.size();
polylines_out.resize(j + polylines.size(), Polyline());
for (size_t i = 0; i < polylines.size(); ++ i)
std::swap(polylines_out[j ++], polylines[i]);
} }
// Follow an Archimedean spiral, in polar coordinates: r=a+b\theta // Follow an Archimedean spiral, in polar coordinates: r=a+b\theta
@ -85,13 +71,13 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m
coordf_t r = 1; coordf_t r = 1;
Pointfs out; Pointfs out;
//FIXME Vojtech: If used as a solid infill, there is a gap left at the center. //FIXME Vojtech: If used as a solid infill, there is a gap left at the center.
out.push_back(Vec2d(0, 0)); out.emplace_back(0, 0);
out.push_back(Vec2d(1, 0)); out.emplace_back(1, 0);
while (r < rmax) { while (r < rmax) {
// Discretization angle to achieve a discretization error lower than RESOLUTION. // Discretization angle to achieve a discretization error lower than RESOLUTION.
theta += 2. * acos(1. - RESOLUTION / r); theta += 2. * acos(1. - RESOLUTION / r);
r = a + b * theta; r = a + b * theta;
out.push_back(Vec2d(r * cos(theta), r * sin(theta))); out.emplace_back(r * cos(theta), r * sin(theta));
} }
return out; return out;
} }
@ -128,15 +114,12 @@ static inline Point hilbert_n_to_xy(const size_t n)
++ ndigits; ++ ndigits;
} }
} }
int state = (ndigits & 1) ? 4 : 0; int state = (ndigits & 1) ? 4 : 0;
// int dirstate = (ndigits & 1) ? 0 : 4;
coord_t x = 0; coord_t x = 0;
coord_t y = 0; coord_t y = 0;
for (int i = (int)ndigits - 1; i >= 0; -- i) { for (int i = (int)ndigits - 1; i >= 0; -- i) {
int digit = (n >> (i * 2)) & 3; int digit = (n >> (i * 2)) & 3;
state += digit; state += digit;
// if (digit != 3)
// dirstate = state; // lowest non-3 digit
x |= digit_to_x[state] << i; x |= digit_to_x[state] << i;
y |= digit_to_y[state] << i; y |= digit_to_y[state] << i;
state = next_state[state]; state = next_state[state];
@ -162,7 +145,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x,
line.reserve(sz2); line.reserve(sz2);
for (size_t i = 0; i < sz2; ++ i) { for (size_t i = 0; i < sz2; ++ i) {
Point p = hilbert_n_to_xy(i); Point p = hilbert_n_to_xy(i);
line.push_back(Vec2d(p(0) + min_x, p(1) + min_y)); line.emplace_back(p.x() + min_x, p.y() + min_y);
} }
return line; return line;
} }
@ -175,27 +158,27 @@ Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_
coordf_t r = 0; coordf_t r = 0;
coordf_t r_inc = sqrt(2.); coordf_t r_inc = sqrt(2.);
Pointfs out; Pointfs out;
out.push_back(Vec2d(0, 0)); out.emplace_back(0., 0.);
while (r < rmax) { while (r < rmax) {
r += r_inc; r += r_inc;
coordf_t rx = r / sqrt(2.); coordf_t rx = r / sqrt(2.);
coordf_t r2 = r + rx; coordf_t r2 = r + rx;
out.push_back(Vec2d( r, 0.)); out.emplace_back( r, 0.);
out.push_back(Vec2d( r2, rx)); out.emplace_back( r2, rx);
out.push_back(Vec2d( rx, rx)); out.emplace_back( rx, rx);
out.push_back(Vec2d( rx, r2)); out.emplace_back( rx, r2);
out.push_back(Vec2d(0., r)); out.emplace_back( 0., r);
out.push_back(Vec2d(-rx, r2)); out.emplace_back(-rx, r2);
out.push_back(Vec2d(-rx, rx)); out.emplace_back(-rx, rx);
out.push_back(Vec2d(-r2, rx)); out.emplace_back(-r2, rx);
out.push_back(Vec2d(-r, 0.)); out.emplace_back(- r, 0.);
out.push_back(Vec2d(-r2, -rx)); out.emplace_back(-r2, -rx);
out.push_back(Vec2d(-rx, -rx)); out.emplace_back(-rx, -rx);
out.push_back(Vec2d(-rx, -r2)); out.emplace_back(-rx, -r2);
out.push_back(Vec2d(0., -r)); out.emplace_back( 0., -r);
out.push_back(Vec2d( rx, -r2)); out.emplace_back( rx, -r2);
out.push_back(Vec2d( rx, -rx)); out.emplace_back( rx, -rx);
out.push_back(Vec2d( r2+r_inc, -rx)); out.emplace_back( r2+r_inc, -rx);
} }
return out; return out;
} }

View file

@ -16,17 +16,17 @@ namespace Slic3r {
class FillPlanePath : public Fill class FillPlanePath : public Fill
{ {
public: public:
virtual ~FillPlanePath() {} ~FillPlanePath() override = default;
protected: protected:
virtual void _fill_surface_single( void _fill_surface_single(
const FillParams &params, const FillParams &params,
unsigned int thickness_layers, unsigned int thickness_layers,
const std::pair<float, Point> &direction, const std::pair<float, Point> &direction,
ExPolygon &expolygon, ExPolygon expolygon,
Polylines &polylines_out); Polylines &polylines_out) override;
virtual float _layer_angle(size_t idx) const { return 0.f; } float _layer_angle(size_t idx) const override { return 0.f; }
virtual bool _centered() const = 0; virtual bool _centered() const = 0;
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) = 0; virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) = 0;
}; };
@ -34,34 +34,34 @@ protected:
class FillArchimedeanChords : public FillPlanePath class FillArchimedeanChords : public FillPlanePath
{ {
public: public:
virtual Fill* clone() const { return new FillArchimedeanChords(*this); }; Fill* clone() const override { return new FillArchimedeanChords(*this); };
virtual ~FillArchimedeanChords() {} ~FillArchimedeanChords() override = default;
protected: protected:
virtual bool _centered() const { return true; } bool _centered() const override { return true; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y); Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
}; };
class FillHilbertCurve : public FillPlanePath class FillHilbertCurve : public FillPlanePath
{ {
public: public:
virtual Fill* clone() const { return new FillHilbertCurve(*this); }; Fill* clone() const override { return new FillHilbertCurve(*this); };
virtual ~FillHilbertCurve() {} ~FillHilbertCurve() override = default;
protected: protected:
virtual bool _centered() const { return false; } bool _centered() const override { return false; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y); Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
}; };
class FillOctagramSpiral : public FillPlanePath class FillOctagramSpiral : public FillPlanePath
{ {
public: public:
virtual Fill* clone() const { return new FillOctagramSpiral(*this); }; Fill* clone() const override { return new FillOctagramSpiral(*this); };
virtual ~FillOctagramSpiral() {} ~FillOctagramSpiral() override = default;
protected: protected:
virtual bool _centered() const { return true; } bool _centered() const override { return true; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y); Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override;
}; };
} // namespace Slic3r } // namespace Slic3r

File diff suppressed because it is too large Load diff

View file

@ -12,68 +12,92 @@ class Surface;
class FillRectilinear : public Fill class FillRectilinear : public Fill
{ {
public: public:
virtual Fill* clone() const { return new FillRectilinear(*this); }; Fill* clone() const override { return new FillRectilinear(*this); };
virtual ~FillRectilinear() {} ~FillRectilinear() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected: protected:
virtual void _fill_surface_single( // Fill by single directional lines, interconnect the lines along perimeters.
const FillParams &params, bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out);
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
coord_t _min_spacing;
coord_t _line_spacing;
// distance threshold for allowing the horizontal infill lines to be connected into a continuous path
coord_t _diagonal_distance;
// only for line infill
coord_t _line_oscillation;
// Enabled for the grid infill, disabled for the rectilinear and line infill. // Fill by multiple sweeps of differing directions.
virtual bool _horizontal_lines() const { return false; } struct SweepParams {
float angle_base;
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const float pattern_shift;
{ return Line(Point(x, y_min), Point(x, y_max)); } };
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y) {
return dist_X <= this->_diagonal_distance
&& dist_Y <= this->_diagonal_distance;
}
}; };
class FillLine : public FillRectilinear class FillAlignedRectilinear : public FillRectilinear
{ {
public: public:
virtual ~FillLine() {} Fill* clone() const override { return new FillAlignedRectilinear(*this); };
~FillAlignedRectilinear() override = default;
protected: protected:
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const { // Always generate infill at the same angle.
coord_t osc = (i & 1) ? this->_line_oscillation : 0; virtual float _layer_angle(size_t idx) const { return 0.f; }
return Line(Point(x - osc, y_min), Point(x + osc, y_max)); };
}
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y) class FillMonotonic : public FillRectilinear
{ {
coord_t TOLERANCE = 10 * SCALED_EPSILON; public:
return (dist_X >= (this->_line_spacing - this->_line_oscillation) - TOLERANCE) Fill* clone() const override { return new FillMonotonic(*this); };
&& (dist_X <= (this->_line_spacing + this->_line_oscillation) + TOLERANCE) ~FillMonotonic() override = default;
&& (dist_Y <= this->_diagonal_distance); Polylines fill_surface(const Surface *surface, const FillParams &params) override;
} bool no_sort() const override { return true; }
}; };
class FillGrid : public FillRectilinear class FillGrid : public FillRectilinear
{ {
public: public:
virtual ~FillGrid() {} Fill* clone() const override { return new FillGrid(*this); };
~FillGrid() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected: protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill. // The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; } float _layer_angle(size_t idx) const override { return 0.f; }
// Flag for Slic3r::Fill::Rectilinear to fill both directions.
virtual bool _horizontal_lines() const { return true; }
}; };
class FillTriangles : public FillRectilinear
{
public:
Fill* clone() const override { return new FillTriangles(*this); };
~FillTriangles() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
float _layer_angle(size_t idx) const override { return 0.f; }
};
class FillStars : public FillRectilinear
{
public:
Fill* clone() const override { return new FillStars(*this); };
~FillStars() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
float _layer_angle(size_t idx) const override { return 0.f; }
};
class FillCubic : public FillRectilinear
{
public:
Fill* clone() const override { return new FillCubic(*this); };
~FillCubic() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
float _layer_angle(size_t idx) const override { return 0.f; }
};
}; // namespace Slic3r }; // namespace Slic3r
#endif // slic3r_FillRectilinear_hpp_ #endif // slic3r_FillRectilinear_hpp_

File diff suppressed because it is too large Load diff

View file

@ -1,83 +0,0 @@
#ifndef slic3r_FillRectilinear2_hpp_
#define slic3r_FillRectilinear2_hpp_
#include "../libslic3r.h"
#include "FillBase.hpp"
namespace Slic3r {
class Surface;
class FillRectilinear2 : public Fill
{
public:
virtual Fill* clone() const { return new FillRectilinear2(*this); };
virtual ~FillRectilinear2() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
protected:
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out);
};
class FillMonotonic : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillMonotonic(*this); };
virtual ~FillMonotonic() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual bool no_sort() const { return true; }
};
class FillGrid2 : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillGrid2(*this); };
virtual ~FillGrid2() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillTriangles : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillTriangles(*this); };
virtual ~FillTriangles() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillStars : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillStars(*this); };
virtual ~FillStars() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillCubic : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillCubic(*this); };
virtual ~FillCubic() = default;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
}; // namespace Slic3r
#endif // slic3r_FillRectilinear2_hpp_

View file

@ -18,7 +18,7 @@
#include "libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfig.hpp"
#include "libslic3r/SLA/RasterBase.hpp" #include "libslic3r/SLA/RasterBase.hpp"
#include "libslic3r/miniz_extension.hpp" #include "libslic3r/miniz_extension.hpp"
#include "libslic3r/PNGRead.hpp" #include "libslic3r/PNGReadWrite.hpp"
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>

View file

@ -169,6 +169,10 @@ namespace Slic3r {
// subdivide the retraction in segments // subdivide the retraction in segments
if (!wipe_path.empty()) { if (!wipe_path.empty()) {
#if ENABLE_SHOW_WIPE_MOVES
// add tag for processor
gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
#endif // ENABLE_SHOW_WIPE_MOVES
for (const Line& line : wipe_path.lines()) { for (const Line& line : wipe_path.lines()) {
double segment_length = line.length(); double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one /* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
@ -183,6 +187,10 @@ namespace Slic3r {
"wipe and retract" "wipe and retract"
); );
} }
#if ENABLE_SHOW_WIPE_MOVES
// add tag for processor
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
#endif // ENABLE_SHOW_WIPE_MOVES
gcodegen.set_last_pos(wipe_path.points.back()); gcodegen.set_last_pos(wipe_path.points.back());
} }
@ -1764,7 +1772,7 @@ void GCode::process_layer(
std::string gcode; std::string gcode;
// add tag for processor // add tag for processor
gcode += "; " + GCodeProcessor::Layer_Change_Tag + "\n"; gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n";
// export layer z // export layer z
char buf[64]; char buf[64];
sprintf(buf, ";Z:%g\n", print_z); sprintf(buf, ";Z:%g\n", print_z);
@ -2240,7 +2248,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
const EdgeGrid::Grid* edge_grid_ptr = (lower_layer_edge_grid && *lower_layer_edge_grid) const EdgeGrid::Grid* edge_grid_ptr = (lower_layer_edge_grid && *lower_layer_edge_grid)
? lower_layer_edge_grid->get() ? lower_layer_edge_grid->get()
: nullptr; : nullptr;
Point seam = m_seam_placer.get_seam(m_layer->id(), seam_position, loop, Point seam = m_seam_placer.get_seam(*m_layer, seam_position, loop,
last_pos, EXTRUDER_CONFIG(nozzle_diameter), last_pos, EXTRUDER_CONFIG(nozzle_diameter),
(m_layer == NULL ? nullptr : m_layer->object()), (m_layer == NULL ? nullptr : m_layer->object()),
was_clockwise, edge_grid_ptr); was_clockwise, edge_grid_ptr);

View file

@ -25,6 +25,10 @@ static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
namespace Slic3r { namespace Slic3r {
const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:"; const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:";
#if ENABLE_SHOW_WIPE_MOVES
const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START";
const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END";
#endif // ENABLE_SHOW_WIPE_MOVES
const std::string GCodeProcessor::Height_Tag = "HEIGHT:"; const std::string GCodeProcessor::Height_Tag = "HEIGHT:";
const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE"; const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE";
const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE"; const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE";
@ -35,6 +39,11 @@ const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _
const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER"; const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"; const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER";
#if ENABLE_SHOW_WIPE_MOVES
const float GCodeProcessor::Wipe_Width = 0.05f;
const float GCodeProcessor::Wipe_Height = 0.05f;
#endif // ENABLE_SHOW_WIPE_MOVES
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
const std::string GCodeProcessor::Width_Tag = "WIDTH:"; const std::string GCodeProcessor::Width_Tag = "WIDTH:";
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:"; const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
@ -390,13 +399,17 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
}; };
// check for temporary lines // check for temporary lines
auto is_temporary_decoration = [](const std::string& gcode_line) { auto is_temporary_decoration = [](const std::string_view gcode_line) {
// remove trailing '\n' // remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1); assert(! gcode_line.empty());
if (line == "; " + Layer_Change_Tag) assert(gcode_line.back() == '\n');
return true;
else // return true for decorations which are used in processing the gcode but that should not be exported into the final gcode
return false; // i.e.:
// bool ret = gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag;
// ...
// return ret;
return false;
}; };
// Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1. // Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1.
@ -488,7 +501,8 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
{ EProducer::Cura, "Cura_SteamEngine" }, { EProducer::Cura, "Cura_SteamEngine" },
{ EProducer::Simplify3D, "Simplify3D" }, { EProducer::Simplify3D, "Simplify3D" },
{ EProducer::CraftWare, "CraftWare" }, { EProducer::CraftWare, "CraftWare" },
{ EProducer::ideaMaker, "ideaMaker" } { EProducer::ideaMaker, "ideaMaker" },
{ EProducer::KissSlicer, "KISSlicer" }
}; };
unsigned int GCodeProcessor::s_result_id = 0; unsigned int GCodeProcessor::s_result_id = 0;
@ -591,9 +605,6 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
} }
} }
// ensure at least one (default) color is defined
std::string default_color = "#FF8000";
m_result.extruder_colors = std::vector<std::string>(1, default_color);
const ConfigOptionStrings* extruder_colour = config.option<ConfigOptionStrings>("extruder_colour"); const ConfigOptionStrings* extruder_colour = config.option<ConfigOptionStrings>("extruder_colour");
if (extruder_colour != nullptr) { if (extruder_colour != nullptr) {
// takes colors from config // takes colors from config
@ -608,7 +619,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
} }
} }
// replace missing values with default // replace missing values with default
std::string default_color = "#FF8000";
for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) { for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
if (m_result.extruder_colors[i].empty()) if (m_result.extruder_colors[i].empty())
m_result.extruder_colors[i] = default_color; m_result.extruder_colors[i] = default_color;
@ -725,6 +738,9 @@ void GCodeProcessor::reset()
m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f }; m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
m_origin = { 0.0f, 0.0f, 0.0f, 0.0f }; m_origin = { 0.0f, 0.0f, 0.0f, 0.0f };
m_cached_position.reset(); m_cached_position.reset();
#if ENABLE_SHOW_WIPE_MOVES
m_wiping = false;
#endif // ENABLE_SHOW_WIPE_MOVES
m_feedrate = 0.0f; m_feedrate = 0.0f;
m_width = 0.0f; m_width = 0.0f;
@ -806,6 +822,16 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
process_gcode_line(line); process_gcode_line(line);
}); });
#if ENABLE_SHOW_WIPE_MOVES
// update width/height of wipe moves
for (MoveVertex& move : m_result.moves) {
if (move.type == EMoveType::Wipe) {
move.width = Wipe_Width;
move.height = Wipe_Height;
}
}
#endif // ENABLE_SHOW_WIPE_MOVES
// process the time blocks // process the time blocks
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i]; TimeMachine& machine = m_time_processor.machines[i];
@ -1027,6 +1053,20 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return; return;
} }
#if ENABLE_SHOW_WIPE_MOVES
// wipe start tag
if (starts_with(comment, Wipe_Start_Tag)) {
m_wiping = true;
return;
}
// wipe end tag
if (starts_with(comment, Wipe_End_Tag)) {
m_wiping = false;
return;
}
#endif // ENABLE_SHOW_WIPE_MOVES
if ((!m_producers_enabled || m_producer == EProducer::PrusaSlicer) && if ((!m_producers_enabled || m_producer == EProducer::PrusaSlicer) &&
starts_with(comment, Height_Tag)) { starts_with(comment, Height_Tag)) {
// height tag // height tag
@ -1104,11 +1144,14 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{ {
switch (m_producer) switch (m_producer)
{ {
case EProducer::Slic3rPE:
case EProducer::Slic3r:
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); } case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); } case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); } case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
case EProducer::CraftWare: { return process_craftware_tags(comment); } case EProducer::CraftWare: { return process_craftware_tags(comment); }
case EProducer::ideaMaker: { return process_ideamaker_tags(comment); } case EProducer::ideaMaker: { return process_ideamaker_tags(comment); }
case EProducer::KissSlicer: { return process_kissslicer_tags(comment); }
default: { return false; } default: { return false; }
} }
} }
@ -1178,6 +1221,14 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment)
return true; return true;
} }
// layer
tag = "LAYER:";
pos = comment.find(tag);
if (pos != comment.npos) {
++m_layer_id;
return true;
}
return false; return false;
} }
@ -1262,9 +1313,8 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
return true; return true;
} }
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// geometry // geometry
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// ; tool // ; tool
std::string tag = " tool"; std::string tag = " tool";
pos = comment.find(tag); pos = comment.find(tag);
@ -1289,6 +1339,19 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
} }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// ; layer
std::string tag = " layer";
pos = comment.find(tag);
if (pos == 0) {
// skip lines "; layer end"
const std::string_view data = comment.substr(pos + tag.length());
size_t end_start = data.find("end");
if (end_start == data.npos)
++m_layer_id;
return true;
}
return false; return false;
} }
@ -1329,6 +1392,13 @@ bool GCodeProcessor::process_craftware_tags(const std::string_view comment)
return true; return true;
} }
// layer
pos = comment.find(" Layer #");
if (pos == 0) {
++m_layer_id;
return true;
}
return false; return false;
} }
@ -1360,9 +1430,8 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
return true; return true;
} }
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// geometry // geometry
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// width // width
tag = "WIDTH:"; tag = "WIDTH:";
pos = comment.find(tag); pos = comment.find(tag);
@ -1382,6 +1451,120 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
} }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// layer
pos = comment.find("LAYER:");
if (pos == 0) {
++m_layer_id;
return true;
}
return false;
}
bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment)
{
// extrusion roles
// ; 'Raft Path'
size_t pos = comment.find(" 'Raft Path'");
if (pos == 0) {
m_extrusion_role = erSkirt;
return true;
}
// ; 'Support Interface Path'
pos = comment.find(" 'Support Interface Path'");
if (pos == 0) {
m_extrusion_role = erSupportMaterialInterface;
return true;
}
// ; 'Travel/Ironing Path'
pos = comment.find(" 'Travel/Ironing Path'");
if (pos == 0) {
m_extrusion_role = erIroning;
return true;
}
// ; 'Support (may Stack) Path'
pos = comment.find(" 'Support (may Stack) Path'");
if (pos == 0) {
m_extrusion_role = erSupportMaterial;
return true;
}
// ; 'Perimeter Path'
pos = comment.find(" 'Perimeter Path'");
if (pos == 0) {
m_extrusion_role = erExternalPerimeter;
return true;
}
// ; 'Pillar Path'
pos = comment.find(" 'Pillar Path'");
if (pos == 0) {
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true;
}
// ; 'Destring/Wipe/Jump Path'
pos = comment.find(" 'Destring/Wipe/Jump Path'");
if (pos == 0) {
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true;
}
// ; 'Prime Pillar Path'
pos = comment.find(" 'Prime Pillar Path'");
if (pos == 0) {
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true;
}
// ; 'Loop Path'
pos = comment.find(" 'Loop Path'");
if (pos == 0) {
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true;
}
// ; 'Crown Path'
pos = comment.find(" 'Crown Path'");
if (pos == 0) {
m_extrusion_role = erNone; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return true;
}
// ; 'Solid Path'
pos = comment.find(" 'Solid Path'");
if (pos == 0) {
m_extrusion_role = erNone;
return true;
}
// ; 'Stacked Sparse Infill Path'
pos = comment.find(" 'Stacked Sparse Infill Path'");
if (pos == 0) {
m_extrusion_role = erInternalInfill;
return true;
}
// ; 'Sparse Infill Path'
pos = comment.find(" 'Sparse Infill Path'");
if (pos == 0) {
m_extrusion_role = erSolidInfill;
return true;
}
// geometry
// layer
pos = comment.find(" BEGIN_LAYER_");
if (pos == 0) {
++m_layer_id;
return true;
}
return false; return false;
} }
@ -1423,7 +1606,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
auto move_type = [this](const AxisCoords& delta_pos) { auto move_type = [this](const AxisCoords& delta_pos) {
EMoveType type = EMoveType::Noop; EMoveType type = EMoveType::Noop;
#if ENABLE_SHOW_WIPE_MOVES
if (m_wiping)
type = EMoveType::Wipe;
else if (delta_pos[E] < 0.0f)
#else
if (delta_pos[E] < 0.0f) if (delta_pos[E] < 0.0f)
#endif // ENABLE_SHOW_WIPE_MOVES
type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract; type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
else if (delta_pos[E] > 0.0f) { else if (delta_pos[E] > 0.0f) {
if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f) if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)

View file

@ -24,6 +24,9 @@ namespace Slic3r {
Pause_Print, Pause_Print,
Custom_GCode, Custom_GCode,
Travel, Travel,
#if ENABLE_SHOW_WIPE_MOVES
Wipe,
#endif // ENABLE_SHOW_WIPE_MOVES
Extrude, Extrude,
Count Count
}; };
@ -69,6 +72,10 @@ namespace Slic3r {
{ {
public: public:
static const std::string Extrusion_Role_Tag; static const std::string Extrusion_Role_Tag;
#if ENABLE_SHOW_WIPE_MOVES
static const std::string Wipe_Start_Tag;
static const std::string Wipe_End_Tag;
#endif // ENABLE_SHOW_WIPE_MOVES
static const std::string Height_Tag; static const std::string Height_Tag;
static const std::string Layer_Change_Tag; static const std::string Layer_Change_Tag;
static const std::string Color_Change_Tag; static const std::string Color_Change_Tag;
@ -78,6 +85,11 @@ namespace Slic3r {
static const std::string Last_Line_M73_Placeholder_Tag; static const std::string Last_Line_M73_Placeholder_Tag;
static const std::string Estimated_Printing_Time_Placeholder_Tag; static const std::string Estimated_Printing_Time_Placeholder_Tag;
#if ENABLE_SHOW_WIPE_MOVES
static const float Wipe_Width;
static const float Wipe_Height;
#endif // ENABLE_SHOW_WIPE_MOVES
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
static const std::string Width_Tag; static const std::string Width_Tag;
static const std::string Mm3_Per_Mm_Tag; static const std::string Mm3_Per_Mm_Tag;
@ -390,6 +402,9 @@ namespace Slic3r {
AxisCoords m_end_position; // mm AxisCoords m_end_position; // mm
AxisCoords m_origin; // mm AxisCoords m_origin; // mm
CachedPosition m_cached_position; CachedPosition m_cached_position;
#if ENABLE_SHOW_WIPE_MOVES
bool m_wiping;
#endif // ENABLE_SHOW_WIPE_MOVES
float m_feedrate; // mm/s float m_feedrate; // mm/s
float m_width; // mm float m_width; // mm
@ -414,7 +429,8 @@ namespace Slic3r {
Cura, Cura,
Simplify3D, Simplify3D,
CraftWare, CraftWare,
ideaMaker ideaMaker,
KissSlicer
}; };
static const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> Producers; static const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> Producers;
@ -471,6 +487,7 @@ namespace Slic3r {
bool process_simplify3d_tags(const std::string_view comment); bool process_simplify3d_tags(const std::string_view comment);
bool process_craftware_tags(const std::string_view comment); bool process_craftware_tags(const std::string_view comment);
bool process_ideamaker_tags(const std::string_view comment); bool process_ideamaker_tags(const std::string_view comment);
bool process_kissslicer_tags(const std::string_view comment);
bool detect_producer(const std::string_view comment); bool detect_producer(const std::string_view comment);

View file

@ -6,6 +6,7 @@
#include "libslic3r/EdgeGrid.hpp" #include "libslic3r/EdgeGrid.hpp"
#include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/SVG.hpp" #include "libslic3r/SVG.hpp"
#include "libslic3r/Layer.hpp"
namespace Slic3r { namespace Slic3r {
@ -191,24 +192,98 @@ void SeamPlacer::init(const Print& print)
{ {
m_enforcers.clear(); m_enforcers.clear();
m_blockers.clear(); m_blockers.clear();
//m_last_seam_position.clear();
m_seam_history.clear(); m_seam_history.clear();
m_po_list.clear();
for (const PrintObject* po : print.objects()) { const std::vector<double>& nozzle_dmrs = print.config().nozzle_diameter.values;
po->project_and_append_custom_facets(true, EnforcerBlockerType::ENFORCER, m_enforcers); float max_nozzle_dmr = *std::max_element(nozzle_dmrs.begin(), nozzle_dmrs.end());
po->project_and_append_custom_facets(true, EnforcerBlockerType::BLOCKER, m_blockers);
}
const std::vector<double>& nozzle_dmrs = print.config().nozzle_diameter.values; std::vector<ExPolygons> temp_enf;
float max_nozzle_dmr = *std::max_element(nozzle_dmrs.begin(), nozzle_dmrs.end()); std::vector<ExPolygons> temp_blk;
for (ExPolygons& explgs : m_enforcers)
explgs = Slic3r::offset_ex(explgs, scale_(max_nozzle_dmr)); for (const PrintObject* po : print.objects()) {
for (ExPolygons& explgs : m_blockers) temp_enf.clear();
explgs = Slic3r::offset_ex(explgs, scale_(max_nozzle_dmr)); temp_blk.clear();
po->project_and_append_custom_facets(true, EnforcerBlockerType::ENFORCER, temp_enf);
po->project_and_append_custom_facets(true, EnforcerBlockerType::BLOCKER, temp_blk);
// Offset the triangles out slightly.
for (auto* custom_per_object : {&temp_enf, &temp_blk})
for (ExPolygons& explgs : *custom_per_object)
explgs = Slic3r::offset_ex(explgs, scale_(max_nozzle_dmr));
// FIXME: Offsetting should be done somehow cheaper, but following does not work
// for (auto* custom_per_object : {&temp_enf, &temp_blk}) {
// for (ExPolygons& plgs : *custom_per_object) {
// for (ExPolygon& plg : plgs) {
// auto out = Slic3r::offset_ex(plg, scale_(max_nozzle_dmr));
// plg = out.empty() ? ExPolygon() : out.front();
// assert(out.empty() || out.size() == 1);
// }
// }
// }
// Remember this PrintObject and initialize a store of enforcers and blockers for it.
m_po_list.push_back(po);
size_t po_idx = m_po_list.size() - 1;
m_enforcers.emplace_back(std::vector<CustomTrianglesPerLayer>(temp_enf.size()));
m_blockers.emplace_back(std::vector<CustomTrianglesPerLayer>(temp_blk.size()));
// A helper class to store data to build the AABB tree from.
class CustomTriangleRef {
public:
CustomTriangleRef(size_t idx,
Point&& centroid,
BoundingBox&& bb)
: m_idx{idx}, m_centroid{centroid},
m_bbox{AlignedBoxType(bb.min, bb.max)}
{}
size_t idx() const { return m_idx; }
const Point& centroid() const { return m_centroid; }
const TreeType::BoundingBox& bbox() const { return m_bbox; }
private:
size_t m_idx;
Point m_centroid;
AlignedBoxType m_bbox;
};
// A lambda to extract the ExPolygons and save them into the member AABB tree.
// Will be called for enforcers and blockers separately.
auto add_custom = [](std::vector<ExPolygons>& src, std::vector<CustomTrianglesPerLayer>& dest) {
// Go layer by layer, and append all the ExPolygons into the AABB tree.
size_t layer_idx = 0;
for (ExPolygons& expolys_on_layer : src) {
CustomTrianglesPerLayer& layer_data = dest[layer_idx];
std::vector<CustomTriangleRef> triangles_data;
layer_data.polys.reserve(expolys_on_layer.size());
triangles_data.reserve(expolys_on_layer.size());
for (ExPolygon& expoly : expolys_on_layer) {
if (expoly.empty())
continue;
layer_data.polys.emplace_back(std::move(expoly));
triangles_data.emplace_back(layer_data.polys.size() - 1,
layer_data.polys.back().centroid(),
layer_data.polys.back().bounding_box());
}
// All polygons are saved, build the AABB tree for them.
layer_data.tree.build(std::move(triangles_data));
++layer_idx;
}
};
add_custom(temp_enf, m_enforcers.at(po_idx));
add_custom(temp_blk, m_blockers.at(po_idx));
}
} }
Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_position, Point SeamPlacer::get_seam(const Layer& layer, const SeamPosition seam_position,
const ExtrusionLoop& loop, Point last_pos, coordf_t nozzle_dmr, const ExtrusionLoop& loop, Point last_pos, coordf_t nozzle_dmr,
const PrintObject* po, bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid) const PrintObject* po, bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid)
{ {
@ -216,7 +291,28 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
BoundingBox polygon_bb = polygon.bounding_box(); BoundingBox polygon_bb = polygon.bounding_box();
const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5); const coord_t nozzle_r = coord_t(scale_(0.5 * nozzle_dmr) + 0.5);
if (this->is_custom_seam_on_layer(layer_idx)) { size_t po_idx = std::find(m_po_list.begin(), m_po_list.end(), po) - m_po_list.begin();
// Find current layer in respective PrintObject. Cache the result so the
// lookup is only done once per layer, not for each loop.
const Layer* layer_po = nullptr;
if (po == m_last_po && layer.print_z == m_last_print_z)
layer_po = m_last_layer_po;
else {
layer_po = po->get_layer_at_printz(layer.print_z);
m_last_po = po;
m_last_print_z = layer.print_z;
m_last_layer_po = layer_po;
}
if (! layer_po)
return last_pos;
// Index of this layer in the respective PrintObject.
size_t layer_idx = layer_po->id() - po->layers().front()->id(); // raft layers
assert(layer_idx < po->layer_count());
if (this->is_custom_seam_on_layer(layer_idx, po_idx)) {
// Seam enf/blockers can begin and end in between the original vertices. // Seam enf/blockers can begin and end in between the original vertices.
// Let add extra points in between and update the leghths. // Let add extra points in between and update the leghths.
polygon.densify(MINIMAL_POLYGON_SIDE); polygon.densify(MINIMAL_POLYGON_SIDE);
@ -229,11 +325,10 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
if (seam_position == spAligned) { if (seam_position == spAligned) {
// Seam is aligned to the seam at the preceding layer. // Seam is aligned to the seam at the preceding layer.
if (po != nullptr) { if (po != nullptr) {
std::optional<Point> pos = m_seam_history.get_last_seam(po, layer_idx, polygon_bb); std::optional<Point> pos = m_seam_history.get_last_seam(m_po_list[po_idx], layer_idx, polygon_bb);
if (pos.has_value()) { if (pos.has_value()) {
//last_pos = m_last_seam_position[po];
last_pos = *pos; last_pos = *pos;
last_pos_weight = is_custom_enforcer_on_layer(layer_idx) ? 0.f : 1.f; last_pos_weight = is_custom_enforcer_on_layer(layer_idx, po_idx) ? 0.f : 1.f;
} }
} }
} }
@ -313,12 +408,12 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
// Custom seam. Huge (negative) constant penalty is applied inside // Custom seam. Huge (negative) constant penalty is applied inside
// blockers (enforcers) to rule out points that should not win. // blockers (enforcers) to rule out points that should not win.
this->apply_custom_seam(polygon, penalties, lengths, layer_idx, seam_position); this->apply_custom_seam(polygon, po_idx, penalties, lengths, layer_idx, seam_position);
// Find a point with a minimum penalty. // Find a point with a minimum penalty.
size_t idx_min = std::min_element(penalties.begin(), penalties.end()) - penalties.begin(); size_t idx_min = std::min_element(penalties.begin(), penalties.end()) - penalties.begin();
if (seam_position != spAligned || ! is_custom_enforcer_on_layer(layer_idx)) { if (seam_position != spAligned || ! is_custom_enforcer_on_layer(layer_idx, po_idx)) {
// Very likely the weight of idx_min is very close to the weight of last_pos_proj_idx. // Very likely the weight of idx_min is very close to the weight of last_pos_proj_idx.
// In that case use last_pos_proj_idx instead. // In that case use last_pos_proj_idx instead.
float penalty_aligned = penalties[last_pos_proj_idx]; float penalty_aligned = penalties[last_pos_proj_idx];
@ -363,29 +458,45 @@ Point SeamPlacer::get_seam(const size_t layer_idx, const SeamPosition seam_posit
return polygon.points[idx_min]; return polygon.points[idx_min];
} else { // spRandom } else { // spRandom
if (loop.loop_role() == elrContourInternalPerimeter && loop.role() != erExternalPerimeter) { if (po->print()->default_region_config().external_perimeters_first) {
// This loop does not contain any other loop. Set a random position. if (loop.role() == erExternalPerimeter)
// The other loops will get a seam close to the random point chosen last_pos = this->get_random_seam(layer_idx, polygon, po_idx);
// on the innermost contour. else {
//FIXME This works correctly for inner contours first only. // Internal perimeters will just use last_pos.
last_pos = this->get_random_seam(layer_idx, polygon); }
} } else {
if (loop.role() == erExternalPerimeter && is_custom_seam_on_layer(layer_idx)) { if (loop.loop_role() == elrContourInternalPerimeter && loop.role() != erExternalPerimeter) {
// There is a possibility that the loop will be influenced by custom // This loop does not contain any other loop. Set a random position.
// seam enforcer/blocker. In this case do not inherit the seam // The other loops will get a seam close to the random point chosen
// from internal loops (which may conflict with the custom selection // on the innermost contour.
// and generate another random one. last_pos = this->get_random_seam(layer_idx, polygon, po_idx);
bool saw_custom = false; m_last_loop_was_external = false;
Point candidate = this->get_random_seam(layer_idx, polygon, &saw_custom); }
if (saw_custom) if (loop.role() == erExternalPerimeter) {
last_pos = candidate; if (m_last_loop_was_external) {
// There was no internal perimeter before this one.
last_pos = this->get_random_seam(layer_idx, polygon, po_idx);
} else {
if (is_custom_seam_on_layer(layer_idx, po_idx)) {
// There is a possibility that the loop will be influenced by custom
// seam enforcer/blocker. In this case do not inherit the seam
// from internal loops (which may conflict with the custom selection
// and generate another random one.
bool saw_custom = false;
Point candidate = this->get_random_seam(layer_idx, polygon, po_idx, &saw_custom);
if (saw_custom)
last_pos = candidate;
}
}
m_last_loop_was_external = true;
}
} }
return last_pos; return last_pos;
} }
} }
Point SeamPlacer::get_random_seam(size_t layer_idx, const Polygon& polygon, Point SeamPlacer::get_random_seam(size_t layer_idx, const Polygon& polygon, size_t po_idx,
bool* saw_custom) const bool* saw_custom) const
{ {
// Parametrize the polygon by its length. // Parametrize the polygon by its length.
@ -394,7 +505,7 @@ Point SeamPlacer::get_random_seam(size_t layer_idx, const Polygon& polygon,
// Which of the points are inside enforcers/blockers? // Which of the points are inside enforcers/blockers?
std::vector<size_t> enforcers_idxs; std::vector<size_t> enforcers_idxs;
std::vector<size_t> blockers_idxs; std::vector<size_t> blockers_idxs;
this->get_enforcers_and_blockers(layer_idx, polygon, enforcers_idxs, blockers_idxs); this->get_enforcers_and_blockers(layer_idx, polygon, po_idx, enforcers_idxs, blockers_idxs);
bool has_enforcers = ! enforcers_idxs.empty(); bool has_enforcers = ! enforcers_idxs.empty();
bool has_blockers = ! blockers_idxs.empty(); bool has_blockers = ! blockers_idxs.empty();
@ -444,32 +555,44 @@ Point SeamPlacer::get_random_seam(size_t layer_idx, const Polygon& polygon,
void SeamPlacer::get_enforcers_and_blockers(size_t layer_id, void SeamPlacer::get_enforcers_and_blockers(size_t layer_id,
const Polygon& polygon, const Polygon& polygon,
size_t po_idx,
std::vector<size_t>& enforcers_idxs, std::vector<size_t>& enforcers_idxs,
std::vector<size_t>& blockers_idxs) const std::vector<size_t>& blockers_idxs) const
{ {
enforcers_idxs.clear(); enforcers_idxs.clear();
blockers_idxs.clear(); blockers_idxs.clear();
// FIXME: This is quadratic and it should be improved, maybe by building auto is_inside = [](const Point& pt,
// an AABB tree (or at least utilize bounding boxes). const CustomTrianglesPerLayer& custom_data) -> bool {
for (size_t i=0; i<polygon.points.size(); ++i) { assert(! custom_data.polys.empty());
// Now ask the AABB tree which polygon we should check and check it.
size_t candidate = AABBTreeIndirect::get_candidate_idx(custom_data.tree, pt);
if (candidate != size_t(-1)
&& custom_data.polys[candidate].contains(pt))
return true;
return false;
};
if (! m_enforcers.empty()) { if (! m_enforcers[po_idx].empty()) {
assert(layer_id < m_enforcers.size()); const CustomTrianglesPerLayer& enforcers = m_enforcers[po_idx][layer_id];
for (const ExPolygon& explg : m_enforcers[layer_id]) { if (! enforcers.polys.empty()) {
if (explg.contains(polygon.points[i])) for (size_t i=0; i<polygon.points.size(); ++i) {
enforcers_idxs.push_back(i); if (is_inside(polygon.points[i], enforcers))
} enforcers_idxs.emplace_back(i);
}
if (! m_blockers.empty()) {
assert(layer_id < m_blockers.size());
for (const ExPolygon& explg : m_blockers[layer_id]) {
if (explg.contains(polygon.points[i]))
blockers_idxs.push_back(i);
} }
} }
} }
if (! m_blockers[po_idx].empty()) {
const CustomTrianglesPerLayer& blockers = m_blockers[po_idx][layer_id];
if (! blockers.polys.empty()) {
for (size_t i=0; i<polygon.points.size(); ++i) {
if (is_inside(polygon.points[i], blockers))
blockers_idxs.emplace_back(i);
}
}
}
} }
@ -543,17 +666,17 @@ static std::vector<size_t> find_enforcer_centers(const Polygon& polygon,
void SeamPlacer::apply_custom_seam(const Polygon& polygon, void SeamPlacer::apply_custom_seam(const Polygon& polygon, size_t po_idx,
std::vector<float>& penalties, std::vector<float>& penalties,
const std::vector<float>& lengths, const std::vector<float>& lengths,
int layer_id, SeamPosition seam_position) const int layer_id, SeamPosition seam_position) const
{ {
if (! is_custom_seam_on_layer(layer_id)) if (! is_custom_seam_on_layer(layer_id, po_idx))
return; return;
std::vector<size_t> enforcers_idxs; std::vector<size_t> enforcers_idxs;
std::vector<size_t> blockers_idxs; std::vector<size_t> blockers_idxs;
this->get_enforcers_and_blockers(layer_id, polygon, enforcers_idxs, blockers_idxs); this->get_enforcers_and_blockers(layer_id, polygon, po_idx, enforcers_idxs, blockers_idxs);
for (size_t i : enforcers_idxs) { for (size_t i : enforcers_idxs) {
assert(i < penalties.size()); assert(i < penalties.size());

View file

@ -3,15 +3,17 @@
#include <optional> #include <optional>
#include "libslic3r/ExPolygon.hpp" #include "libslic3r/Polygon.hpp"
#include "libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfig.hpp"
#include "libslic3r/BoundingBox.hpp" #include "libslic3r/BoundingBox.hpp"
#include "libslic3r/AABBTreeIndirect.hpp"
namespace Slic3r { namespace Slic3r {
class PrintObject; class PrintObject;
class ExtrusionLoop; class ExtrusionLoop;
class Print; class Print;
class Layer;
namespace EdgeGrid { class Grid; } namespace EdgeGrid { class Grid; }
@ -39,14 +41,31 @@ class SeamPlacer {
public: public:
void init(const Print& print); void init(const Print& print);
Point get_seam(const size_t layer_idx, const SeamPosition seam_position, Point get_seam(const Layer& layer, const SeamPosition seam_position,
const ExtrusionLoop& loop, Point last_pos, const ExtrusionLoop& loop, Point last_pos,
coordf_t nozzle_diameter, const PrintObject* po, coordf_t nozzle_diameter, const PrintObject* po,
bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid); bool was_clockwise, const EdgeGrid::Grid* lower_layer_edge_grid);
using TreeType = AABBTreeIndirect::Tree<2, coord_t>;
using AlignedBoxType = Eigen::AlignedBox<TreeType::CoordType, TreeType::NumDimensions>;
private: private:
std::vector<ExPolygons> m_enforcers;
std::vector<ExPolygons> m_blockers; struct CustomTrianglesPerLayer {
Polygons polys;
TreeType tree;
};
// Just a cache to save some lookups.
const Layer* m_last_layer_po = nullptr;
coordf_t m_last_print_z = -1.;
const PrintObject* m_last_po = nullptr;
bool m_last_loop_was_external = true;
std::vector<std::vector<CustomTrianglesPerLayer>> m_enforcers;
std::vector<std::vector<CustomTrianglesPerLayer>> m_blockers;
std::vector<const PrintObject*> m_po_list;
//std::map<const PrintObject*, Point> m_last_seam_position; //std::map<const PrintObject*, Point> m_last_seam_position;
SeamHistory m_seam_history; SeamHistory m_seam_history;
@ -54,32 +73,33 @@ private:
// Get indices of points inside enforcers and blockers. // Get indices of points inside enforcers and blockers.
void get_enforcers_and_blockers(size_t layer_id, void get_enforcers_and_blockers(size_t layer_id,
const Polygon& polygon, const Polygon& polygon,
size_t po_id,
std::vector<size_t>& enforcers_idxs, std::vector<size_t>& enforcers_idxs,
std::vector<size_t>& blockers_idxs) const; std::vector<size_t>& blockers_idxs) const;
// Apply penalties to points inside enforcers/blockers. // Apply penalties to points inside enforcers/blockers.
void apply_custom_seam(const Polygon& polygon, void apply_custom_seam(const Polygon& polygon, size_t po_id,
std::vector<float>& penalties, std::vector<float>& penalties,
const std::vector<float>& lengths, const std::vector<float>& lengths,
int layer_id, SeamPosition seam_position) const; int layer_id, SeamPosition seam_position) const;
// Return random point of a polygon. The distribution will be uniform // Return random point of a polygon. The distribution will be uniform
// along the contour and account for enforcers and blockers. // along the contour and account for enforcers and blockers.
Point get_random_seam(size_t layer_idx, const Polygon& polygon, Point get_random_seam(size_t layer_idx, const Polygon& polygon, size_t po_id,
bool* saw_custom = nullptr) const; bool* saw_custom = nullptr) const;
// Is there any enforcer/blocker on this layer? // Is there any enforcer/blocker on this layer?
bool is_custom_seam_on_layer(size_t layer_id) const { bool is_custom_seam_on_layer(size_t layer_id, size_t po_idx) const {
return is_custom_enforcer_on_layer(layer_id) return is_custom_enforcer_on_layer(layer_id, po_idx)
|| is_custom_blocker_on_layer(layer_id); || is_custom_blocker_on_layer(layer_id, po_idx);
} }
bool is_custom_enforcer_on_layer(size_t layer_id) const { bool is_custom_enforcer_on_layer(size_t layer_id, size_t po_idx) const {
return (! m_enforcers.empty() && ! m_enforcers[layer_id].empty()); return (! m_enforcers.at(po_idx).empty() && ! m_enforcers.at(po_idx)[layer_id].polys.empty());
} }
bool is_custom_blocker_on_layer(size_t layer_id) const { bool is_custom_blocker_on_layer(size_t layer_id, size_t po_idx) const {
return (! m_blockers.empty() && ! m_blockers[layer_id].empty()); return (! m_blockers.at(po_idx).empty() && ! m_blockers.at(po_idx)[layer_id].polys.empty());
} }
}; };

View file

@ -338,19 +338,19 @@ double rad2deg_dir(double angle)
return rad2deg(angle); return rad2deg(angle);
} }
Point circle_taubin_newton(const Points::const_iterator& input_begin, const Points::const_iterator& input_end, size_t cycles) Point circle_center_taubin_newton(const Points::const_iterator& input_begin, const Points::const_iterator& input_end, size_t cycles)
{ {
Vec2ds tmp; Vec2ds tmp;
tmp.reserve(std::distance(input_begin, input_end)); tmp.reserve(std::distance(input_begin, input_end));
std::transform(input_begin, input_end, std::back_inserter(tmp), [] (const Point& in) { return unscale(in); } ); std::transform(input_begin, input_end, std::back_inserter(tmp), [] (const Point& in) { return unscale(in); } );
Vec2d center = circle_taubin_newton(tmp.cbegin(), tmp.end(), cycles); Vec2d center = circle_center_taubin_newton(tmp.cbegin(), tmp.end(), cycles);
return Point::new_scale(center.x(), center.y()); return Point::new_scale(center.x(), center.y());
} }
/// Adapted from work in "Circular and Linear Regression: Fitting circles and lines by least squares", pg 126 /// Adapted from work in "Circular and Linear Regression: Fitting circles and lines by least squares", pg 126
/// Returns a point corresponding to the center of a circle for which all of the points from input_begin to input_end /// Returns a point corresponding to the center of a circle for which all of the points from input_begin to input_end
/// lie on. /// lie on.
Vec2d circle_taubin_newton(const Vec2ds::const_iterator& input_begin, const Vec2ds::const_iterator& input_end, size_t cycles) Vec2d circle_center_taubin_newton(const Vec2ds::const_iterator& input_begin, const Vec2ds::const_iterator& input_end, size_t cycles)
{ {
// calculate the centroid of the data set // calculate the centroid of the data set
const Vec2d sum = std::accumulate(input_begin, input_end, Vec2d(0,0)); const Vec2d sum = std::accumulate(input_begin, input_end, Vec2d(0,0));

View file

@ -201,6 +201,57 @@ inline double ray_point_distance(const Line &iline, const Point &ipt)
} }
// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html // Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html
template<typename T>
inline bool liang_barsky_line_clipping_interval(
// Start and end points of the source line, result will be stored there as well.
const Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &x0,
const Eigen::Matrix<T, 2, 1, Eigen::DontAlign> &v,
// Bounding box to clip with.
const BoundingBoxBase<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &bbox,
std::pair<double, double> &out_interval)
{
double t0 = 0.0;
double t1 = 1.0;
// Traverse through left, right, bottom, top edges.
auto clip_side = [&x0, &v, &bbox, &t0, &t1](double p, double q) -> bool {
if (p == 0) {
if (q < 0)
// Line parallel to the bounding box edge is fully outside of the bounding box.
return false;
// else don't clip
} else {
double r = q / p;
if (p < 0) {
if (r > t1)
// Fully clipped.
return false;
if (r > t0)
// Partially clipped.
t0 = r;
} else {
assert(p > 0);
if (r < t0)
// Fully clipped.
return false;
if (r < t1)
// Partially clipped.
t1 = r;
}
}
return true;
};
if (clip_side(- v.x(), - bbox.min.x() + x0.x()) &&
clip_side( v.x(), bbox.max.x() - x0.x()) &&
clip_side(- v.y(), - bbox.min.y() + x0.y()) &&
clip_side( v.y(), bbox.max.y() - x0.y())) {
out_interval.first = t0;
out_interval.second = t1;
return true;
}
return false;
}
template<typename T> template<typename T>
inline bool liang_barsky_line_clipping( inline bool liang_barsky_line_clipping(
// Start and end points of the source line, result will be stored there as well. // Start and end points of the source line, result will be stored there as well.
@ -210,49 +261,12 @@ inline bool liang_barsky_line_clipping(
const BoundingBoxBase<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &bbox) const BoundingBoxBase<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &bbox)
{ {
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> v = x1 - x0; Eigen::Matrix<T, 2, 1, Eigen::DontAlign> v = x1 - x0;
double t0 = 0.0; std::pair<double, double> interval;
double t1 = 1.0; if (liang_barsky_line_clipping_interval(x0, v, bbox, interval)) {
// Clipped successfully.
// Traverse through left, right, bottom, top edges. x1 = x0 + interval.second * v;
for (int edge = 0; edge < 4; ++ edge) x0 += interval.first * v;
{
double p, q;
switch (edge) {
case 0: p = - v.x(); q = - bbox.min.x() + x0.x(); break;
case 1: p = v.x(); q = bbox.max.x() - x0.x(); break;
case 2: p = - v.y(); q = - bbox.min.y() + x0.y(); break;
default: p = v.y(); q = bbox.max.y() - x0.y(); break;
}
if (p == 0) {
if (q < 0)
// Line parallel to the bounding box edge is fully outside of the bounding box.
return false;
// else don't clip
} else {
double r = q / p;
if (p < 0) {
if (r > t1)
// Fully clipped.
return false;
if (r > t0)
// Partially clipped.
t0 = r;
} else {
assert(p > 0);
if (r < t0)
// Fully clipped.
return false;
if (r < t1)
// Partially clipped.
t1 = r;
}
}
} }
// Clipped successfully.
x1 = x0 + t1 * v;
x0 += t0 * v;
return true; return true;
} }
@ -273,6 +287,35 @@ bool liang_barsky_line_clipping(
return liang_barsky_line_clipping(x0clip, x1clip, bbox); return liang_barsky_line_clipping(x0clip, x1clip, bbox);
} }
// Ugly named variant, that accepts the squared line
// Don't call me with a nearly zero length vector!
template<typename T>
int ray_circle_intersections_r2_lv2_c(T r2, T a, T b, T lv2, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
{
T x0 = - a * c / lv2;
T y0 = - b * c / lv2;
T d = r2 - c * c / lv2;
if (d < T(0))
return 0;
T mult = sqrt(d / lv2);
out.first.x() = x0 + b * mult;
out.first.y() = y0 - a * mult;
out.second.x() = x0 - b * mult;
out.second.y() = y0 + a * mult;
return mult == T(0) ? 1 : 2;
}
template<typename T>
int ray_circle_intersections(T r, T a, T b, T c, std::pair<Eigen::Matrix<T, 2, 1, Eigen::DontAlign>, Eigen::Matrix<T, 2, 1, Eigen::DontAlign>> &out)
{
T lv2 = a * a + b * b;
if (lv2 < T(SCALED_EPSILON * SCALED_EPSILON)) {
//FIXME what is the correct epsilon?
// What if the line touches the circle?
return false;
}
return ray_circle_intersections_r2_lv2_c2(r * r, a, b, a * a + b * b, c, out);
}
Pointf3s convex_hull(Pointf3s points); Pointf3s convex_hull(Pointf3s points);
Polygon convex_hull(Points points); Polygon convex_hull(Points points);
Polygon convex_hull(const Polygons &polygons); Polygon convex_hull(const Polygons &polygons);
@ -298,12 +341,12 @@ template<typename T> T angle_to_0_2PI(T angle)
} }
/// Find the center of the circle corresponding to the vector of Points as an arc. /// Find the center of the circle corresponding to the vector of Points as an arc.
Point circle_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20); Point circle_center_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20);
inline Point circle_taubin_newton(const Points& input, size_t cycles = 20) { return circle_taubin_newton(input.cbegin(), input.cend(), cycles); } inline Point circle_center_taubin_newton(const Points& input, size_t cycles = 20) { return circle_center_taubin_newton(input.cbegin(), input.cend(), cycles); }
/// Find the center of the circle corresponding to the vector of Pointfs as an arc. /// Find the center of the circle corresponding to the vector of Pointfs as an arc.
Vec2d circle_taubin_newton(const Vec2ds::const_iterator& input_start, const Vec2ds::const_iterator& input_end, size_t cycles = 20); Vec2d circle_center_taubin_newton(const Vec2ds::const_iterator& input_start, const Vec2ds::const_iterator& input_end, size_t cycles = 20);
inline Vec2d circle_taubin_newton(const Vec2ds& input, size_t cycles = 20) { return circle_taubin_newton(input.cbegin(), input.cend(), cycles); } inline Vec2d circle_center_taubin_newton(const Vec2ds& input, size_t cycles = 20) { return circle_center_taubin_newton(input.cbegin(), input.cend(), cycles); }
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval); void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);

View file

@ -100,6 +100,13 @@ bool Line::clip_with_bbox(const BoundingBox &bbox)
return result; return result;
} }
void Line::extend(double offset)
{
Vector offset_vector = (offset * this->vector().cast<double>().normalized()).cast<coord_t>();
this->a -= offset_vector;
this->b += offset_vector;
}
Vec3d Linef3::intersect_plane(double z) const Vec3d Linef3::intersect_plane(double z) const
{ {
auto v = (this->b - this->a).cast<double>(); auto v = (this->b - this->a).cast<double>();

View file

@ -24,7 +24,7 @@ namespace line_alg {
template<class L, class T, int N> template<class L, class T, int N>
double distance_to_squared(const L &line, const Vec<N, T> &point) double distance_to_squared(const L &line, const Vec<N, T> &point)
{ {
const Vec<N, double> v = line.vector().template cast<double>(); const Vec<N, double> v = (line.b - line.a).template cast<double>();
const Vec<N, double> va = (point - line.a).template cast<double>(); const Vec<N, double> va = (point - line.a).template cast<double>();
const double l2 = v.squaredNorm(); // avoid a sqrt const double l2 = v.squaredNorm(); // avoid a sqrt
if (l2 == 0.0) if (l2 == 0.0)
@ -54,7 +54,8 @@ public:
Line(const Point& _a, const Point& _b) : a(_a), b(_b) {} Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}
explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; } explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
void scale(double factor) { this->a *= factor; this->b *= factor; } void scale(double factor) { this->a *= factor; this->b *= factor; }
void translate(double x, double y) { Vector v(x, y); this->a += v; this->b += v; } void translate(const Point &v) { this->a += v; this->b += v; }
void translate(double x, double y) { this->translate(Point(x, y)); }
void rotate(double angle, const Point &center) { this->a.rotate(angle, center); this->b.rotate(angle, center); } void rotate(double angle, const Point &center) { this->a.rotate(angle, center); this->b.rotate(angle, center); }
void reverse() { std::swap(this->a, this->b); } void reverse() { std::swap(this->a, this->b); }
double length() const { return (b - a).cast<double>().norm(); } double length() const { return (b - a).cast<double>().norm(); }
@ -75,6 +76,8 @@ public:
double ccw(const Point& point) const { return point.ccw(*this); } double ccw(const Point& point) const { return point.ccw(*this); }
// Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box. // Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box.
bool clip_with_bbox(const BoundingBox &bbox); bool clip_with_bbox(const BoundingBox &bbox);
// Extend the line from both sides by an offset.
void extend(double offset);
static inline double distance_to_squared(const Point &point, const Point &a, const Point &b) { return line_alg::distance_to_squared(Line{a, b}, Vec<2, coord_t>{point}); } static inline double distance_to_squared(const Point &point, const Point &a, const Point &b) { return line_alg::distance_to_squared(Line{a, b}, Vec<2, coord_t>{point}); }
static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); } static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }

View file

@ -49,7 +49,7 @@ Slic3r::arrangement::ArrangePolygon get_arrange_poly(const Model &model)
std::copy(pts.begin(), pts.end(), std::back_inserter(apts)); std::copy(pts.begin(), pts.end(), std::back_inserter(apts));
} }
apts = Geometry::convex_hull(apts); apts = std::move(Geometry::convex_hull(apts).points);
return ap; return ap;
} }

View file

@ -17,8 +17,6 @@ class MultiPoint
public: public:
Points points; Points points;
operator Points() const { return this->points; }
MultiPoint() {} MultiPoint() {}
MultiPoint(const MultiPoint &other) : points(other.points) {} MultiPoint(const MultiPoint &other) : points(other.points) {}
MultiPoint(MultiPoint &&other) : points(std::move(other.points)) {} MultiPoint(MultiPoint &&other) : points(std::move(other.points)) {}

View file

@ -1,100 +0,0 @@
#include "PNGRead.hpp"
#include <memory>
#include <cstdio>
#include <png.h>
namespace Slic3r { namespace png {
struct PNGDescr {
png_struct *png = nullptr; png_info *info = nullptr;
PNGDescr() = default;
PNGDescr(const PNGDescr&) = delete;
PNGDescr(PNGDescr&&) = delete;
PNGDescr& operator=(const PNGDescr&) = delete;
PNGDescr& operator=(PNGDescr&&) = delete;
~PNGDescr()
{
if (png && info) png_destroy_info_struct(png, &info);
if (png) png_destroy_read_struct( &png, nullptr, nullptr);
}
};
bool is_png(const ReadBuf &rb)
{
static const constexpr int PNG_SIG_BYTES = 8;
#if PNG_LIBPNG_VER_MINOR <= 2
// Earlier libpng versions had png_sig_cmp(png_bytep, ...) which is not
// a const pointer. It is not possible to cast away the const qualifier from
// the input buffer so... yes... life is challenging...
png_byte buf[PNG_SIG_BYTES];
auto inbuf = static_cast<const std::uint8_t *>(rb.buf);
std::copy(inbuf, inbuf + PNG_SIG_BYTES, buf);
#else
auto buf = static_cast<png_const_bytep>(rb.buf);
#endif
return rb.sz >= PNG_SIG_BYTES && !png_sig_cmp(buf, 0, PNG_SIG_BYTES);
}
// Buffer read callback for libpng. It provides an allocated output buffer and
// the amount of data it desires to read from the input.
void png_read_callback(png_struct *png_ptr,
png_bytep outBytes,
png_size_t byteCountToRead)
{
// Retrieve our input buffer through the png_ptr
auto reader = static_cast<IStream *>(png_get_io_ptr(png_ptr));
if (!reader || !reader->is_ok()) return;
reader->read(static_cast<std::uint8_t *>(outBytes), byteCountToRead);
}
bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
{
static const constexpr int PNG_SIG_BYTES = 8;
std::vector<png_byte> sig(PNG_SIG_BYTES, 0);
in_buf.read(sig.data(), PNG_SIG_BYTES);
if (!png_check_sig(sig.data(), PNG_SIG_BYTES))
return false;
PNGDescr dsc;
dsc.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
nullptr);
if(!dsc.png) return false;
dsc.info = png_create_info_struct(dsc.png);
if(!dsc.info) return false;
png_set_read_fn(dsc.png, static_cast<void *>(&in_buf), png_read_callback);
// Tell that we have already read the first bytes to check the signature
png_set_sig_bytes(dsc.png, PNG_SIG_BYTES);
png_read_info(dsc.png, dsc.info);
out_img.cols = png_get_image_width(dsc.png, dsc.info);
out_img.rows = png_get_image_height(dsc.png, dsc.info);
size_t color_type = png_get_color_type(dsc.png, dsc.info);
size_t bit_depth = png_get_bit_depth(dsc.png, dsc.info);
if (color_type != PNG_COLOR_TYPE_GRAY || bit_depth != 8)
return false;
out_img.buf.resize(out_img.rows * out_img.cols);
auto readbuf = static_cast<png_bytep>(out_img.buf.data());
for (size_t r = 0; r < out_img.rows; ++r)
png_read_row(dsc.png, readbuf + r * out_img.cols, nullptr);
return true;
}
}} // namespace Slic3r::png

View file

@ -0,0 +1,225 @@
#include "PNGReadWrite.hpp"
#include <memory>
#include <cstdio>
#include <png.h>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp>
namespace Slic3r { namespace png {
struct PNGDescr {
png_struct *png = nullptr; png_info *info = nullptr;
PNGDescr() = default;
PNGDescr(const PNGDescr&) = delete;
PNGDescr(PNGDescr&&) = delete;
PNGDescr& operator=(const PNGDescr&) = delete;
PNGDescr& operator=(PNGDescr&&) = delete;
~PNGDescr()
{
if (png && info) png_destroy_info_struct(png, &info);
if (png) png_destroy_read_struct( &png, nullptr, nullptr);
}
};
bool is_png(const ReadBuf &rb)
{
static const constexpr int PNG_SIG_BYTES = 8;
#if PNG_LIBPNG_VER_MINOR <= 2
// Earlier libpng versions had png_sig_cmp(png_bytep, ...) which is not
// a const pointer. It is not possible to cast away the const qualifier from
// the input buffer so... yes... life is challenging...
png_byte buf[PNG_SIG_BYTES];
auto inbuf = static_cast<const std::uint8_t *>(rb.buf);
std::copy(inbuf, inbuf + PNG_SIG_BYTES, buf);
#else
auto buf = static_cast<png_const_bytep>(rb.buf);
#endif
return rb.sz >= PNG_SIG_BYTES && !png_sig_cmp(buf, 0, PNG_SIG_BYTES);
}
// Buffer read callback for libpng. It provides an allocated output buffer and
// the amount of data it desires to read from the input.
static void png_read_callback(png_struct *png_ptr,
png_bytep outBytes,
png_size_t byteCountToRead)
{
// Retrieve our input buffer through the png_ptr
auto reader = static_cast<IStream *>(png_get_io_ptr(png_ptr));
if (!reader || !reader->is_ok()) return;
reader->read(static_cast<std::uint8_t *>(outBytes), byteCountToRead);
}
bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
{
static const constexpr int PNG_SIG_BYTES = 8;
std::vector<png_byte> sig(PNG_SIG_BYTES, 0);
in_buf.read(sig.data(), PNG_SIG_BYTES);
if (!png_check_sig(sig.data(), PNG_SIG_BYTES))
return false;
PNGDescr dsc;
dsc.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
nullptr);
if(!dsc.png) return false;
dsc.info = png_create_info_struct(dsc.png);
if(!dsc.info) return false;
png_set_read_fn(dsc.png, static_cast<void *>(&in_buf), png_read_callback);
// Tell that we have already read the first bytes to check the signature
png_set_sig_bytes(dsc.png, PNG_SIG_BYTES);
png_read_info(dsc.png, dsc.info);
out_img.cols = png_get_image_width(dsc.png, dsc.info);
out_img.rows = png_get_image_height(dsc.png, dsc.info);
size_t color_type = png_get_color_type(dsc.png, dsc.info);
size_t bit_depth = png_get_bit_depth(dsc.png, dsc.info);
if (color_type != PNG_COLOR_TYPE_GRAY || bit_depth != 8)
return false;
out_img.buf.resize(out_img.rows * out_img.cols);
auto readbuf = static_cast<png_bytep>(out_img.buf.data());
for (size_t r = 0; r < out_img.rows; ++r)
png_read_row(dsc.png, readbuf + r * out_img.cols, nullptr);
return true;
}
// Down to earth function to store a packed RGB image to file. Mostly useful for debugging purposes.
// Based on https://www.lemoda.net/c/write-png/
bool write_rgb_to_file(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb)
{
bool result = false;
// Forward declaration due to the gotos.
png_structp png_ptr = nullptr;
png_infop info_ptr = nullptr;
png_byte **row_pointers = nullptr;
FILE *fp = boost::nowide::fopen(file_name_utf8, "wb");
if (! fp) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: File could not be opened for writing: " << file_name_utf8;
goto fopen_failed;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (! png_ptr) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: png_create_write_struct() failed";
goto png_create_write_struct_failed;
}
info_ptr = png_create_info_struct(png_ptr);
if (! info_ptr) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: png_create_info_struct() failed";
goto png_create_info_struct_failed;
}
// Set up error handling.
if (setjmp(png_jmpbuf(png_ptr))) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: setjmp() failed";
goto png_failure;
}
// Set image attributes.
png_set_IHDR(png_ptr,
info_ptr,
png_uint_32(width),
png_uint_32(height),
8, // depth
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
// Initialize rows of PNG.
row_pointers = reinterpret_cast<png_byte**>(::png_malloc(png_ptr, height * sizeof(png_byte*)));
for (size_t y = 0; y < height; ++ y) {
auto row = reinterpret_cast<png_byte*>(::png_malloc(png_ptr, sizeof(uint8_t) * width * 3));
row_pointers[y] = row;
memcpy(row, data_rgb + width * y * 3, sizeof(uint8_t) * width * 3);
}
// Write the image data to "fp".
png_init_io(png_ptr, fp);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
for (size_t y = 0; y < height; ++ y)
png_free(png_ptr, row_pointers[y]);
png_free(png_ptr, row_pointers);
result = true;
png_failure:
png_create_info_struct_failed:
::png_destroy_write_struct(&png_ptr, &info_ptr);
png_create_write_struct_failed:
::fclose(fp);
fopen_failed:
return result;
}
bool write_rgb_to_file(const std::string &file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb)
{
return write_rgb_to_file(file_name_utf8.c_str(), width, height, data_rgb);
}
bool write_rgb_to_file(const std::string &file_name_utf8, size_t width, size_t height, const std::vector<uint8_t> &data_rgb)
{
assert(width * height * 3 == data_rgb.size());
return write_rgb_to_file(file_name_utf8.c_str(), width, height, data_rgb.data());
}
// Scaled variants are mostly useful for debugging purposes, for example to export images of low resolution distance fileds.
// Scaling is done by multiplying rows and columns without any smoothing to emphasise the original pixels.
bool write_rgb_to_file_scaled(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb, size_t scale)
{
if (scale <= 1)
return write_rgb_to_file(file_name_utf8, width, height, data_rgb);
else {
std::vector<uint8_t> scaled(width * height * 3 * scale * scale);
uint8_t *dst = scaled.data();
for (size_t r = 0; r < height; ++ r) {
for (size_t repr = 0; repr < scale; ++ repr) {
const uint8_t *row = data_rgb + width * 3 * r;
for (size_t c = 0; c < width; ++ c) {
for (size_t repc = 0; repc < scale; ++ repc) {
*dst ++ = row[0];
*dst ++ = row[1];
*dst ++ = row[2];
}
row += 3;
}
}
}
return write_rgb_to_file(file_name_utf8, width * scale, height * scale, scaled.data());
}
}
bool write_rgb_to_file_scaled(const std::string &file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb, size_t scale)
{
return write_rgb_to_file_scaled(file_name_utf8.c_str(), width, height, data_rgb, scale);
}
bool write_rgb_to_file_scaled(const std::string &file_name_utf8, size_t width, size_t height, const std::vector<uint8_t> &data_rgb, size_t scale)
{
assert(width * height * 3 == data_rgb.size());
return write_rgb_to_file_scaled(file_name_utf8.c_str(), width, height, data_rgb.data(), scale);
}
}} // namespace Slic3r::png

View file

@ -65,6 +65,18 @@ template<class Img> bool decode_png(const ReadBuf &in_buf, Img &out_img)
// TODO: std::istream of FILE* could be similarly adapted in case its needed... // TODO: std::istream of FILE* could be similarly adapted in case its needed...
// Down to earth function to store a packed RGB image to file. Mostly useful for debugging purposes.
bool write_rgb_to_file(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb);
bool write_rgb_to_file(const std::string &file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb);
bool write_rgb_to_file(const std::string &file_name_utf8, size_t width, size_t height, const std::vector<uint8_t> &data_rgb);
// Scaled variants are mostly useful for debugging purposes, for example to export images of low resolution distance fileds.
// Scaling is done by multiplying rows and columns without any smoothing to emphasise the original pixels.
bool write_rgb_to_file_scaled(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb, size_t scale);
bool write_rgb_to_file_scaled(const std::string &file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb, size_t scale);
bool write_rgb_to_file_scaled(const std::string &file_name_utf8, size_t width, size_t height, const std::vector<uint8_t> &data_rgb, size_t scale);
}} // namespace Slic3r::png }} // namespace Slic3r::png
#endif // PNGREAD_HPP #endif // PNGREAD_HPP

View file

@ -158,7 +158,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// get non-overhang paths by intersecting this loop with the grown lower slices // get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append( extrusion_paths_append(
paths, paths,
intersection_pl(loop.polygon, perimeter_generator.lower_slices_polygons()), intersection_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()),
role, role,
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(), is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(),
is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width, is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width,
@ -169,7 +169,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// the loop centerline and original lower slices is >= half nozzle diameter // the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append( extrusion_paths_append(
paths, paths,
diff_pl(loop.polygon, perimeter_generator.lower_slices_polygons()), diff_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()),
erOverhangPerimeter, erOverhangPerimeter,
perimeter_generator.mm3_per_mm_overhang(), perimeter_generator.mm3_per_mm_overhang(),
perimeter_generator.overhang_flow.width, perimeter_generator.overhang_flow.width,

View file

@ -2,6 +2,7 @@
#include "Line.hpp" #include "Line.hpp"
#include "MultiPoint.hpp" #include "MultiPoint.hpp"
#include "Int128.hpp" #include "Int128.hpp"
#include "BoundingBox.hpp"
#include <algorithm> #include <algorithm>
namespace Slic3r { namespace Slic3r {
@ -176,6 +177,19 @@ Point Point::projection_onto(const Line &line) const
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b; return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
} }
BoundingBox get_extents(const Points &pts)
{
return BoundingBox(pts);
}
BoundingBox get_extents(const std::vector<Points> &pts)
{
BoundingBox bbox;
for (const Points &p : pts)
bbox.merge(get_extents(p));
return bbox;
}
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf) std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf)
{ {
return stm << pointf(0) << "," << pointf(1); return stm << pointf(0) << "," << pointf(1);

View file

@ -13,6 +13,7 @@
namespace Slic3r { namespace Slic3r {
class BoundingBox;
class Line; class Line;
class MultiPoint; class MultiPoint;
class Point; class Point;
@ -55,23 +56,20 @@ typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d
inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); } inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); }
inline int32_t cross2(const Vec2i32 &v1, const Vec2i32 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } // One likely does not want to perform the cross product with a 32bit accumulator.
//inline int32_t cross2(const Vec2i32 &v1, const Vec2i32 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); } inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
template<class T, int N> Eigen::Matrix<T, 2, 1, Eigen::DontAlign> template<typename T, int Options>
to_2d(const Eigen::Matrix<T, N, 1, Eigen::DontAlign> &ptN) { return {ptN(0), ptN(1)}; } inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); }
//inline Vec2i32 to_2d(const Vec3i32 &pt3) { return Vec2i32(pt3(0), pt3(1)); } template<class T, int N, int Options>
//inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); } Eigen::Matrix<T, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Eigen::Matrix<T, N, 1, Options>> &ptN) { return { ptN(0), ptN(1) }; }
//inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
//inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); }
inline Vec3d to_3d(const Vec2d &v, double z) { return Vec3d(v(0), v(1), z); } template<class T, int Options>
inline Vec3f to_3d(const Vec2f &v, float z) { return Vec3f(v(0), v(1), z); } Eigen::Matrix<T, 3, 1, Eigen::DontAlign> to_3d(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> & pt, const T z) { return { pt(0), pt(1), z }; }
inline Vec3i64 to_3d(const Vec2i64 &v, float z) { return Vec3i64(int64_t(v(0)), int64_t(v(1)), int64_t(z)); }
inline Vec3crd to_3d(const Vec3crd &p, coord_t z) { return Vec3crd(p(0), p(1), z); }
inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); } inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); }
inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); } inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); }
@ -132,6 +130,7 @@ public:
void rotate(double angle, const Point &center); void rotate(double angle, const Point &center);
Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; } Point rotated(double angle) const { Point res(*this); res.rotate(angle); return res; }
Point rotated(double cos_a, double sin_a) const { Point res(*this); res.rotate(cos_a, sin_a); return res; }
Point rotated(double angle, const Point &center) const { Point res(*this); res.rotate(angle, center); return res; } Point rotated(double angle, const Point &center) const { Point res(*this); res.rotate(angle, center); return res; }
int nearest_point_index(const Points &points) const; int nearest_point_index(const Points &points) const;
int nearest_point_index(const PointConstPtrs &points) const; int nearest_point_index(const PointConstPtrs &points) const;
@ -174,6 +173,15 @@ inline bool is_approx(const Vec3d &p1, const Vec3d &p2, double epsilon = EPSILON
return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon; return d.x() < epsilon && d.y() < epsilon && d.z() < epsilon;
} }
inline Point lerp(const Point &a, const Point &b, double t)
{
assert((t >= -EPSILON) && (t <= 1. + EPSILON));
return ((1. - t) * a.cast<double>() + t * b.cast<double>()).cast<coord_t>();
}
extern BoundingBox get_extents(const Points &pts);
extern BoundingBox get_extents(const std::vector<Points> &pts);
namespace int128 { namespace int128 {
// Exact orientation predicate, // Exact orientation predicate,
// returns +1: CCW, 0: collinear, -1: CW. // returns +1: CCW, 0: collinear, -1: CW.
@ -291,6 +299,33 @@ public:
std::make_pair(nullptr, std::numeric_limits<double>::max()); std::make_pair(nullptr, std::numeric_limits<double>::max());
} }
// Returns all pairs of values and squared distances.
std::vector<std::pair<const ValueType*, double>> find_all(const Vec2crd &pt) {
// Iterate over 4 closest grid cells around pt,
// Round pt to a closest grid_cell corner.
Vec2crd grid_corner((pt(0)+(m_grid_resolution>>1))>>m_grid_log2, (pt(1)+(m_grid_resolution>>1))>>m_grid_log2);
// For four neighbors of grid_corner:
std::vector<std::pair<const ValueType*, double>> out;
const double r2 = double(m_search_radius) * m_search_radius;
for (coord_t neighbor_y = -1; neighbor_y < 1; ++ neighbor_y) {
for (coord_t neighbor_x = -1; neighbor_x < 1; ++ neighbor_x) {
// Range of fragment starts around grid_corner, close to pt.
auto range = m_map.equal_range(Vec2crd(grid_corner(0) + neighbor_x, grid_corner(1) + neighbor_y));
// Find the map entry closest to pt.
for (auto it = range.first; it != range.second; ++it) {
const ValueType &value = it->second;
const Vec2crd *pt2 = m_point_accessor(value);
if (pt2 != nullptr) {
const double d2 = (pt - *pt2).cast<double>().squaredNorm();
if (d2 <= r2)
out.emplace_back(&value, d2);
}
}
}
}
return out;
}
private: private:
typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type; typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type;
PointAccessor m_point_accessor; PointAccessor m_point_accessor;

View file

@ -298,11 +298,6 @@ void Polygon::densify(float min_length, std::vector<float>* lengths_ptr)
assert(points.size() == lengths.size() - 1); assert(points.size() == lengths.size() - 1);
} }
BoundingBox get_extents(const Points &points)
{
return BoundingBox(points);
}
BoundingBox get_extents(const Polygon &poly) BoundingBox get_extents(const Polygon &poly)
{ {
return poly.bounding_box(); return poly.bounding_box();

View file

@ -16,12 +16,12 @@ typedef std::vector<Polygon> Polygons;
class Polygon : public MultiPoint class Polygon : public MultiPoint
{ {
public: public:
operator Polygons() const { Polygons pp; pp.push_back(*this); return pp; } explicit operator Polygons() const { Polygons pp; pp.push_back(*this); return pp; }
operator Polyline() const { return this->split_at_first_point(); } explicit operator Polyline() const { return this->split_at_first_point(); }
Point& operator[](Points::size_type idx) { return this->points[idx]; } Point& operator[](Points::size_type idx) { return this->points[idx]; }
const Point& operator[](Points::size_type idx) const { return this->points[idx]; } const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
Polygon() {} Polygon() = default;
virtual ~Polygon() = default; virtual ~Polygon() = default;
explicit Polygon(const Points &points) : MultiPoint(points) {} explicit Polygon(const Points &points) : MultiPoint(points) {}
Polygon(std::initializer_list<Point> points) : MultiPoint(points) {} Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
@ -74,7 +74,6 @@ public:
inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; } inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; }
inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; } inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; }
extern BoundingBox get_extents(const Points &points);
extern BoundingBox get_extents(const Polygon &poly); extern BoundingBox get_extents(const Polygon &poly);
extern BoundingBox get_extents(const Polygons &polygons); extern BoundingBox get_extents(const Polygons &polygons);
extern BoundingBox get_extents_rotated(const Polygon &poly, double angle); extern BoundingBox get_extents_rotated(const Polygon &poly, double angle);

View file

@ -200,7 +200,7 @@ BoundingBox get_extents(const Polylines &polylines)
if (! polylines.empty()) { if (! polylines.empty()) {
bb = polylines.front().bounding_box(); bb = polylines.front().bounding_box();
for (size_t i = 1; i < polylines.size(); ++ i) for (size_t i = 1; i < polylines.size(); ++ i)
bb.merge(polylines[i]); bb.merge(polylines[i].points);
} }
return bb; return bb;
} }

View file

@ -60,8 +60,8 @@ public:
} }
} }
operator Polylines() const; explicit operator Polylines() const;
operator Line() const; explicit operator Line() const;
const Point& last_point() const override { return this->points.back(); } const Point& last_point() const override { return this->points.back(); }
const Point& leftmost_point() const; const Point& leftmost_point() const;

View file

@ -427,7 +427,7 @@ const std::vector<std::string>& Preset::print_options()
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects",
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming",
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits" "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits"
@ -439,7 +439,7 @@ const std::vector<std::string>& Preset::filament_options()
{ {
static std::vector<std::string> s_opts { static std::vector<std::string> s_opts {
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
"extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time", "extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
"filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves",
"filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
"temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
@ -1840,8 +1840,11 @@ namespace PresetUtils {
{ {
std::string out; std::string out;
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset); const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && !pm->bed_model.empty()) if (pm != nullptr && !pm->bed_model.empty()) {
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model; out = Slic3r::data_dir() + "/vendor/" + preset.vendor->id + "/" + pm->bed_model;
if (!boost::filesystem::exists(boost::filesystem::path(out)))
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model;
}
return out; return out;
} }
@ -1849,8 +1852,11 @@ namespace PresetUtils {
{ {
std::string out; std::string out;
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset); const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && !pm->bed_texture.empty()) if (pm != nullptr && !pm->bed_texture.empty()) {
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture; out = Slic3r::data_dir() + "/vendor/" + preset.vendor->id + "/" + pm->bed_texture;
if (!boost::filesystem::exists(boost::filesystem::path(out)))
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
}
return out; return out;
} }
} // namespace PresetUtils } // namespace PresetUtils

View file

@ -99,6 +99,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"filament_density", "filament_density",
"filament_notes", "filament_notes",
"filament_cost", "filament_cost",
"filament_spool_weight",
"first_layer_acceleration", "first_layer_acceleration",
"first_layer_bed_temperature", "first_layer_bed_temperature",
"first_layer_speed", "first_layer_speed",
@ -1220,9 +1221,9 @@ static inline bool sequential_print_horizontal_clearance_valid(const Print &prin
// instance.shift is a position of a centered object, while model object may not be centered. // instance.shift is a position of a centered object, while model object may not be centered.
// Conver the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset. // Conver the shift from the PrintObject's coordinates into ModelObject's coordinates by removing the centering offset.
convex_hull.translate(instance.shift - print_object->center_offset()); convex_hull.translate(instance.shift - print_object->center_offset());
if (! intersection(convex_hulls_other, convex_hull).empty()) if (! intersection(convex_hulls_other, (Polygons)convex_hull).empty())
return false; return false;
polygons_append(convex_hulls_other, convex_hull); convex_hulls_other.emplace_back(std::move(convex_hull));
} }
} }
return true; return true;

View file

@ -470,12 +470,14 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonic"); def->enum_values.push_back("monotonic");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("concentric"); def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve"); def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("archimedeanchords"); def->enum_values.push_back("archimedeanchords");
def->enum_values.push_back("octagramspiral"); def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Monotonic")); def->enum_labels.push_back(L("Monotonic"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Concentric")); def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Hilbert Curve")); def->enum_labels.push_back(L("Hilbert Curve"));
def->enum_labels.push_back(L("Archimedean Chords")); def->enum_labels.push_back(L("Archimedean Chords"));
@ -493,7 +495,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values = def_top_fill_pattern->enum_values; def->enum_values = def_top_fill_pattern->enum_values;
def->enum_labels = def_top_fill_pattern->enum_labels; def->enum_labels = def_top_fill_pattern->enum_labels;
def->aliases = def_top_fill_pattern->aliases; def->aliases = def_top_fill_pattern->aliases;
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear)); def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipMonotonic));
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent); def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
def->label = L("External perimeters"); def->label = L("External perimeters");
@ -816,6 +818,16 @@ void PrintConfigDef::init_fff_params()
def->min = 0; def->min = 0;
def->set_default_value(new ConfigOptionFloats { 0. }); def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_spool_weight", coFloats);
def->label = L("Spool weight");
def->tooltip = L("Enter weight of the empty filament spool. "
"One may weigh a partially consumed filament spool before printing and one may compare the measured weight "
"with the calculated weight of the filament with the spool to find out whether the amount "
"of filament on the spool is sufficient to finish the print.");
def->sidetext = L("g");
def->min = 0;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_settings_id", coStrings); def = this->add("filament_settings_id", coStrings);
def->set_default_value(new ConfigOptionStrings { "" }); def->set_default_value(new ConfigOptionStrings { "" });
def->cli = ConfigOptionDef::nocli; def->cli = ConfigOptionDef::nocli;
@ -881,6 +893,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Fill pattern for general low-density infill."); def->tooltip = L("Fill pattern for general low-density infill.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("grid"); def->enum_values.push_back("grid");
def->enum_values.push_back("triangles"); def->enum_values.push_back("triangles");
def->enum_values.push_back("stars"); def->enum_values.push_back("stars");
@ -896,6 +909,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("adaptivecubic"); def->enum_values.push_back("adaptivecubic");
def->enum_values.push_back("supportcubic"); def->enum_values.push_back("supportcubic");
def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Aligned Rectilinear"));
def->enum_labels.push_back(L("Grid")); def->enum_labels.push_back(L("Grid"));
def->enum_labels.push_back(L("Triangles")); def->enum_labels.push_back(L("Triangles"));
def->enum_labels.push_back(L("Stars")); def->enum_labels.push_back(L("Stars"));
@ -1060,6 +1074,55 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(1)); def->set_default_value(new ConfigOptionInt(1));
auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent);
def->label = L("Length of the infill anchor");
def->category = L("Advanced");
def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. "
"If expressed as percentage (example: 15%) it is calculated over infill extrusion width. "
"PrusaSlicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment "
"shorter than infill_anchor_max is found, the infill line is connected to a perimeter segment at just one side "
"and the length of the perimeter segment taken is limited to this parameter, but no longer than anchor_length_max. "
"Set this parameter to zero to disable anchoring perimeters connected to a single infill line.");
def->sidetext = L("mm or %");
def->ratio_over = "infill_extrusion_width";
def->gui_type = "f_enum_open";
def->enum_values.push_back("0");
def->enum_values.push_back("1");
def->enum_values.push_back("2");
def->enum_values.push_back("5");
def->enum_values.push_back("10");
def->enum_values.push_back("1000");
def->enum_labels.push_back(L("0 (no open anchors)"));
def->enum_labels.push_back("1 mm");
def->enum_labels.push_back("2 mm");
def->enum_labels.push_back("5 mm");
def->enum_labels.push_back("10 mm");
def->enum_labels.push_back(L("1000 (unlimited)"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(600, true));
def = this->add("infill_anchor_max", coFloatOrPercent);
def->label = L("Maximum length of the infill anchor");
def->category = def_infill_anchor_min->category;
def->tooltip = L("Connect an infill line to an internal perimeter with a short segment of an additional perimeter. "
"If expressed as percentage (example: 15%) it is calculated over infill extrusion width. "
"PrusaSlicer tries to connect two close infill lines to a short perimeter segment. If no such perimeter segment "
"shorter than this parameter is found, the infill line is connected to a perimeter segment at just one side "
"and the length of the perimeter segment taken is limited to infill_anchor, but no longer than this parameter. "
"Set this parameter to zero to disable anchoring.");
def->sidetext = def_infill_anchor_min->sidetext;
def->ratio_over = def_infill_anchor_min->ratio_over;
def->gui_type = def_infill_anchor_min->gui_type;
def->enum_values = def_infill_anchor_min->enum_values;
def->enum_labels.push_back(L("0 (not anchored)"));
def->enum_labels.push_back("1 mm");
def->enum_labels.push_back("2 mm");
def->enum_labels.push_back("5 mm");
def->enum_labels.push_back("10 mm");
def->enum_labels.push_back(L("1000 (unlimited)"));
def->mode = def_infill_anchor_min->mode;
def->set_default_value(new ConfigOptionFloatOrPercent(50, false));
def = this->add("infill_extruder", coInt); def = this->add("infill_extruder", coInt);
def->label = L("Infill extruder"); def->label = L("Infill extruder");
def->category = L("Extruders"); def->category = L("Extruders");
@ -1527,8 +1590,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("perimeter_acceleration", coFloat); def = this->add("perimeter_acceleration", coFloat);
def->label = L("Perimeters"); def->label = L("Perimeters");
def->tooltip = L("This is the acceleration your printer will use for perimeters. " def->tooltip = L("This is the acceleration your printer will use for perimeters. "
"A high value like 9000 usually gives good results if your hardware is up to the job. " "Set zero to disable acceleration control for perimeters.");
"Set zero to disable acceleration control for perimeters.");
def->sidetext = L("mm/s²"); def->sidetext = L("mm/s²");
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));

View file

@ -44,7 +44,7 @@ enum AuthorizationType {
}; };
enum InfillPattern : int { enum InfillPattern : int {
ipRectilinear, ipMonotonic, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, ipRectilinear, ipMonotonic, ipAlignedRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount, ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipAdaptiveCubic, ipSupportCubic, ipCount,
}; };
@ -145,6 +145,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
if (keys_map.empty()) { if (keys_map.empty()) {
keys_map["rectilinear"] = ipRectilinear; keys_map["rectilinear"] = ipRectilinear;
keys_map["monotonic"] = ipMonotonic; keys_map["monotonic"] = ipMonotonic;
keys_map["alignedrectilinear"] = ipAlignedRectilinear;
keys_map["grid"] = ipGrid; keys_map["grid"] = ipGrid;
keys_map["triangles"] = ipTriangles; keys_map["triangles"] = ipTriangles;
keys_map["stars"] = ipStars; keys_map["stars"] = ipStars;
@ -530,6 +531,8 @@ public:
ConfigOptionPercent fill_density; ConfigOptionPercent fill_density;
ConfigOptionEnum<InfillPattern> fill_pattern; ConfigOptionEnum<InfillPattern> fill_pattern;
ConfigOptionFloat gap_fill_speed; ConfigOptionFloat gap_fill_speed;
ConfigOptionFloatOrPercent infill_anchor;
ConfigOptionFloatOrPercent infill_anchor_max;
ConfigOptionInt infill_extruder; ConfigOptionInt infill_extruder;
ConfigOptionFloatOrPercent infill_extrusion_width; ConfigOptionFloatOrPercent infill_extrusion_width;
ConfigOptionInt infill_every_layers; ConfigOptionInt infill_every_layers;
@ -581,6 +584,8 @@ protected:
OPT_PTR(fill_density); OPT_PTR(fill_density);
OPT_PTR(fill_pattern); OPT_PTR(fill_pattern);
OPT_PTR(gap_fill_speed); OPT_PTR(gap_fill_speed);
OPT_PTR(infill_anchor);
OPT_PTR(infill_anchor_max);
OPT_PTR(infill_extruder); OPT_PTR(infill_extruder);
OPT_PTR(infill_extrusion_width); OPT_PTR(infill_extrusion_width);
OPT_PTR(infill_every_layers); OPT_PTR(infill_every_layers);
@ -681,6 +686,7 @@ public:
ConfigOptionStrings filament_type; ConfigOptionStrings filament_type;
ConfigOptionBools filament_soluble; ConfigOptionBools filament_soluble;
ConfigOptionFloats filament_cost; ConfigOptionFloats filament_cost;
ConfigOptionFloats filament_spool_weight;
ConfigOptionFloats filament_max_volumetric_speed; ConfigOptionFloats filament_max_volumetric_speed;
ConfigOptionFloats filament_loading_speed; ConfigOptionFloats filament_loading_speed;
ConfigOptionFloats filament_loading_speed_start; ConfigOptionFloats filament_loading_speed_start;
@ -757,6 +763,7 @@ protected:
OPT_PTR(filament_type); OPT_PTR(filament_type);
OPT_PTR(filament_soluble); OPT_PTR(filament_soluble);
OPT_PTR(filament_cost); OPT_PTR(filament_cost);
OPT_PTR(filament_spool_weight);
OPT_PTR(filament_max_volumetric_speed); OPT_PTR(filament_max_volumetric_speed);
OPT_PTR(filament_loading_speed); OPT_PTR(filament_loading_speed);
OPT_PTR(filament_loading_speed_start); OPT_PTR(filament_loading_speed_start);

View file

@ -11,7 +11,6 @@
#include "Slicing.hpp" #include "Slicing.hpp"
#include "Tesselate.hpp" #include "Tesselate.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "AABBTreeIndirect.hpp"
#include "Fill/FillAdaptive.hpp" #include "Fill/FillAdaptive.hpp"
#include "Format/STL.hpp" #include "Format/STL.hpp"
@ -590,7 +589,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "external_fill_link_max_length" || opt_key == "external_fill_link_max_length"
|| opt_key == "fill_angle" || opt_key == "fill_angle"
|| opt_key == "fill_pattern" || opt_key == "fill_pattern"
|| opt_key == "fill_link_max_length" || opt_key == "infill_anchor"
|| opt_key == "infill_anchor_max"
|| opt_key == "top_infill_extrusion_width" || opt_key == "top_infill_extrusion_width"
|| opt_key == "first_layer_extrusion_width") { || opt_key == "first_layer_extrusion_width") {
steps.emplace_back(posInfill); steps.emplace_back(posInfill);

View file

@ -369,7 +369,7 @@ bool add_cavity(Contour3D &pad, ExPolygon &top_poly, const PadConfig3D &cfg,
if (inner_base.empty() || middle_base.empty()) { logerr(); return false; } if (inner_base.empty() || middle_base.empty()) { logerr(); return false; }
ExPolygons pdiff = diff_ex(top_poly, middle_base.contour); ExPolygons pdiff = diff_ex((Polygons)top_poly, (Polygons)middle_base.contour);
if (pdiff.size() != 1) { logerr(); return false; } if (pdiff.size() != 1) { logerr(); return false; }

View file

@ -350,6 +350,7 @@ struct SLAPrintStatistics
size_t fast_layers_count; size_t fast_layers_count;
double total_cost; double total_cost;
double total_weight; double total_weight;
std::vector<double> layers_times;
// Config with the filled in print statistics. // Config with the filled in print statistics.
DynamicConfig config() const; DynamicConfig config() const;
@ -366,6 +367,7 @@ struct SLAPrintStatistics
fast_layers_count = 0; fast_layers_count = 0;
total_cost = 0.; total_cost = 0.;
total_weight = 0.; total_weight = 0.;
layers_times.clear();
} }
}; };

View file

@ -671,6 +671,8 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
double models_volume(0.0); double models_volume(0.0);
double estim_time(0.0); double estim_time(0.0);
std::vector<double> layers_times;
layers_times.reserve(printer_input.size());
size_t slow_layers = 0; size_t slow_layers = 0;
size_t fast_layers = 0; size_t fast_layers = 0;
@ -688,7 +690,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// write vars // write vars
&mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers,
&fast_layers, &fade_layer_time](size_t sliced_layer_cnt) &fast_layers, &fade_layer_time, &layers_times](size_t sliced_layer_cnt)
{ {
PrintLayer &layer = m_print->m_printer_input[sliced_layer_cnt]; PrintLayer &layer = m_print->m_printer_input[sliced_layer_cnt];
@ -775,20 +777,21 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
else else
slow_layers++; slow_layers++;
// Calculation of the printing time // Calculation of the printing time
double layer_times = 0.0;
if (sliced_layer_cnt < 3) if (sliced_layer_cnt < 3)
estim_time += init_exp_time; layer_times += init_exp_time;
else if (fade_layer_time > exp_time) else if (fade_layer_time > exp_time) {
{
fade_layer_time -= delta_fade_time; fade_layer_time -= delta_fade_time;
estim_time += fade_layer_time; layer_times += fade_layer_time;
} }
else else
estim_time += exp_time; layer_times += exp_time;
layer_times += tilt_time;
estim_time += tilt_time;
layers_times.push_back(layer_times);
estim_time += layer_times;
} }
}; };
@ -804,8 +807,10 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// A layers count o the highest object // A layers count o the highest object
if (printer_input.size() == 0) if (printer_input.size() == 0)
print_statistics.estimated_print_time = std::nan(""); print_statistics.estimated_print_time = std::nan("");
else else {
print_statistics.estimated_print_time = estim_time; print_statistics.estimated_print_time = estim_time;
print_statistics.layers_times = layers_times;
}
print_statistics.fast_layers_count = fast_layers; print_statistics.fast_layers_count = fast_layers;
print_statistics.slow_layers_count = slow_layers; print_statistics.slow_layers_count = slow_layers;

View file

@ -3,8 +3,6 @@
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#define COORD(x) (unscale<float>((x))*10)
namespace Slic3r { namespace Slic3r {
bool SVG::open(const char* afilename) bool SVG::open(const char* afilename)
@ -33,8 +31,9 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo
this->f = boost::nowide::fopen(afilename, "w"); this->f = boost::nowide::fopen(afilename, "w");
if (f == NULL) if (f == NULL)
return false; return false;
float w = COORD(bbox.max(0) - bbox.min(0) + 2 * bbox_offset); float w = to_svg_coord(bbox.max(0) - bbox.min(0) + 2 * bbox_offset);
float h = COORD(bbox.max(1) - bbox.min(1) + 2 * bbox_offset); float h = to_svg_coord(bbox.max(1) - bbox.min(1) + 2 * bbox_offset);
this->height = h;
fprintf(this->f, fprintf(this->f,
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
@ -47,12 +46,11 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo
return true; return true;
} }
void void SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
{ {
fprintf(this->f, fprintf(this->f,
" <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"", " <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke: %s; stroke-width: %f\"",
COORD(line.a(0) - origin(0)), COORD(line.a(1) - origin(1)), COORD(line.b(0) - origin(0)), COORD(line.b(1) - origin(1)), stroke.c_str(), (stroke_width == 0) ? 1.f : COORD(stroke_width)); to_svg_x(line.a(0) - origin(0)), to_svg_y(line.a(1) - origin(1)), to_svg_x(line.b(0) - origin(0)), to_svg_y(line.b(1) - origin(1)), stroke.c_str(), (stroke_width == 0) ? 1.f : to_svg_coord(stroke_width));
if (this->arrows) if (this->arrows)
fprintf(this->f, " marker-end=\"url(#endArrow)\""); fprintf(this->f, " marker-end=\"url(#endArrow)\"");
fprintf(this->f, "/>\n"); fprintf(this->f, "/>\n");
@ -67,34 +65,31 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string
coordf_t db = coordf_t(0.5)*line.b_width/len; coordf_t db = coordf_t(0.5)*line.b_width/len;
fprintf(this->f, fprintf(this->f,
" <polygon points=\"%f,%f %f,%f %f,%f %f,%f\" style=\"fill:%s; stroke: %s; stroke-width: %f\"/>\n", " <polygon points=\"%f,%f %f,%f %f,%f %f,%f\" style=\"fill:%s; stroke: %s; stroke-width: %f\"/>\n",
COORD(line.a(0)-da*perp(0)-origin(0)), to_svg_x(line.a(0)-da*perp(0)-origin(0)),
COORD(line.a(1)-da*perp(1)-origin(1)), to_svg_y(line.a(1)-da*perp(1)-origin(1)),
COORD(line.b(0)-db*perp(0)-origin(0)), to_svg_x(line.b(0)-db*perp(0)-origin(0)),
COORD(line.b(1)-db*perp(1)-origin(1)), to_svg_y(line.b(1)-db*perp(1)-origin(1)),
COORD(line.b(0)+db*perp(0)-origin(0)), to_svg_x(line.b(0)+db*perp(0)-origin(0)),
COORD(line.b(1)+db*perp(1)-origin(1)), to_svg_y(line.b(1)+db*perp(1)-origin(1)),
COORD(line.a(0)+da*perp(0)-origin(0)), to_svg_x(line.a(0)+da*perp(0)-origin(0)),
COORD(line.a(1)+da*perp(1)-origin(1)), to_svg_y(line.a(1)+da*perp(1)-origin(1)),
fill.c_str(), stroke.c_str(), fill.c_str(), stroke.c_str(),
(stroke_width == 0) ? 1.f : COORD(stroke_width)); (stroke_width == 0) ? 1.f : to_svg_coord(stroke_width));
} }
void void SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
{ {
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it) for (const Line &l : lines)
this->draw(*it, stroke, stroke_width); this->draw(l, stroke, stroke_width);
} }
void void SVG::draw(const IntersectionLines &lines, std::string stroke)
SVG::draw(const IntersectionLines &lines, std::string stroke)
{ {
for (IntersectionLines::const_iterator it = lines.begin(); it != lines.end(); ++it) for (const IntersectionLine &il : lines)
this->draw((Line)*it, stroke); this->draw((Line)il, stroke);
} }
void void SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity)
SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity)
{ {
this->fill = fill; this->fill = fill;
@ -106,8 +101,7 @@ SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity
this->path(d, true, 0, fill_opacity); this->path(d, true, 0, fill_opacity);
} }
void void SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
draw_outline(expolygon.contour, stroke_outer, stroke_width); draw_outline(expolygon.contour, stroke_outer, stroke_width);
for (Polygons::const_iterator it = expolygon.holes.begin(); it != expolygon.holes.end(); ++ it) { for (Polygons::const_iterator it = expolygon.holes.begin(); it != expolygon.holes.end(); ++ it) {
@ -115,83 +109,71 @@ SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::str
} }
} }
void void SVG::draw(const ExPolygons &expolygons, std::string fill, const float fill_opacity)
SVG::draw(const ExPolygons &expolygons, std::string fill, const float fill_opacity)
{ {
for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++it) for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++it)
this->draw(*it, fill, fill_opacity); this->draw(*it, fill, fill_opacity);
} }
void void SVG::draw_outline(const ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
SVG::draw_outline(const ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++ it) for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++ it)
draw_outline(*it, stroke_outer, stroke_holes, stroke_width); draw_outline(*it, stroke_outer, stroke_holes, stroke_width);
} }
void void SVG::draw(const Surface &surface, std::string fill, const float fill_opacity)
SVG::draw(const Surface &surface, std::string fill, const float fill_opacity)
{ {
draw(surface.expolygon, fill, fill_opacity); draw(surface.expolygon, fill, fill_opacity);
} }
void void SVG::draw_outline(const Surface &surface, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
SVG::draw_outline(const Surface &surface, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
draw_outline(surface.expolygon, stroke_outer, stroke_holes, stroke_width); draw_outline(surface.expolygon, stroke_outer, stroke_holes, stroke_width);
} }
void void SVG::draw(const Surfaces &surfaces, std::string fill, const float fill_opacity)
SVG::draw(const Surfaces &surfaces, std::string fill, const float fill_opacity)
{ {
for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it)
this->draw(*it, fill, fill_opacity); this->draw(*it, fill, fill_opacity);
} }
void void SVG::draw_outline(const Surfaces &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
SVG::draw_outline(const Surfaces &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it) for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it)
draw_outline(*it, stroke_outer, stroke_holes, stroke_width); draw_outline(*it, stroke_outer, stroke_holes, stroke_width);
} }
void void SVG::draw(const SurfacesPtr &surfaces, std::string fill, const float fill_opacity)
SVG::draw(const SurfacesPtr &surfaces, std::string fill, const float fill_opacity)
{ {
for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it)
this->draw(*(*it), fill, fill_opacity); this->draw(*(*it), fill, fill_opacity);
} }
void void SVG::draw_outline(const SurfacesPtr &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
SVG::draw_outline(const SurfacesPtr &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
{ {
for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it) for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it)
draw_outline(*(*it), stroke_outer, stroke_holes, stroke_width); draw_outline(*(*it), stroke_outer, stroke_holes, stroke_width);
} }
void void SVG::draw(const Polygon &polygon, std::string fill)
SVG::draw(const Polygon &polygon, std::string fill)
{ {
this->fill = fill; this->fill = fill;
this->path(this->get_path_d(polygon, true), !fill.empty(), 0, 1.f); this->path(this->get_path_d(polygon, true), !fill.empty(), 0, 1.f);
} }
void void SVG::draw(const Polygons &polygons, std::string fill)
SVG::draw(const Polygons &polygons, std::string fill)
{ {
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it) for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it)
this->draw(*it, fill); this->draw(*it, fill);
} }
void void SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width)
SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width)
{ {
this->stroke = stroke; this->stroke = stroke;
this->path(this->get_path_d(polyline, false), false, stroke_width, 1.f); this->path(this->get_path_d(polyline, false), false, stroke_width, 1.f);
} }
void void SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width)
SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width)
{ {
for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
this->draw(*it, stroke, stroke_width); this->draw(*it, stroke, stroke_width);
@ -203,73 +185,64 @@ void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std:
this->draw(*it, fill, stroke, stroke_width); this->draw(*it, fill, stroke, stroke_width);
} }
void void SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width)
SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width)
{ {
for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
this->draw((Polyline)*it, stroke, stroke_width); this->draw((Polyline)*it, stroke, stroke_width);
} }
void void SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
{ {
for (ThickPolylines::const_iterator it = thickpolylines.begin(); it != thickpolylines.end(); ++ it) for (ThickPolylines::const_iterator it = thickpolylines.begin(); it != thickpolylines.end(); ++ it)
draw(it->thicklines(), fill, stroke, stroke_width); draw(it->thicklines(), fill, stroke, stroke_width);
} }
void void SVG::draw(const Point &point, std::string fill, coord_t iradius)
SVG::draw(const Point &point, std::string fill, coord_t iradius)
{ {
float radius = (iradius == 0) ? 3.f : COORD(iradius); float radius = (iradius == 0) ? 3.f : to_svg_coord(iradius);
std::ostringstream svg; std::ostringstream svg;
svg << " <circle cx=\"" << COORD(point(0) - origin(0)) << "\" cy=\"" << COORD(point(1) - origin(1)) svg << " <circle cx=\"" << to_svg_x(point(0) - origin(0)) << "\" cy=\"" << to_svg_y(point(1) - origin(1))
<< "\" r=\"" << radius << "\" " << "\" r=\"" << radius << "\" "
<< "style=\"stroke: none; fill: " << fill << "\" />"; << "style=\"stroke: none; fill: " << fill << "\" />";
fprintf(this->f, "%s\n", svg.str().c_str()); fprintf(this->f, "%s\n", svg.str().c_str());
} }
void void SVG::draw(const Points &points, std::string fill, coord_t radius)
SVG::draw(const Points &points, std::string fill, coord_t radius)
{ {
for (Points::const_iterator it = points.begin(); it != points.end(); ++it) for (Points::const_iterator it = points.begin(); it != points.end(); ++it)
this->draw(*it, fill, radius); this->draw(*it, fill, radius);
} }
void void SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width)
SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width)
{ {
this->stroke = stroke; this->stroke = stroke;
this->path(this->get_path_d(polygon, scale, true), false, stroke_width, 1.f); this->path(this->get_path_d(polygon, scale, true), false, stroke_width, 1.f);
} }
void void SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width)
SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width)
{ {
for (ClipperLib::Paths::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) for (ClipperLib::Paths::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
draw(*it, scale, stroke, stroke_width); draw(*it, scale, stroke, stroke_width);
} }
void void SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width)
SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width)
{ {
this->stroke = stroke; this->stroke = stroke;
this->path(this->get_path_d(polygon, true), false, stroke_width, 1.f); this->path(this->get_path_d(polygon, true), false, stroke_width, 1.f);
} }
void void SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width)
SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width)
{ {
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
draw_outline(*it, stroke, stroke_width); draw_outline(*it, stroke, stroke_width);
} }
void void SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity)
SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity)
{ {
float lineWidth = 0.f; float lineWidth = 0.f;
if (! fill) if (! fill)
lineWidth = (stroke_width == 0) ? 2.f : COORD(stroke_width); lineWidth = (stroke_width == 0) ? 2.f : to_svg_coord(stroke_width);
fprintf( fprintf(
this->f, this->f,
@ -283,27 +256,25 @@ SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fi
); );
} }
std::string std::string SVG::get_path_d(const MultiPoint &mp, bool closed) const
SVG::get_path_d(const MultiPoint &mp, bool closed) const
{ {
std::ostringstream d; std::ostringstream d;
d << "M "; d << "M ";
for (Points::const_iterator p = mp.points.begin(); p != mp.points.end(); ++p) { for (Points::const_iterator p = mp.points.begin(); p != mp.points.end(); ++p) {
d << COORD((*p)(0) - origin(0)) << " "; d << to_svg_x((*p)(0) - origin(0)) << " ";
d << COORD((*p)(1) - origin(1)) << " "; d << to_svg_y((*p)(1) - origin(1)) << " ";
} }
if (closed) d << "z"; if (closed) d << "z";
return d.str(); return d.str();
} }
std::string std::string SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
{ {
std::ostringstream d; std::ostringstream d;
d << "M "; d << "M ";
for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) { for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) {
d << COORD(scale * p->X - origin(0)) << " "; d << to_svg_x(scale * p->X - origin(0)) << " ";
d << COORD(scale * p->Y - origin(1)) << " "; d << to_svg_y(scale * p->Y - origin(1)) << " ";
} }
if (closed) d << "z"; if (closed) d << "z";
return d.str(); return d.str();
@ -313,8 +284,8 @@ void SVG::draw_text(const Point &pt, const char *text, const char *color)
{ {
fprintf(this->f, fprintf(this->f,
"<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"20px\" fill=\"%s\">%s</text>", "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"20px\" fill=\"%s\">%s</text>",
COORD(pt(0)-origin(0)), to_svg_x(pt(0)-origin(0)),
COORD(pt(1)-origin(1)), to_svg_y(pt(1)-origin(1)),
color, text); color, text);
} }
@ -322,18 +293,17 @@ void SVG::draw_legend(const Point &pt, const char *text, const char *color)
{ {
fprintf(this->f, fprintf(this->f,
"<circle cx=\"%f\" cy=\"%f\" r=\"10\" fill=\"%s\"/>", "<circle cx=\"%f\" cy=\"%f\" r=\"10\" fill=\"%s\"/>",
COORD(pt(0)-origin(0)), to_svg_x(pt(0)-origin(0)),
COORD(pt(1)-origin(1)), to_svg_y(pt(1)-origin(1)),
color); color);
fprintf(this->f, fprintf(this->f,
"<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"10px\" fill=\"%s\">%s</text>", "<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"10px\" fill=\"%s\">%s</text>",
COORD(pt(0)-origin(0)) + 20.f, to_svg_x(pt(0)-origin(0)) + 20.f,
COORD(pt(1)-origin(1)), to_svg_y(pt(1)-origin(1)),
"black", text); "black", text);
} }
void void SVG::Close()
SVG::Close()
{ {
fprintf(this->f, "</svg>\n"); fprintf(this->f, "</svg>\n");
fclose(this->f); fclose(this->f);

View file

@ -16,27 +16,28 @@ public:
bool arrows; bool arrows;
std::string fill, stroke; std::string fill, stroke;
Point origin; Point origin;
bool flipY; float height;
bool flipY;
SVG(const char* afilename) : SVG(const char* afilename) :
arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false) arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false)
{ open(filename); } { open(filename); }
SVG(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) : SVG(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = true) :
arrows(false), fill("grey"), stroke("black"), filename(afilename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY) arrows(false), fill("grey"), stroke("black"), filename(afilename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(flipY)
{ open(filename, bbox, bbox_offset, aflipY); } { open(filename, bbox, bbox_offset, flipY); }
SVG(const std::string &filename) : SVG(const std::string &filename) :
arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false) arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false)
{ open(filename); } { open(filename); }
SVG(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) : SVG(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = true) :
arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY) arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(flipY)
{ open(filename, bbox, bbox_offset, aflipY); } { open(filename, bbox, bbox_offset, flipY); }
~SVG() { if (f != NULL) Close(); } ~SVG() { if (f != NULL) Close(); }
bool open(const char* filename); bool open(const char* filename);
bool open(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false); bool open(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = true);
bool open(const std::string &filename) bool open(const std::string &filename)
{ return open(filename.c_str()); } { return open(filename.c_str()); }
bool open(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false) bool open(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = true)
{ return open(filename.c_str(), bbox, bbox_offset, flipY); } { return open(filename.c_str(), bbox, bbox_offset, flipY); }
void draw(const Line &line, std::string stroke = "black", coordf_t stroke_width = 0); void draw(const Line &line, std::string stroke = "black", coordf_t stroke_width = 0);
@ -127,6 +128,11 @@ public:
}; };
static void export_expolygons(const char *path, const std::vector<std::pair<Slic3r::ExPolygons, ExPolygonAttributes>> &expolygons_with_attributes); static void export_expolygons(const char *path, const std::vector<std::pair<Slic3r::ExPolygons, ExPolygonAttributes>> &expolygons_with_attributes);
private:
static float to_svg_coord(float x) throw() { return unscale<float>(x) * 10.f; }
static float to_svg_x(float x) throw() { return to_svg_coord(x); }
float to_svg_y(float x) const throw() { return flipY ? this->height - to_svg_coord(x) : to_svg_coord(x); }
}; };
} }

View file

@ -2324,7 +2324,6 @@ static inline void fill_expolygons_generate_paths(
{ {
FillParams fill_params; FillParams fill_params;
fill_params.density = density; fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true; fill_params.dont_adjust = true;
for (const ExPolygon &expoly : expolygons) { for (const ExPolygon &expoly : expolygons) {
Surface surface(stInternal, expoly); Surface surface(stInternal, expoly);
@ -2351,7 +2350,6 @@ static inline void fill_expolygons_generate_paths(
{ {
FillParams fill_params; FillParams fill_params;
fill_params.density = density; fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true; fill_params.dont_adjust = true;
for (ExPolygon &expoly : expolygons) { for (ExPolygon &expoly : expolygons) {
Surface surface(stInternal, std::move(expoly)); Surface surface(stInternal, std::move(expoly));
@ -2515,7 +2513,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
Polygon &contour = (i_contour == 0) ? it_contact_expoly->contour : it_contact_expoly->holes[i_contour - 1]; Polygon &contour = (i_contour == 0) ? it_contact_expoly->contour : it_contact_expoly->holes[i_contour - 1];
const Point *seg_current_pt = nullptr; const Point *seg_current_pt = nullptr;
coordf_t seg_current_t = 0.; coordf_t seg_current_t = 0.;
if (! intersection_pl(contour.split_at_first_point(), overhang_with_margin).empty()) { if (! intersection_pl((Polylines)contour.split_at_first_point(), overhang_with_margin).empty()) {
// The contour is below the overhang at least to some extent. // The contour is below the overhang at least to some extent.
//FIXME ideally one would place the circles below the overhang only. //FIXME ideally one would place the circles below the overhang only.
// Walk around the contour and place circles so their centers are not closer than circle_distance from each other. // Walk around the contour and place circles so their centers are not closer than circle_distance from each other.

View file

@ -1,9 +1,9 @@
#ifndef _prusaslicer_technologies_h_ #ifndef _prusaslicer_technologies_h_
#define _prusaslicer_technologies_h_ #define _prusaslicer_technologies_h_
//============ //=============
// debug techs // debug techs
//============ //=============
// Shows camera target in the 3D scene // Shows camera target in the 3D scene
#define ENABLE_SHOW_CAMERA_TARGET 0 #define ENABLE_SHOW_CAMERA_TARGET 0
@ -23,20 +23,24 @@
#define DISABLE_INSTANCES_SYNCH 0 #define DISABLE_INSTANCES_SYNCH 0
// Use wxDataViewRender instead of wxDataViewCustomRenderer // Use wxDataViewRender instead of wxDataViewCustomRenderer
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0 #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0
// Enable G-Code viewer statistics imgui dialog
#define ENABLE_GCODE_VIEWER_STATISTICS 0
// Enable G-Code viewer comparison between toolpaths height and width detected from gcode and calculated at gcode generation
#define ENABLE_GCODE_VIEWER_DATA_CHECKING 0
//================ //=================
// 2.2.0.rc1 techs // 2.2.0.rc1 techs
//================ //=================
#define ENABLE_2_2_0_RC1 1 #define ENABLE_2_2_0_RC1 1
// Enable hack to remove crash when closing on OSX 10.9.5 // Enable hack to remove crash when closing on OSX 10.9.5
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1) #define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
//=================== //====================
// 2.3.0.alpha1 techs // 2.3.0.alpha1 techs
//=================== //====================
#define ENABLE_2_3_0_ALPHA1 1 #define ENABLE_2_3_0_ALPHA1 1
// Enable rendering of objects using environment map // Enable rendering of objects using environment map
@ -51,26 +55,32 @@
// Enable built-in DPI changed event handler of wxWidgets 3.1.3 // Enable built-in DPI changed event handler of wxWidgets 3.1.3
#define ENABLE_WX_3_1_3_DPI_CHANGED_EVENT (1 && ENABLE_2_3_0_ALPHA1) #define ENABLE_WX_3_1_3_DPI_CHANGED_EVENT (1 && ENABLE_2_3_0_ALPHA1)
// Enable G-Code viewer
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
#define ENABLE_GCODE_VIEWER_DATA_CHECKING (0 && ENABLE_GCODE_VIEWER)
//====================
//===================
// 2.3.0.alpha3 techs // 2.3.0.alpha3 techs
//=================== //====================
#define ENABLE_2_3_0_ALPHA3 1 #define ENABLE_2_3_0_ALPHA3 1
#define ENABLE_CTRL_M_ON_WINDOWS (0 && ENABLE_2_3_0_ALPHA3) #define ENABLE_CTRL_M_ON_WINDOWS (1 && ENABLE_2_3_0_ALPHA3)
//=================== //====================
// 2.3.0.alpha4 techs // 2.3.0.alpha4 techs
//=================== //====================
#define ENABLE_2_3_0_ALPHA4 1 #define ENABLE_2_3_0_ALPHA4 1
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS (1 && ENABLE_GCODE_VIEWER && ENABLE_2_3_0_ALPHA4) #define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS (1 && ENABLE_2_3_0_ALPHA4)
#define ENABLE_SHOW_OPTION_POINT_LAYERS (1 && ENABLE_2_3_0_ALPHA4)
//===================
// 2.3.0.beta1 techs
//===================
#define ENABLE_2_3_0_BETA1 1
#define ENABLE_SHOW_WIPE_MOVES (1 && ENABLE_2_3_0_BETA1)
#define ENABLE_DRAG_AND_DROP_FIX (1 && ENABLE_2_3_0_BETA1)
#define ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN (1 && ENABLE_2_3_0_BETA1)
#endif // _prusaslicer_technologies_h_ #endif // _prusaslicer_technologies_h_

View file

@ -103,12 +103,6 @@ enum Axis {
NUM_AXES_WITH_UNKNOWN, NUM_AXES_WITH_UNKNOWN,
}; };
template <class T>
inline void append_to(std::vector<T> &dst, const std::vector<T> &src)
{
dst.insert(dst.end(), src.begin(), src.end());
}
template <typename T> template <typename T>
inline void append(std::vector<T>& dest, const std::vector<T>& src) inline void append(std::vector<T>& dest, const std::vector<T>& src)
{ {
@ -131,6 +125,30 @@ inline void append(std::vector<T>& dest, std::vector<T>&& src)
src.shrink_to_fit(); src.shrink_to_fit();
} }
// Append the source in reverse.
template <typename T>
inline void append_reversed(std::vector<T>& dest, const std::vector<T>& src)
{
if (dest.empty())
dest = src;
else
dest.insert(dest.end(), src.rbegin(), src.rend());
}
// Append the source in reverse.
template <typename T>
inline void append_reversed(std::vector<T>& dest, std::vector<T>&& src)
{
if (dest.empty())
dest = std::move(src);
else {
dest.reserve(dest.size() + src.size());
std::move(std::rbegin(src), std::rend(src), std::back_inserter(dest));
}
src.clear();
src.shrink_to_fit();
}
// Casting an std::vector<> from one type to another type without warnings about a loss of accuracy. // Casting an std::vector<> from one type to another type without warnings about a loss of accuracy.
template<typename T_TO, typename T_FROM> template<typename T_TO, typename T_FROM>
std::vector<T_TO> cast(const std::vector<T_FROM> &src) std::vector<T_TO> cast(const std::vector<T_FROM> &src)

View file

@ -432,7 +432,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
boost::system::error_code ec; boost::system::error_code ec;
boost::filesystem::permissions(target, perms, ec); boost::filesystem::permissions(target, perms, ec);
if (ec) if (ec)
BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message(); BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear(); ec.clear();
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec); boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) { if (ec) {
@ -442,7 +442,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
ec.clear(); ec.clear();
boost::filesystem::permissions(target, perms, ec); boost::filesystem::permissions(target, perms, ec);
if (ec) if (ec)
BOOST_LOG_TRIVIAL(error) << "boost::filesystem::permisions after copy error message (this could be irrelevant message based on file system): " << ec.message(); BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions after copy error message (this could be irrelevant message based on file system): " << ec.message();
return SUCCESS; return SUCCESS;
} }

View file

@ -162,6 +162,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Jobs/ArrangeJob.cpp GUI/Jobs/ArrangeJob.cpp
GUI/Jobs/RotoptimizeJob.hpp GUI/Jobs/RotoptimizeJob.hpp
GUI/Jobs/RotoptimizeJob.cpp GUI/Jobs/RotoptimizeJob.cpp
GUI/Jobs/FillBedJob.hpp
GUI/Jobs/FillBedJob.cpp
GUI/Jobs/SLAImportJob.hpp GUI/Jobs/SLAImportJob.hpp
GUI/Jobs/SLAImportJob.cpp GUI/Jobs/SLAImportJob.cpp
GUI/Jobs/ProgressIndicator.hpp GUI/Jobs/ProgressIndicator.hpp

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