mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'origin/main' into dev/gizmo
This commit is contained in:
		
						commit
						cf5c19fa24
					
				
					 19 changed files with 328 additions and 170 deletions
				
			
		|  | @ -1787,10 +1787,10 @@ msgid "An SD card needs to be inserted before printing via LAN." | |||
| msgstr "Před tiskem přes LAN je třeba vložit SD kartu." | ||||
| 
 | ||||
| msgid "Sending gcode file over LAN" | ||||
| msgstr "Odesílání souboru gcode přes LAN" | ||||
| msgstr "Odesílání souboru gkód přes LAN" | ||||
| 
 | ||||
| msgid "Sending gcode file to sdcard" | ||||
| msgstr "Odesílání souboru gcode na sdcard" | ||||
| msgstr "Odesílání souboru gkód na sd kartu" | ||||
| 
 | ||||
| #, c-format, boost-format | ||||
| msgid "Successfully sent. Close current page in %s s" | ||||
|  | @ -2181,7 +2181,7 @@ msgid "" | |||
| "(Currently supporting automatic supply of consumables with the same brand, " | ||||
| "material type, and color)" | ||||
| msgstr "" | ||||
| "Pokud v AMS existují dva identické filameny, bude povolena záloha AMS " | ||||
| "Pokud v AMS existují dva identické filamenty, bude povolena záloha AMS " | ||||
| "filamentu. \n" | ||||
| "(Aktuálně podporuje automatické doplňování spotřebního materiálu stejné " | ||||
| "značky, typu materiálu a barvy)" | ||||
|  | @ -2333,7 +2333,7 @@ msgid "" | |||
| "Error message: %1%.\n" | ||||
| "Source file %2%." | ||||
| msgstr "" | ||||
| "Soubor gcode se nepodařilo uložit.\n" | ||||
| "Soubor gkód se nepodařilo uložit.\n" | ||||
| "Chybová zpráva: %1%.\n" | ||||
| "Zdrojový soubor %2%." | ||||
| 
 | ||||
|  | @ -2524,7 +2524,7 @@ msgstr "" | |||
| "typ časosběru je tradiční." | ||||
| 
 | ||||
| msgid " But machines with I3 structure will not generate timelapse videos." | ||||
| msgstr " Ale stroje s I3 strukturou nevytvoří timelapse videa." | ||||
| msgstr " Ale stroje s I3 strukturou nevytvářejí časosběrná videa." | ||||
| 
 | ||||
| msgid "" | ||||
| "Change these settings automatically? \n" | ||||
|  | @ -2645,7 +2645,7 @@ msgid "Calibrating the micro lida" | |||
| msgstr "Kalibrace mikro lida" | ||||
| 
 | ||||
| msgid "Calibrating extrusion flow" | ||||
| msgstr "Kalibrace extruze průtpku" | ||||
| msgstr "Kalibrace extruze průtoku" | ||||
| 
 | ||||
| msgid "Paused due to nozzle temperature malfunction" | ||||
| msgstr "Pozastaveno kvůli poruše teploty trysky" | ||||
|  | @ -3449,7 +3449,7 @@ msgid "Export current sliced file" | |||
| msgstr "Exportovat aktuální Slicovaný soubor" | ||||
| 
 | ||||
| msgid "Export all plate sliced file" | ||||
| msgstr "Exportovat všechny soubor slicované na pdložce" | ||||
| msgstr "Exportovat všechny soubor slicované na podložce" | ||||
| 
 | ||||
| msgid "Export G-code" | ||||
| msgstr "Exportovat G-kód" | ||||
|  | @ -4132,7 +4132,7 @@ msgid " upload config prase failed\n" | |||
| msgstr " nahrávání konfigurace se nepodařilo zpracovat\n" | ||||
| 
 | ||||
| msgid " No corresponding storage bucket\n" | ||||
| msgstr " Žádný odpovídající úložný bucket\n" | ||||
| msgstr " Žádný odpovídající úložný prostor\n" | ||||
| 
 | ||||
| msgid " can not be opened\n" | ||||
| msgstr " nelze otevřít\n" | ||||
|  | @ -4366,7 +4366,7 @@ msgid "" | |||
| "The application cannot run normally because OpenGL version is lower than " | ||||
| "2.0.\n" | ||||
| msgstr "" | ||||
| "Aplikace nemůže běžet normálně, protože máte nižší verzi OpenGLnež 2.0.\n" | ||||
| "Aplikace nemůže běžet normálně, protože máte nižší verzi OpenGL než 2.0.\n" | ||||
| 
 | ||||
| msgid "Please upgrade your graphics card driver." | ||||
| msgstr "Prosím aktualizujte ovladač grafické karty." | ||||
|  | @ -4808,7 +4808,7 @@ msgid "" | |||
| "The loaded file contains gcode only, Can not enter the Prepare page" | ||||
| msgstr "" | ||||
| "Režim pouze náhled:\n" | ||||
| "Načtený soubor obsahuje pouze gcode, nelze vstoupit na stránku Příprava" | ||||
| "Načtený soubor obsahuje pouze gkód, nelze vstoupit na stránku Příprava" | ||||
| 
 | ||||
| msgid "You can keep the modified presets to the new project or discard them" | ||||
| msgstr "Upravené předvolby si můžete ponechat pro nový projekt nebo je zahodit" | ||||
|  | @ -4914,7 +4914,7 @@ msgid "The following characters are not allowed by a FAT file system:" | |||
| msgstr "Následující znaky nejsou v souborovém systému FAT povoleny:" | ||||
| 
 | ||||
| msgid "Save Sliced file as:" | ||||
| msgstr "Uložit Slicované soubor jako:" | ||||
| msgstr "Uložit Slicovaný soubor jako:" | ||||
| 
 | ||||
| #, c-format, boost-format | ||||
| msgid "" | ||||
|  | @ -4932,7 +4932,7 @@ msgstr "" | |||
| "kladné části." | ||||
| 
 | ||||
| msgid "Is the printer ready? Is the print sheet in place, empty and clean?" | ||||
| msgstr "Je tiskarna připravená k tisku? Je podložka prázdná a čistá?" | ||||
| msgstr "Je tiskárna připravená k tisku? Je podložka prázdná a čistá?" | ||||
| 
 | ||||
| msgid "Upload and Print" | ||||
| msgstr "Nahrát a Tisknout" | ||||
|  | @ -6226,7 +6226,7 @@ msgid "Jerk limitation" | |||
| msgstr "Omezení Jerk-Ryv" | ||||
| 
 | ||||
| msgid "Single extruder multimaterial setup" | ||||
| msgstr "Nastavení multimaterialu s jedním extruderem" | ||||
| msgstr "Nastavení multimateriálu s jedním extruderem" | ||||
| 
 | ||||
| msgid "Wipe tower" | ||||
| msgstr "Čistící věž" | ||||
|  | @ -6558,7 +6558,7 @@ msgid "Login" | |||
| msgstr "Přihlášení" | ||||
| 
 | ||||
| msgid "The configuration package is changed in previous Config Guide" | ||||
| msgstr "Konfigurační balíček byl změněn v předchozím Config Guide" | ||||
| msgstr "Konfigurační balíček byl změněn v předchozím průvodci konfigurací" | ||||
| 
 | ||||
| msgid "Configuration package changed" | ||||
| msgstr "Konfigurační balíček změněn" | ||||
|  | @ -8221,7 +8221,7 @@ msgid "" | |||
| msgstr "" | ||||
| "Materiál může mít objemovou změnu po přepnutí mezi roztaveným a krystalickým " | ||||
| "stavem. Toto nastavení proporcionálně změní veškerý vytlačovací tok tohoto " | ||||
| "filamentu v gcode. Doporučený rozsah hodnot je mezi 0,95 a 1,05. Možná " | ||||
| "filamentu v gkódu. Doporučený rozsah hodnot je mezi 0,95 a 1,05. Možná " | ||||
| "můžete tuto hodnotu vyladit, abyste získali pěkně rovný povrch, když dochází " | ||||
| "k mírnému přetečení nebo podtečení" | ||||
| 
 | ||||
|  | @ -8323,7 +8323,7 @@ msgid "" | |||
| "Filament diameter is used to calculate extrusion in gcode, so it's important " | ||||
| "and should be accurate" | ||||
| msgstr "" | ||||
| "Průměr filamentu se používá k výpočtu vytlačování v gcode, takže je důležitý " | ||||
| "Průměr filamentu se používá k výpočtu vytlačování v gkódu, takže je důležitý " | ||||
| "a měl by být přesný" | ||||
| 
 | ||||
