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-smtp
--disable-gopher
--disable-crypto-auth
--without-gssapi
--without-libpsl
--without-libidn2

View file

@ -67,7 +67,6 @@ ExternalProject_Add(dep_libcurl
--disable-smb
--disable-smtp
--disable-gopher
--disable-crypto-auth
--without-gssapi
--without-libpsl
--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-Transfer-Encoding: 8bit\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"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Oleksandra Iushchenko <yusanka@gmail.com>\n"
"Last-Translator: \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
msgid ""
"\"%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."
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
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"
@ -98,6 +94,11 @@ msgstr "%s &Webová stránka"
msgid "%s - BREAKING CHANGE"
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
#, c-format
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
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
#, c-format
@ -428,6 +429,10 @@ msgstr "Přesnost"
msgid "Accurate"
msgstr "Přesné"
#: src/slic3r/GUI/Plater.cpp:1423
msgid "Action"
msgstr "Akce"
#: src/slic3r/GUI/ConfigSnapshotDialog.cpp:78
msgid "Activate"
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."
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
msgid "All objects are outside of the print volume."
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?"
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
msgid "All standard"
msgstr "Všechny běžné"
@ -987,6 +992,10 @@ msgstr "Automatické aktualizace"
msgid "Automatically repair an STL file"
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
msgid "Autoset custom supports"
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 ""
"Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\n"
"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
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"
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
msgid "Don't support bridges"
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."
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
msgid "Empty layers detected, the output would not be printable."
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
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
msgid "Enable support material generation."
@ -2975,10 +2994,6 @@ msgstr "Exportovat vybrané objekty jako STL soubor"
msgid "Export to SD card / Flash drive"
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
msgid "Export toolpaths as 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:316
msgid "Feature types"
msgstr "Typy extruzí"
msgstr "Typy extrudování"
#: src/slic3r/GUI/ConfigWizard.cpp:1926
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
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
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."
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
msgid "Ignore non-existent config files"
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"
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
msgid "Import file: "
msgstr "Importovat soubor:"
msgid "Import file"
msgstr "Importovat soubor"
#: src/slic3r/GUI/Plater.cpp:1418
msgid "Import geometry only"
msgstr "Importovat pouze modely"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:46
msgid "Import model and profile"
@ -4566,10 +4593,6 @@ msgstr "Vrchních"
msgid "Layout Options"
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
msgid "Leaving Paint-on supports"
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"
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
msgid "Load Part"
msgstr "Přidání části"
@ -4710,9 +4725,9 @@ msgstr "Načteno"
msgid "Loading"
msgstr "Načítání"
#: src/slic3r/GUI/GUI_App.cpp:759
msgid "Loading configuration..."
msgstr "Načítání konfigurace ..."
#: src/slic3r/GUI/GUI_App.cpp:797
msgid "Loading configuration"
msgstr "Načítání konfigurace"
#: src/slic3r/GUI/Plater.cpp:2226
msgid "Loading file"
@ -5690,7 +5705,7 @@ msgstr "Teplota trysky"
#: 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."
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
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"
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
msgid "Open CA certificate file"
msgstr "Otevřít soubor s certifikátem CA"
@ -6338,9 +6357,9 @@ msgstr "Preferovaný směr švu - rozkmit"
msgid "Preparing infill"
msgstr "Příprava výplně"
#: src/slic3r/GUI/GUI_App.cpp:895
msgid "Preparing settings tabs..."
msgstr "Příprava karet s nastavením..."
#: src/slic3r/GUI/GUI_App.cpp:855
msgid "Preparing settings tabs"
msgstr "Příprava karet s nastavením"
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:1009
msgid "Preset \"%1%\" has the following unsaved changes:"
@ -6662,10 +6681,6 @@ msgstr "Kvalita (pomalejší slicing)"
msgid "Quality / Speed"
msgstr "Kvalita / Rychlost"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:56
msgid "Quality: "
msgstr "Kvalita:"
#: src/slic3r/GUI/Jobs/SLAImportJob.cpp:61
msgid "Quick"
msgstr "Rychlé"
@ -6693,7 +6708,7 @@ msgstr "Ukončit %s"
#: src/slic3r/GUI/GUI_App.cpp:396
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
msgid "Radius"
@ -6880,6 +6895,10 @@ msgstr "Zapamatovat moji volbu"
msgid "Remember output directory"
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
msgid "remove"
msgstr "odebrat"
@ -7345,7 +7364,7 @@ msgstr "Uložit SL1 soubor jako:"
#: src/slic3r/GUI/UnsavedChangesDialog.cpp:744
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
msgid "Save the selected options."
@ -7470,6 +7489,10 @@ msgstr "Vybrat všechny body"
msgid "Select all standard printers"
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
msgid "Select by rectangle"
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"
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
msgid "Seq."
msgstr "Sekv."
@ -7861,6 +7880,10 @@ msgstr "Zobrazit okno o Slic3ru"
msgid "Show advanced settings"
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
msgid "Show error message"
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."
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
msgid "support"
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"
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
msgid "There are active warnings concerning sliced models:\n"
msgstr "Varování týkající se slicovaných modelů:\n"
#: src/slic3r/GUI/Plater.cpp:3563
msgid "There are active warnings concerning sliced models:"
msgstr "Varování týkající se slicovaných modelů:"
#: src/libslic3r/SLAPrintSteps.cpp:619
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
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
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
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
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"
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
msgid "Use forward slashes ( / ) as a directory separator if needed."
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"
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
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"

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
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.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.

View file

@ -5,7 +5,7 @@
name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.6
config_version = 0.0.7
# Where to get the updates from?
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%
@ -666,14 +666,14 @@ deretract_speed = 40
retract_before_wipe = 70%
default_print_profile = 0.16mm OPTIMAL @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
[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*]
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*]
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_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
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
[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
1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.1.10 Updated firmware version.
1.1.9 Updated K values in filament profiles (linear advance). Added new filament profiles and SLA materials.
1.1.8 Updated start/end g-code scripts for MK3 family printer profiles (reduced extruder motor current for some print profiles). Added new filament and SLA material profiles.

File diff suppressed because it is too large Load diff

View file

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

View file

@ -6,7 +6,7 @@
name = TriLAB
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.3
config_version = 0.0.4
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/TriLAB/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -17,21 +17,21 @@ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/Prus
[printer_model:DQ2]
name = DeltiQ 2
variants = 0.4
variants = 0.4; 0.8
technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
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]
name = DeltiQ 2 Plus
variants = 0.4
variants = 0.4; 0.8
technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
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]
name = DeltiQ 2 + FlexPrint 2
@ -40,7 +40,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
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]
name = DeltiQ 2 Plus + FlexPrint 2
@ -49,7 +49,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
bed_texture = dq2_bed_texture.svg
default_materials = DeltiQ 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]
name = DeltiQ 2 + FlexPrint
@ -58,7 +58,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
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]
name = DeltiQ 2 Plus + FlexPrint
@ -67,7 +67,7 @@ technology = FFF
family = DeltiQ 2
bed_model = dq2_bed.stl
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]
name = DeltiQ M
@ -105,7 +105,7 @@ bridge_speed = 30
brim_width = 0
clip_multipart_objects = 1
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
default_acceleration = 2000
dont_support_bridges = 0
@ -176,7 +176,7 @@ solid_infill_speed = 60
spiral_vase = 0
standby_temperature_delta = -5
support_material = 0
support_material_angle = 40
support_material_angle = 30
support_material_auto = 1
support_material_buildplate_only = 0
support_material_contact_distance = 0.1
@ -192,7 +192,7 @@ support_material_pattern = rectilinear
support_material_spacing = 2
support_material_speed = 50
support_material_synchronize_layers = 0
support_material_threshold = 55
support_material_threshold = 40
support_material_with_sheath = 0
support_material_xy_spacing = 0.6
thin_walls = 0
@ -254,9 +254,11 @@ thin_walls = 0
[print:DeltiQ 0.20mm FLEX]
inherits = DeltiQ 0.20mm Normal
avoid_crossing_perimeters = 0
bridge_flow_ratio = 0.90
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*FLEXPRINT.*/
bridge_flow_ratio = 0.80
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
extrusion_width = 0.40
overhangs = 0
seam_position = nearest
thin_walls = 0
@ -264,23 +266,71 @@ bridge_speed = 20
external_perimeter_speed = 20
first_layer_speed = 20
gap_fill_speed = 25
infill_speed = 30
infill_extrusion_width = 0.55
infill_speed = 40
infill_overlap = 27%
perimeter_speed = 25
small_perimeter_speed = 20
solid_infill_speed = 30
solid_infill_extrusion_width = 0.45
support_material_contact_distance = 0.3
support_material_speed = 30
top_solid_infill_speed = 20
top_fill_pattern = rectilinear
fill_pattern = grid
fill_density = 25%
travel_speed = 200
max_print_speed = 30
max_print_speed = 40
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*]
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
extrusion_multiplier = 1
filament_colour = #FF0000
@ -294,7 +344,37 @@ filament_toolchange_delay = 0
start_filament_gcode = "; FILAMENT_START_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*
bed_temperature = 90
bridge_fan_speed = 50
@ -322,34 +402,7 @@ min_print_speed = 10
slowdown_below_layer_time = 5
temperature = 245
[filament:DeltiQ PLA]
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]
[filament:DeltiQ - ABS - Generic]
inherits = *DeltiQ common*
bed_temperature = 100
bridge_fan_speed = 25
@ -376,14 +429,24 @@ min_print_speed = 10
slowdown_below_layer_time = 15
temperature = 255
[filament:DeltiQ ASA]
inherits = DeltiQ ABS
[filament:DeltiQ - PLA - ExtraFill (Fillamentum)]
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_type = ASA
filament_vendor = Fillamentum
first_layer_temperature = 265
temperature = 265
[filament:DeltiQ CPE]
[filament:DeltiQ - CPE - HG100 (Fillamentum)]
inherits = *DeltiQ common*
bed_temperature = 90
bridge_fan_speed = 50
@ -411,41 +474,155 @@ min_print_speed = 10
slowdown_below_layer_time = 5
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]
inherits = DeltiQ PET
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ - PETG (Devil Design) @0.8 nozzle]
inherits = DeltiQ - PETG (Devil Design)
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_speed = 35
filament_retract_before_wipe = 0%
[filament:DeltiQ FlexPrint 2 PLA]
inherits = DeltiQ PLA
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
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:DeltiQ FP2 - ABS - Generic]
inherits = DeltiQ FP - ABS - 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 = 0.8
filament_retract_speed = 25
[filament:DeltiQ FlexPrint 2 ASA]
inherits = DeltiQ ASA
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FP2 - PLA - ExtraFill (Fillamentum)]
inherits = DeltiQ FP2 - PLA - Generic
[filament:DeltiQ FlexPrint 2 CPE]
inherits = DeltiQ CPE
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FP2 - PETG (Devil Design)]
inherits = DeltiQ FP2 - PETG - Generic
[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_speed = 35
filament_deretract_speed = 0
filament_retract_before_wipe = 0%
[filament:DeltiQ FlexPrint 2 FLEX]
inherits = *DeltiQ common*
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FP2 - FLEX - Generic]
inherits = DeltiQ FP - FLEX - 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
bed_temperature = 50
bridge_fan_speed = 80
cooling = 1
@ -456,12 +633,12 @@ fan_below_layer_time = 20
filament_vendor = Fillamentum
filament_cost = 1870
filament_density = 1.22
filament_deretract_speed = 0
filament_deretract_speed = nil
filament_max_volumetric_speed = 2.9
filament_retract_before_travel = 1
filament_retract_before_travel = 2
filament_retract_before_wipe = 70%
filament_retract_layer_change = 0
filament_retract_length = 1.6
filament_retract_length = 2.5
filament_retract_lift = 0.2
filament_retract_restart_extra = nil
filament_retract_speed = 20
@ -475,72 +652,52 @@ min_print_speed = 5
slowdown_below_layer_time = 4
temperature = 225
[filament:DeltiQ FlexPrint 2 FLEX Smartfil]
inherits = *DeltiQ common*
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_TRILAB.*/ and printer_notes=~/.*PRINTER_FAMILY_DQ.*/ and printer_notes=~/.*FLEXPRINT2.*/
[filament:DeltiQ FP2 - TPU 92A - FlexFill (Fillamentum)]
inherits = DeltiQ FP2 - FLEX - Generic
bed_temperature = 50
bridge_fan_speed = 80
cooling = 0
disable_fan_first_layers = 3
extrusion_multiplier = 1.07
cooling = 1
disable_fan_first_layers = 1
extrusion_multiplier = 1.10
fan_always_on = 1
fan_below_layer_time = 20
filament_vendor = Smart Materials 3D
filament_cost = 1209
filament_density = 1.21
filament_deretract_speed = 0
filament_max_volumetric_speed = 2.5
filament_retract_before_travel = 1
filament_retract_before_wipe = nil
filament_vendor = Fillamentum
filament_cost = 1870
filament_density = 1.22
filament_deretract_speed = nil
filament_max_volumetric_speed = 2.9
filament_retract_before_travel = 2
filament_retract_before_wipe = 70%
filament_retract_layer_change = 0
filament_retract_length = 1.2
filament_retract_length = 2.5
filament_retract_lift = 0.2
filament_retract_restart_extra = nil
filament_retract_speed = 20
filament_type = FLEX
filament_wipe = 0
filament_type = TPU92A
filament_wipe = 1
first_layer_bed_temperature = 50
first_layer_temperature = 240
max_fan_speed = 50
first_layer_temperature = 230
max_fan_speed = 70
min_fan_speed = 50
min_print_speed = 10
min_print_speed = 5
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
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
# DeltiQ Printer #
[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*]
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
@ -597,68 +754,6 @@ variable_layer_height = 0
wipe = 1
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]
inherits = *DeltiQ*
printer_model = DQL
@ -686,7 +781,88 @@ max_print_height = 500
retract_length = 4.5
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]
print = DeltiQ 0.20mm Normal
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 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 ()