| msgid "Shrinkage" | ||||
|  | @ -8337,7 +8337,7 @@ msgid "" | |||
| "Be sure to allow enough space between objects, as this compensation is done " | ||||
| "after the checks." | ||||
| msgstr "" | ||||
| "Zadejte procento smrštění, které filament získá po ochlazení (94%      pokud " | ||||
| "Zadejte procento smrštění, které filament získá po ochlazení (94% i pokud " | ||||
| "naměříte 94mm místo 100mm). Část bude pro kompenzaci zmenšena v xy. Bere se " | ||||
| "v úvahu pouze filamentu použit pro obvod.\n" | ||||
| "Ujistěte se aby byl mezi objekty dostatek prostoru, protože tato kompenzace " | ||||
|  | @ -8431,7 +8431,7 @@ msgid "" | |||
| msgstr "" | ||||
| "Doba, po kterou firmware tiskárny (nebo jednotka Multi Material 2.0) zavádí " | ||||
| "nový filament během jeho výměny (při provádění kódu T). Tento čas je přidán " | ||||
| "k celkové době tisku pomocí G-code odhadovače tiskového času." | ||||
| "k celkové době tisku pomocí G-kódu odhadovače tiskového času." | ||||
| 
 | ||||
| msgid "Ramming parameters" | ||||
| msgstr "Parametry rapidní extruze" | ||||
|  | @ -8450,7 +8450,7 @@ msgid "" | |||
| msgstr "" | ||||
| "Doba, po kterou firmware tiskárny (nebo jednotka Multi Material 2.0) vysouvá " | ||||
| "filament během jeho výměny (při provádění kódu T). Tento čas je přidán k " | ||||
| "celkové době tisku pomocí G-code odhadovače tiskového času." | ||||
| "celkové době tisku pomocí G-kódu odhadovače tiskového času." | ||||
| 
 | ||||
| msgid "Enable ramming for multitool setups" | ||||
| msgstr "Povolení rapidní extruze tiskárny s více nástroji" | ||||
|  | @ -9037,7 +9037,7 @@ msgid "G-code flavor" | |||
| msgstr "Druh G-kódu" | ||||
| 
 | ||||
| msgid "What kind of gcode the printer is compatible with" | ||||
| msgstr "S jakým typem gcode je tiskárna kompatibilní" | ||||
| msgstr "S jakým typem gkódu je tiskárna kompatibilní" | ||||
| 
 | ||||
| msgid "Klipper" | ||||
| msgstr "Klipper" | ||||
|  | @ -9181,7 +9181,7 @@ msgstr "" | |||
| "použije výchozí metodu." | ||||
| 
 | ||||
| msgid "This gcode part is inserted at every layer change after lift z" | ||||
| msgstr "Tato část gcode je vložena při každé změně vrstvy po zvednutí z" | ||||
| msgstr "Tato část gkódu je vložena při každé změně vrstvy po zvednutí z" | ||||
| 
 | ||||
| msgid "Supports silent mode" | ||||
| msgstr "Podporuje tichý režim" | ||||
|  | @ -9198,7 +9198,7 @@ msgid "" | |||
| "pause G-code in gcode viewer" | ||||
| msgstr "" | ||||
| "Tento G-kód bude použit jako kód pro pozastavený tisk. Uživatel může vložit " | ||||
| "pauzu G-kód do prohlížeče gcode" | ||||
| "pauzu G-kód do prohlížeče gkódu" | ||||
| 
 | ||||
| msgid "This G-code will be used as a custom code" | ||||
| msgstr "Tento G-kód bude použit jako vlastní kód" | ||||
|  | @ -9669,7 +9669,7 @@ msgid "" | |||
| "resolution and more time to slice" | ||||
| msgstr "" | ||||
| "Cesta G-kódu se generuje po zjednodušení obrysu modelu, aby se předešlo " | ||||
| "příliš velkému počtu bodů a Linek gcode v souboru gcode. Menší hodnota " | ||||
| "příliš velkému počtu bodů a Linek gkódu v souboru gkód. Menší hodnota " | ||||
| "znamená vyšší rozlišení a více času na slicování" | ||||
| 
 | ||||
| msgid "Travel distance threshold" | ||||
|  | @ -9680,7 +9680,7 @@ msgid "" | |||
| "threshold" | ||||
| msgstr "" | ||||
| "Spusťte retrakci pouze tehdy, když je dráha jízdy delší než tato hraniční " | ||||
| "hohnota" | ||||
| "hodnota" | ||||
| 
 | ||||
| msgid "Retract amount before wipe" | ||||
| msgstr "Délka retrakce před očištěním" | ||||
|  | @ -9925,7 +9925,7 @@ msgid "" | |||
| "The printing speed in exported gcode will be slowed down, when the estimated " | ||||
| "layer time is shorter than this value, to get better cooling for these layers" | ||||
| msgstr "" | ||||
| "Rychlost tisku v exportovaném kódu gcode se zpomalí, když je odhadovaná doba " | ||||
| "Rychlost tisku v exportovaném kódu gkód se zpomalí, když je odhadovaná doba " | ||||
| "vrstvy kratší než tato hodnota, aby se dosáhlo lepšího chlazení pro tyto " | ||||
| "vrstvy" | ||||
| 
 | ||||
|  | @ -10089,7 +10089,7 @@ msgid "" | |||
| "print bed, set this to -0.3 (or fix your endstop)." | ||||
| msgstr "" | ||||
| "Tato hodnota bude přidána (nebo odečtena) ze všech souřadnic Z ve výstupním " | ||||
| "G-code. Používá se ke kompenzování špatné pozice endstopu Z. Například pokud " | ||||
| "G-kódu. Používá se ke kompenzování špatné pozice endstopu Z. Například pokud " | ||||
| "endstop 0 skutečně ponechá trysku 0,3 mm daleko od tiskové podložky, " | ||||
| "nastavte hodnotu -0,3 (nebo dolaďte svůj koncový doraz)." | ||||
| 
 | ||||
|  | @ -10283,7 +10283,7 @@ msgstr "" | |||
| "ušetří materiál a sníží poškození objektu.\n" | ||||
| "Pro stromovou podpěru, tenký a organický styl bude agresivněji slučovat " | ||||
| "větve a ušetří mnoho materiálu (výchozí organický), zatímco hybridní styl " | ||||
| "vytvoří podobnou strukturu jako běžná podpěra pod velkými plochými převiy." | ||||
| "vytvoří podobnou strukturu jako běžná podpěra pod velkými plochými převisy." | ||||
| 
 | ||||
| msgid "Snug" | ||||
| msgstr "Přiléhavý" | ||||
|  | @ -10390,7 +10390,7 @@ msgstr "" | |||
| "automaticky vypočítány" | ||||
| 
 | ||||
| msgid "Tree support brim width" | ||||
| msgstr "Šířka Limce podpěr stromů" | ||||
| msgstr "Šířka Límce podpěr stromů" | ||||
| 
 | ||||
| msgid "Distance from tree branch to the outermost brim line" | ||||
| msgstr "Vzdálenost od větve stromu k nejvzdálenější linii Límce" | ||||
|  | @ -10406,7 +10406,7 @@ msgid "Tree support branch diameter" | |||
| msgstr "Průměr větve podpěr stromů" | ||||
| 
 | ||||
| msgid "This setting determines the initial diameter of support nodes." | ||||
| msgstr "Toto nastavení určuje počáteční průměr uzlů poděry." | ||||
| msgstr "Toto nastavení určuje počáteční průměr uzlů podpěr." | ||||
| 
 | ||||
| #. TRN PrintSettings: #lmFIXME | ||||
| msgid "Branch Diameter Angle" | ||||
|  | @ -10501,7 +10501,7 @@ msgid "" | |||
| "This gcode is inserted when change filament, including T command to trigger " | ||||
| "tool change" | ||||
| msgstr "" | ||||
| "Tento gcode se vloží při výměně filamentu, včetně příkazu T ke spuštění " | ||||
| "Tento gkód se vloží při výměně filamentu, včetně příkazu T ke spuštění " | ||||
| "výměny nástroje" | ||||
| 
 | ||||
| msgid "" | ||||
|  | @ -10957,7 +10957,7 @@ msgid "Update the configs values of 3mf to latest." | |||
| msgstr "Aktualizujte konfigurační hodnoty 3mf na nejnovější." | ||||
| 
 | ||||
| msgid "Load default filaments" | ||||
| msgstr "Načíst výchozí filameny" | ||||
| msgstr "Načíst výchozí filamenty" | ||||
| 
 | ||||