View file

@ -741,6 +741,10 @@ public:
return impl_.getResult();
}
inline int lastPackedBinId() const {
return impl_.lastPackedBinId();
}
void clear() { impl_.clear(); }
};
@ -862,6 +866,10 @@ public:
{
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>;
// Norming factor for the optimization function
const double norm_;
public:
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):
Base(bin),
norm_(std::sqrt(sl::area(bin)))
@ -616,135 +621,9 @@ private:
template<class Level>
Shapes calcnfp(const Item &trsh, Level)
{ // Function for arbitrary level of nfp implementation
using namespace nfp;
Shapes nfps;
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;
}
// TODO: implement
return {};
}
struct Optimum {
@ -798,6 +677,50 @@ private:
Radians final_rot = initial_rot;
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) {
item.translation(initial_tr);
@ -822,57 +745,6 @@ private:
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
auto rawobjfunc = [_objfunc, iv, startpos]
(Vertex v, Item& itm)
@ -1045,6 +917,7 @@ private:
if(can_pack) {
ret = PackResult(item);
merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
} else {
ret = PackResult(best_overfit);
}

View file

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

View file

@ -18,6 +18,8 @@ public:
return packed_bins_;
}
inline int lastPackedBinId() const { return last_packed_bin_id_; }
inline void progressIndicator(ProgressFunction fn) { progress_ = fn; }
inline void stopCondition(StopCondition cond) { stopcond_ = cond; }
@ -54,6 +56,7 @@ protected:
PackGroup packed_bins_;
ProgressFunction progress_ = [](unsigned){};
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();
}
// 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 Slic3r

View file

@ -68,6 +68,15 @@ void AppConfig::set_defaults()
if (get("export_sources_full_pathnames").empty())
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
if (!get("use_legacy_opengl").empty())
erase("", "use_legacy_opengl");
@ -108,7 +117,21 @@ void AppConfig::set_defaults()
if (get("use_inches").empty())
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())
set("seq_top_layer_only", "1");
@ -125,11 +148,12 @@ void AppConfig::set_defaults()
if (get("show_splash_screen").empty())
set("show_splash_screen", "1");
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_CTRL_M_ON_WINDOWS
#ifdef _WIN32
if (get("use_legacy_3DConnexion").empty())
set("use_legacy_3DConnexion", "0");
#endif // _WIN32
#endif // ENABLE_CTRL_M_ON_WINDOWS
// Remove legacy window positions/sizes
erase("", "main_frame_maximized");

View file

@ -7,6 +7,7 @@
#include <libnest2d/optimizers/nlopt/subplex.hpp>
#include <libnest2d/placers/nfpplacer.hpp>
#include <libnest2d/selections/firstfit.hpp>
#include <libnest2d/utils/rotcalipers.hpp>
#include <numeric>
#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
// Slic3r.
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
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
// 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.
// Goes from 0.0 to 1.0 and scales performance as well
pcfg.accuracy = 0.65f;
pcfg.accuracy = params.accuracy;
// Allow parallel execution.
pcfg.parallel = true;
pcfg.parallel = params.parallel;
}
// Apply penalty to object function result. This is used only when alignment
@ -277,10 +281,10 @@ protected:
if (result.empty())
score = 0.50 * dist + 0.50 * density;
else
score = R * 0.60 * dist +
(1.0 - R) * 0.20 * density +
0.20 * alignment_score;
// Let the density matter more when fewer objects remain
score = 0.50 * dist + (1.0 - R) * 0.20 * density +
0.30 * alignment_score;
break;
}
case LAST_BIG_ITEM: {
@ -304,15 +308,15 @@ protected:
public:
AutoArranger(const TBin & bin,
Distance dist,
const ArrangeParams &params,
std::function<void(unsigned)> progressind,
std::function<bool(void)> stopcond)
: m_pck(bin, dist)
: m_pck(bin, params.min_obj_distance)
, m_bin(bin)
, m_bin_area(sl::area(bin))
, 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
// This functionality is provided by the Nester class (m_pack).
@ -343,18 +347,31 @@ public:
};
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);
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) {
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);
}
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
void _arrange(
std::vector<Item> & shapes,
std::vector<Item> & excludes,
const BinT & bin,
const ArrangeParams & params,
const ArrangeParams &params,
std::function<void(unsigned)> progressfn,
std::function<bool()> stopfn)
{
@ -467,11 +490,10 @@ void _arrange(
auto corrected_bin = bin;
sl::offset(corrected_bin, md);
AutoArranger<BinT> arranger{corrected_bin, progressfn, stopfn};
arranger.config().accuracy = params.accuracy;
arranger.config().parallel = params.parallel;
ArrangeParams mod_params = params;
mod_params.min_obj_distance = 0;
AutoArranger<BinT> arranger{corrected_bin, mod_params, progressfn, stopfn};
auto infl = coord_t(std::ceil(params.min_obj_distance / 2.0));
for (Item& itm : shapes) itm.inflate(infl);
@ -487,6 +509,13 @@ void _arrange(
for (auto &itm : shapes ) 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());
for (Item &itm : inp) itm.inflate(-infl);
}
@ -556,28 +585,35 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
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<>
void arrange(ArrangePolygons & items,
const ArrangePolygons &excludes,
const Points & bed,
const ArrangeParams & params)
{
if (bed.empty())
arrange(items, excludes, InfiniteBed{}, 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);
}
call_with_bed(bed, [&](const auto &bin) {
arrange(items, excludes, bin, params);
});
}
template<class BedT>

View file

@ -74,14 +74,18 @@ struct ArrangeParams {
/// The accuracy of optimization.
/// Goes from 0.0 to 1.0 and scales performance as well
float accuracy = 0.65f;
float accuracy = 1.f;
/// Allow parallel execution.
bool parallel = true;
bool allow_rotations = false;
/// Progress indicator callback called when an object gets packed.
/// The unsigned argument is the number of items remaining to pack.
std::function<void(unsigned)> progressind;
std::function<void(const ArrangePolygon &)> on_packed;
/// A predicate returning true if abort is needed.
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(const Vec2d &v) { this->min += v; this->max += v; }
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;
bool contains(const PointClass &point) const {
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(const Vec3d &v) { this->min += v; this->max += v; }
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;
coordf_t max_size() const;
@ -159,6 +161,8 @@ public:
BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase<Point>(pmin, pmax) {}
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);
};

View file

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

View file

@ -1069,7 +1069,7 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
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
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
@ -1113,7 +1113,7 @@ for (const std::vector<float>& ds : deltas)
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
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
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
@ -1157,7 +1157,7 @@ for (const std::vector<float>& ds : deltas)
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
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
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
@ -1205,7 +1205,7 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
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
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);

View file

@ -3,16 +3,16 @@
#include <float.h>
#include <unordered_map>
#if 0
// #ifdef SLIC3R_GUI
#include <wx/image.h>
#endif /* SLIC3R_GUI */
#include <png.h>
#include "libslic3r.h"
#include "ClipperUtils.hpp"
#include "EdgeGrid.hpp"
#include "Geometry.hpp"
#include "SVG.hpp"
#include "PNGReadWrite.hpp"
// #define EDGE_GRID_DEBUG_OUTPUT
#if 0
// 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);
}
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)
{
// Count the contours.
@ -659,6 +677,11 @@ struct PropagateDanielssonSingleVStep3 {
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.
size_t nrows = m_rows + 1;
size_t ncols = m_cols + 1;
@ -756,19 +779,12 @@ void EdgeGrid::Grid::calculate_sdf()
}
}
#if 0
static int iRun = 0;
++ iRun;
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler);
//#ifdef SLIC3R_GUI
#ifdef EDGE_GRID_DEBUG_OUTPUT
{
wxImage img(ncols, nrows);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
for (coord_t r = 0; r < nrows; ++r) {
for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3;
std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
for (coord_t r = 0; r < nrows; ++ r) {
for (coord_t c = 0; c < ncols; ++ c) {
uint8_t *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
float d = m_signed_distance_field[r * ncols + c];
if (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);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
for (coord_t r = 0; r < nrows; ++r) {
for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3;
std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
for (coord_t r = 0; r < nrows; ++ r) {
for (coord_t c = 0; c < ncols; ++ c) {
unsigned char *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
float d = m_signed_distance_field[r * ncols + c];
if (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.
#define PROPAGATE_SIGNUM_SINGLE_STEP(DELTA) do { \
@ -891,17 +905,14 @@ void EdgeGrid::Grid::calculate_sdf()
}
}
#if 0
//#ifdef SLIC3R_GUI
#ifdef EDGE_GRID_DEBUG_OUTPUT
{
wxImage img(ncols, nrows);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
float search_radius = float(m_resolution * 5);
for (coord_t r = 0; r < nrows; ++r) {
for (coord_t c = 0; c < ncols; ++c) {
unsigned char *pxl = data + (((nrows - r - 1) * ncols) + c) * 3;
unsigned char sign = signs[r * ncols + c];
uint8_t *pxl = pixels.data() + (((nrows - r - 1) * ncols) + c) * 3;
uint8_t sign = signs[r * ncols + c];
switch (sign) {
case 0:
// 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 SLIC3R_GUI
#ifdef EDGE_GRID_DEBUG_OUTPUT
{
wxImage img(ncols, nrows);
unsigned char *data = img.GetData();
memset(data, 0, ncols * nrows * 3);
std::vector<uint8_t> pixels(ncols * nrows * 3, 0);
float search_radius = float(m_resolution * 5);
for (coord_t r = 0; r < nrows; ++r) {
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 s = 255.f * fabs(d) / search_radius;
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
@ -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)) {
result.distance = d_min * sign_min;
result.t /= l2_seg_min;
assert(result.t >= 0. && result.t < 1.);
assert(result.t >= 0. && result.t <= 1.);
#ifndef NDEBUG
{
const Slic3r::Points &pts = *m_contours[result.contour_idx];
@ -1473,26 +1481,18 @@ bool EdgeGrid::Grid::has_intersecting_edges() const
return false;
}
#if 0
void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path)
void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path, size_t scale)
{
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 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;
++iRun;
std::vector<uint8_t> pixels(w * h * 3, 0);
const coord_t search_radius = grid.resolution() * 2;
const coord_t display_blend_radius = grid.resolution() * 2;
for (coord_t r = 0; r < h; ++r) {
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));
coordf_t min_dist;
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.
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 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 ExPolygon &expoly, 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
{
// End points of the line segment.
p1(0) -= m_bbox.min(0);
p1(1) -= m_bbox.min(1);
p2(0) -= m_bbox.min(0);
p2(1) -= m_bbox.min(1);
assert(m_bbox.contains(p1));
assert(m_bbox.contains(p2));
p1 -= m_bbox.min;
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.
coord_t ix = p1(0) / m_resolution;
coord_t iy = p1(1) / m_resolution;
@ -114,18 +119,22 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix += 1;
assert(ix <= ixb);
}
else if (ex == ey) {
ex = int64_t(dy) * m_resolution;
ey = int64_t(dx) * m_resolution;
ix += 1;
iy += 1;
assert(ix <= ixb);
assert(iy <= iyb);
}
else {
assert(ex > ey);
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy += 1;
assert(iy <= iyb);
}
if (! visitor(iy, ix))
return;
@ -140,11 +149,13 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix += 1;
assert(ix <= ixb);
}
else {
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
if (! visitor(iy, ix))
return;
@ -162,12 +173,14 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
else {
assert(ex >= ey);
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy += 1;
assert(iy <= iyb);
}
if (! visitor(iy, ix))
return;
@ -182,6 +195,7 @@ public:
ey -= ex;
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
else if (ex == ey) {
// The lower edge of a grid cell belongs to the cell.
@ -190,10 +204,12 @@ public:
if (dx > 0) {
ex = int64_t(dy) * m_resolution;
ix -= 1;
assert(ix >= ixb);
}
if (dy > 0) {
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
}
else {
@ -201,6 +217,7 @@ public:
ex -= ey;
ey = int64_t(dx) * m_resolution;
iy -= 1;
assert(iy >= iyb);
}
if (! visitor(iy, ix))
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
{
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];
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;
};
#if 0
// Debugging utility. Save the signed distance field.
extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path);
#endif /* SLIC3R_GUI */
extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path, size_t scale = 1);
} // 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
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
if (*x == next_x) continue;
// build rectangle
Polygon poly;
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)));
if (*x != next_x)
// intersect with rectangle
// append results to return value
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)));
}
}

View file

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

View file