| msgid "Load first filament as default for those not loaded" | ||||
| msgstr "Načíst první filament jako výchozí pro ty, které nebyly načteny" | ||||
|  | @ -11399,7 +11399,7 @@ msgid "" | |||
| "3. If the max volumetric speed or print temperature is changed in the " | ||||
| "filament setting." | ||||
| msgstr "" | ||||
| "Nyní jsme přidali automatickou kalibraci pro různé filameny, která je plně " | ||||
| "Nyní jsme přidali automatickou kalibraci pro různé filamenty, která je plně " | ||||
| "automatizovaná a výsledek bude uložen do tiskárny pro budoucí použití. " | ||||
| "Kalibraci musíte provést pouze v následujících omezených případech:\n" | ||||
| "1. Pokud použijete nový filament jiné značky/modelu nebo je filament vlhký;\n" | ||||
|  | @ -11747,7 +11747,7 @@ msgid "Success to get history result" | |||
| msgstr "Úspěšně načtený historický výsledek kalibrace dynamiky průtoku" | ||||
| 
 | ||||
| msgid "Refreshing the historical Flow Dynamics Calibration records" | ||||
| msgstr "Aktualizace historických záznamů kalibrace dynamiky průtpku probíhá" | ||||
| msgstr "Aktualizace historických záznamů kalibrace dynamiky průtoku probíhá" | ||||
| 
 | ||||
| msgid "Action" | ||||
| msgstr "Akce" | ||||
|  | @ -11768,7 +11768,7 @@ msgid "Service name" | |||
| msgstr "Název služby" | ||||
| 
 | ||||
| msgid "OctoPrint version" | ||||
| msgstr "Service name" | ||||
| msgstr "Verze OctoPrintu" | ||||
| 
 | ||||
| msgid "Searching for devices" | ||||
| msgstr "Vyhledávání zařízení" | ||||
|  |  | |||
|  | @ -148,7 +148,7 @@ msgid "Bucket fill" | |||
| msgstr "Flächenfüllung" | ||||
| 
 | ||||
| msgid "Height range" | ||||
| msgstr "Höhenreichweite" | ||||
| msgstr "Höhenbereich" | ||||
| 
 | ||||
| msgid "Ctrl + Shift + Enter" | ||||
| msgstr "Strg + Umschalt + Eingabetaste" | ||||
|  | @ -163,7 +163,7 @@ msgid "Triangle" | |||
| msgstr "Dreieck" | ||||
| 
 | ||||
| msgid "Height Range" | ||||
| msgstr "Höhenreichweite" | ||||
| msgstr "Höhenbereich" | ||||
| 
 | ||||
| msgid "Vertical" | ||||
| msgstr "Vertikal" | ||||
|  |  | |||
|  | @ -65,7 +65,10 @@ | |||
|         "50%" | ||||
|     ], | ||||
|     "close_fan_the_first_x_layers": [ | ||||
|         "1" | ||||
|         "2" | ||||
|     ], | ||||
|         "full_fan_speed_layer": [ | ||||
|         "4" | ||||
|     ], | ||||
|     "nozzle_temperature": [ | ||||
|         "220" | ||||
|  |  | |||
|  | @ -22,9 +22,8 @@ public: | |||
|         } else { | ||||
|             m_E             = 0; | ||||
|             m_retracted     = 0; | ||||
|             m_restart_extra = 0; | ||||
|         } | ||||
| 
 | ||||
|         m_restart_extra = 0; | ||||
|         m_absolute_E    = 0; | ||||
|     } | ||||
| 
 | ||||
|  | @ -34,7 +33,7 @@ public: | |||
|     double retract(double length, double restart_extra); | ||||
|     double unretract(); | ||||
|     double E() const { return m_share_extruder ? m_share_E : m_E; } | ||||
|     void   reset_E() { m_E = 0.; m_share_E = 0.; } | ||||
|     void   reset_E() { reset(); } | ||||
|     double e_per_mm(double mm3_per_mm) const { return mm3_per_mm * m_e_per_mm3; } | ||||
|     double e_per_mm3() const { return m_e_per_mm3; } | ||||
|     // Used filament volume in mm^3.
 | ||||
|  |  | |||
|  | @ -1402,6 +1402,8 @@ namespace DoExport { | |||
|         //BBS
 | ||||
|         //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value);
 | ||||
|         //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
 | ||||
|         //Orca
 | ||||
|         if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value); | ||||
|         if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause G-code")), config.machine_pause_gcode.value); | ||||
|         if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value); | ||||
|         if (ret.size() < MAX_TAGS_COUNT) { | ||||
|  | @ -4755,6 +4757,18 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
| 
 | ||||
|     double F = speed * 60;  // convert mm/sec to mm/min
 | ||||
| 
 | ||||
|     //Orca: process custom gcode for extrusion role change
 | ||||
|     if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) { | ||||
|             DynamicConfig config; | ||||
|             config.set_key_value("extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(path.role()))); | ||||
|             config.set_key_value("last_extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(m_last_extrusion_role))); | ||||
|             config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); | ||||
|             config.set_key_value("layer_z", new ConfigOptionFloat(m_layer == nullptr ? m_last_height : m_layer->print_z)); | ||||
|             gcode += this->placeholder_parser_process("change_extrusion_role_gcode", | ||||
|                                                       m_config.change_extrusion_role_gcode.value, m_writer.extruder()->id(), &config) | ||||
|                      + "\n"; | ||||
|     } | ||||
| 
 | ||||
|     // extrude arc or line
 | ||||
|     if (m_enable_extrusion_role_markers) { | ||||
|         if (path.role() != m_last_extrusion_role) { | ||||
|  | @ -5002,6 +5016,35 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
|     return gcode; | ||||
| } | ||||
| 
 | ||||
| //Orca: get string name of extrusion role. used for change_extruder_role_gcode
 | ||||
| std::string GCode::extrusion_role_to_string_for_parser(const ExtrusionRole & role) | ||||
| { | ||||
|     switch (role) { | ||||
|         case erPerimeter: return "Perimeter"; | ||||
|         case erExternalPerimeter: return "ExternalPerimeter"; | ||||
|         case erOverhangPerimeter: return "OverhangPerimeter"; | ||||
|         case erInternalInfill: return "InternalInfill"; | ||||
|         case erSolidInfill: return "SolidInfill"; | ||||
|         case erTopSolidInfill: return "TopSolidInfill"; | ||||
|         case erBottomSurface: return "BottomSurface"; | ||||
|         case erBridgeInfill: | ||||
|         case erInternalBridgeInfill: return "BridgeInfill"; | ||||
|         case erGapFill: return "GapFill"; | ||||
|         case erIroning: return "Ironing"; | ||||
|         case erSkirt: return "Skirt"; | ||||
|         case erBrim: return "Brim"; | ||||
|         case erSupportMaterial: return "SupportMaterial"; | ||||
|         case erSupportMaterialInterface: return "SupportMaterialInterface"; | ||||
|         case erSupportTransition: return "SupportTransition"; | ||||
|         case erWipeTower: return "WipeTower"; | ||||
|         case erCustom: | ||||
|         case erMixed: | ||||
|         case erCount: | ||||
|         case erNone: | ||||
|         default: return "Mixed"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::string encodeBase64(uint64_t value) | ||||
| { | ||||
|     //Always use big endian mode
 | ||||
|  |  | |||
|  | @ -205,6 +205,7 @@ public: | |||
|     // inside the generated string and after the G-code export finishes.
 | ||||
|     std::string     placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); | ||||
|     bool            enable_cooling_markers() const { return m_enable_cooling_markers; } | ||||
|     std::string     extrusion_role_to_string_for_parser(const ExtrusionRole &); | ||||
| 
 | ||||
|     // For Perl bindings, to be used exclusively by unit tests.
 | ||||
|     unsigned int    layer_count() const { return m_layer_count; } | ||||
|  | @ -213,7 +214,7 @@ public: | |||
| 
 | ||||
|     std::string     travel_to(const Point& point, ExtrusionRole role, std::string comment); | ||||
|     bool            needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type); | ||||
|     std::string     retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::SpiralLift); | ||||
|     std::string     retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift); | ||||
|     std::string     unretract() { return m_writer.unlift() + m_writer.unretract(); } | ||||
|     std::string     set_extruder(unsigned int extruder_id, double print_z); | ||||
|     bool is_BBL_Printer(); | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| ///|/ Copyright (c) Prusa Research 2020 - 2022 Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas
 | ||||
| ///|/
 | ||||
| ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
 | ||||
| ///|/
 | ||||
| #include "../Layer.hpp" | ||||
| #include "../GCode.hpp" | ||||
| #include "../EdgeGrid.hpp" | ||||
|  | @ -13,6 +17,8 @@ | |||
| #include <unordered_set> | ||||
| #include <boost/range/adaptor/reversed.hpp> | ||||
| 
 | ||||
| //#define AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| struct TravelPoint | ||||
|  | @ -20,6 +26,8 @@ struct TravelPoint | |||
|     Point point; | ||||
|     // Index of the polygon containing this point. A negative value indicates that the point is not on any border.
 | ||||
|     int   border_idx; | ||||
|     // simplify_travel() doesn't remove this point.
 | ||||
|     bool  do_not_remove = false; | ||||
| }; | ||||
| 
 | ||||