@ -14,12 +14,12 @@ namespace Slic3r {
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
{
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)

View file

@ -10,7 +10,7 @@
#include "../Surface.hpp"
#include "FillBase.hpp"
#include "FillRectilinear2.hpp"
#include "FillRectilinear.hpp"
namespace Slic3r {
@ -33,10 +33,12 @@ struct SurfaceFillParams
// FillParams
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.
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
// For the output, for fill generator.
@ -65,8 +67,9 @@ struct SurfaceFillParams
RETURN_COMPARE_NON_EQUAL(overlap);
RETURN_COMPARE_NON_EQUAL(angle);
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(anchor_length);
RETURN_COMPARE_NON_EQUAL(anchor_length_max);
RETURN_COMPARE_NON_EQUAL(flow.width);
RETURN_COMPARE_NON_EQUAL(flow.height);
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
@ -83,8 +86,9 @@ struct SurfaceFillParams
this->overlap == rhs.overlap &&
this->angle == rhs.angle &&
this->density == rhs.density &&
this->dont_connect == rhs.dont_connect &&
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->extrusion_role == rhs.extrusion_role;
}
@ -115,16 +119,17 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
if (surface.surface_type == stInternalVoid)
has_internal_voids = true;
else {
const PrintRegionConfig &region_config = layerm.region()->config();
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
bool is_bridge = layer.id() > 0 && surface.is_bridge();
params.extruder = layerm.region()->extruder(extrusion_role);
params.pattern = layerm.region()->config().fill_pattern.value;
params.density = float(layerm.region()->config().fill_density);
params.pattern = region_config.fill_pattern.value;
params.density = float(region_config.fill_density);
if (surface.is_solid()) {
params.density = 100.f;
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;
} else if (params.density <= 0)
continue;
@ -136,7 +141,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
erInternalInfill);
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
params.flow = layerm.region()->flow(
@ -149,7 +154,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
);
// 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
// for all layers, for avoiding the ugly effect of
// 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
*layer.object()
).spacing();
} else
params.spacing = params.flow.spacing();
// Anchor a sparse infill to inner perimeters with the following anchor length:
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);
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
FillParams params;
params.density = float(0.01 * surface_fill.params.density);
params.dont_adjust = surface_fill.params.dont_adjust; // false
params.density = float(0.01 * surface_fill.params.density);
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) {
// 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());
FillRectilinear2 fill;
FillRectilinear fill;
FillParams fill_params;
fill.set_bounding_box(this->object()->bounding_box());
fill.layer_id = this->id();
fill.z = this->print_z;
fill.overlap = 0;
fill_params.density = 1.;
// fill_params.dont_connect = true;
fill_params.dont_connect = false;
fill_params.monotonic = true;
for (size_t i = 0; i < by_extruder.size(); ++ i) {

View file

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

View file

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

View file

@ -12,19 +12,19 @@ namespace Slic3r {
class Fill3DHoneycomb : public Fill
{
public:
virtual Fill* clone() const { return new Fill3DHoneycomb(*this); };
virtual ~Fill3DHoneycomb() {}
Fill* clone() const override { return new Fill3DHoneycomb(*this); };
~Fill3DHoneycomb() override {}
// 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:
virtual void _fill_surface_single(
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
ExPolygon expolygon,
Polylines &polylines_out) override;
};
} // namespace Slic3r

View file

@ -14,11 +14,18 @@
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <numeric>
// Boost pool: Don't use mutexes to synchronize memory allocation.
#define BOOST_POOL_NO_MT
#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 FillAdaptive {
@ -288,7 +295,7 @@ std::pair<double, double> adaptive_fill_line_spacing(const PrintObject &print_ob
bool build_octree = false;
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 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()) {
const PrintRegionConfig &config = region->config();
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));
if (last_line.a.x() == std::numeric_limits<coord_t>::max()) {
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);
last_line.a = new_line.a;
}
@ -501,7 +508,7 @@ static void generate_infill_lines_recursive(
#endif
#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);
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(polylines, "red");
static constexpr double trim_length = scale_(0.4);
for (Polyline polyline : polylines) {
Vec2d a = polyline.points.front().cast<double>();
Vec2d d = polyline.points.back().cast<double>();
if (polyline.size() == 2) {
Vec2d v = d - a;
double l = v.norm();
if (l > 2. * trim_length) {
a += v * trim_length / l;
d -= v * trim_length / l;
polyline.points.front() = a.cast<coord_t>();
polyline.points.back() = d.cast<coord_t>();
} else
polyline.points.clear();
} else if (polyline.size() > 2) {
Vec2d b = polyline.points[1].cast<double>();
Vec2d c = polyline.points[polyline.points.size() - 2].cast<double>();
Vec2d v = b - a;
double l = v.norm();
if (l > trim_length) {
a += v * trim_length / l;
polyline.points.front() = a.cast<coord_t>();
} else
polyline.points.erase(polyline.points.begin());
v = d - c;
l = v.norm();
if (l > trim_length)
polyline.points.back() = (d - v * trim_length / l).cast<coord_t>();
else
polyline.points.pop_back();
for (Polyline polyline : polylines)
if (! polyline.empty()) {
Vec2d a = polyline.points.front().cast<double>();
Vec2d d = polyline.points.back().cast<double>();
if (polyline.size() == 2) {
Vec2d v = d - a;
double l = v.norm();
if (l > 2. * trim_length) {
a += v * trim_length / l;
d -= v * trim_length / l;
polyline.points.front() = a.cast<coord_t>();
polyline.points.back() = d.cast<coord_t>();
} else
polyline.points.clear();
} else if (polyline.size() > 2) {
Vec2d b = polyline.points[1].cast<double>();
Vec2d c = polyline.points[polyline.points.size() - 2].cast<double>();
Vec2d v = b - a;
double l = v.norm();
if (l > trim_length) {
a += v * trim_length / l;
polyline.points.front() = a.cast<coord_t>();
} else
polyline.points.erase(polyline.points.begin());
v = d - c;
l = v.norm();
if (l > trim_length)
polyline.points.back() = (d - v * trim_length / l).cast<coord_t>();
else
polyline.points.pop_back();
}
svg.draw(polyline, "black");
}
svg.draw(polyline, "black");
}
svg.draw(pts, "magenta");
}
#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(
const FillParams & params,
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
ExPolygon expolygon,
Polylines &polylines_out)
{
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);
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.
std::vector<Line> lines;
lines.reserve(num_lines);
@ -578,18 +1361,21 @@ void Filler::_fill_surface_single(
if (line.a.x() != std::numeric_limits<coord_t>::max())
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.
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 }; });
// Crop all polylines
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
#endif
}
// Crop all polylines
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
// After intersection_pl some polylines with only one line are split into more lines
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
{
@ -598,10 +1384,22 @@ void Filler::_fill_surface_single(
}
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
if (params.dont_connect || all_polylines.size() <= 1)
append(polylines_out, std::move(all_polylines));
const auto hook_length = coordf_t(std::min<float>(std::numeric_limits<coord_t>::max(), scale_(params.anchor_length)));
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
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
{

View file

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

File diff suppressed because it is too large Load diff

View file

@ -33,12 +33,16 @@ public:
struct FillParams
{
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>
float density { 0.f };
// Don't connect the fill lines around the inner perimeter.
bool dont_connect { false };
// Length of an infill anchor along the perimeter.
// 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.
bool dont_adjust { true };
@ -80,6 +84,7 @@ public:
public:
virtual ~Fill() {}
virtual Fill* clone() const = 0;
static Fill* new_from_type(const InfillPattern type);
static Fill* new_from_type(const std::string &type);
@ -116,7 +121,7 @@ protected:
const FillParams & /* params */,
unsigned int /* thickness_layers */,
const std::pair<float, Point> & /* direction */,
ExPolygon & /* expolygon */,
ExPolygon /* expolygon */,
Polylines & /* polylines_out */) {};
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;
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);

View file

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

View file

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

View file

@ -37,12 +37,12 @@ static inline Polyline make_wave(
double period = points.back()(0);
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();
int n = points.size();
size_t n = points.size();
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);
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;
double dx = M_PI_2; // exact coordinates on main inflexion lobes
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) {
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,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
ExPolygon expolygon,
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)
expolygon.rotate(-infill_angle);
@ -182,19 +182,20 @@ void FillGyroid::_fill_surface_single(
polylines = intersection_pl(polylines, to_polygons(expolygon));
if (! polylines.empty())
// remove too small bits (larger than longer)
if (! polylines.empty()) {
// 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(
//FIXME what is the small size? Removing tiny extrusions disconnects walls!
std::remove_if(polylines.begin(), polylines.end(), [this](const Polyline &pl) { return pl.length() < scale_(this->spacing * 3); }),
std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl) { return pl.length() < minlength; }),
polylines.end());
}
if (! polylines.empty()) {
polylines = chain_polylines(polylines);
// connect lines
size_t polylines_out_first_idx = polylines_out.size();
if (params.dont_connect)
append(polylines_out, std::move(polylines));
if (params.dont_connect())
append(polylines_out, chain_polylines(polylines));
else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);

View file

@ -11,10 +11,10 @@ class FillGyroid : public Fill
{
public:
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
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
// speed in default configuration (degrees)
@ -28,12 +28,12 @@ public:
protected:
virtual void _fill_surface_single(
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
ExPolygon expolygon,
Polylines &polylines_out) override;
};
} // namespace Slic3r

View file

@ -10,7 +10,7 @@ void FillHoneycomb::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
ExPolygon expolygon,
Polylines &polylines_out)
{
// cache hexagons math
@ -18,21 +18,21 @@ void FillHoneycomb::_fill_surface_single(
Cache::iterator it_m = this->cache.find(cache_id);
if (it_m == this->cache.end()) {
it_m = this->cache.insert(it_m, std::pair<CacheID, CacheData>(cache_id, CacheData()));
CacheData &m = it_m->second;
coord_t min_spacing = scale_(this->spacing);
m.distance = min_spacing / params.density;
m.hex_side = m.distance / (sqrt(3)/2);
m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3);
coord_t hex_height = m.hex_side * 2;
m.pattern_height = hex_height + m.hex_side;
m.y_short = m.distance * sqrt(3)/3;
m.x_offset = min_spacing / 2;
m.y_offset = m.x_offset * sqrt(3)/3;
m.hex_center = Point(m.hex_width/2, m.hex_side);
CacheData &m = it_m->second;
coord_t min_spacing = coord_t(scale_(this->spacing));
m.distance = coord_t(min_spacing / params.density);
m.hex_side = coord_t(m.distance / (sqrt(3)/2));
m.hex_width = m.distance * 2; // $m->{hex_width} == $m->{hex_side} * sqrt(3);
coord_t hex_height = m.hex_side * 2;
m.pattern_height = hex_height + m.hex_side;
m.y_short = coord_t(m.distance * sqrt(3)/3);
m.x_offset = min_spacing / 2;
m.y_offset = coord_t(m.x_offset * sqrt(3)/3);
m.hex_center = Point(m.hex_width/2, m.hex_side);
}
CacheData &m = it_m->second;
Polygons polygons;
Polylines all_polylines;
{
// adjust actual bounding box to the nearest multiple of our hex pattern
// 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);
while (x <= bounding_box.max(0)) {
Polygon p;
Polyline p;
coord_t ax[2] = { x + m.x_offset, x + m.distance - m.x_offset };
for (size_t i = 0; i < 2; ++ i) {
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;
}
p.rotate(-direction.first, m.hex_center);
polygons.push_back(p);
all_polylines.push_back(p);
}
}
if (params.complete || true) {
// we were requested to complete each loop;
// in this case we don't try to make more continuous paths
Polygons polygons_trimmed = intersection((Polygons)expolygon, polygons);
for (Polygons::iterator it = polygons_trimmed.begin(); it != polygons_trimmed.end(); ++ it)
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]);
}
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
if (params.dont_connect() || all_polylines.size() <= 1)
append(polylines_out, chain_polylines(std::move(all_polylines)));
else
connect_infill(std::move(all_polylines), expolygon, polylines_out, this->spacing, params);
}
} // namespace Slic3r

View file

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

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -12,68 +12,92 @@ class Surface;
class FillRectilinear : public Fill
{
public:
virtual Fill* clone() const { return new FillRectilinear(*this); };
virtual ~FillRectilinear() {}
Fill* clone() const override { return new FillRectilinear(*this); };
~FillRectilinear() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
virtual void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
// Fill by single directional lines, interconnect the lines along perimeters.
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, 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.
virtual bool _horizontal_lines() const { return false; }
virtual Line _line(int i, coord_t x, coord_t y_min, coord_t y_max) const
{ return Line(Point(x, y_min), Point(x, y_max)); }
virtual bool _can_connect(coord_t dist_X, coord_t dist_Y) {
return dist_X <= this->_diagonal_distance
&& dist_Y <= this->_diagonal_distance;
}
// Fill by multiple sweeps of differing directions.
struct SweepParams {
float angle_base;
float pattern_shift;
};
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
};
class FillLine : public FillRectilinear
class FillAlignedRectilinear : public FillRectilinear
{
public:
virtual ~FillLine() {}
Fill* clone() const override { return new FillAlignedRectilinear(*this); };
~FillAlignedRectilinear() override = default;
protected:
virtual 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));
}
// Always generate infill at the same angle.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
virtual 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);
}
class FillMonotonic : public FillRectilinear
{
public:
Fill* clone() const override { return new FillMonotonic(*this); };
~FillMonotonic() override = default;
Polylines fill_surface(const Surface *surface, const FillParams &params) override;
bool no_sort() const override { return true; }
};
class FillGrid : public FillRectilinear
{
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:
// 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; }
// Flag for Slic3r::Fill::Rectilinear to fill both directions.
virtual bool _horizontal_lines() const { return true; }
float _layer_angle(size_t idx) const override { return 0.f; }
};
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
#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/SLA/RasterBase.hpp"
#include "libslic3r/miniz_extension.hpp"
#include "libslic3r/PNGRead.hpp"
#include "libslic3r/PNGReadWrite.hpp"
#include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem/path.hpp>

View file