| struct Intersection | ||||
|  | @ -32,6 +40,8 @@ struct Intersection | |||
|     Point  point; | ||||
|     // Distance from the first point in the corresponding boundary
 | ||||
|     float  distance; | ||||
|     // simplify_travel() doesn't remove this point.
 | ||||
|     bool   do_not_remove = false; | ||||
| }; | ||||
| 
 | ||||
| struct ClosestLine | ||||
|  | @ -207,8 +217,8 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte | |||
|             const ClosestLine &cl_start = start_lines[cl_indices.first]; | ||||
|             const ClosestLine &cl_end   = end_lines[cl_indices.second]; | ||||
|             std::vector<Intersection> new_intersections; | ||||
|             new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}); | ||||
|             new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}); | ||||
|             new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}); | ||||
|             new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}); | ||||
|             return new_intersections; | ||||
|         } | ||||
|     } | ||||
|  | @ -259,7 +269,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte | |||
|         if (cl_start_idx != std::numeric_limits<size_t>::max()) { | ||||
|             // If there is any ClosestLine around the start point closer to the Intersection, then replace this Intersection with ClosestLine.
 | ||||
|             const ClosestLine &cl_start = start_lines[cl_start_idx]; | ||||
|             new_intersections.front()   = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}; | ||||
|             new_intersections.front()   = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}; | ||||
|         } else { | ||||
|             // Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the
 | ||||
|             // vector of intersections. This allows in some cases when it is more than one around ClosestLine start point chose that one which
 | ||||
|  | @ -267,7 +277,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte | |||
|             // use the first one, which is the closest one to the start point.
 | ||||
|             size_t             start_closest_lines_idx = find_closest_line_with_same_boundary_idx(start_lines, new_intersections, true); | ||||
|             const ClosestLine &cl_start                = (start_closest_lines_idx != std::numeric_limits<size_t>::max()) ? start_lines[start_closest_lines_idx] : start_lines.front(); | ||||
|             new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)}); | ||||
|             new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true}); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -276,7 +286,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte | |||
|         if (cl_end_idx != std::numeric_limits<size_t>::max()) { | ||||
|             // If there is any ClosestLine around the end point closer to the Intersection, then replace this Intersection with ClosestLine.
 | ||||
|             const ClosestLine &cl_end = end_lines[cl_end_idx]; | ||||
|             new_intersections.back()  = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}; | ||||
|             new_intersections.back()  = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}; | ||||
|         } else { | ||||
|             // Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the
 | ||||
|             // vector of intersections. This allows in some cases when it is more than one around ClosestLine end point chose that one which
 | ||||
|  | @ -284,7 +294,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte | |||
|             // use the first one, which is the closest one to the end point.
 | ||||
|             size_t             end_closest_lines_idx = find_closest_line_with_same_boundary_idx(end_lines, new_intersections, false); | ||||
|             const ClosestLine &cl_end                = (end_closest_lines_idx != std::numeric_limits<size_t>::max()) ? end_lines[end_closest_lines_idx] : end_lines.front(); | ||||
|             new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)}); | ||||
|             new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true}); | ||||
|         } | ||||
|     } | ||||
|     return new_intersections; | ||||
|  | @ -350,8 +360,6 @@ static Polyline to_polyline(const std::vector<TravelPoint> &travel) | |||
|     return result; | ||||
| } | ||||
| 
 | ||||
| // #define AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT
 | ||||
| 
 | ||||
| #ifdef AVOID_CROSSING_PERIMETERS_DEBUG_OUTPUT | ||||
| static void export_travel_to_svg(const Polygons                  &boundary, | ||||
|                                  const Line                      &original_travel, | ||||
|  | @ -359,16 +367,17 @@ static void export_travel_to_svg(const Polygons                  &boundary, | |||
|                                  const std::vector<Intersection> &intersections, | ||||
|                                  const std::string               &path) | ||||
| { | ||||
|     BoundingBox   bbox = get_extents(boundary); | ||||
|     coordf_t      stroke_width = scale_(0.05); | ||||
|     BoundingBox   bbox         = get_extents(boundary); | ||||
|     ::Slic3r::SVG svg(path, bbox); | ||||
|     svg.draw_outline(boundary, "green"); | ||||
|     svg.draw(original_travel, "blue"); | ||||
|     svg.draw(result_travel, "red"); | ||||
|     svg.draw(original_travel.a, "black"); | ||||
|     svg.draw(original_travel.b, "grey"); | ||||
|     svg.draw_outline(boundary, "green", stroke_width); | ||||
|     svg.draw(original_travel, "blue", stroke_width); | ||||
|     svg.draw(result_travel, "red", stroke_width); | ||||
|     svg.draw(original_travel.a, "black", stroke_width); | ||||
|     svg.draw(original_travel.b, "grey", stroke_width); | ||||
| 
 | ||||
|     for (const Intersection &intersection : intersections) | ||||
|         svg.draw(intersection.point, "lightseagreen"); | ||||
|         svg.draw(intersection.point, "lightseagreen", stroke_width); | ||||
| } | ||||
| 
 | ||||
| static void export_travel_to_svg(const Polygons                  &boundary, | ||||
|  | @ -433,21 +442,30 @@ static std::vector<TravelPoint> simplify_travel(const AvoidCrossingPerimeters::B | |||
| 
 | ||||
|         visitor.pt_current = ¤t_point; | ||||
| 
 | ||||
|         for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) { | ||||
|             if (travel[point_idx_2].point == current_point) { | ||||
|                 next      = travel[point_idx_2]; | ||||
|                 point_idx = point_idx_2; | ||||
|                 continue; | ||||
|             } | ||||
|         if (!next.do_not_remove) | ||||
|             for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) { | ||||
|                 // Workaround for some issue in MSVC 19.29.30037 32-bit compiler.
 | ||||
| #if defined(_WIN32) && !defined(_WIN64) | ||||
|                 if (bool volatile do_not_remove = travel[point_idx_2].do_not_remove; do_not_remove) | ||||
|                     break; | ||||
| #else | ||||
|                 if (travel[point_idx_2].do_not_remove) | ||||
|                     break; | ||||
| #endif | ||||
|                 if (travel[point_idx_2].point == current_point) { | ||||
|                     next      = travel[point_idx_2]; | ||||
|                     point_idx = point_idx_2; | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|             visitor.pt_next = &travel[point_idx_2].point; | ||||
|             boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|             // Check if deleting point causes crossing a boundary
 | ||||
|             if (!visitor.intersect) { | ||||
|                 next      = travel[point_idx_2]; | ||||
|                 point_idx = point_idx_2; | ||||
|                 visitor.pt_next = &travel[point_idx_2].point; | ||||
|                 boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|                 // Check if deleting point causes crossing a boundary
 | ||||
|                 if (!visitor.intersect) { | ||||
|                     next      = travel[point_idx_2]; | ||||
|                     point_idx = point_idx_2; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         simplified_path.emplace_back(next); | ||||
|     } | ||||
|  | @ -473,7 +491,7 @@ static float get_perimeter_spacing(const Layer &layer) | |||
|     size_t regions_count     = 0; | ||||
|     float  perimeter_spacing = 0.f; | ||||
|     for (const LayerRegion *layer_region : layer.regions()) | ||||
|         if (layer_region != nullptr && !layer_region->slices.empty()) { | ||||
|         if (layer_region != nullptr && ! layer_region->slices.empty()) { | ||||
|             perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing(); | ||||
|             ++regions_count; | ||||
|         } | ||||
|  | @ -494,7 +512,7 @@ static float get_perimeter_spacing_external(const Layer &layer) | |||
|     for (const PrintObject *object : layer.object()->print()->objects()) | ||||
|         if (const Layer *l = object->get_layer_at_printz(layer.print_z, EPSILON); l) | ||||
|             for (const LayerRegion *layer_region : l->regions()) | ||||
|                 if (layer_region != nullptr && !layer_region->slices.empty()) { | ||||
|                 if (layer_region != nullptr && ! layer_region->slices.empty()) { | ||||
|                     perimeter_spacing += layer_region->flow(frPerimeter).scaled_spacing(); | ||||
|                     ++ regions_count; | ||||
|                 } | ||||
|  | @ -507,6 +525,25 @@ static float get_perimeter_spacing_external(const Layer &layer) | |||
|     return perimeter_spacing; | ||||
| } | ||||
| 
 | ||||
| // Returns average perimeter width calculated from all LayerRegion within the layer.
 | ||||
| static float get_external_perimeter_width(const Layer &layer) | ||||
| { | ||||
|     size_t regions_count     = 0; | ||||
|     float  perimeter_width   = 0.f; | ||||
|     for (const LayerRegion *layer_region : layer.regions()) | ||||
|         if (layer_region != nullptr && ! layer_region->slices.empty()) { | ||||
|             perimeter_width += float(layer_region->flow(frExternalPerimeter).scaled_width()); | ||||
|             ++regions_count; | ||||
|         } | ||||
| 
 | ||||
|     assert(perimeter_width >= 0.f); | ||||
|     if (regions_count != 0) | ||||
|         perimeter_width /= float(regions_count); | ||||
|     else | ||||
|         perimeter_width = get_default_perimeter_spacing(*layer.object()); | ||||
|     return perimeter_width; | ||||
| } | ||||
| 
 | ||||
| // Called by avoid_perimeters() and by simplify_travel_heuristics().
 | ||||
| static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &boundary, | ||||
|                                      const Point                             &start, | ||||
|  | @ -566,7 +603,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo | |||
|         // Offset of the polygon's point using get_middle_point_offset is used to simplify the calculation of intersection between the
 | ||||
|         // boundary and the travel. The appended point is translated in the direction of inward normal. This translation ensures that the
 | ||||
|         // appended point will be inside the polygon and not on the polygon border.
 | ||||
|         result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx)}); | ||||
|         result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx), intersection_first.do_not_remove}); | ||||
| 
 | ||||