@ -169,6 +169,10 @@ namespace Slic3r {
// subdivide the retraction in segments
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()) {
double segment_length = line.length();
/* 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"
);
}
#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());
}
@ -1764,7 +1772,7 @@ void GCode::process_layer(
std::string gcode;
// add tag for processor
gcode += "; " + GCodeProcessor::Layer_Change_Tag + "\n";
gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n";
// export layer z
char buf[64];
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)
? lower_layer_edge_grid->get()
: 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),
(m_layer == NULL ? nullptr : m_layer->object()),
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 {
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::Layer_Change_Tag = "LAYER_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::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
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
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
auto is_temporary_decoration = [](const std::string& gcode_line) {
auto is_temporary_decoration = [](const std::string_view gcode_line) {
// remove trailing '\n'
std::string line = gcode_line.substr(0, gcode_line.length() - 1);
if (line == "; " + Layer_Change_Tag)
return true;
else
return false;
assert(! gcode_line.empty());
assert(gcode_line.back() == '\n');
// return true for decorations which are used in processing the gcode but that should not be exported into the final gcode
// 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.
@ -488,7 +501,8 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
{ EProducer::Cura, "Cura_SteamEngine" },
{ EProducer::Simplify3D, "Simplify3D" },
{ EProducer::CraftWare, "CraftWare" },
{ EProducer::ideaMaker, "ideaMaker" }
{ EProducer::ideaMaker, "ideaMaker" },
{ EProducer::KissSlicer, "KISSlicer" }
};
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");
if (extruder_colour != nullptr) {
// takes colors from config
@ -608,7 +619,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
}
}
// replace missing values with default
std::string default_color = "#FF8000";
for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
if (m_result.extruder_colors[i].empty())
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_origin = { 0.0f, 0.0f, 0.0f, 0.0f };
m_cached_position.reset();
#if ENABLE_SHOW_WIPE_MOVES
m_wiping = false;
#endif // ENABLE_SHOW_WIPE_MOVES
m_feedrate = 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);
});
#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
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
TimeMachine& machine = m_time_processor.machines[i];
@ -1027,6 +1053,20 @@ void GCodeProcessor::process_tags(const std::string_view comment)
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) &&
starts_with(comment, Height_Tag)) {
// height tag
@ -1104,11 +1144,14 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
{
switch (m_producer)
{
case EProducer::Slic3rPE:
case EProducer::Slic3r:
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
case EProducer::Cura: { return process_cura_tags(comment); }
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
case EProducer::CraftWare: { return process_craftware_tags(comment); }
case EProducer::ideaMaker: { return process_ideamaker_tags(comment); }
case EProducer::KissSlicer: { return process_kissslicer_tags(comment); }
default: { return false; }
}
}
@ -1178,6 +1221,14 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment)
return true;
}
// layer
tag = "LAYER:";
pos = comment.find(tag);
if (pos != comment.npos) {
++m_layer_id;
return true;
}
return false;
}
@ -1262,9 +1313,8 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
return true;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// geometry
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// ; tool
std::string tag = " tool";
pos = comment.find(tag);
@ -1289,6 +1339,19 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment)
}
#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;
}
@ -1329,6 +1392,13 @@ bool GCodeProcessor::process_craftware_tags(const std::string_view comment)
return true;
}
// layer
pos = comment.find(" Layer #");
if (pos == 0) {
++m_layer_id;
return true;
}
return false;
}
@ -1360,9 +1430,8 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
return true;
}
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// geometry
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
// width
tag = "WIDTH:";
pos = comment.find(tag);
@ -1382,6 +1451,120 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment)
}
#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;
}
@ -1423,7 +1606,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
auto move_type = [this](const AxisCoords& delta_pos) {
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)
#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;
else if (delta_pos[E] > 0.0f) {
if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)

View file

@ -24,6 +24,9 @@ namespace Slic3r {
Pause_Print,
Custom_GCode,
Travel,
#if ENABLE_SHOW_WIPE_MOVES
Wipe,
#endif // ENABLE_SHOW_WIPE_MOVES
Extrude,
Count
};
@ -69,6 +72,10 @@ namespace Slic3r {
{
public:
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 Layer_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 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
static const std::string Width_Tag;
static const std::string Mm3_Per_Mm_Tag;
@ -390,6 +402,9 @@ namespace Slic3r {
AxisCoords m_end_position; // mm
AxisCoords m_origin; // mm
CachedPosition m_cached_position;
#if ENABLE_SHOW_WIPE_MOVES
bool m_wiping;
#endif // ENABLE_SHOW_WIPE_MOVES
float m_feedrate; // mm/s
float m_width; // mm
@ -414,7 +429,8 @@ namespace Slic3r {
Cura,
Simplify3D,
CraftWare,
ideaMaker
ideaMaker,
KissSlicer
};
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_craftware_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);

View file

@ -6,6 +6,7 @@
#include "libslic3r/EdgeGrid.hpp"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/SVG.hpp"
#include "libslic3r/Layer.hpp"
namespace Slic3r {
@ -191,24 +192,98 @@ void SeamPlacer::init(const Print& print)
{
m_enforcers.clear();
m_blockers.clear();
//m_last_seam_position.clear();
m_seam_history.clear();
m_po_list.clear();
for (const PrintObject* po : print.objects()) {
po->project_and_append_custom_facets(true, EnforcerBlockerType::ENFORCER, m_enforcers);
po->project_and_append_custom_facets(true, EnforcerBlockerType::BLOCKER, m_blockers);
}
const std::vector<double>& nozzle_dmrs = print.config().nozzle_diameter.values;
float max_nozzle_dmr = *std::max_element(nozzle_dmrs.begin(), nozzle_dmrs.end());
for (ExPolygons& explgs : m_enforcers)
explgs = Slic3r::offset_ex(explgs, scale_(max_nozzle_dmr));
for (ExPolygons& explgs : m_blockers)
explgs = Slic3r::offset_ex(explgs, scale_(max_nozzle_dmr));
const std::vector<double>& nozzle_dmrs = print.config().nozzle_diameter.values;
float max_nozzle_dmr = *std::max_element(nozzle_dmrs.begin(), nozzle_dmrs.end());
std::vector<ExPolygons> temp_enf;
std::vector<ExPolygons> temp_blk;
for (const PrintObject* po : print.objects()) {
temp_enf.clear();
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 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();
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.
// Let add extra points in between and update the leghths.
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) {
// Seam is aligned to the seam at the preceding layer.
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()) {
//last_pos = m_last_seam_position[po];
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
// 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.
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.
// In that case use last_pos_proj_idx instead.
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];
} else { // spRandom
if (loop.loop_role() == elrContourInternalPerimeter && loop.role() != erExternalPerimeter) {
// This loop does not contain any other loop. Set a random position.
// The other loops will get a seam close to the random point chosen
// on the innermost contour.
//FIXME This works correctly for inner contours first only.
last_pos = this->get_random_seam(layer_idx, polygon);
}
if (loop.role() == erExternalPerimeter && is_custom_seam_on_layer(layer_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, &saw_custom);
if (saw_custom)
last_pos = candidate;
if (po->print()->default_region_config().external_perimeters_first) {
if (loop.role() == erExternalPerimeter)
last_pos = this->get_random_seam(layer_idx, polygon, po_idx);
else {
// Internal perimeters will just use last_pos.
}
} else {
if (loop.loop_role() == elrContourInternalPerimeter && loop.role() != erExternalPerimeter) {
// This loop does not contain any other loop. Set a random position.
// The other loops will get a seam close to the random point chosen
// on the innermost contour.
last_pos = this->get_random_seam(layer_idx, polygon, po_idx);
m_last_loop_was_external = false;
}
if (loop.role() == erExternalPerimeter) {
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;
}
}
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
{
// 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?
std::vector<size_t> enforcers_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_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,
const Polygon& polygon,
size_t po_idx,
std::vector<size_t>& enforcers_idxs,
std::vector<size_t>& blockers_idxs) const
{
enforcers_idxs.clear();
blockers_idxs.clear();
// FIXME: This is quadratic and it should be improved, maybe by building
// an AABB tree (or at least utilize bounding boxes).
for (size_t i=0; i<polygon.points.size(); ++i) {
auto is_inside = [](const Point& pt,
const CustomTrianglesPerLayer& custom_data) -> bool {
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()) {
assert(layer_id < m_enforcers.size());
for (const ExPolygon& explg : m_enforcers[layer_id]) {
if (explg.contains(polygon.points[i]))
enforcers_idxs.push_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_enforcers[po_idx].empty()) {
const CustomTrianglesPerLayer& enforcers = m_enforcers[po_idx][layer_id];
if (! enforcers.polys.empty()) {
for (size_t i=0; i<polygon.points.size(); ++i) {
if (is_inside(polygon.points[i], enforcers))
enforcers_idxs.emplace_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,
const std::vector<float>& lengths,
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;
std::vector<size_t> enforcers_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) {
assert(i < penalties.size());

View file

@ -3,15 +3,17 @@
#include <optional>
#include "libslic3r/ExPolygon.hpp"
#include "libslic3r/Polygon.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/AABBTreeIndirect.hpp"
namespace Slic3r {
class PrintObject;
class ExtrusionLoop;
class Print;
class Layer;
namespace EdgeGrid { class Grid; }
@ -39,14 +41,31 @@ class SeamPlacer {
public:
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,
coordf_t nozzle_diameter, const PrintObject* po,
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:
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;
SeamHistory m_seam_history;
@ -54,32 +73,33 @@ private:
// Get indices of points inside enforcers and blockers.
void get_enforcers_and_blockers(size_t layer_id,
const Polygon& polygon,
size_t po_id,
std::vector<size_t>& enforcers_idxs,
std::vector<size_t>& blockers_idxs) const;
// 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,
const std::vector<float>& lengths,
int layer_id, SeamPosition seam_position) const;
// Return random point of a polygon. The distribution will be uniform
// 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;
// Is there any enforcer/blocker on this layer?
bool is_custom_seam_on_layer(size_t layer_id) const {
return is_custom_enforcer_on_layer(layer_id)
|| is_custom_blocker_on_layer(layer_id);
bool is_custom_seam_on_layer(size_t layer_id, size_t po_idx) const {
return is_custom_enforcer_on_layer(layer_id, po_idx)
|| is_custom_blocker_on_layer(layer_id, po_idx);
}
bool is_custom_enforcer_on_layer(size_t layer_id) const {
return (! m_enforcers.empty() && ! m_enforcers[layer_id].empty());
bool is_custom_enforcer_on_layer(size_t layer_id, size_t po_idx) const {
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 {
return (! m_blockers.empty() && ! m_blockers[layer_id].empty());
bool is_custom_blocker_on_layer(size_t layer_id, size_t po_idx) const {
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);
}
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;
tmp.reserve(std::distance(input_begin, input_end));
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());
}
/// 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
/// 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
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
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>
inline bool liang_barsky_line_clipping(
// 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)
{
Eigen::Matrix<T, 2, 1, Eigen::DontAlign> v = x1 - x0;
double t0 = 0.0;
double t1 = 1.0;
// Traverse through left, right, bottom, top edges.
for (int edge = 0; edge < 4; ++ edge)
{
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;
}
}
std::pair<double, double> interval;
if (liang_barsky_line_clipping_interval(x0, v, bbox, interval)) {
// Clipped successfully.
x1 = x0 + interval.second * v;
x0 += interval.first * v;
}
// Clipped successfully.
x1 = x0 + t1 * v;
x0 += t0 * v;
return true;
}
@ -273,6 +287,35 @@ bool liang_barsky_line_clipping(
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);
Polygon convex_hull(Points points);
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.
Point circle_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); }
Point circle_center_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20);
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.
Vec2d circle_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); }
Vec2d circle_center_taubin_newton(const Vec2ds::const_iterator& input_start, const Vec2ds::const_iterator& input_end, size_t cycles = 20);
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);

View file

@ -100,6 +100,13 @@ bool Line::clip_with_bbox(const BoundingBox &bbox)
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
{
auto v = (this->b - this->a).cast<double>();

View file

@ -24,7 +24,7 @@ namespace line_alg {
template<class L, class T, int N>
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 double l2 = v.squaredNorm(); // avoid a sqrt
if (l2 == 0.0)
@ -54,7 +54,8 @@ public:
Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}
explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
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 reverse() { std::swap(this->a, this->b); }
double length() const { return (b - a).cast<double>().norm(); }
@ -75,6 +76,8 @@ public:
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.
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 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));
}
apts = Geometry::convex_hull(apts);
apts = std::move(Geometry::convex_hull(apts).points);
return ap;
}

View file

@ -17,8 +17,6 @@ class MultiPoint
public:
Points points;
operator Points() const { return this->points; }
MultiPoint() {}
MultiPoint(const MultiPoint &other) : points(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...
// 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
#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
extrusion_paths_append(
paths,
intersection_pl(loop.polygon, perimeter_generator.lower_slices_polygons()),
intersection_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()),
role,
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,
@ -169,7 +169,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append(
paths,
diff_pl(loop.polygon, perimeter_generator.lower_slices_polygons()),
diff_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()),
erOverhangPerimeter,
perimeter_generator.mm3_per_mm_overhang(),
perimeter_generator.overhang_flow.width,

View file

@ -2,6 +2,7 @@
#include "Line.hpp"
#include "MultiPoint.hpp"
#include "Int128.hpp"
#include "BoundingBox.hpp"
#include <algorithm>
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;
}
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)
{
return stm << pointf(0) << "," << pointf(1);

View file

@ -13,6 +13,7 @@
namespace Slic3r {
class BoundingBox;
class Line;
class MultiPoint;
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 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 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); }
template<class T, int N> Eigen::Matrix<T, 2, 1, Eigen::DontAlign>
to_2d(const Eigen::Matrix<T, N, 1, Eigen::DontAlign> &ptN) { return {ptN(0), ptN(1)}; }
template<typename T, int Options>
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)); }
//inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(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)); }
template<class T, int N, int Options>
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 Vec3d to_3d(const Vec2d &v, double z) { return Vec3d(v(0), v(1), z); }
inline Vec3f to_3d(const Vec2f &v, float z) { return Vec3f(v(0), v(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); }
template<class T, int Options>
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 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))); }
@ -132,6 +130,7 @@ public:
void rotate(double angle, const Point &center);
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; }
int nearest_point_index(const Points &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;
}
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 {
// Exact orientation predicate,
// returns +1: CCW, 0: collinear, -1: CW.
@ -291,6 +299,33 @@ public:
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:
typedef typename std::unordered_multimap<Vec2crd, ValueType, PointHash> map_type;
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);
}
BoundingBox get_extents(const Points &points)
{
return BoundingBox(points);
}
BoundingBox get_extents(const Polygon &poly)
{
return poly.bounding_box();

View file

@ -16,12 +16,12 @@ typedef std::vector<Polygon> Polygons;
class Polygon : public MultiPoint
{
public:
operator Polygons() const { Polygons pp; pp.push_back(*this); return pp; }
operator Polyline() const { return this->split_at_first_point(); }
explicit operator Polygons() const { Polygons pp; pp.push_back(*this); return pp; }
explicit operator Polyline() const { return this->split_at_first_point(); }
Point& operator[](Points::size_type idx) { return this->points[idx]; }
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
Polygon() {}
Polygon() = default;
virtual ~Polygon() = default;
explicit Polygon(const Points &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; }
extern BoundingBox get_extents(const Points &points);
extern BoundingBox get_extents(const Polygon &poly);
extern BoundingBox get_extents(const Polygons &polygons);
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()) {
bb = polylines.front().bounding_box();
for (size_t i = 1; i < polylines.size(); ++ i)
bb.merge(polylines[i]);
bb.merge(polylines[i].points);
}
return bb;
}

View file

@ -60,8 +60,8 @@ public:
}
}
operator Polylines() const;
operator Line() const;
explicit operator Polylines() const;
explicit operator Line() const;
const Point& last_point() const override { return this->points.back(); }
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",
"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",
"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",
"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"
@ -439,7 +439,7 @@ const std::vector<std::string>& Preset::filament_options()
{
static std::vector<std::string> s_opts {
"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_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",
@ -1840,8 +1840,11 @@ namespace PresetUtils {
{
std::string out;
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && !pm->bed_model.empty())
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model;
if (pm != nullptr && !pm->bed_model.empty()) {
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;
}
@ -1849,8 +1852,11 @@ namespace PresetUtils {
{
std::string out;
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && !pm->bed_texture.empty())
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
if (pm != nullptr && !pm->bed_texture.empty()) {
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;
}
} // namespace PresetUtils

View file

@ -99,6 +99,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"filament_density",
"filament_notes",
"filament_cost",
"filament_spool_weight",
"first_layer_acceleration",
"first_layer_bed_temperature",
"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.
// 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());
if (! intersection(convex_hulls_other, convex_hull).empty())
if (! intersection(convex_hulls_other, (Polygons)convex_hull).empty())
return false;
polygons_append(convex_hulls_other, convex_hull);
convex_hulls_other.emplace_back(std::move(convex_hull));
}
}
return true;

View file

@ -470,12 +470,14 @@ void PrintConfigDef::init_fff_params()
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("monotonic");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("concentric");
def->enum_values.push_back("hilbertcurve");
def->enum_values.push_back("archimedeanchords");
def->enum_values.push_back("octagramspiral");
def->enum_labels.push_back(L("Rectilinear"));
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("Hilbert Curve"));
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_labels = def_top_fill_pattern->enum_labels;
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->label = L("External perimeters");
@ -816,6 +818,16 @@ void PrintConfigDef::init_fff_params()
def->min = 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->set_default_value(new ConfigOptionStrings { "" });
def->cli = ConfigOptionDef::nocli;
@ -881,6 +893,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Fill pattern for general low-density infill.");
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("alignedrectilinear");
def->enum_values.push_back("grid");
def->enum_values.push_back("triangles");
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("supportcubic");
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("Triangles"));
def->enum_labels.push_back(L("Stars"));
@ -1060,6 +1074,55 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
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->label = L("Infill extruder");
def->category = L("Extruders");
@ -1527,8 +1590,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("perimeter_acceleration", coFloat);
def->label = L("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->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0));

View file

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

View file

@ -11,7 +11,6 @@
#include "Slicing.hpp"
#include "Tesselate.hpp"
#include "Utils.hpp"
#include "AABBTreeIndirect.hpp"
#include "Fill/FillAdaptive.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 == "fill_angle"
|| 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 == "first_layer_extrusion_width") {
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; }
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; }

View file

@ -350,6 +350,7 @@ struct SLAPrintStatistics
size_t fast_layers_count;
double total_cost;
double total_weight;
std::vector<double> layers_times;
// Config with the filled in print statistics.
DynamicConfig config() const;
@ -366,6 +367,7 @@ struct SLAPrintStatistics
fast_layers_count = 0;
total_cost = 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 estim_time(0.0);
std::vector<double> layers_times;
layers_times.reserve(printer_input.size());
size_t slow_layers = 0;
size_t fast_layers = 0;
@ -688,7 +690,7 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
// write vars
&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];
@ -775,20 +777,21 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() {
else
slow_layers++;
// Calculation of the printing time
double layer_times = 0.0;
if (sliced_layer_cnt < 3)
estim_time += init_exp_time;
else if (fade_layer_time > exp_time)
{
layer_times += init_exp_time;
else if (fade_layer_time > exp_time) {
fade_layer_time -= delta_fade_time;
estim_time += fade_layer_time;
layer_times += fade_layer_time;
}
else
estim_time += exp_time;
estim_time += tilt_time;
layer_times += exp_time;
layer_times += 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
if (printer_input.size() == 0)
print_statistics.estimated_print_time = std::nan("");
else
else {
print_statistics.estimated_print_time = estim_time;
print_statistics.layers_times = layers_times;
}
print_statistics.fast_layers_count = fast_layers;
print_statistics.slow_layers_count = slow_layers;

View file

@ -3,8 +3,6 @@
#include <boost/nowide/cstdio.hpp>
#define COORD(x) (unscale<float>((x))*10)
namespace Slic3r {
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");
if (f == NULL)
return false;
float w = COORD(bbox.max(0) - bbox.min(0) + 2 * bbox_offset);
float h = COORD(bbox.max(1) - bbox.min(1) + 2 * bbox_offset);
float w = to_svg_coord(bbox.max(0) - bbox.min(0) + 2 * bbox_offset);
float h = to_svg_coord(bbox.max(1) - bbox.min(1) + 2 * bbox_offset);
this->height = h;
fprintf(this->f,
"<?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"
@ -47,12 +46,11 @@ bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbo
return true;
}
void
SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
void SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
{
fprintf(this->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)
fprintf(this->f, " marker-end=\"url(#endArrow)\"");
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;
fprintf(this->f,
" <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)),
COORD(line.a(1)-da*perp(1)-origin(1)),
COORD(line.b(0)-db*perp(0)-origin(0)),
COORD(line.b(1)-db*perp(1)-origin(1)),
COORD(line.b(0)+db*perp(0)-origin(0)),
COORD(line.b(1)+db*perp(1)-origin(1)),
COORD(line.a(0)+da*perp(0)-origin(0)),
COORD(line.a(1)+da*perp(1)-origin(1)),
to_svg_x(line.a(0)-da*perp(0)-origin(0)),
to_svg_y(line.a(1)-da*perp(1)-origin(1)),
to_svg_x(line.b(0)-db*perp(0)-origin(0)),
to_svg_y(line.b(1)-db*perp(1)-origin(1)),
to_svg_x(line.b(0)+db*perp(0)-origin(0)),
to_svg_y(line.b(1)+db*perp(1)-origin(1)),
to_svg_x(line.a(0)+da*perp(0)-origin(0)),
to_svg_y(line.a(1)+da*perp(1)-origin(1)),
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
SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
void SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
{
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it)
this->draw(*it, stroke, stroke_width);
for (const Line &l : lines)
this->draw(l, stroke, stroke_width);
}
void
SVG::draw(const IntersectionLines &lines, std::string stroke)
void SVG::draw(const IntersectionLines &lines, std::string stroke)
{
for (IntersectionLines::const_iterator it = lines.begin(); it != lines.end(); ++it)
this->draw((Line)*it, stroke);
for (const IntersectionLine &il : lines)
this->draw((Line)il, stroke);
}
void
SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity)
void SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity)
{
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);
}
void
SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
void 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);
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
SVG::draw(const ExPolygons &expolygons, std::string fill, const float fill_opacity)
void SVG::draw(const ExPolygons &expolygons, std::string fill, const float fill_opacity)
{
for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++it)
this->draw(*it, fill, fill_opacity);
}
void
SVG::draw_outline(const ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
void 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)
draw_outline(*it, stroke_outer, stroke_holes, stroke_width);
}
void
SVG::draw(const Surface &surface, std::string fill, const float fill_opacity)
void SVG::draw(const Surface &surface, std::string fill, const float fill_opacity)
{
draw(surface.expolygon, fill, fill_opacity);
}
void
SVG::draw_outline(const Surface &surface, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
void 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);
}
void
SVG::draw(const Surfaces &surfaces, std::string fill, const float fill_opacity)
void SVG::draw(const Surfaces &surfaces, std::string fill, const float fill_opacity)
{
for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it)
this->draw(*it, fill, fill_opacity);
}
void
SVG::draw_outline(const Surfaces &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
void 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)
draw_outline(*it, stroke_outer, stroke_holes, stroke_width);
}
void
SVG::draw(const SurfacesPtr &surfaces, std::string fill, const float fill_opacity)
void SVG::draw(const SurfacesPtr &surfaces, std::string fill, const float fill_opacity)
{
for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it)
this->draw(*(*it), fill, fill_opacity);
}
void
SVG::draw_outline(const SurfacesPtr &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
void 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)
draw_outline(*(*it), stroke_outer, stroke_holes, stroke_width);
}
void
SVG::draw(const Polygon &polygon, std::string fill)
void SVG::draw(const Polygon &polygon, std::string fill)
{
this->fill = fill;
this->path(this->get_path_d(polygon, true), !fill.empty(), 0, 1.f);
}
void
SVG::draw(const Polygons &polygons, std::string fill)
void SVG::draw(const Polygons &polygons, std::string fill)
{
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it)
this->draw(*it, fill);
}
void
SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width)
void SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width)
{
this->stroke = stroke;
this->path(this->get_path_d(polyline, false), false, stroke_width, 1.f);
}
void
SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width)
void SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width)
{
for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
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);
}
void
SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width)
void SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width)
{
for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
this->draw((Polyline)*it, stroke, stroke_width);
}
void
SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
void 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)
draw(it->thicklines(), fill, stroke, stroke_width);
}
void
SVG::draw(const Point &point, std::string fill, coord_t iradius)
void 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;
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 << "\" "
<< "style=\"stroke: none; fill: " << fill << "\" />";
fprintf(this->f, "%s\n", svg.str().c_str());
}
void
SVG::draw(const Points &points, std::string fill, coord_t radius)
void SVG::draw(const Points &points, std::string fill, coord_t radius)
{
for (Points::const_iterator it = points.begin(); it != points.end(); ++it)
this->draw(*it, fill, radius);
}
void
SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width)
void SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width)
{
this->stroke = stroke;
this->path(this->get_path_d(polygon, scale, true), false, stroke_width, 1.f);
}
void
SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width)
void 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)
draw(*it, scale, stroke, stroke_width);
}
void
SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width)
void SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width)
{
this->stroke = stroke;
this->path(this->get_path_d(polygon, true), false, stroke_width, 1.f);
}
void
SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width)
void SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width)
{
for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it)
draw_outline(*it, stroke, stroke_width);
}
void
SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity)
void SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity)
{
float lineWidth = 0.f;
if (! fill)
lineWidth = (stroke_width == 0) ? 2.f : COORD(stroke_width);
lineWidth = (stroke_width == 0) ? 2.f : to_svg_coord(stroke_width);
fprintf(
this->f,
@ -283,27 +256,25 @@ SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fi
);
}
std::string
SVG::get_path_d(const MultiPoint &mp, bool closed) const
std::string SVG::get_path_d(const MultiPoint &mp, bool closed) const
{
std::ostringstream d;
d << "M ";
for (Points::const_iterator p = mp.points.begin(); p != mp.points.end(); ++p) {
d << COORD((*p)(0) - origin(0)) << " ";
d << COORD((*p)(1) - origin(1)) << " ";
d << to_svg_x((*p)(0) - origin(0)) << " ";
d << to_svg_y((*p)(1) - origin(1)) << " ";
}
if (closed) d << "z";
return d.str();
}
std::string
SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
std::string SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const
{
std::ostringstream d;
d << "M ";
for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) {
d << COORD(scale * p->X - origin(0)) << " ";
d << COORD(scale * p->Y - origin(1)) << " ";
d << to_svg_x(scale * p->X - origin(0)) << " ";
d << to_svg_y(scale * p->Y - origin(1)) << " ";
}
if (closed) d << "z";
return d.str();
@ -313,8 +284,8 @@ void SVG::draw_text(const Point &pt, const char *text, const char *color)
{
fprintf(this->f,
"<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"20px\" fill=\"%s\">%s</text>",
COORD(pt(0)-origin(0)),
COORD(pt(1)-origin(1)),
to_svg_x(pt(0)-origin(0)),
to_svg_y(pt(1)-origin(1)),
color, text);
}
@ -322,18 +293,17 @@ void SVG::draw_legend(const Point &pt, const char *text, const char *color)
{
fprintf(this->f,
"<circle cx=\"%f\" cy=\"%f\" r=\"10\" fill=\"%s\"/>",
COORD(pt(0)-origin(0)),
COORD(pt(1)-origin(1)),
to_svg_x(pt(0)-origin(0)),
to_svg_y(pt(1)-origin(1)),
color);
fprintf(this->f,
"<text x=\"%f\" y=\"%f\" font-family=\"sans-serif\" font-size=\"10px\" fill=\"%s\">%s</text>",
COORD(pt(0)-origin(0)) + 20.f,
COORD(pt(1)-origin(1)),
to_svg_x(pt(0)-origin(0)) + 20.f,
to_svg_y(pt(1)-origin(1)),
"black", text);
}
void
SVG::Close()
void SVG::Close()
{
fprintf(this->f, "</svg>\n");
fclose(this->f);

View file

@ -16,27 +16,28 @@ public:
bool arrows;
std::string fill, stroke;
Point origin;
bool flipY;
float height;
bool flipY;
SVG(const char* afilename) :
arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false)
{ open(filename); }
SVG(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) :
arrows(false), fill("grey"), stroke("black"), filename(afilename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY)
{ open(filename, bbox, bbox_offset, aflipY); }
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(flipY)
{ open(filename, bbox, bbox_offset, flipY); }
SVG(const std::string &filename) :
arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false)
{ open(filename); }
SVG(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) :
arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY)
{ open(filename, bbox, bbox_offset, aflipY); }
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(flipY)
{ open(filename, bbox, bbox_offset, flipY); }
~SVG() { if (f != NULL) Close(); }
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)
{ 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); }
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);
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;
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
for (const ExPolygon &expoly : expolygons) {
Surface surface(stInternal, expoly);
@ -2351,7 +2350,6 @@ static inline void fill_expolygons_generate_paths(
{
FillParams fill_params;
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
for (ExPolygon &expoly : expolygons) {
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];
const Point *seg_current_pt = nullptr;
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.
//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.

View file

@ -1,9 +1,9 @@
#ifndef _prusaslicer_technologies_h_
#define _prusaslicer_technologies_h_
//============
//=============
// debug techs
//============
//=============
// Shows camera target in the 3D scene
#define ENABLE_SHOW_CAMERA_TARGET 0
@ -23,20 +23,24 @@
#define DISABLE_INSTANCES_SYNCH 0
// Use wxDataViewRender instead of wxDataViewCustomRenderer
#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
//================
//=================
#define ENABLE_2_2_0_RC1 1
// 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)
//===================
//====================
// 2.3.0.alpha1 techs
//===================
//====================
#define ENABLE_2_3_0_ALPHA1 1
// Enable rendering of objects using environment map
@ -51,26 +55,32 @@
// 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)
// 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
//===================
//====================
#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
//===================
//====================
#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_

View file

@ -103,12 +103,6 @@ enum Axis {
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>
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();
}
// 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.
template<typename T_TO, typename T_FROM>
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::filesystem::permissions(target, perms, 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();
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
@ -442,7 +442,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
ec.clear();
boost::filesystem::permissions(target, perms, 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;
}

View file

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

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