|         // Check if intersection line also exit the boundary polygon
 | ||||
|         if (it_second_r != it_last_item) { | ||||
|  | @ -590,7 +627,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo | |||
|             // Append the farthest intersection into the path
 | ||||
|             left_idx  = intersection_second.line_idx; | ||||
|             right_idx = (intersection_second.line_idx >= (boundaries[intersection_second.border_idx].points.size() - 1)) ? 0 : (intersection_second.line_idx + 1); | ||||
|             result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx)}); | ||||
|             result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx), intersection_second.do_not_remove}); | ||||
|             // Skip intersections in between
 | ||||
|             it_first = it_second; | ||||
|         } | ||||
|  | @ -645,22 +682,22 @@ static size_t avoid_perimeters(const AvoidCrossingPerimeters::Boundary &boundary | |||
| // Check if anyone of ExPolygons contains whole travel.
 | ||||
| // called by need_wipe() and AvoidCrossingPerimeters::travel_to()
 | ||||
| // FIXME Lukas H.: Maybe similar approach could also be used for ExPolygon::contains()
 | ||||
| static bool any_expolygon_contains(const ExPolygons               &ex_polygons, | ||||
|                                    const std::vector<BoundingBox> &ex_polygons_bboxes, | ||||
|                                    const EdgeGrid::Grid            &grid_lslice, | ||||
| static bool any_expolygon_contains(const ExPolygons               &lslices_offset, | ||||
|                                    const std::vector<BoundingBox> &lslices_offset_bboxes, | ||||
|                                    const EdgeGrid::Grid            &grid_lslices_offset, | ||||
|                                    const Line                      &travel) | ||||
| { | ||||
|     assert(ex_polygons.size() == ex_polygons_bboxes.size()); | ||||
|     if(!grid_lslice.bbox().contains(travel.a) || !grid_lslice.bbox().contains(travel.b)) | ||||
|     assert(lslices_offset.size() == lslices_offset_bboxes.size()); | ||||
|     if(!grid_lslices_offset.bbox().contains(travel.a) || !grid_lslices_offset.bbox().contains(travel.b)) | ||||
|         return false; | ||||
| 
 | ||||
|     FirstIntersectionVisitor visitor(grid_lslice); | ||||
|     FirstIntersectionVisitor visitor(grid_lslices_offset); | ||||
|     visitor.pt_current = &travel.a; | ||||
|     visitor.pt_next    = &travel.b; | ||||
|     grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|     grid_lslices_offset.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|     if (!visitor.intersect) { | ||||
|         for (const ExPolygon &ex_polygon : ex_polygons) { | ||||
|             const BoundingBox &bbox = ex_polygons_bboxes[&ex_polygon - &ex_polygons.front()]; | ||||
|         for (const ExPolygon &ex_polygon : lslices_offset) { | ||||
|             const BoundingBox &bbox = lslices_offset_bboxes[&ex_polygon - &lslices_offset.front()]; | ||||
|             if (bbox.contains(travel.a) && bbox.contains(travel.b) && ex_polygon.contains(travel.a)) | ||||
|                 return true; | ||||
|         } | ||||
|  | @ -670,18 +707,18 @@ static bool any_expolygon_contains(const ExPolygons               &ex_polygons, | |||
| 
 | ||||
| // Check if anyone of ExPolygons contains whole travel.
 | ||||
| // called by need_wipe()
 | ||||
| static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector<BoundingBox> &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice, const Polyline &travel) | ||||
| static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vector<BoundingBox> &ex_polygons_bboxes, const EdgeGrid::Grid &grid_lslice_offset, const Polyline &travel) | ||||
| { | ||||
|     assert(ex_polygons.size() == ex_polygons_bboxes.size()); | ||||
|     if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice](const Point &point) { return !grid_lslice.bbox().contains(point); })) | ||||
|     if(std::any_of(travel.points.begin(), travel.points.end(), [&grid_lslice_offset](const Point &point) { return !grid_lslice_offset.bbox().contains(point); })) | ||||
|         return false; | ||||
| 
 | ||||
|     FirstIntersectionVisitor visitor(grid_lslice); | ||||
|     FirstIntersectionVisitor visitor(grid_lslice_offset); | ||||
|     bool any_intersection = false; | ||||
|     for (size_t line_idx = 1; line_idx < travel.size(); ++line_idx) { | ||||
|         visitor.pt_current = &travel.points[line_idx - 1]; | ||||
|         visitor.pt_next    = &travel.points[line_idx]; | ||||
|         grid_lslice.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|         grid_lslice_offset.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor); | ||||
|         any_intersection = visitor.intersect; | ||||
|         if (any_intersection) break; | ||||
|     } | ||||
|  | @ -698,13 +735,13 @@ static bool any_expolygon_contains(const ExPolygons &ex_polygons, const std::vec | |||
| } | ||||
| 
 | ||||
| static bool need_wipe(const GCode          &gcodegen, | ||||
|                       const EdgeGrid::Grid &grid_lslice, | ||||
|                       const Line           &original_travel, | ||||
|                       const Polyline       &result_travel, | ||||
|                       const size_t          intersection_count) | ||||
|                       const ExPolygons               &lslices_offset, | ||||
|                       const std::vector<BoundingBox> &lslices_offset_bboxes, | ||||
|                       const EdgeGrid::Grid           &grid_lslices_offset, | ||||
|                       const Line                     &original_travel, | ||||
|                       const Polyline                 &result_travel, | ||||
|                       const size_t                    intersection_count) | ||||
| { | ||||
|     const ExPolygons               &lslices        = gcodegen.layer()->lslices; | ||||
|     const std::vector<BoundingBox> &lslices_bboxes = gcodegen.layer()->lslices_bboxes; | ||||
|     bool z_lift_enabled = gcodegen.config().z_hop.get_at(gcodegen.writer().extruder()->id()) > 0.; | ||||
|     bool wipe_needed    = false; | ||||
| 
 | ||||
|  | @ -714,16 +751,16 @@ static bool need_wipe(const GCode          &gcodegen, | |||
|         // The original layer is intersected with defined boundaries. Then it is necessary to make a detailed test.
 | ||||
|         // If the z-lift is enabled, then a wipe is needed when the original travel leads above the holes.
 | ||||
|         if (z_lift_enabled) { | ||||
|             if (any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, original_travel)) { | ||||
|             if (any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, original_travel)) { | ||||
|                 // Check if original_travel and result_travel are not same.
 | ||||
|                 // If both are the same, then it is possible to skip testing of result_travel
 | ||||
|                 wipe_needed = !(result_travel.size() > 2 && result_travel.first_point() == original_travel.a && result_travel.last_point() == original_travel.b) && | ||||
|                               !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); | ||||
|                               !any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, result_travel); | ||||
|             } else { | ||||
|                 wipe_needed = true; | ||||
|             } | ||||
|         } else { | ||||
|             wipe_needed = !any_expolygon_contains(lslices, lslices_bboxes, grid_lslice, result_travel); | ||||
|             wipe_needed = !any_expolygon_contains(lslices_offset, lslices_offset_bboxes, grid_lslices_offset, result_travel); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -945,55 +982,71 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid, | |||
| // ExPolygons are handled one by one so returned ExPolygons could intersect.
 | ||||
| static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset) | ||||
| { | ||||
|     double     min_contour_width = 2. * offset + SCALED_EPSILON; | ||||
|     double     search_radius     = 2. * (offset + min_contour_width); | ||||
|     ExPolygons ex_poly_result    = ex_polygons; | ||||
|     const std::vector<double> min_contour_width_values = {offset / 2., offset, 2. * offset + SCALED_EPSILON}; | ||||
|     ExPolygons                ex_poly_result           = ex_polygons; | ||||
|     resample_expolygons(ex_poly_result, offset / 2, scaled<double>(0.5)); | ||||
| 
 | ||||
|     for (ExPolygon &ex_poly : ex_poly_result) { | ||||
|         BoundingBox bbox(get_extents(ex_poly)); | ||||
|         bbox.offset(SCALED_EPSILON); | ||||
|         EdgeGrid::Grid grid; | ||||
|         grid.set_bbox(bbox); | ||||
|         grid.create(ex_poly, coord_t(0.7 * search_radius)); | ||||
| 
 | ||||
|         std::vector<std::vector<float>> ex_poly_distances; | ||||
|         precompute_expolygon_distances(ex_poly, ex_poly_distances); | ||||
|         // Filter out expolygons smaller than 0.1mm^2
 | ||||
|         if (Vec2d bbox_size = bbox.size().cast<double>(); bbox_size.x() * bbox_size.y() < Slic3r::sqr(scale_(0.1f))) | ||||
|             continue; | ||||
| 
 | ||||
|         std::vector<std::vector<float>> offsets; | ||||
|         offsets.reserve(ex_poly.holes.size() + 1); | ||||
|         for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) { | ||||
|             const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1]; | ||||
|             assert(poly.is_counter_clockwise() == (idx_contour == 0)); | ||||
|             std::vector<float> distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius); | ||||
|             for (float &distance : distances) { | ||||
|                 if (distance < min_contour_width) | ||||
|                     distance = 0.f; | ||||
|                 else if (distance > min_contour_width + 2. * offset) | ||||
|                     distance = - float(offset); | ||||
|                 else | ||||
|                     distance = - (distance - float(min_contour_width)) / 2.f; | ||||
|             } | ||||
|             offsets.emplace_back(distances); | ||||
|         } | ||||
|         for (const double &min_contour_width : min_contour_width_values) { | ||||
|             const size_t min_contour_width_idx = &min_contour_width - &min_contour_width_values.front(); | ||||
|             const double search_radius         = 2. * (offset + min_contour_width); | ||||
| 
 | ||||
|         ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets); | ||||
|         // If variable_offset_inner_ex produces empty result, then original ex_polygon is used
 | ||||
|         if (offset_ex_poly.size() == 1) { | ||||
|             ex_poly = std::move(offset_ex_poly.front()); | ||||
|         } else if (offset_ex_poly.size() > 1) { | ||||
|             // fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces
 | ||||
|             // tiny artefacts polygons, so these artefacts are removed.
 | ||||
|             double max_area     = offset_ex_poly.front().area(); | ||||
|             size_t max_area_idx = 0; | ||||
|             for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) { | ||||
|                 double area = offset_ex_poly[poly_idx].area(); | ||||
|                 if (max_area < area) { | ||||
|                     max_area     = area; | ||||
|                     max_area_idx = poly_idx; | ||||
|             EdgeGrid::Grid grid; | ||||
|             grid.set_bbox(bbox); | ||||
|             grid.create(ex_poly, coord_t(0.7 * search_radius)); | ||||
| 
 | ||||
|             std::vector<std::vector<float>> ex_poly_distances; | ||||
|             precompute_expolygon_distances(ex_poly, ex_poly_distances); | ||||
| 
 | ||||
|             std::vector<std::vector<float>> offsets; | ||||
|             offsets.reserve(ex_poly.holes.size() + 1); | ||||
|             for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) { | ||||
|                 const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1]; | ||||
|                 assert(poly.is_counter_clockwise() == (idx_contour == 0)); | ||||
|                 std::vector<float> distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius); | ||||
|                 for (float &distance : distances) { | ||||
|                     if (distance < min_contour_width) | ||||
|                         distance = 0.f; | ||||
|                     else if (distance > min_contour_width + 2. * offset) | ||||
|                         distance = -float(offset); | ||||
|                     else | ||||
|                         distance = -(distance - float(min_contour_width)) / 2.f; | ||||
|                 } | ||||
|                 offsets.emplace_back(distances); | ||||
|             } | ||||
| 
 | ||||
|             ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets); | ||||
|             // If variable_offset_inner_ex produces empty result, then original ex_polygon is used
 | ||||
|             if (offset_ex_poly.size() == 1 && offset_ex_poly.front().holes.size() == ex_poly.holes.size()) { | ||||
|                 ex_poly = std::move(offset_ex_poly.front()); | ||||
|                 break; | ||||
|             } else if ((min_contour_width_idx + 1) < min_contour_width_values.size()) { | ||||
|                 continue; // Try the next round with bigger min_contour_width.
 | ||||
|             } else if (offset_ex_poly.size() == 1) { | ||||
|                 ex_poly = std::move(offset_ex_poly.front()); | ||||
|                 break; | ||||
|             } else if (offset_ex_poly.size() > 1) { | ||||
|                 // fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces
 | ||||
|                 // tiny artefacts polygons, so these artefacts are removed.
 | ||||
|                 double max_area     = offset_ex_poly.front().area(); | ||||
|                 size_t max_area_idx = 0; | ||||
|                 for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) { | ||||
|                     double area = offset_ex_poly[poly_idx].area(); | ||||
|                     if (max_area < area) { | ||||
|                         max_area     = area; | ||||
|                         max_area_idx = poly_idx; | ||||
|                     } | ||||
|                 } | ||||
|                 ex_poly = std::move(offset_ex_poly[max_area_idx]); | ||||
|                 break; | ||||
|             } | ||||
|             ex_poly = std::move(offset_ex_poly[max_area_idx]); | ||||
|         } | ||||
|     } | ||||
|     return ex_poly_result; | ||||
|  | @ -1133,10 +1186,8 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & | |||
|     Vec2d startf = start.cast<double>(); | ||||
|     Vec2d endf   = end  .cast<double>(); | ||||
| 
 | ||||
|     const ExPolygons               &lslices          = gcodegen.layer()->lslices; | ||||
|     const std::vector<BoundingBox> &lslices_bboxes   = gcodegen.layer()->lslices_bboxes; | ||||
|     bool                            is_support_layer = (dynamic_cast<const SupportLayer *>(gcodegen.layer()) != nullptr); | ||||
|     if (!use_external && (is_support_layer || (!lslices.empty() && !any_expolygon_contains(lslices, lslices_bboxes, m_grid_lslice, travel)))) { | ||||
|     bool is_support_layer = dynamic_cast<const SupportLayer *>(gcodegen.layer()) != nullptr; | ||||
|     if (!use_external && (is_support_layer || (!m_lslices_offset.empty() && !any_expolygon_contains(m_lslices_offset, m_lslices_offset_bboxes, m_grid_lslices_offset, travel)))) { | ||||
|         // Initialize m_internal only when it is necessary.
 | ||||
|         if (m_internal.boundaries.empty()) | ||||
|             init_boundary(&m_internal, to_polygons(get_boundary(*gcodegen.layer()))); | ||||
|  | @ -1186,7 +1237,7 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & | |||
|     } else if (max_detour_length_exceeded) { | ||||
|         *could_be_wipe_disabled = false; | ||||
|     } else | ||||
|         *could_be_wipe_disabled = !need_wipe(gcodegen, m_grid_lslice, travel, result_pl, travel_intersection_count); | ||||
|         *could_be_wipe_disabled = !need_wipe(gcodegen, m_lslices_offset, m_lslices_offset_bboxes, m_grid_lslices_offset, travel, result_pl, travel_intersection_count); | ||||
| 
 | ||||
|     return result_pl; | ||||
| } | ||||
|  | @ -1197,13 +1248,21 @@ void AvoidCrossingPerimeters::init_layer(const Layer &layer) | |||
| { | ||||
|     m_internal.clear(); | ||||
|     m_external.clear(); | ||||
|     m_lslices_offset.clear(); | ||||
|     m_lslices_offset_bboxes.clear(); | ||||
| 
 | ||||
|     float perimeter_offset = -get_external_perimeter_width(layer) / float(2.); | ||||
|     m_lslices_offset        = offset_ex(layer.lslices, perimeter_offset); | ||||
| 
 | ||||
|     m_lslices_offset_bboxes.reserve(m_lslices_offset.size()); | ||||
|     for (const ExPolygon &ex_poly : m_lslices_offset) | ||||
|         m_lslices_offset_bboxes.emplace_back(get_extents(ex_poly)); | ||||
| 
 | ||||
|     BoundingBox bbox_slice(get_extents(layer.lslices)); | ||||
|     bbox_slice.offset(SCALED_EPSILON); | ||||
| 
 | ||||
|     m_grid_lslice.set_bbox(bbox_slice); | ||||
|     //FIXME 1mm grid?
 | ||||
|     m_grid_lslice.create(layer.lslices, coord_t(scale_(1.))); | ||||
|     m_grid_lslices_offset.set_bbox(bbox_slice); | ||||
|     m_grid_lslices_offset.create(m_lslices_offset, coord_t(scale_(1.))); | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| ///|/ Copyright (c) Prusa Research 2020 - 2022 Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv
 | ||||
| ///|/
 | ||||
| ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
 | ||||
| ///|/
 | ||||
| #ifndef slic3r_AvoidCrossingPerimeters_hpp_ | ||||
| #define slic3r_AvoidCrossingPerimeters_hpp_ | ||||
| 
 | ||||
|  | @ -58,8 +62,11 @@ private: | |||
|     // we enable it by default for the first travel move in print
 | ||||
|     bool           m_disabled_once { true }; | ||||
| 
 | ||||
|     // Lslices offseted by half an external perimeter width. Used for detection if line or polyline is inside of any polygon.
 | ||||
|     ExPolygons               m_lslices_offset; | ||||
|     std::vector<BoundingBox> m_lslices_offset_bboxes; | ||||
|     // Used for detection of line or polyline is inside of any polygon.
 | ||||
|     EdgeGrid::Grid m_grid_lslice; | ||||
|     EdgeGrid::Grid           m_grid_lslices_offset; | ||||
|     // Store all needed data for travels inside object
 | ||||
|     Boundary m_internal; | ||||
|     // Store all needed data for travels outside object
 | ||||
|  |  | |||
|  | @ -320,7 +320,7 @@ std::string GCodeWriter::reset_e(bool force) | |||
|         return ""; | ||||
|      | ||||
|     if (m_extruder != nullptr) { | ||||
|         if (m_extruder->E() == 0. && ! force) | ||||
|         if (is_zero(m_extruder->E()) && ! force) | ||||
|             return ""; | ||||
|         m_extruder->reset_E(); | ||||
|     } | ||||
|  | @ -709,7 +709,7 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std | |||
|         length = 1; | ||||
| 
 | ||||
|     std::string gcode; | ||||
|     if (double dE = m_extruder->retract(length, restart_extra);  dE != 0) { | ||||
|     if (double dE = m_extruder->retract(length, restart_extra);  !is_zero(dE)) { | ||||
|         if (this->config.use_firmware_retraction) { | ||||
|             gcode = FLAVOR_IS(gcfMachinekit) ? "G22 ; retract\n" : "G10 ; retract\n"; | ||||
|         } | ||||
|  | @ -737,7 +737,7 @@ std::string GCodeWriter::unretract() | |||
|     if (FLAVOR_IS(gcfMakerWare)) | ||||
|         gcode = "M101 ; extruder on\n"; | ||||
|      | ||||
|     if (double dE = m_extruder->unretract(); dE != 0) { | ||||
|     if (double dE = m_extruder->unretract(); !is_zero(dE)) { | ||||
|         if (this->config.use_firmware_retraction) { | ||||
|             gcode += FLAVOR_IS(gcfMachinekit) ? "G23 ; unretract\n" : "G11 ; unretract\n"; | ||||
|             gcode += this->reset_e(); | ||||
|  |  | |||
|  | @ -819,7 +819,7 @@ static std::vector<std::string> s_Preset_printer_options { | |||
|     "printer_technology", | ||||
|     "printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", | ||||
|     "fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs", | ||||
|     "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", | ||||
|     "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode", | ||||
|     "printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", | ||||
|     "default_print_profile", "inherits", | ||||
|     "silent_mode", | ||||
|  |  | |||
|  | @ -3970,6 +3970,15 @@ def = this->add("filament_loading_speed", coFloats); | |||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionString("")); | ||||
| 
 | ||||
|     def = this->add("change_extrusion_role_gcode", coString); | ||||
|     def->label = L("Change extrusion role G-code"); | ||||
|     def->tooltip = L("This gcode is inserted when the extrusion role is changed"); | ||||
|     def->multiline = true; | ||||
|     def->full_width = true; | ||||
|     def->height = 5; | ||||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionString("")); | ||||
| 
 | ||||
|     def = this->add("top_surface_line_width", coFloatOrPercent); | ||||
|     def->label = L("Top surface"); | ||||
|     def->category = L("Quality"); | ||||
|  |  | |||
|  | @ -969,6 +969,7 @@ PRINT_CONFIG_CLASS_DEFINE( | |||
|     ((ConfigOptionBool,                single_extruder_multi_material_priming)) | ||||
|     ((ConfigOptionBool,                wipe_tower_no_sparse_layers)) | ||||
|     ((ConfigOptionString,              change_filament_gcode)) | ||||
|     ((ConfigOptionString,              change_extrusion_role_gcode)) | ||||
|     ((ConfigOptionFloat,               travel_speed)) | ||||
|     ((ConfigOptionFloat,               travel_speed_z)) | ||||
|     ((ConfigOptionBool,                silent_mode)) | ||||
|  |  | |||
|  | @ -278,6 +278,12 @@ constexpr inline T sqr(T x) | |||
|     return x * x; | ||||
| } | ||||
| 
 | ||||
| template<typename Number> constexpr  | ||||
| inline bool is_zero(Number value) | ||||
| { | ||||
|     return std::fabs(double(value)) < 1e-6; | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Number> | ||||
| constexpr inline T lerp(const T& a, const T& b, Number t) | ||||
| { | ||||
|  |  | |||
|  | @ -2123,16 +2123,15 @@ void GUI_App::init_app_config() | |||
|         app_config = new AppConfig(); | ||||
|         //app_config = new AppConfig(is_editor() ? AppConfig::EAppMode::Editor : AppConfig::EAppMode::GCodeViewer);
 | ||||
| 
 | ||||
|     m_config_corrupted = false; | ||||
| 	// load settings
 | ||||
| 	m_app_conf_exists = app_config->exists(); | ||||
| 	if (m_app_conf_exists) { | ||||
|         std::string error = app_config->load(); | ||||
|         if (!error.empty()) { | ||||
|             // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
 | ||||
|             throw Slic3r::RuntimeError( | ||||
|                 _u8L("OrcaSlicer configuration file may be corrupted and is not abled to be parsed." | ||||
|                      "Please delete the file and try again.") + | ||||
|                 "\n\n" + app_config->config_path() + "\n\n" + error); | ||||
|             // Orca: if the config file is corrupted, we will show a error dialog and create a default config file.
 | ||||
|             m_config_corrupted = true; | ||||
| 
 | ||||
|         } | ||||
|         // Save orig_version here, so its empty if no app_config existed before this run.
 | ||||
|         m_last_config_version = app_config->orig_version();//parse_semver_from_ini(app_config->config_path());
 | ||||
|  | @ -2749,6 +2748,7 @@ bool GUI_App::on_init_inner() | |||
| 
 | ||||
|         if (m_post_initialized && app_config->dirty()) | ||||
|             app_config->save(); | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|     m_initialized = true; | ||||
|  | @ -2756,6 +2756,13 @@ bool GUI_App::on_init_inner() | |||
|     flush_logs(); | ||||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(info) << "finished the gui app init"; | ||||
|     if (m_config_corrupted) { | ||||
|         m_config_corrupted = false; | ||||
|         show_error(nullptr, | ||||
|                    _u8L( | ||||
|                        "The OrcaSlicer configuration file may be corrupted and cannot be parsed.\nOrcaSlicer has attempted to recreate the " | ||||
|                        "configuration file.\nPlease note, application settings will be lost, but printer profiles will not be affected.")); | ||||
|     } | ||||
|     //BBS: delete splash screen
 | ||||
|     delete scrn; | ||||
|     return true; | ||||
|  |  | |||
|  | @ -658,6 +658,7 @@ private: | |||
|     bool                    m_datadir_redefined { false }; | ||||
|     std::string             m_older_data_dir_path; | ||||
|     boost::optional<Semver> m_last_config_version; | ||||
|     bool                    m_config_corrupted { false }; | ||||
| }; | ||||
| 
 | ||||
| DECLARE_APP(GUI_App) | ||||
|  |  | |||
|  | @ -149,6 +149,17 @@ bool GLGizmoText::on_init() | |||
| 
 | ||||
|     reset_text_info(); | ||||
| 
 | ||||
|     m_desc["font"]          = _L("Font"); | ||||
|     m_desc["size"]          = _L("Size"); | ||||
|     m_desc["thickness"]     = _L("Thickness"); | ||||
|     m_desc["text_gap"]      = _L("Text Gap"); | ||||
|     m_desc["angle"]         = _L("Angle"); | ||||
|     m_desc["embeded_depth"] = _L("Embeded\ndepth"); | ||||
|     m_desc["input_text"]    = _L("Input text"); | ||||
| 
 | ||||
|     m_desc["surface"]         = _L("Surface"); | ||||
|     m_desc["horizontal_text"] = _L("Horizontal text"); | ||||
| 
 | ||||
|     m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or dowm"); | ||||
|     m_desc["rotate_text"]         = _L("Rotate text"); | ||||
| 
 | ||||
|  | @ -667,13 +678,13 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|     ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale); | ||||
|     GizmoImguiBegin("Text", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); | ||||
| 
 | ||||
|     float space_size = m_imgui->get_style_scaling() * 8; | ||||
|     float font_cap = m_imgui->calc_text_size(_L("Font")).x; | ||||
|     float size_cap = m_imgui->calc_text_size(_L("Size")).x; | ||||
|     float thickness_cap = m_imgui->calc_text_size(_L("Thickness")).x; | ||||
|     float input_cap = m_imgui->calc_text_size(_L("Input text")).x; | ||||
|     float depth_cap = m_imgui->calc_text_size(_L("Embeded")).x; | ||||
|     float caption_size  = std::max(std::max(font_cap, size_cap), std::max(depth_cap, input_cap)) + space_size + ImGui::GetStyle().WindowPadding.x; | ||||
|     const float space_size = m_imgui->get_style_scaling() * 8; | ||||
|     const std::array<std::string, 7> cap_array = std::array<std::string, 7>{ "font", "size", "thickness", "text_gap", "angle", "embeded_depth", "input_text" }; | ||||
|     float caption_size  = 0.0f; | ||||
|     for (const auto &t : cap_array) { | ||||
|         caption_size = std::max(caption_size, m_imgui->calc_text_size(m_desc[t]).x); | ||||
|     } | ||||
|     caption_size += space_size + ImGui::GetStyle().WindowPadding.x; | ||||
| 
 | ||||
|     float input_text_size = m_imgui->scaled(10.0f); | ||||
|     float button_size = ImGui::GetFrameHeight(); | ||||
|  | @ -700,7 +711,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
| 
 | ||||
|     m_imgui->text(_L("Font")); | ||||
|     m_imgui->text(m_desc["font"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(list_width); | ||||
|     push_combo_style(currt_scale); | ||||
|  | @ -740,7 +751,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|     ImGui::PopStyleVar(2); | ||||
|     pop_combo_style(); | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Size")); | ||||
|     m_imgui->text(m_desc["size"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(input_size); | ||||
|     if(ImGui::InputFloat("###font_size", &m_font_size, 0.0f, 0.0f, "%.2f")) | ||||
|  | @ -767,7 +778,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|     ImGui::PopStyleVar(3); | ||||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Thickness")); | ||||
|     m_imgui->text(m_desc["thickness"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(list_width); | ||||
|     float old_value = m_thickness; | ||||
|  | @ -782,7 +793,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|     const float drag_left_width   = caption_size + slider_width + space_size; | ||||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Text Gap")); | ||||
|     m_imgui->text(m_desc["text_gap"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(slider_width); | ||||
|     if (m_imgui->bbl_slider_float_style("##text_gap", &m_text_gap, -100, 100, "%.2f", 1.0f, true)) | ||||
|  | @ -793,7 +804,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|         m_need_update_text = true; | ||||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Angle")); | ||||
|     m_imgui->text(m_desc["angle"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(slider_width); | ||||
|     if (m_imgui->bbl_slider_float_style("##angle", &m_rotate_angle, 0, 360, "%.2f", 1.0f, true)) | ||||
|  | @ -804,7 +815,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|         m_need_update_text = true; | ||||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Embeded\ndepth")); | ||||
|     m_imgui->text(m_desc["embeded_depth"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(list_width); | ||||
|     old_value = m_embeded_depth; | ||||
|  | @ -815,7 +826,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|         m_need_update_text = true; | ||||
| 
 | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(_L("Input text")); | ||||
|     m_imgui->text(m_desc["input_text"]); | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::PushItemWidth(list_width); | ||||
| 
 | ||||
|  | @ -833,12 +844,12 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) | |||
|      | ||||
|     ImGui::SameLine(caption_size); | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     if (m_imgui->bbl_checkbox(_L("Surface"), m_is_surface_text)) | ||||
|     if (m_imgui->bbl_checkbox(m_desc["surface"], m_is_surface_text)) | ||||
|         m_need_update_text = true; | ||||
| 
 | ||||
|     ImGui::SameLine(); | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     if (m_imgui->bbl_checkbox(_L("Horizontal text"), m_keep_horizontal)) | ||||
|     if (m_imgui->bbl_checkbox(m_desc["horizontal_text"], m_keep_horizontal)) | ||||
|         m_need_update_text = true; | ||||
| 
 | ||||
|     //ImGui::SameLine();
 | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ constexpr double miscalculation = scale_(scale_(1));   // equal to 1 mm2 | |||
| 
 | ||||
| static const float  LEFT_MARGIN       = 13.0f + 100.0f;  // avoid thumbnail toolbar
 | ||||
| static const float  HORIZONTAL_SLIDER_WINDOW_HEIGHT  = 64.0f; | ||||
| static const float  VERTICAL_SLIDER_WINDOW_WIDTH     = 124.0f; | ||||
| static const float  VERTICAL_SLIDER_WINDOW_WIDTH     = 160.0f; | ||||
| static const float  GROOVE_WIDTH      = 12.0f; | ||||
| static const ImVec2 ONE_LAYER_MARGIN  = ImVec2(20.0f, 20.0f); | ||||
| static const ImVec2 ONE_LAYER_BUTTON_SIZE  = ImVec2(28.0f, 28.0f); | ||||
|  |  | |||
|  | @ -534,7 +534,7 @@ void PartPlate::calc_vertex_for_icons(int index, PickingModel &model) | |||
| 	ExPolygon poly; | ||||
| 	auto bed_ext = get_extents(m_shape); | ||||
|     Vec2d p = bed_ext[2]; | ||||
|     if (m_plater->get_build_volume_type() == BuildVolume_Type::Circle) | ||||
|     if (m_plater && m_plater->get_build_volume_type() == BuildVolume_Type::Circle) | ||||
|         p[1] -= std::max( | ||||
|             0.0, (bed_ext.size()(1) - 5 * PARTPLATE_ICON_SIZE - 4 * PARTPLATE_ICON_GAP_Y - PARTPLATE_ICON_GAP_TOP) / 2); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3232,6 +3232,17 @@ void TabPrinter::build_fff() | |||
|         option.opt.height = gcode_field_height;//150;
 | ||||
|         optgroup->append_single_option_line(option); | ||||
| 
 | ||||
|         optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0); | ||||
|         optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { | ||||
|             validate_custom_gcode_cb(this, optgroup, opt_key, value); | ||||
|         }; | ||||
| 
 | ||||
|         option = optgroup->get_option("change_extrusion_role_gcode"); | ||||
|         option.opt.full_width = true; | ||||
|         option.opt.is_code = true; | ||||
|         option.opt.height = gcode_field_height;//150;
 | ||||
|         optgroup->append_single_option_line(option); | ||||
| 
 | ||||
|         optgroup = page->new_optgroup(L("Pause G-code"), L"param_gcode", 0); | ||||
|         optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { | ||||
|             validate_custom_gcode_cb(this, optgroup_title, opt_key, value); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Noisyfox
						Noisyfox