mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-14 18:27:58 -06:00
Merge branch 'main' into enh-port-edit-gcode-dlg
This commit is contained in:
commit
11fd73a90d
34 changed files with 2622 additions and 745 deletions
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-01-13 17:34+0100\n"
|
"POT-Creation-Date: 2024-01-19 18:27+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -3758,7 +3758,7 @@ msgstr ""
|
||||||
msgid "Size:"
|
msgid "Size:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, possible-c-format, possible-boost-format
|
#, possible-boost-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please "
|
"Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please "
|
||||||
"separate the conflicted objects farther (%s <-> %s)."
|
"separate the conflicted objects farther (%s <-> %s)."
|
||||||
|
@ -3830,6 +3830,15 @@ msgstr ""
|
||||||
msgid "Resolution"
|
msgid "Resolution"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enable"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Hostname or IP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Custom camera source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Show \"Live Video\" guide page."
|
msgid "Show \"Live Video\" guide page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -4605,6 +4614,9 @@ msgstr ""
|
||||||
msgid "Camera Setting"
|
msgid "Camera Setting"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Switch Camera View"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Control"
|
msgid "Control"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -8126,6 +8138,29 @@ msgid ""
|
||||||
"bottom shell layers"
|
"bottom shell layers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Apply gap fill"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Enables gap fill for the selected surfaces. The minimum gap length that will "
|
||||||
|
"be filled can be controlled from the filter out tiny gaps option below.\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
"1. Everywhere: Applies gap fill to top, bottom and internal solid surfaces\n"
|
||||||
|
"2. Top and Bottom surfaces: Applies gap fill to top and bottom surfaces "
|
||||||
|
"only\n"
|
||||||
|
"3. Nowhere: Disables gap fill\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Everywhere"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Top and bottom surfaces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Nowhere"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Force cooling for overhang and bridge"
|
msgid "Force cooling for overhang and bridge"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -8562,6 +8597,18 @@ msgid ""
|
||||||
"thickness (top+bottom solid layers)"
|
"thickness (top+bottom solid layers)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Further reduce solid infill on walls (experimental)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Further reduces any solid infill applied to walls. As there will be very "
|
||||||
|
"limited infill supporting solid surfaces, make sure that you are using "
|
||||||
|
"adequate number of walls to support the part on sloping surfaces.\n"
|
||||||
|
"\n"
|
||||||
|
"For heavily sloped surfaces this option is not suitable as it will generate "
|
||||||
|
"too thin of a top layer and should be disabled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Top surface pattern"
|
msgid "Top surface pattern"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -9840,9 +9887,6 @@ msgid ""
|
||||||
"model and save printing time, but make slicing and G-code generating slower"
|
"model and save printing time, but make slicing and G-code generating slower"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enable"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Filename format"
|
msgid "Filename format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -12557,3 +12601,151 @@ msgid ""
|
||||||
"Message body: \"%1%\"\n"
|
"Message body: \"%1%\"\n"
|
||||||
"Error: \"%2%\""
|
"Error: \"%2%\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Precise wall]
|
||||||
|
msgid "Precise wall\nDid you know that turning on precise wall can improve precision and layer consistency?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Sandwich mode]
|
||||||
|
msgid "Sandwich mode\nDid you know that you can use sandwich mode (inner-outer-inner) to improve precision and layer consistency if your model doesn't have very steep overhangs?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Chamber temperature]
|
||||||
|
msgid "Chamber temperature\nDid you know that OrcaSlicer supports chamber temperature?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Calibration]
|
||||||
|
msgid "Calibration\nDid you know that calibrating your printer can do wonders? Check out our beloved calibration solution in OrcaSlicer."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Auxiliary fan]
|
||||||
|
msgid "Auxiliary fan\nDid you know that OrcaSlicer supports Auxiliary part cooling fan?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Air filtration]
|
||||||
|
msgid "Air filtration/Exhuast Fan\nDid you know that OrcaSlicer can support Air filtration/Exhuast Fan?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:G-code window]
|
||||||
|
msgid "G-code window\nYou can turn on/off the G-code window by pressing the <b>C</b> key."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Switch workspaces]
|
||||||
|
msgid "Switch workspaces\nYou can switch between <b>Prepare</b> and <b>Preview</b> workspaces by pressing the <b>Tab</b> key."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:How to use keyboard shortcuts]
|
||||||
|
msgid "How to use keyboard shortcuts\nDid you know that Orca Slicer offers a wide range of keyboard shortcuts and 3D scene operations."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Reverse on odd]
|
||||||
|
msgid "Reverse on odd\nDid you know that <b>Reverse on odd</b> feature can significantly improve the surface quality of your overhangs?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Cut Tool]
|
||||||
|
msgid "Cut Tool\nDid you know that you can cut a model at any angle and position with the cutting tool?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Fix Model]
|
||||||
|
msgid "Fix Model\nDid you know that you can fix a corrupted 3D model to avoid a lot of slicing problems on the Windows system?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Timelapse]
|
||||||
|
msgid "Timelapse\nDid you know that you can generate a timelapse video during each print?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Auto-Arrange]
|
||||||
|
msgid "Auto-Arrange\nDid you know that you can auto-arrange all objects in your project?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Auto-Orient]
|
||||||
|
msgid "Auto-Orient\nDid you know that you can rotate objects to an optimal orientation for printing by a simple click?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Lay on Face]
|
||||||
|
msgid "Lay on Face\nDid you know that you can quickly orient a model so that one of its faces sits on the print bed? Select the \"Place on face\" function or press the <b>F</b> key."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Object List]
|
||||||
|
msgid "Object List\nDid you know that you can view all objects/parts in a list and change settings for each object/part?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Search Functionality]
|
||||||
|
msgid "Search Functionality\nDid you know that you use the Search tool to quickly find a specific Orca Slicer setting?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Simplify Model]
|
||||||
|
msgid "Simplify Model\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Slicing Parameter Table]
|
||||||
|
msgid "Slicing Parameter Table\nDid you know that you can view all objects/parts on a table and change settings for each object/part?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Split to Objects/Parts]
|
||||||
|
msgid "Split to Objects/Parts\nDid you know that you can split a big object into small ones for easy colorizing or printing?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Subtract a Part]
|
||||||
|
msgid "Subtract a Part\nDid you know that you can subtract one mesh from another using the Negative part modifier? That way you can, for example, create easily resizable holes directly in Orca Slicer."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:STEP]
|
||||||
|
msgid "STEP\nDid you know that you can improve your print quality by slicing a STEP file instead of an STL?\nOrca Slicer supports slicing STEP files, providing smoother results than a lower resolution STL. Give it a try!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Z seam location]
|
||||||
|
msgid "Z seam location\nDid you know that you can customize the location of the Z seam, and even paint it on your print, to have it in a less visible location? This improves the overall look of your model. Check it out!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Fine-tuning for flow rate]
|
||||||
|
msgid "Fine-tuning for flow rate\nDid you know that flow rate can be fine-tuned for even better-looking prints? Depending on the material, you can improve the overall finish of the printed model by doing some fine-tuning."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Split your prints into plates]
|
||||||
|
msgid "Split your prints into plates\nDid you know that you can split a model that has a lot of parts into individual plates ready to print? This will simplify the process of keeping track of all the parts."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer Height]
|
||||||
|
msgid "Speed up your print with Adaptive Layer Height\nDid you know that you can print a model even faster, by using the Adaptive Layer Height option? Check it out!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Support painting]
|
||||||
|
msgid "Support painting\nDid you know that you can paint the location of your supports? This feature makes it easy to place the support material only on the sections of the model that actually need it."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Different types of supports]
|
||||||
|
msgid "Different types of supports\nDid you know that you can choose from multiple types of supports? Tree supports work great for organic models, while saving filament and improving print speed. Check them out!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Printing Silk Filament]
|
||||||
|
msgid "Printing Silk Filament\nDid you know that Silk filament needs special consideration to print it successfully? Higher temperature and lower speed are always recommended for the best results."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Brim for better adhesion]
|
||||||
|
msgid "Brim for better adhesion\nDid you know that when printing models have a small contact interface with the printing surface, it's recommended to use a brim?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Set parameters for multiple objects]
|
||||||
|
msgid "Set parameters for multiple objects\nDid you know that you can set slicing parameters for all selected objects at one time?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Stack objects]
|
||||||
|
msgid "Stack objects\nDid you know that you can stack objects as a whole one?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Flush into support/objects/infill]
|
||||||
|
msgid "Flush into support/objects/infill\nDid you know that you can save the wasted filament by flushing them into support/objects/infill during filament change?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Improve strength]
|
||||||
|
msgid "Improve strength\nDid you know that you can use more wall loops and higher sparse infill density to improve the strength of the model?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:When need to print with the printer door opened]
|
||||||
|
msgid "When need to print with the printer door opened\nDid you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature. More info about this in the Wiki."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: resources/data/hints.ini: [hint:Avoid warping]
|
||||||
|
msgid "Avoid warping\nDid you know that when printing materials that are prone to warping such as ABS, appropriately increasing the heatbed temperature can reduce the probability of warping."
|
||||||
|
msgstr ""
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Orca Slicer\n"
|
"Project-Id-Version: Orca Slicer\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-01-13 17:34+0100\n"
|
"POT-Creation-Date: 2024-01-21 14:28+0100\n"
|
||||||
"PO-Revision-Date: \n"
|
"PO-Revision-Date: \n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Guislain Cyril, Thomas Lété\n"
|
"Language-Team: Guislain Cyril, Thomas Lété\n"
|
||||||
|
@ -759,7 +759,7 @@ msgstr "Annuler les modifications apportées à la police."
|
||||||
|
|
||||||
#, boost-format
|
#, boost-format
|
||||||
msgid "Font \"%1%\" can't be selected."
|
msgid "Font \"%1%\" can't be selected."
|
||||||
msgstr "La police « %1% » ne peut pas être sélectionnée."
|
msgstr "La police « %1% » ne peut pas être sélectionnée."
|
||||||
|
|
||||||
msgid "Operation"
|
msgid "Operation"
|
||||||
msgstr "Opération"
|
msgstr "Opération"
|
||||||
|
@ -845,7 +845,7 @@ msgstr "Impossible de supprimer le dernier style existant."
|
||||||
|
|
||||||
#, boost-format
|
#, boost-format
|
||||||
msgid "Are you sure you want to permanently remove the \"%1%\" style?"
|
msgid "Are you sure you want to permanently remove the \"%1%\" style?"
|
||||||
msgstr "Êtes-vous sûr de vouloir supprimer définitivement le style « %1% » ?"
|
msgstr "Êtes-vous sûr de vouloir supprimer définitivement le style « %1% » ?"
|
||||||
|
|
||||||
#, boost-format
|
#, boost-format
|
||||||
msgid "Delete \"%1%\" style."
|
msgid "Delete \"%1%\" style."
|
||||||
|
@ -1015,8 +1015,8 @@ msgid ""
|
||||||
"Can't load exactly same font(\"%1%\"). Aplication selected a similar "
|
"Can't load exactly same font(\"%1%\"). Aplication selected a similar "
|
||||||
"one(\"%2%\"). You have to specify font for enable edit text."
|
"one(\"%2%\"). You have to specify font for enable edit text."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Impossible de charger exactement la même police (« %1% »). L’application a "
|
"Impossible de charger exactement la même police (« %1% »). L’application a "
|
||||||
"sélectionné une police similaire (« %2% »). Vous devez spécifier la police "
|
"sélectionné une police similaire (« %2% »). Vous devez spécifier la police "
|
||||||
"pour permettre l’édition du texte."
|
"pour permettre l’édition du texte."
|
||||||
|
|
||||||
msgid "No symbol"
|
msgid "No symbol"
|
||||||
|
@ -2995,8 +2995,8 @@ msgid ""
|
||||||
"A desiccant status lower than two bars indicates that desiccant may be "
|
"A desiccant status lower than two bars indicates that desiccant may be "
|
||||||
"inactive. Please change the desiccant.(The bars: higher the better.)"
|
"inactive. Please change the desiccant.(The bars: higher the better.)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Un état du dessicant inférieur à deux barres indique que le dessicant est "
|
"Un état du dessicateur inférieur à deux barres indique que le dessicateur "
|
||||||
"peut-être inactif. Veuillez changer le déshydratant. (Plus c'est élevé, "
|
"est peut-être inactif. Veuillez changer le déshydratant. (Plus c'est élevé, "
|
||||||
"mieux c'est.)"
|
"mieux c'est.)"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -3005,7 +3005,7 @@ msgid ""
|
||||||
"process. During this time, the indicator may not represent the chamber "
|
"process. During this time, the indicator may not represent the chamber "
|
||||||
"accurately."
|
"accurately."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Remarque: Lorsque le couvercle est ouvert ou que le sachet de dessinateur "
|
"Remarque: Lorsque le couvercle est ouvert ou que le sachet de dessicateur "
|
||||||
"est changé, cela peut prendre plusieurs heures ou une nuit pour absorber "
|
"est changé, cela peut prendre plusieurs heures ou une nuit pour absorber "
|
||||||
"l'humidité. Les basses températures ralentissent également le processus. "
|
"l'humidité. Les basses températures ralentissent également le processus. "
|
||||||
"Pendant ce temps, l'indicateur pourrait ne pas représenter l'humidité dans "
|
"Pendant ce temps, l'indicateur pourrait ne pas représenter l'humidité dans "
|
||||||
|
@ -3423,8 +3423,8 @@ msgid ""
|
||||||
"Alternate extra wall only works with ensure vertical shell thickness "
|
"Alternate extra wall only works with ensure vertical shell thickness "
|
||||||
"disabled. "
|
"disabled. "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La paroi supplémentaire alternée ne fonctionne que si « Assurer l’épaisseur "
|
"La paroi supplémentaire alternée ne fonctionne que si « Assurer l’épaisseur "
|
||||||
"verticale de la coque » est désactivé. "
|
"verticale de la coque » est désactivé. "
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Change these settings automatically? \n"
|
"Change these settings automatically? \n"
|
||||||
|
@ -3433,9 +3433,9 @@ msgid ""
|
||||||
"No - Dont use alternate extra wall"
|
"No - Dont use alternate extra wall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Modifier ces paramètres automatiquement ? \n"
|
"Modifier ces paramètres automatiquement ? \n"
|
||||||
"Oui - Désactiver « Assurer l’épaisseur verticale de la coque » et activer "
|
"Oui - Désactiver « Assurer l’épaisseur verticale de la coque » et activer « "
|
||||||
"« Paroi supplémentaire alternée »\n"
|
"Paroi supplémentaire alternée »\n"
|
||||||
"Non - Ne pas utiliser « Paroi supplémentaire alternée »"
|
"Non - Ne pas utiliser « Paroi supplémentaire alternée »"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Prime tower does not work when Adaptive Layer Height or Independent Support "
|
"Prime tower does not work when Adaptive Layer Height or Independent Support "
|
||||||
|
@ -4148,6 +4148,15 @@ msgstr "Passer en LIVE"
|
||||||
msgid "Resolution"
|
msgid "Resolution"
|
||||||
msgstr "Résolution"
|
msgstr "Résolution"
|
||||||
|
|
||||||
|
msgid "Enable"
|
||||||
|
msgstr "Activer"
|
||||||
|
|
||||||
|
msgid "Hostname or IP"
|
||||||
|
msgstr "Nom d’hôte ou IP"
|
||||||
|
|
||||||
|
msgid "Custom camera source"
|
||||||
|
msgstr "Source caméra personnalisée"
|
||||||
|
|
||||||
msgid "Show \"Live Video\" guide page."
|
msgid "Show \"Live Video\" guide page."
|
||||||
msgstr "Afficher la page de guide « Vidéo en direct »."
|
msgstr "Afficher la page de guide « Vidéo en direct »."
|
||||||
|
|
||||||
|
@ -4968,6 +4977,9 @@ msgstr "Carte SD"
|
||||||
msgid "Camera Setting"
|
msgid "Camera Setting"
|
||||||
msgstr "Réglage de la Caméra"
|
msgstr "Réglage de la Caméra"
|
||||||
|
|
||||||
|
msgid "Switch Camera View"
|
||||||
|
msgstr "Changer la vue de la caméra"
|
||||||
|
|
||||||
msgid "Control"
|
msgid "Control"
|
||||||
msgstr "Contrôle"
|
msgstr "Contrôle"
|
||||||
|
|
||||||
|
@ -6591,7 +6603,7 @@ msgid "Busy"
|
||||||
msgstr "Occupé"
|
msgstr "Occupé"
|
||||||
|
|
||||||
msgid "Bambu Cool Plate"
|
msgid "Bambu Cool Plate"
|
||||||
msgstr "Plaque Bambu Cool Plate"
|
msgstr "Plateau Cool Plate"
|
||||||
|
|
||||||
msgid "PLA Plate"
|
msgid "PLA Plate"
|
||||||
msgstr "Plaque PLA"
|
msgstr "Plaque PLA"
|
||||||
|
@ -6603,7 +6615,7 @@ msgid "Bambu Smooth PEI Plate"
|
||||||
msgstr "Bambu Smooth PEI Plate"
|
msgstr "Bambu Smooth PEI Plate"
|
||||||
|
|
||||||
msgid "High temperature Plate"
|
msgid "High temperature Plate"
|
||||||
msgstr "Bambu High Temperature Plate"
|
msgstr "Plateau haute température"
|
||||||
|
|
||||||
msgid "Bambu Textured PEI Plate"
|
msgid "Bambu Textured PEI Plate"
|
||||||
msgstr "Bambu Textured PEI Plate"
|
msgstr "Bambu Textured PEI Plate"
|
||||||
|
@ -6827,8 +6839,8 @@ msgid ""
|
||||||
"Caution to use! Flow calibration on Textured PEI Plate may fail due to the "
|
"Caution to use! Flow calibration on Textured PEI Plate may fail due to the "
|
||||||
"scattered surface."
|
"scattered surface."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Attention à l’utilisation ! La calibration du débit sur le plateau Bambu "
|
"Attention à l’utilisation ! La calibration du débit sur le plateau PEI "
|
||||||
"Dual-Sided Textured PEI peut échouer en raison de la surface texturée."
|
"texturé double face peut échouer en raison de la surface texturée."
|
||||||
|
|
||||||
msgid "Automatic flow calibration using Micro Lidar"
|
msgid "Automatic flow calibration using Micro Lidar"
|
||||||
msgstr "Calibration automatique du débit à l’aide du Micro-Lidar"
|
msgstr "Calibration automatique du débit à l’aide du Micro-Lidar"
|
||||||
|
@ -7112,6 +7124,10 @@ msgstr "Générateur de paroi"
|
||||||
msgid "Walls and surfaces"
|
msgid "Walls and surfaces"
|
||||||
msgstr "Parois et surfaces"
|
msgstr "Parois et surfaces"
|
||||||
|
|
||||||
|
msgid "Small Area Infill Flow Compensation (experimental)"
|
||||||
|
msgstr ""
|
||||||
|
"Compensation des débits de remplissage des petites zones (expérimental)"
|
||||||
|
|
||||||
msgid "Bridging"
|
msgid "Bridging"
|
||||||
msgstr "Ponts"
|
msgstr "Ponts"
|
||||||
|
|
||||||
|
@ -7258,17 +7274,16 @@ msgstr ""
|
||||||
"sur le plateau Engineering."
|
"sur le plateau Engineering."
|
||||||
|
|
||||||
msgid "Smooth PEI Plate / High Temp Plate"
|
msgid "Smooth PEI Plate / High Temp Plate"
|
||||||
msgstr "Bambu Smooth PEI Plate / High Temp Plate"
|
msgstr "Plateau PEI lisse / Plateau haute température"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bed temperature when Smooth PEI Plate/High temperature plate is installed. "
|
"Bed temperature when Smooth PEI Plate/High temperature plate is installed. "
|
||||||
"Value 0 means the filament does not support to print on the Smooth PEI Plate/"
|
"Value 0 means the filament does not support to print on the Smooth PEI Plate/"
|
||||||
"High Temp Plate"
|
"High Temp Plate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Température du plateau lorsque le plateau Bambu Smooth PEI Plate/High "
|
"Température du plateau lorsque le Plateau PEI lisse / haute température est "
|
||||||
"Temperature Plate est installé. Une valeur à 0 signifie que le filament ne "
|
"installé. Une valeur à 0 signifie que le filament ne prend pas en charge "
|
||||||
"prend pas en charge l'impression sur le plateau Bambu Smooth PEI Plate/High "
|
"l'impression sur le plateau PEI lisse/haute température"
|
||||||
"Temperature Plate"
|
|
||||||
|
|
||||||
msgid "Textured PEI Plate"
|
msgid "Textured PEI Plate"
|
||||||
msgstr "Plaque PEI texturée"
|
msgstr "Plaque PEI texturée"
|
||||||
|
@ -8564,7 +8579,7 @@ msgid ""
|
||||||
"when prime tower is enabled."
|
"when prime tower is enabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L’utilisation de diamètres de buses et de filaments différents n’est pas "
|
"L’utilisation de diamètres de buses et de filaments différents n’est pas "
|
||||||
"autorisée lorsque l’option « prime tower » est activée."
|
"autorisée lorsque l’option « prime tower » est activée."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"The Wipe Tower is currently only supported with the relative extruder "
|
"The Wipe Tower is currently only supported with the relative extruder "
|
||||||
|
@ -9011,6 +9026,39 @@ msgstr ""
|
||||||
"que l'épaisseur de la coque inférieure est absolument déterminée par les "
|
"que l'épaisseur de la coque inférieure est absolument déterminée par les "
|
||||||
"couches de la coque inférieure"
|
"couches de la coque inférieure"
|
||||||
|
|
||||||
|
msgid "Apply gap fill"
|
||||||
|
msgstr "Remplissage des trous"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Enables gap fill for the selected surfaces. The minimum gap length that will "
|
||||||
|
"be filled can be controlled from the filter out tiny gaps option below.\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
"1. Everywhere: Applies gap fill to top, bottom and internal solid surfaces\n"
|
||||||
|
"2. Top and Bottom surfaces: Applies gap fill to top and bottom surfaces "
|
||||||
|
"only\n"
|
||||||
|
"3. Nowhere: Disables gap fill\n"
|
||||||
|
msgstr ""
|
||||||
|
"Active le remplissage des trous pour les surfaces sélectionnées. La longueur "
|
||||||
|
"minimale du trou qui sera comblé peut être contrôlée à l’aide de l’option "
|
||||||
|
"« Filtrer les petits trous » ci-dessous.\n"
|
||||||
|
"\n"
|
||||||
|
"Options :\n"
|
||||||
|
"1. Partout : Applique le remplissage des trous aux surfaces solides "
|
||||||
|
"supérieures, inférieures et internes.\n"
|
||||||
|
"2. Surfaces supérieure et inférieure : Remplissage des trous uniquement sur "
|
||||||
|
"les surfaces supérieures et inférieures.\n"
|
||||||
|
"3. Nulle part : Désactive le remplissage des trous\n"
|
||||||
|
|
||||||
|
msgid "Everywhere"
|
||||||
|
msgstr "Partout"
|
||||||
|
|
||||||
|
msgid "Top and bottom surfaces"
|
||||||
|
msgstr "Surfaces supérieure et inférieure"
|
||||||
|
|
||||||
|
msgid "Nowhere"
|
||||||
|
msgstr "Nulle part"
|
||||||
|
|
||||||
msgid "Force cooling for overhang and bridge"
|
msgid "Force cooling for overhang and bridge"
|
||||||
msgstr "Forcer la ventilation pour les surplombs et ponts"
|
msgstr "Forcer la ventilation pour les surplombs et ponts"
|
||||||
|
|
||||||
|
@ -9150,7 +9198,7 @@ msgstr ""
|
||||||
"Si une surface supérieure doit être imprimée et qu’elle est partiellement "
|
"Si une surface supérieure doit être imprimée et qu’elle est partiellement "
|
||||||
"couverte par une autre couche, elle ne sera pas considérée comme une couche "
|
"couverte par une autre couche, elle ne sera pas considérée comme une couche "
|
||||||
"supérieure si sa largeur est inférieure à cette valeur. Cela peut être utile "
|
"supérieure si sa largeur est inférieure à cette valeur. Cela peut être utile "
|
||||||
"pour ne pas déclencher l’option « un périmètre sur le dessus » sur des "
|
"pour ne pas déclencher l’option « un périmètre sur le dessus » sur des "
|
||||||
"surfaces qui ne devraient être couvertes que par des périmètres. Cette "
|
"surfaces qui ne devraient être couvertes que par des périmètres. Cette "
|
||||||
"valeur peut être un mm ou un % de la largeur d’extrusion du périmètre.\n"
|
"valeur peut être un mm ou un % de la largeur d’extrusion du périmètre.\n"
|
||||||
"Attention : Si cette option est activée, des artefacts peuvent être créés si "
|
"Attention : Si cette option est activée, des artefacts peuvent être créés si "
|
||||||
|
@ -9376,6 +9424,15 @@ msgstr "Par couche"
|
||||||
msgid "By object"
|
msgid "By object"
|
||||||
msgstr "Par objet"
|
msgstr "Par objet"
|
||||||
|
|
||||||
|
msgid "Layer order"
|
||||||
|
msgstr "Ordre des couches"
|
||||||
|
|
||||||
|
msgid "Print order within a single layer"
|
||||||
|
msgstr "Ordre d’impression au sein d’une même couche"
|
||||||
|
|
||||||
|
msgid "As object list"
|
||||||
|
msgstr "En tant que liste d’objets"
|
||||||
|
|
||||||
msgid "Slow printing down for better layer cooling"
|
msgid "Slow printing down for better layer cooling"
|
||||||
msgstr "Impression lente pour un meilleur refroidissement des couches"
|
msgstr "Impression lente pour un meilleur refroidissement des couches"
|
||||||
|
|
||||||
|
@ -9596,6 +9653,25 @@ msgstr ""
|
||||||
"garantir l'épaisseur verticale de la coque (couches solides "
|
"garantir l'épaisseur verticale de la coque (couches solides "
|
||||||
"supérieure+inférieure)."
|
"supérieure+inférieure)."
|
||||||
|
|
||||||
|
msgid "Further reduce solid infill on walls (experimental)"
|
||||||
|
msgstr "Réduire davantage le remplissage solide des parois (expérimental)"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Further reduces any solid infill applied to walls. As there will be very "
|
||||||
|
"limited infill supporting solid surfaces, make sure that you are using "
|
||||||
|
"adequate number of walls to support the part on sloping surfaces.\n"
|
||||||
|
"\n"
|
||||||
|
"For heavily sloped surfaces this option is not suitable as it will generate "
|
||||||
|
"too thin of a top layer and should be disabled."
|
||||||
|
msgstr ""
|
||||||
|
"Réduit encore davantage les remplissages solides appliqués aux parois. Étant "
|
||||||
|
"donné que le remplissage des surfaces solides sera très limité, assurez-vous "
|
||||||
|
"que vous utilisez un nombre suffisant de parois pour soutenir la partie sur "
|
||||||
|
"les surfaces inclinées.\n"
|
||||||
|
"\n"
|
||||||
|
"Pour les surfaces fortement inclinées, cette option n’est pas adaptée car "
|
||||||
|
"elle génère une couche supérieure trop fine et doit être désactivée."
|
||||||
|
|
||||||
msgid "Top surface pattern"
|
msgid "Top surface pattern"
|
||||||
msgstr "Motif de surface supérieure"
|
msgstr "Motif de surface supérieure"
|
||||||
|
|
||||||
|
@ -10887,6 +10963,28 @@ msgstr ""
|
||||||
msgid "This G-code will be used as a custom code"
|
msgid "This G-code will be used as a custom code"
|
||||||
msgstr "Ce G-code sera utilisé comme code personnalisé"
|
msgstr "Ce G-code sera utilisé comme code personnalisé"
|
||||||
|
|
||||||
|
msgid "Enable Flow Compensation"
|
||||||
|
msgstr "Activer la compensation de débit"
|
||||||
|
|
||||||
|
msgid "Enable flow compensation for small infill areas"
|
||||||
|
msgstr ""
|
||||||
|
"Activer la compensation des débits pour les petites zones de remplissage"
|
||||||
|
|
||||||
|
msgid "Flow Compensation Model"
|
||||||
|
msgstr "Modèle de compensation de débit"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Flow Compensation Model, used to adjust the flow for small infill areas. The "
|
||||||
|
"model is expressed as a comma separated pair of values for extrusion length "
|
||||||
|
"and flow correction factors, one per line, in the following format: "
|
||||||
|
"\"1.234,5.678\""
|
||||||
|
msgstr ""
|
||||||
|
"Modèle de compensation du débit, utilisé pour ajuster le débit pour les "
|
||||||
|
"petites zones de remplissage. Le modèle est exprimé sous la forme d’une "
|
||||||
|
"paire de valeurs séparées par des virgules pour la longueur d’extrusion et "
|
||||||
|
"les facteurs de correction du débit, une par ligne, dans le format suivant : "
|
||||||
|
"« 1.234,5.678 »"
|
||||||
|
|
||||||
msgid "Maximum speed X"
|
msgid "Maximum speed X"
|
||||||
msgstr "Vitesse maximale X"
|
msgstr "Vitesse maximale X"
|
||||||
|
|
||||||
|
@ -11246,9 +11344,6 @@ msgstr ""
|
||||||
"peut réduire les rétractions pour les modèles complexes et économiser du "
|
"peut réduire les rétractions pour les modèles complexes et économiser du "
|
||||||
"temps d’impression, mais ralentit la découpe et la génération du G-code."
|
"temps d’impression, mais ralentit la découpe et la génération du G-code."
|
||||||
|
|
||||||
msgid "Enable"
|
|
||||||
msgstr "Activer"
|
|
||||||
|
|
||||||
msgid "Filename format"
|
msgid "Filename format"
|
||||||
msgstr "Format du nom de fichier"
|
msgstr "Format du nom de fichier"
|
||||||
|
|
||||||
|
@ -11332,8 +11427,8 @@ msgstr ""
|
||||||
"manière, le remplissage est coincé verticalement entre les parois, ce qui "
|
"manière, le remplissage est coincé verticalement entre les parois, ce qui "
|
||||||
"permet d’obtenir des impressions plus solides. \n"
|
"permet d’obtenir des impressions plus solides. \n"
|
||||||
"\n"
|
"\n"
|
||||||
"Lorsque cette option est activée, l’option « assurer l’épaisseur verticale "
|
"Lorsque cette option est activée, l’option « assurer l’épaisseur verticale "
|
||||||
"de la coque » doit être désactivée. \n"
|
"de la coque » doit être désactivée. \n"
|
||||||
"\n"
|
"\n"
|
||||||
"Il n’est pas recommandé d’utiliser le remplissage par éclairs avec cette "
|
"Il n’est pas recommandé d’utiliser le remplissage par éclairs avec cette "
|
||||||
"option, car il y a peu de remplissage pour ancrer les périmètres "
|
"option, car il y a peu de remplissage pour ancrer les périmètres "
|
||||||
|
@ -11461,7 +11556,7 @@ msgid ""
|
||||||
"parameter: \"Z hop upper boundary\""
|
"parameter: \"Z hop upper boundary\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Le saut de Z ne sera effectif que si Z est supérieur à cette valeur et "
|
"Le saut de Z ne sera effectif que si Z est supérieur à cette valeur et "
|
||||||
"inférieur au paramètre : « Limite supérieure du saut de Z »"
|
"inférieur au paramètre : « Limite supérieure du saut de Z »"
|
||||||
|
|
||||||
msgid "Z hop upper boundary"
|
msgid "Z hop upper boundary"
|
||||||
msgstr "Limite supérieure du saut de Z"
|
msgstr "Limite supérieure du saut de Z"
|
||||||
|
@ -11471,7 +11566,7 @@ msgid ""
|
||||||
"the parameter: \"Z hop lower boundary\" and is below this value"
|
"the parameter: \"Z hop lower boundary\" and is below this value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Si cette valeur est positive, le saut de Z ne sera effectif que si Z est "
|
"Si cette valeur est positive, le saut de Z ne sera effectif que si Z est "
|
||||||
"supérieur au paramètre : « Limite inférieure de Z hop » et qu’il est "
|
"supérieur au paramètre : « Limite inférieure de Z hop » et qu’il est "
|
||||||
"inférieur à cette valeur."
|
"inférieur à cette valeur."
|
||||||
|
|
||||||
msgid "Z hop type"
|
msgid "Z hop type"
|
||||||
|
@ -11758,7 +11853,7 @@ msgid ""
|
||||||
"Smooth Spiral smoothes out X and Y moves as wellresulting in no visible seam "
|
"Smooth Spiral smoothes out X and Y moves as wellresulting in no visible seam "
|
||||||
"at all, even in the XY directions on walls that are not vertical"
|
"at all, even in the XY directions on walls that are not vertical"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"« Spirale lisse » lisse également les mouvements X et Y, de sorte qu’aucune "
|
"« Spirale lisse » lisse également les mouvements X et Y, de sorte qu’aucune "
|
||||||
"couture n’est visible, même dans les directions XY sur des parois qui ne "
|
"couture n’est visible, même dans les directions XY sur des parois qui ne "
|
||||||
"sont pas verticales."
|
"sont pas verticales."
|
||||||
|
|
||||||
|
@ -12649,8 +12744,8 @@ msgid ""
|
||||||
"Wipe tower is only compatible with relative mode. It is recommended on most "
|
"Wipe tower is only compatible with relative mode. It is recommended on most "
|
||||||
"printers. Default is checked"
|
"printers. Default is checked"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L’extrusion relative est recommandée lors de l’utilisation de l’option "
|
"L’extrusion relative est recommandée lors de l’utilisation de l’option « "
|
||||||
"« label_objects ». Certains extrudeurs fonctionnent mieux avec cette option "
|
"label_objects ». Certains extrudeurs fonctionnent mieux avec cette option "
|
||||||
"non verrouillée (mode d’extrusion absolu). La tour d’essuyage n’est "
|
"non verrouillée (mode d’extrusion absolu). La tour d’essuyage n’est "
|
||||||
"compatible qu’avec le mode relatif. Il est recommandé sur la plupart des "
|
"compatible qu’avec le mode relatif. Il est recommandé sur la plupart des "
|
||||||
"imprimantes. L’option par défaut est cochée"
|
"imprimantes. L’option par défaut est cochée"
|
||||||
|
@ -12767,11 +12862,11 @@ msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"REMARQUE : les surfaces inférieures et supérieures ne sont pas affectées par "
|
"REMARQUE : les surfaces inférieures et supérieures ne sont pas affectées par "
|
||||||
"cette valeur afin d’éviter les lacunes visuelles sur le côté du modèle. "
|
"cette valeur afin d’éviter les lacunes visuelles sur le côté du modèle. "
|
||||||
"Réglez le « seuil d’une paroi » dans les paramètres avancés ci-dessous pour "
|
"Réglez le « seuil d’une paroi » dans les paramètres avancés ci-dessous pour "
|
||||||
"ajuster la sensibilité de ce qui est considéré comme une surface supérieure. "
|
"ajuster la sensibilité de ce qui est considéré comme une surface supérieure. "
|
||||||
"Le « seuil d’une paroi » n’est visible que si ce paramètre est supérieur à "
|
"Le « seuil d’une paroi » n’est visible que si ce paramètre est supérieur à "
|
||||||
"la valeur par défaut de 0,5 ou si l’option « surfaces supérieures à une "
|
"la valeur par défaut de 0,5 ou si l’option « surfaces supérieures à une "
|
||||||
"paroi » est activée."
|
"paroi » est activée."
|
||||||
|
|
||||||
msgid "First layer minimum wall width"
|
msgid "First layer minimum wall width"
|
||||||
msgstr "Largeur minimale de la paroi de la première couche"
|
msgstr "Largeur minimale de la paroi de la première couche"
|
||||||
|
@ -13644,11 +13739,9 @@ msgstr "Filament"
|
||||||
msgid "Start temp: "
|
msgid "Start temp: "
|
||||||
msgstr "Temp. de début: "
|
msgstr "Temp. de début: "
|
||||||
|
|
||||||
|
|
||||||
msgid "End temp: "
|
msgid "End temp: "
|
||||||
msgstr "Temp. de fin: "
|
msgstr "Temp. de fin: "
|
||||||
|
|
||||||
|
|
||||||
msgid "Temp step: "
|
msgid "Temp step: "
|
||||||
msgstr "Intervalle de temp. : "
|
msgstr "Intervalle de temp. : "
|
||||||
|
|
||||||
|
@ -13946,7 +14039,7 @@ msgstr ""
|
||||||
msgid ""
|
msgid ""
|
||||||
"\"Bambu\" or \"Generic\" can not be used as a Vendor for custom filaments."
|
"\"Bambu\" or \"Generic\" can not be used as a Vendor for custom filaments."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"« Bambu » ou « Générique » ne peuvent pas être utilisés comme fournisseur de "
|
"« Bambu » ou « Générique » ne peuvent pas être utilisés comme fournisseur de "
|
||||||
"filaments personnalisés."
|
"filaments personnalisés."
|
||||||
|
|
||||||
msgid "Filament type is not selected, please reselect type."
|
msgid "Filament type is not selected, please reselect type."
|
||||||
|
@ -13993,10 +14086,10 @@ msgstr ""
|
||||||
msgid ""
|
msgid ""
|
||||||
"We would rename the presets as \"Vendor Type Serial @printer you "
|
"We would rename the presets as \"Vendor Type Serial @printer you "
|
||||||
"selected\". \n"
|
"selected\". \n"
|
||||||
"To add preset for more prinetrs, Please go to printer selection"
|
"To add preset for more printers, Please go to printer selection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nous renommerions les préréglages en « Fournisseur Type Série @imprimante "
|
"Nous renommerions les préréglages en « Vendor Type Serial @printer you "
|
||||||
"que vous avez sélectionnée ». \n"
|
"selected ». \n"
|
||||||
"Pour ajouter des préréglages pour d’autres imprimantes, veuillez aller à la "
|
"Pour ajouter des préréglages pour d’autres imprimantes, veuillez aller à la "
|
||||||
"sélection de l’imprimante."
|
"sélection de l’imprimante."
|
||||||
|
|
||||||
|
@ -14112,7 +14205,7 @@ msgid ""
|
||||||
"You have entered an illegal input in the printable area section on the first "
|
"You have entered an illegal input in the printable area section on the first "
|
||||||
"page. Please check before creating it."
|
"page. Please check before creating it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous avez introduit une donnée illégale dans la section « zone imprimable » "
|
"Vous avez introduit une donnée illégale dans la section « zone imprimable » "
|
||||||
"de la première page. Veuillez vérifier avant de la créer."
|
"de la première page. Veuillez vérifier avant de la créer."
|
||||||
|
|
||||||
msgid "The custom printer or model is not inputed, place input."
|
msgid "The custom printer or model is not inputed, place input."
|
||||||
|
@ -14578,7 +14671,7 @@ msgid ""
|
||||||
"Message body: \"%2%\""
|
"Message body: \"%2%\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Statut HTTP : %1%\n"
|
"Statut HTTP : %1%\n"
|
||||||
"Corps du message : « %2% »"
|
"Corps du message : « %2% »"
|
||||||
|
|
||||||
#, boost-format
|
#, boost-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -14587,8 +14680,8 @@ msgid ""
|
||||||
"Error: \"%2%\""
|
"Error: \"%2%\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L’analyse de la réponse de l’hôte a échoué.\n"
|
"L’analyse de la réponse de l’hôte a échoué.\n"
|
||||||
"Corps du message : « %1% »\n"
|
"Corps du message : « %1% »\n"
|
||||||
"Erreur : « %2% »"
|
"Erreur : « %2% »"
|
||||||
|
|
||||||
#, boost-format
|
#, boost-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -14597,8 +14690,21 @@ msgid ""
|
||||||
"Error: \"%2%\""
|
"Error: \"%2%\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L’énumération des imprimantes hôtes a échoué.\n"
|
"L’énumération des imprimantes hôtes a échoué.\n"
|
||||||
"Corps du message : « %1% »\n"
|
"Corps du message : « %1% »\n"
|
||||||
"Erreur : « %2% »"
|
"Erreur : « %2% »"
|
||||||
|
|
||||||
|
#~ msgid "End end: "
|
||||||
|
#~ msgstr "Temp. de fin: "
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "We would rename the presets as \"Vendor Type Serial @printer you "
|
||||||
|
#~ "selected\". \n"
|
||||||
|
#~ "To add preset for more prinetrs, Please go to printer selection"
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Nous renommerions les préréglages en « Fournisseur Type Série @imprimante "
|
||||||
|
#~ "que vous avez sélectionnée ». \n"
|
||||||
|
#~ "Pour ajouter des préréglages pour d’autres imprimantes, veuillez aller à "
|
||||||
|
#~ "la sélection de l’imprimante."
|
||||||
|
|
||||||
#~ msgid "The Config can not be loaded."
|
#~ msgid "The Config can not be loaded."
|
||||||
#~ msgstr "La configuration ne peut pas être chargée."
|
#~ msgstr "La configuration ne peut pas être chargée."
|
||||||
|
|
|
@ -84,9 +84,21 @@ var LangText = {
|
||||||
t89: "Open Containing Folder",
|
t89: "Open Containing Folder",
|
||||||
t90: "3D Model",
|
t90: "3D Model",
|
||||||
t91: "Download 3D models",
|
t91: "Download 3D models",
|
||||||
t92: "Bambu Christmas Cabin",
|
"t92": "Create by",
|
||||||
t93: "Printer Connection",
|
"t93": "Remixed by",
|
||||||
t94: "Please set up your printer connection to view the device.",
|
"t94": "Shared by",
|
||||||
|
"t95": "Model Information",
|
||||||
|
"t96": "Accessories",
|
||||||
|
"t97": "Profile Information",
|
||||||
|
"t98": "Model name",
|
||||||
|
"t100":"Model description",
|
||||||
|
"t101":"BOM",
|
||||||
|
"t102":"Assembly Guide",
|
||||||
|
"t103":"Other",
|
||||||
|
"t104":"Profile name",
|
||||||
|
"t105":"Profile Author",
|
||||||
|
"t106":"Profile description",
|
||||||
|
orca1: "Edit Project Info",
|
||||||
},
|
},
|
||||||
es_ES: {
|
es_ES: {
|
||||||
t1: "Bienvenido a Orca Slicer",
|
t1: "Bienvenido a Orca Slicer",
|
||||||
|
@ -173,9 +185,20 @@ var LangText = {
|
||||||
t89: "Abrir carpeta contenedora",
|
t89: "Abrir carpeta contenedora",
|
||||||
t90: "Modelo 3D",
|
t90: "Modelo 3D",
|
||||||
t91: "Descargar modelos 3D",
|
t91: "Descargar modelos 3D",
|
||||||
t92: "Cabina Bambú de Navidad",
|
"t92": "Creado por",
|
||||||
t93: "Conexión de Impresora",
|
"t93": "Remixado por",
|
||||||
t94: "Por favor, configure la conexión de red de la impresora para encontrarla.",
|
"t94": "Compartido por",
|
||||||
|
"t95": "Información del modelo",
|
||||||
|
"t96": "Accesorios",
|
||||||
|
"t97": "Información del perfil",
|
||||||
|
"t98": "Nombre del modelo",
|
||||||
|
"t100": "Descripción del modelo",
|
||||||
|
"t101": "Lista de materiales",
|
||||||
|
"t102": "Guía de ensamblaje",
|
||||||
|
"t103": "Otros",
|
||||||
|
"t104": "Nombre del perfil",
|
||||||
|
"t105": "Autor del perfil",
|
||||||
|
"t106": "Descripción del perfil",
|
||||||
},
|
},
|
||||||
de_DE: {
|
de_DE: {
|
||||||
t1: "Willkommen im Orca Slicer",
|
t1: "Willkommen im Orca Slicer",
|
||||||
|
@ -262,7 +285,20 @@ var LangText = {
|
||||||
t89: "Enthaltenden Ordner öffnen",
|
t89: "Enthaltenden Ordner öffnen",
|
||||||
t90: "3D-Modell",
|
t90: "3D-Modell",
|
||||||
t91: "3D-Modelle herunterladen",
|
t91: "3D-Modelle herunterladen",
|
||||||
t92: "Bambu Weihnachtshütte",
|
"t92": "Erstellt von",
|
||||||
|
"t93": "Remixed von",
|
||||||
|
"t94": "Geteilt von",
|
||||||
|
"t95": "Modellinformationen",
|
||||||
|
"t96": "Zubehör",
|
||||||
|
"t97": "Profilinformationen",
|
||||||
|
"t98": "Modellname",
|
||||||
|
"t100": "Modellbeschreibung",
|
||||||
|
"t101": "Stückliste",
|
||||||
|
"t102": "Montageanleitung",
|
||||||
|
"t103": "Andere",
|
||||||
|
"t104": "Profilname",
|
||||||
|
"t105": "Profilautor",
|
||||||
|
"t106": "Profilbeschreibung",
|
||||||
},
|
},
|
||||||
cs_CZ: {
|
cs_CZ: {
|
||||||
t1: "Vítejte v Orca Slicer",
|
t1: "Vítejte v Orca Slicer",
|
||||||
|
@ -349,7 +385,20 @@ var LangText = {
|
||||||
t89: "Otevřít složku obsahující",
|
t89: "Otevřít složku obsahující",
|
||||||
t90: "3D model",
|
t90: "3D model",
|
||||||
t91: "Stáhnout 3D modely",
|
t91: "Stáhnout 3D modely",
|
||||||
t92: "Vánoční kabina Bambu",
|
"t92": "Vytvořil",
|
||||||
|
"t93": "Přepracováno",
|
||||||
|
"t94": "Sdíleno",
|
||||||
|
"t95": "Informace o modelu",
|
||||||
|
"t96": "Příslušenství",
|
||||||
|
"t97": "Informace o profilu",
|
||||||
|
"t98": "Název modelu",
|
||||||
|
"t100":"Popis modelu",
|
||||||
|
"t101":"Seznam součástek (BOM)",
|
||||||
|
"t102":"Průvodce sestavením",
|
||||||
|
"t103":"Jiné",
|
||||||
|
"t104":"Název profilu",
|
||||||
|
"t105":"Autor profilu",
|
||||||
|
"t106":"Popis profilu",
|
||||||
},
|
},
|
||||||
fr_FR: {
|
fr_FR: {
|
||||||
t1: "Bienvenue sur Orca Slicer",
|
t1: "Bienvenue sur Orca Slicer",
|
||||||
|
@ -436,9 +485,20 @@ var LangText = {
|
||||||
t89: "Ouvrir le dossier contenant",
|
t89: "Ouvrir le dossier contenant",
|
||||||
t90: "Modèle 3D",
|
t90: "Modèle 3D",
|
||||||
t91: "Télécharger des modèles 3D",
|
t91: "Télécharger des modèles 3D",
|
||||||
t92: "Cabane de Noël Bambu",
|
"t92": "Créé par",
|
||||||
t93: "Connexion à l'imprimante",
|
"t93": "Remixé par",
|
||||||
t94: "Veuillez configurer la connexion de votre imprimante pour afficher l'interface.",
|
"t94": "Partagé par",
|
||||||
|
"t95": "Informations sur le modèle",
|
||||||
|
"t96": "Accessoires",
|
||||||
|
"t97": "Informations de profil",
|
||||||
|
"t98": "Nom du modèle",
|
||||||
|
"t100": "Description du modèle",
|
||||||
|
"t101": "BOM",
|
||||||
|
"t102": "Guide d'assemblage",
|
||||||
|
"t103": "Autre",
|
||||||
|
"t104": "Nom du profil",
|
||||||
|
"t105": "Auteur du profil",
|
||||||
|
"t106": "Description du profil",
|
||||||
t109: "Filaments du système",
|
t109: "Filaments du système",
|
||||||
t110: "Filaments personnalisés",
|
t110: "Filaments personnalisés",
|
||||||
t111: "Créer un nouveau filament",
|
t111: "Créer un nouveau filament",
|
||||||
|
@ -544,7 +604,20 @@ var LangText = {
|
||||||
t89: "打开所在的文件夹",
|
t89: "打开所在的文件夹",
|
||||||
t90: "3D 模型",
|
t90: "3D 模型",
|
||||||
t91: "下载3D模型",
|
t91: "下载3D模型",
|
||||||
t92: "Bambu圣诞小屋",
|
"t92": "创作",
|
||||||
|
"t93": "修改",
|
||||||
|
"t94": "分享",
|
||||||
|
"t95": "模型信息",
|
||||||
|
"t96": "附件",
|
||||||
|
"t97": "配置信息",
|
||||||
|
"t98": "模型名称",
|
||||||
|
"t100":"模型介绍",
|
||||||
|
"t101":"物料清单",
|
||||||
|
"t102":"装备指导",
|
||||||
|
"t103":"其他",
|
||||||
|
"t104":"配置名称",
|
||||||
|
"t105":"配置作者",
|
||||||
|
"t106":"配置介绍",
|
||||||
wk1: "快速入门指南",
|
wk1: "快速入门指南",
|
||||||
wk2: "本文介绍了Orca Slicer的最基本用法。它指导用户配置软件,创建项目,并逐步完成第一个打印任务。",
|
wk2: "本文介绍了Orca Slicer的最基本用法。它指导用户配置软件,创建项目,并逐步完成第一个打印任务。",
|
||||||
wk3: "基于项目的工作流",
|
wk3: "基于项目的工作流",
|
||||||
|
@ -561,6 +634,7 @@ var LangText = {
|
||||||
wk14: "与STL相比,STEP带来了更多有效的信息。由于STEP的高精度,切片时可以生成更多的圆弧路径。STEP还包括模型每个零件的装配关系,可分割模型后恢复装配视图。",
|
wk14: "与STL相比,STEP带来了更多有效的信息。由于STEP的高精度,切片时可以生成更多的圆弧路径。STEP还包括模型每个零件的装配关系,可分割模型后恢复装配视图。",
|
||||||
wk15: "3D文本",
|
wk15: "3D文本",
|
||||||
wk16: "使用3D文本工具,用户可以轻松地在项目中创建各种3D文本形状,使模型更加个性化。Orca Slicer提供了数十种字体,并支持粗体和斜体样式,使文本具有更大的灵活性。",
|
wk16: "使用3D文本工具,用户可以轻松地在项目中创建各种3D文本形状,使模型更加个性化。Orca Slicer提供了数十种字体,并支持粗体和斜体样式,使文本具有更大的灵活性。",
|
||||||
|
orca1: "编辑项目信息",
|
||||||
},
|
},
|
||||||
zh_TW: {
|
zh_TW: {
|
||||||
t1: "歡迎使用 Orca Slicer",
|
t1: "歡迎使用 Orca Slicer",
|
||||||
|
|
|
@ -66,3 +66,8 @@ a
|
||||||
{
|
{
|
||||||
background-color:#36363C;
|
background-color:#36363C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#AddModelInfoBtn:hover
|
||||||
|
{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
3
resources/web/model/img/edit.svg
Normal file
3
resources/web/model/img/edit.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="20" height="20" viewBox="-3 -3 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12.0769 6.84171C12.0769 6.58678 12.2835 6.38017 12.5385 6.38017C12.7934 6.38017 13 6.58678 13 6.84171V10.6923C13 11.9668 11.9668 13 10.6923 13H3.30769C2.03323 13 1 11.9668 1 10.6923V3.30769C1 2.03323 2.03323 1 3.30769 1H7.7006C7.95553 1 8.16214 1.20661 8.16214 1.46154C8.16214 1.71647 7.95553 1.92308 7.7006 1.92308H3.30769C2.54309 1.92308 1.92308 2.54309 1.92308 3.30769V10.6923C1.92308 11.4569 2.54309 12.0769 3.30769 12.0769H10.6923C11.4569 12.0769 12.0769 11.4571 12.0769 10.6923V6.84171ZM11.8775 1.74946C12.0528 1.57007 12.3392 1.5634 12.5226 1.73431C12.706 1.90541 12.7191 2.19171 12.5523 2.37885L7.51689 7.77975C7.34309 7.96617 7.05102 7.97644 6.86442 7.80264C6.67801 7.62885 6.66773 7.33678 6.84153 7.15018L11.8775 1.74946Z" fill="#6B6B6B"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 865 B |
|
@ -26,6 +26,7 @@
|
||||||
<div id="EmptyArea">
|
<div id="EmptyArea">
|
||||||
<div><img src="img/null.png"></div>
|
<div><img src="img/null.png"></div>
|
||||||
<div>no model information</div>
|
<div>no model information</div>
|
||||||
|
<div id="AddModelInfoBtn" class="trans TextS1" tid='orca1' onClick="OnClickEditProjectInfo()">Edit Project Info</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="WholeArea">
|
<div id="WholeArea">
|
||||||
|
@ -42,6 +43,9 @@
|
||||||
<div id="Profile_ProcessBar" class="LeftProcessBar" onclick="OnMenuClick('Model_Profile');">
|
<div id="Profile_ProcessBar" class="LeftProcessBar" onclick="OnMenuClick('Model_Profile');">
|
||||||
<img class="LeftTipIcon ProfileIcon" src="img/profile_h.svg" /><span class="trans" tid='t97'>Profile Information</span>
|
<img class="LeftTipIcon ProfileIcon" src="img/profile_h.svg" /><span class="trans" tid='t97'>Profile Information</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="Edit_ProcessBar" class="LeftProcessBar" onclick="OnClickEditProjectInfo();">
|
||||||
|
<img class="LeftTipIcon" src="img/edit.svg" /><span class="trans" tid='orca1'>Edit Project Info</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="LeftEmptyBlock" style="height: 100%;width:280px;"> </div>
|
<div id="LeftEmptyBlock" style="height: 100%;width:280px;"> </div>
|
||||||
|
|
|
@ -153,7 +153,7 @@ body
|
||||||
position:fixed;
|
position:fixed;
|
||||||
top: 24px;
|
top: 24px;
|
||||||
width: 264px;
|
width: 264px;
|
||||||
height: 120px;
|
height: 160px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,3 +376,19 @@ body
|
||||||
background-color: rgba(255,0,0,.5)!important;
|
background-color: rgba(255,0,0,.5)!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#AddModelInfoBtn
|
||||||
|
{
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
padding: 0px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
line-height: 26px;
|
||||||
|
height: 26px;
|
||||||
|
margin-top: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#AddModelInfoBtn:hover
|
||||||
|
{
|
||||||
|
background-color:#CDCECE;
|
||||||
|
}
|
||||||
|
|
|
@ -580,7 +580,14 @@ function OnClickOpenImage( F_ID )
|
||||||
$("img#"+F_ID).click();
|
$("img#"+F_ID).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function OnClickEditProjectInfo()
|
||||||
|
{
|
||||||
|
var tSend={};
|
||||||
|
tSend['sequence_id']=Math.round(new Date() / 1000);
|
||||||
|
tSend['command']="edit_project_info";
|
||||||
|
|
||||||
|
SendWXMessage( JSON.stringify(tSend) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,8 @@ set(lisbslic3r_sources
|
||||||
GCode/PrintExtents.hpp
|
GCode/PrintExtents.hpp
|
||||||
GCode/RetractWhenCrossingPerimeters.cpp
|
GCode/RetractWhenCrossingPerimeters.cpp
|
||||||
GCode/RetractWhenCrossingPerimeters.hpp
|
GCode/RetractWhenCrossingPerimeters.hpp
|
||||||
|
GCode/SmallAreaInfillFlowCompensator.cpp
|
||||||
|
GCode/SmallAreaInfillFlowCompensator.hpp
|
||||||
GCode/SpiralVase.cpp
|
GCode/SpiralVase.cpp
|
||||||
GCode/SpiralVase.hpp
|
GCode/SpiralVase.hpp
|
||||||
GCode/SeamPlacer.cpp
|
GCode/SeamPlacer.cpp
|
||||||
|
|
|
@ -1849,6 +1849,15 @@ static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(c
|
||||||
//BBS: add sort logic for seq-print
|
//BBS: add sort logic for seq-print
|
||||||
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print, bool init_order)
|
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print, bool init_order)
|
||||||
{
|
{
|
||||||
|
auto find_object_index = [](const Model& model, const ModelObject* obj) {
|
||||||
|
for (int index = 0; index < model.objects.size(); index++)
|
||||||
|
{
|
||||||
|
if (model.objects[index] == obj)
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
// Build up map from ModelInstance* to PrintInstance*
|
// Build up map from ModelInstance* to PrintInstance*
|
||||||
std::vector<std::pair<const ModelInstance*, const PrintInstance*>> model_instance_to_print_instance;
|
std::vector<std::pair<const ModelInstance*, const PrintInstance*>> model_instance_to_print_instance;
|
||||||
model_instance_to_print_instance.reserve(print.num_object_instances());
|
model_instance_to_print_instance.reserve(print.num_object_instances());
|
||||||
|
@ -1856,10 +1865,16 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
|
||||||
for (const PrintInstance &print_instance : print_object->instances())
|
for (const PrintInstance &print_instance : print_object->instances())
|
||||||
{
|
{
|
||||||
if (init_order)
|
if (init_order)
|
||||||
const_cast<ModelInstance*>(print_instance.model_instance)->arrange_order = print_instance.model_instance->id().id;
|
const_cast<ModelInstance*>(print_instance.model_instance)->arrange_order = find_object_index(print.model(), print_object->model_object());
|
||||||
model_instance_to_print_instance.emplace_back(print_instance.model_instance, &print_instance);
|
model_instance_to_print_instance.emplace_back(print_instance.model_instance, &print_instance);
|
||||||
}
|
}
|
||||||
std::sort(model_instance_to_print_instance.begin(), model_instance_to_print_instance.end(), [](auto &l, auto &r) { return l.first->arrange_order < r.first->arrange_order; });
|
std::sort(model_instance_to_print_instance.begin(), model_instance_to_print_instance.end(), [](auto &l, auto &r) { return l.first->arrange_order < r.first->arrange_order; });
|
||||||
|
if (init_order) {
|
||||||
|
// Re-assign the arrange_order so each instance has a unique order number
|
||||||
|
for (int k = 0; k < model_instance_to_print_instance.size(); k++) {
|
||||||
|
const_cast<ModelInstance*>(model_instance_to_print_instance[k].first)->arrange_order = k + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const PrintInstance*> instances;
|
std::vector<const PrintInstance*> instances;
|
||||||
instances.reserve(model_instance_to_print_instance.size());
|
instances.reserve(model_instance_to_print_instance.size());
|
||||||
|
@ -1980,6 +1995,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||||
} else
|
} else
|
||||||
m_enable_extrusion_role_markers = false;
|
m_enable_extrusion_role_markers = false;
|
||||||
|
|
||||||
|
if (!print.config().small_area_infill_flow_compensation_model.empty())
|
||||||
|
m_small_area_infill_flow_compensator = make_unique<SmallAreaInfillFlowCompensator>(print.config());
|
||||||
|
|
||||||
// if thumbnail type of BTT_TFT, insert above header
|
// if thumbnail type of BTT_TFT, insert above header
|
||||||
// if not, it is inserted under the header in its normal spot
|
// if not, it is inserted under the header in its normal spot
|
||||||
const GCodeThumbnailsFormat m_gcode_thumbnail_format = print.full_print_config().opt_enum<GCodeThumbnailsFormat>("thumbnails_format");
|
const GCodeThumbnailsFormat m_gcode_thumbnail_format = print.full_print_config().opt_enum<GCodeThumbnailsFormat>("thumbnails_format");
|
||||||
|
@ -2215,8 +2233,11 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||||
// In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
|
// In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
|
||||||
// Therefore initialize the printing extruders from there.
|
// Therefore initialize the printing extruders from there.
|
||||||
this->set_extruders(tool_ordering.all_extruders());
|
this->set_extruders(tool_ordering.all_extruders());
|
||||||
// Order object instances using a nearest neighbor search.
|
print_object_instances_ordering =
|
||||||
print_object_instances_ordering = chain_print_object_instances(print);
|
// By default, order object instances using a nearest neighbor search.
|
||||||
|
print.config().print_order == PrintOrder::Default ? chain_print_object_instances(print)
|
||||||
|
// Otherwise same order as the object list
|
||||||
|
: sort_object_instances_by_model_order(print);
|
||||||
}
|
}
|
||||||
if (initial_extruder_id == (unsigned int)-1) {
|
if (initial_extruder_id == (unsigned int)-1) {
|
||||||
// Nothing to print!
|
// Nothing to print!
|
||||||
|
@ -2540,9 +2561,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||||
// another one, set first layer temperatures. This happens before the Z move
|
// another one, set first layer temperatures. This happens before the Z move
|
||||||
// is triggered, so machine has more time to reach such temperatures.
|
// is triggered, so machine has more time to reach such temperatures.
|
||||||
this->placeholder_parser().set("current_object_idx", int(finished_objects));
|
this->placeholder_parser().set("current_object_idx", int(finished_objects));
|
||||||
//BBS: remove printing_by_object_gcode
|
std::string printing_by_object_gcode = this->placeholder_parser_process("printing_by_object_gcode", print.config().printing_by_object_gcode.value, initial_extruder_id);
|
||||||
//std::string printing_by_object_gcode = this->placeholder_parser_process("printing_by_object_gcode", print.config().printing_by_object_gcode.value, initial_extruder_id);
|
|
||||||
std::string printing_by_object_gcode;
|
|
||||||
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
||||||
this->_print_first_layer_bed_temperature(file, print, printing_by_object_gcode, initial_extruder_id, false);
|
this->_print_first_layer_bed_temperature(file, print, printing_by_object_gcode, initial_extruder_id, false);
|
||||||
this->_print_first_layer_extruder_temperatures(file, print, printing_by_object_gcode, initial_extruder_id, false);
|
this->_print_first_layer_extruder_temperatures(file, print, printing_by_object_gcode, initial_extruder_id, false);
|
||||||
|
@ -4020,7 +4039,7 @@ LayerResult GCode::process_layer(
|
||||||
std::vector<InstanceToPrint> instances_to_print;
|
std::vector<InstanceToPrint> instances_to_print;
|
||||||
bool has_prime_tower = print.config().enable_prime_tower
|
bool has_prime_tower = print.config().enable_prime_tower
|
||||||
&& print.extruders().size() > 1
|
&& print.extruders().size() > 1
|
||||||
&& (print.config().print_sequence == PrintSequence::ByLayer
|
&& ((print.config().print_sequence == PrintSequence::ByLayer && print.config().print_order == PrintOrder::Default)
|
||||||
|| (print.config().print_sequence == PrintSequence::ByObject && print.objects().size() == 1));
|
|| (print.config().print_sequence == PrintSequence::ByObject && print.objects().size() == 1));
|
||||||
if (has_prime_tower) {
|
if (has_prime_tower) {
|
||||||
int plate_idx = print.get_plate_index();
|
int plate_idx = print.get_plate_index();
|
||||||
|
@ -5268,15 +5287,25 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
for (const Line& line : path.polyline.lines()) {
|
for (const Line& line : path.polyline.lines()) {
|
||||||
const double line_length = line.length() * SCALING_FACTOR;
|
const double line_length = line.length() * SCALING_FACTOR;
|
||||||
path_length += line_length;
|
path_length += line_length;
|
||||||
|
auto dE = e_per_mm * line_length;
|
||||||
|
if (m_small_area_infill_flow_compensator && m_config.small_area_infill_flow_compensation.value) {
|
||||||
|
auto oldE = dE;
|
||||||
|
dE = m_small_area_infill_flow_compensator->modify_flow(line_length, dE, path.role());
|
||||||
|
|
||||||
|
if (m_config.gcode_comments && oldE > 0 && oldE != dE) {
|
||||||
|
description += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
gcode += m_writer.extrude_to_xy(
|
gcode += m_writer.extrude_to_xy(
|
||||||
this->point_to_gcode(line.b),
|
this->point_to_gcode(line.b),
|
||||||
e_per_mm * line_length,
|
dE,
|
||||||
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// BBS: start to generate gcode from arc fitting data which includes line and arc
|
// BBS: start to generate gcode from arc fitting data which includes line and arc
|
||||||
const std::vector<PathFittingData>& fitting_result = path.polyline.fitting_result;
|
const std::vector<PathFittingData>& fitting_result = path.polyline.fitting_result;
|
||||||
for (size_t fitting_index = 0; fitting_index < fitting_result.size(); fitting_index++) {
|
for (size_t fitting_index = 0; fitting_index < fitting_result.size(); fitting_index++) {
|
||||||
|
std::string tempDescription = description;
|
||||||
switch (fitting_result[fitting_index].path_type) {
|
switch (fitting_result[fitting_index].path_type) {
|
||||||
case EMovePathType::Linear_move: {
|
case EMovePathType::Linear_move: {
|
||||||
size_t start_index = fitting_result[fitting_index].start_point_index;
|
size_t start_index = fitting_result[fitting_index].start_point_index;
|
||||||
|
@ -5285,10 +5314,19 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
const Line line = Line(path.polyline.points[point_index - 1], path.polyline.points[point_index]);
|
const Line line = Line(path.polyline.points[point_index - 1], path.polyline.points[point_index]);
|
||||||
const double line_length = line.length() * SCALING_FACTOR;
|
const double line_length = line.length() * SCALING_FACTOR;
|
||||||
path_length += line_length;
|
path_length += line_length;
|
||||||
|
auto dE = e_per_mm * line_length;
|
||||||
|
if (m_small_area_infill_flow_compensator && m_config.small_area_infill_flow_compensation.value) {
|
||||||
|
auto oldE = dE;
|
||||||
|
dE = m_small_area_infill_flow_compensator->modify_flow(line_length, dE, path.role());
|
||||||
|
|
||||||
|
if (m_config.gcode_comments && oldE > 0 && oldE != dE) {
|
||||||
|
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
gcode += m_writer.extrude_to_xy(
|
gcode += m_writer.extrude_to_xy(
|
||||||
this->point_to_gcode(line.b),
|
this->point_to_gcode(line.b),
|
||||||
e_per_mm * line_length,
|
dE,
|
||||||
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -5298,12 +5336,21 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
const double arc_length = fitting_result[fitting_index].arc_data.length * SCALING_FACTOR;
|
const double arc_length = fitting_result[fitting_index].arc_data.length * SCALING_FACTOR;
|
||||||
const Vec2d center_offset = this->point_to_gcode(arc.center) - this->point_to_gcode(arc.start_point);
|
const Vec2d center_offset = this->point_to_gcode(arc.center) - this->point_to_gcode(arc.start_point);
|
||||||
path_length += arc_length;
|
path_length += arc_length;
|
||||||
|
auto dE = e_per_mm * arc_length;
|
||||||
|
if (m_small_area_infill_flow_compensator && m_config.small_area_infill_flow_compensation.value) {
|
||||||
|
auto oldE = dE;
|
||||||
|
dE = m_small_area_infill_flow_compensator->modify_flow(arc_length, dE, path.role());
|
||||||
|
|
||||||
|
if (m_config.gcode_comments && oldE > 0 && oldE != dE) {
|
||||||
|
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, arc_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
gcode += m_writer.extrude_arc_to_xy(
|
gcode += m_writer.extrude_arc_to_xy(
|
||||||
this->point_to_gcode(arc.end_point),
|
this->point_to_gcode(arc.end_point),
|
||||||
center_offset,
|
center_offset,
|
||||||
e_per_mm * arc_length,
|
dE,
|
||||||
arc.direction == ArcDirection::Arc_Dir_CCW,
|
arc.direction == ArcDirection::Arc_Dir_CCW,
|
||||||
GCodeWriter::full_gcode_comment ? description : "", path.is_force_no_extrusion());
|
GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -5325,6 +5372,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
pre_fan_enabled = check_overhang_fan(new_points[0].overlap, path.role());
|
pre_fan_enabled = check_overhang_fan(new_points[0].overlap, path.role());
|
||||||
|
|
||||||
for (size_t i = 1; i < new_points.size(); i++) {
|
for (size_t i = 1; i < new_points.size(); i++) {
|
||||||
|
std::string tempDescription = description;
|
||||||
const ProcessedPoint &processed_point = new_points[i];
|
const ProcessedPoint &processed_point = new_points[i];
|
||||||
const ProcessedPoint &pre_processed_point = new_points[i-1];
|
const ProcessedPoint &pre_processed_point = new_points[i-1];
|
||||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||||
|
@ -5363,8 +5411,17 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||||
gcode += m_writer.set_speed(new_speed, "", comment);
|
gcode += m_writer.set_speed(new_speed, "", comment);
|
||||||
last_set_speed = new_speed;
|
last_set_speed = new_speed;
|
||||||
}
|
}
|
||||||
|
auto dE = e_per_mm * line_length;
|
||||||
|
if (m_small_area_infill_flow_compensator && m_config.small_area_infill_flow_compensation.value) {
|
||||||
|
auto oldE = dE;
|
||||||
|
dE = m_small_area_infill_flow_compensator->modify_flow(line_length, dE, path.role());
|
||||||
|
|
||||||
|
if (m_config.gcode_comments && oldE > 0 && oldE != dE) {
|
||||||
|
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
gcode +=
|
gcode +=
|
||||||
m_writer.extrude_to_xy(p, e_per_mm * line_length, GCodeWriter::full_gcode_comment ? description : "");
|
m_writer.extrude_to_xy(p, dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||||
|
|
||||||
prev = p;
|
prev = p;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "GCode/ExtrusionProcessor.hpp"
|
#include "GCode/ExtrusionProcessor.hpp"
|
||||||
|
|
||||||
#include "GCode/PressureEqualizer.hpp"
|
#include "GCode/PressureEqualizer.hpp"
|
||||||
|
#include "GCode/SmallAreaInfillFlowCompensator.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -536,6 +537,8 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
|
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
|
||||||
|
|
||||||
|
std::unique_ptr<SmallAreaInfillFlowCompensator> m_small_area_infill_flow_compensator;
|
||||||
|
|
||||||
// Heights (print_z) at which the skirt has already been extruded.
|
// Heights (print_z) at which the skirt has already been extruded.
|
||||||
std::vector<coordf_t> m_skirt_done;
|
std::vector<coordf_t> m_skirt_done;
|
||||||
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
|
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
|
||||||
|
@ -598,6 +601,7 @@ private:
|
||||||
friend class WipeTowerIntegration;
|
friend class WipeTowerIntegration;
|
||||||
friend class PressureEqualizer;
|
friend class PressureEqualizer;
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
friend class SmallAreaInfillFlowCompensator;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print, bool init_order = false);
|
std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print& print, bool init_order = false);
|
||||||
|
|
88
src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
Normal file
88
src/libslic3r/GCode/SmallAreaInfillFlowCompensator.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// Modify the flow of extrusion lines inversely proportional to the length of
|
||||||
|
// the extrusion line. When infill lines get shorter the flow rate will auto-
|
||||||
|
// matically be reduced to mitigate the effect of small infill areas being
|
||||||
|
// over-extruded.
|
||||||
|
|
||||||
|
// Based on original work by Alexander Þór licensed under the GPLv3:
|
||||||
|
// https://github.com/Alexander-T-Moss/Small-Area-Flow-Comp
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
|
#include "../libslic3r.h"
|
||||||
|
#include "../PrintConfig.hpp"
|
||||||
|
|
||||||
|
#include "SmallAreaInfillFlowCompensator.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
bool nearly_equal(double a, double b)
|
||||||
|
{
|
||||||
|
return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallAreaInfillFlowCompensator::SmallAreaInfillFlowCompensator(const Slic3r::GCodeConfig& config)
|
||||||
|
{
|
||||||
|
for (auto& line : config.small_area_infill_flow_compensation_model.values) {
|
||||||
|
std::istringstream iss(line);
|
||||||
|
std::string value_str;
|
||||||
|
double eLength = 0.0;
|
||||||
|
|
||||||
|
if (std::getline(iss, value_str, ',')) {
|
||||||
|
try {
|
||||||
|
eLength = std::stod(value_str);
|
||||||
|
if (std::getline(iss, value_str, ',')) {
|
||||||
|
eLengths.push_back(eLength);
|
||||||
|
flowComps.push_back(std::stod(value_str));
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Error parsing data point in small area infill compensation model:" << line << std::endl;
|
||||||
|
|
||||||
|
throw Slic3r::InvalidArgument(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < eLengths.size(); i++) {
|
||||||
|
if (i == 0) {
|
||||||
|
if (!nearly_equal(eLengths[i], 0.0)) {
|
||||||
|
throw Slic3r::InvalidArgument("First extrusion length for small area infill compensation model must be 0");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nearly_equal(eLengths[i], 0.0)) {
|
||||||
|
throw Slic3r::InvalidArgument("Only the first extrusion length for small area infill compensation model can be 0");
|
||||||
|
}
|
||||||
|
if (eLengths[i] <= eLengths[i - 1]) {
|
||||||
|
throw Slic3r::InvalidArgument("Extrusion lengths for subsequent points must be increasing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flowComps.empty() && !nearly_equal(flowComps.back(), 1.0)) {
|
||||||
|
throw Slic3r::InvalidArgument("Final compensation factor for small area infill flow compensation model must be 1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
flowModel.set_points(eLengths, flowComps);
|
||||||
|
}
|
||||||
|
|
||||||
|
double SmallAreaInfillFlowCompensator::flow_comp_model(const double line_length)
|
||||||
|
{
|
||||||
|
if (line_length == 0 || line_length > max_modified_length()) {
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flowModel(line_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
double SmallAreaInfillFlowCompensator::modify_flow(const double line_length, const double dE, const ExtrusionRole role)
|
||||||
|
{
|
||||||
|
if (role == ExtrusionRole::erSolidInfill || role == ExtrusionRole::erTopSolidInfill || role == ExtrusionRole::erBottomSurface) {
|
||||||
|
return dE * flow_comp_model(line_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
35
src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
Normal file
35
src/libslic3r/GCode/SmallAreaInfillFlowCompensator.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef slic3r_GCode_SmallAreaInfillFlowCompensator_hpp_
|
||||||
|
#define slic3r_GCode_SmallAreaInfillFlowCompensator_hpp_
|
||||||
|
|
||||||
|
#include "../libslic3r.h"
|
||||||
|
#include "../PrintConfig.hpp"
|
||||||
|
#include "../ExtrusionEntity.hpp"
|
||||||
|
#include "spline/spline.h"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class SmallAreaInfillFlowCompensator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SmallAreaInfillFlowCompensator() = delete;
|
||||||
|
explicit SmallAreaInfillFlowCompensator(const Slic3r::GCodeConfig& config);
|
||||||
|
~SmallAreaInfillFlowCompensator() = default;
|
||||||
|
|
||||||
|
double modify_flow(const double line_length, const double dE, const ExtrusionRole role);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Model points
|
||||||
|
std::vector<double> eLengths;
|
||||||
|
std::vector<double> flowComps;
|
||||||
|
|
||||||
|
// TODO: Cubic Spline
|
||||||
|
tk::spline flowModel;
|
||||||
|
|
||||||
|
double flow_comp_model(const double line_length);
|
||||||
|
|
||||||
|
double max_modified_length() { return eLengths.back(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* slic3r_GCode_SmallAreaInfillFlowCompensator_hpp_ */
|
|
@ -836,7 +836,7 @@ end:
|
||||||
// BBS: backup all in one dir
|
// BBS: backup all in one dir
|
||||||
std::string Model::get_auxiliary_file_temp_path()
|
std::string Model::get_auxiliary_file_temp_path()
|
||||||
{
|
{
|
||||||
return get_backup_path("/Auxiliaries");
|
return get_backup_path("Auxiliaries");
|
||||||
}
|
}
|
||||||
|
|
||||||
// BBS: backup dir
|
// BBS: backup dir
|
||||||
|
|
|
@ -786,7 +786,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||||
"independent_support_layer_height",
|
"independent_support_layer_height",
|
||||||
"support_angle", "support_interface_top_layers", "support_interface_bottom_layers",
|
"support_angle", "support_interface_top_layers", "support_interface_bottom_layers",
|
||||||
"support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern",
|
"support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern",
|
||||||
"support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "thick_internal_bridges","dont_filter_internal_bridges", "max_bridge_length", "print_sequence", "support_remove_small_overhang",
|
"support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "thick_internal_bridges","dont_filter_internal_bridges", "max_bridge_length", "print_sequence", "print_order", "support_remove_small_overhang",
|
||||||
"filename_format", "wall_filament", "support_bottom_z_distance",
|
"filename_format", "wall_filament", "support_bottom_z_distance",
|
||||||
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body",
|
"sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body",
|
||||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width",
|
"ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width",
|
||||||
|
@ -817,6 +817,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||||
"wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming",
|
"wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming",
|
||||||
"wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic",
|
"wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic",
|
||||||
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth",
|
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth",
|
||||||
|
"small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model",
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<std::string> s_Preset_filament_options {
|
static std::vector<std::string> s_Preset_filament_options {
|
||||||
|
|
|
@ -314,6 +314,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||||
//|| opt_key == "resolution"
|
//|| opt_key == "resolution"
|
||||||
//BBS: when enable arc fitting, we must re-generate perimeter
|
//BBS: when enable arc fitting, we must re-generate perimeter
|
||||||
|| opt_key == "enable_arc_fitting"
|
|| opt_key == "enable_arc_fitting"
|
||||||
|
|| opt_key == "print_order"
|
||||||
|| opt_key == "wall_sequence") {
|
|| opt_key == "wall_sequence") {
|
||||||
osteps.emplace_back(posPerimeters);
|
osteps.emplace_back(posPerimeters);
|
||||||
osteps.emplace_back(posEstimateCurledExtrusions);
|
osteps.emplace_back(posEstimateCurledExtrusions);
|
||||||
|
@ -1043,6 +1044,7 @@ boost::regex regex_g92e0 { "^[ \\t]*[gG]92[ \\t]*[eE](0(\\.0*)?|\\.0+)[ \\t]*(;.
|
||||||
StringObjectException Print::validate(StringObjectException *warning, Polygons* collison_polygons, std::vector<std::pair<Polygon, float>>* height_polygons) const
|
StringObjectException Print::validate(StringObjectException *warning, Polygons* collison_polygons, std::vector<std::pair<Polygon, float>>* height_polygons) const
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> extruders = this->extruders();
|
std::vector<unsigned int> extruders = this->extruders();
|
||||||
|
unsigned int nozzles = m_config.nozzle_diameter.size();
|
||||||
|
|
||||||
if (m_objects.empty())
|
if (m_objects.empty())
|
||||||
return {std::string()};
|
return {std::string()};
|
||||||
|
@ -1050,7 +1052,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||||
if (extruders.empty())
|
if (extruders.empty())
|
||||||
return { L("No extrusions under current settings.") };
|
return { L("No extrusions under current settings.") };
|
||||||
|
|
||||||
if (extruders.size() > 1 && m_config.print_sequence != PrintSequence::ByObject) {
|
if (nozzles < 2 && extruders.size() > 1 && m_config.print_sequence != PrintSequence::ByObject) {
|
||||||
auto ret = check_multi_filament_valid(*this);
|
auto ret = check_multi_filament_valid(*this);
|
||||||
if (!ret.string.empty())
|
if (!ret.string.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -195,6 +195,12 @@ static t_config_enum_values s_keys_map_PrintSequence {
|
||||||
};
|
};
|
||||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintSequence)
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintSequence)
|
||||||
|
|
||||||
|
static t_config_enum_values s_keys_map_PrintOrder{
|
||||||
|
{ "default", int(PrintOrder::Default) },
|
||||||
|
{ "as_obj_list", int(PrintOrder::AsObjectList)},
|
||||||
|
};
|
||||||
|
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintOrder)
|
||||||
|
|
||||||
static t_config_enum_values s_keys_map_SlicingMode {
|
static t_config_enum_values s_keys_map_SlicingMode {
|
||||||
{ "regular", int(SlicingMode::Regular) },
|
{ "regular", int(SlicingMode::Regular) },
|
||||||
{ "even_odd", int(SlicingMode::EvenOdd) },
|
{ "even_odd", int(SlicingMode::EvenOdd) },
|
||||||
|
@ -1171,6 +1177,17 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->mode = comSimple;
|
def->mode = comSimple;
|
||||||
def->set_default_value(new ConfigOptionEnum<PrintSequence>(PrintSequence::ByLayer));
|
def->set_default_value(new ConfigOptionEnum<PrintSequence>(PrintSequence::ByLayer));
|
||||||
|
|
||||||
|
def = this->add("print_order", coEnum);
|
||||||
|
def->label = L("Layer order");
|
||||||
|
def->tooltip = L("Print order within a single layer");
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<PrintOrder>::get_enum_values();
|
||||||
|
def->enum_values.push_back("default");
|
||||||
|
def->enum_values.push_back("as_obj_list");
|
||||||
|
def->enum_labels.push_back(L("Default"));
|
||||||
|
def->enum_labels.push_back(L("As object list"));
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionEnum<PrintOrder>(PrintOrder::Default));
|
||||||
|
|
||||||
def = this->add("slow_down_for_layer_cooling", coBools);
|
def = this->add("slow_down_for_layer_cooling", coBools);
|
||||||
def->label = L("Slow printing down for better layer cooling");
|
def->label = L("Slow printing down for better layer cooling");
|
||||||
def->tooltip = L("Enable this option to slow printing speed down to make the final layer time not shorter than "
|
def->tooltip = L("Enable this option to slow printing speed down to make the final layer time not shorter than "
|
||||||
|
@ -2668,6 +2685,26 @@ def = this->add("filament_loading_speed", coFloats);
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionString(""));
|
def->set_default_value(new ConfigOptionString(""));
|
||||||
|
|
||||||
|
def = this->add("small_area_infill_flow_compensation", coBool);
|
||||||
|
def->label = L("Enable Flow Compensation");
|
||||||
|
def->tooltip = L("Enable flow compensation for small infill areas");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionBool(false));
|
||||||
|
|
||||||
|
def = this->add("small_area_infill_flow_compensation_model", coStrings);
|
||||||
|
def->label = L("Flow Compensation Model");
|
||||||
|
def->tooltip = L(
|
||||||
|
"Flow Compensation Model, used to adjust the flow for small infill "
|
||||||
|
"areas. The model is expressed as a comma separated pair of values for "
|
||||||
|
"extrusion length and flow correction factors, one per line, in the "
|
||||||
|
"following format: \"1.234,5.678\"");
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->gui_flags = "serialized";
|
||||||
|
def->multiline = true;
|
||||||
|
def->full_width = true;
|
||||||
|
def->height = 15;
|
||||||
|
def->set_default_value(new ConfigOptionStrings{"0,0", "\n0.2,0.4444", "\n0.4,0.6145", "\n0.6,0.7059", "\n0.8,0.7619", "\n1.5,0.8571", "\n2,0.8889", "\n3,0.9231", "\n5,0.9520", "\n10,1"});
|
||||||
|
|
||||||
{
|
{
|
||||||
struct AxisDefault {
|
struct AxisDefault {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -106,6 +106,13 @@ enum class PrintSequence {
|
||||||
Count,
|
Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PrintOrder
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
AsObjectList,
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
enum class SlicingMode
|
enum class SlicingMode
|
||||||
{
|
{
|
||||||
// Regular, applying ClipperLib::pftNonZero rule when creating ExPolygons.
|
// Regular, applying ClipperLib::pftNonZero rule when creating ExPolygons.
|
||||||
|
@ -920,6 +927,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||||
|
|
||||||
((ConfigOptionEnum<WallSequence>, wall_sequence))
|
((ConfigOptionEnum<WallSequence>, wall_sequence))
|
||||||
((ConfigOptionBool, is_infill_first))
|
((ConfigOptionBool, is_infill_first))
|
||||||
|
((ConfigOptionBool, small_area_infill_flow_compensation))
|
||||||
)
|
)
|
||||||
|
|
||||||
PRINT_CONFIG_CLASS_DEFINE(
|
PRINT_CONFIG_CLASS_DEFINE(
|
||||||
|
@ -1067,6 +1075,8 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||||
((ConfigOptionBool, enable_filament_ramming))
|
((ConfigOptionBool, enable_filament_ramming))
|
||||||
((ConfigOptionBool, support_multi_bed_types))
|
((ConfigOptionBool, support_multi_bed_types))
|
||||||
|
|
||||||
|
// Small Area Infill Flow Compensation
|
||||||
|
((ConfigOptionStrings, small_area_infill_flow_compensation_model))
|
||||||
)
|
)
|
||||||
|
|
||||||
// This object is mapped to Perl as Slic3r::Config::Print.
|
// This object is mapped to Perl as Slic3r::Config::Print.
|
||||||
|
@ -1098,6 +1108,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||||
((ConfigOptionInts, overhang_fan_speed))
|
((ConfigOptionInts, overhang_fan_speed))
|
||||||
((ConfigOptionEnumsGeneric, overhang_fan_threshold))
|
((ConfigOptionEnumsGeneric, overhang_fan_threshold))
|
||||||
((ConfigOptionEnum<PrintSequence>,print_sequence))
|
((ConfigOptionEnum<PrintSequence>,print_sequence))
|
||||||
|
((ConfigOptionEnum<PrintOrder>, print_order))
|
||||||
((ConfigOptionInts, first_layer_print_sequence))
|
((ConfigOptionInts, first_layer_print_sequence))
|
||||||
((ConfigOptionBools, slow_down_for_layer_cooling))
|
((ConfigOptionBools, slow_down_for_layer_cooling))
|
||||||
((ConfigOptionInts, close_fan_the_first_x_layers))
|
((ConfigOptionInts, close_fan_the_first_x_layers))
|
||||||
|
|
|
@ -928,6 +928,10 @@ bool PrintObject::invalidate_state_by_config_options(
|
||||||
|| opt_key == "wipe_on_loops"
|
|| opt_key == "wipe_on_loops"
|
||||||
|| opt_key == "wipe_speed") {
|
|| opt_key == "wipe_speed") {
|
||||||
steps.emplace_back(posPerimeters);
|
steps.emplace_back(posPerimeters);
|
||||||
|
} else if (
|
||||||
|
opt_key == "small_area_infill_flow_compensation"
|
||||||
|
|| opt_key == "small_area_infill_flow_compensation_model") {
|
||||||
|
steps.emplace_back(posSlice);
|
||||||
} else if (opt_key == "gap_infill_speed"
|
} else if (opt_key == "gap_infill_speed"
|
||||||
|| opt_key == "filter_out_gap_fill" ) {
|
|| opt_key == "filter_out_gap_fill" ) {
|
||||||
// Return true if gap-fill speed has changed from zero value to non-zero or from non-zero value to zero.
|
// Return true if gap-fill speed has changed from zero value to non-zero or from non-zero value to zero.
|
||||||
|
|
|
@ -33,17 +33,29 @@ wxDEFINE_EVENT(EVT_AUXILIARY_IMPORT, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_COVER, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_COVER, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_DELETE, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_DELETE, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_RENAME, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_AUXILIARY_UPDATE_RENAME, wxCommandEvent);
|
||||||
|
wxDEFINE_EVENT(EVT_AUXILIARY_DONE, wxCommandEvent);
|
||||||
|
|
||||||
|
|
||||||
const std::vector<std::string> license_list = {
|
const std::vector<std::string> license_list = {
|
||||||
"BSD License",
|
"",
|
||||||
"Apache License",
|
"CC0",
|
||||||
"GPL License",
|
"BY",
|
||||||
"LGPL License",
|
"BY-SA",
|
||||||
"MIT License",
|
"BY-ND",
|
||||||
"CC License"
|
"BY-NC",
|
||||||
|
"BY-NC-SA",
|
||||||
|
"BY-NC-ND",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static std::shared_ptr<ModelInfo> ensure_model_info()
|
||||||
|
{
|
||||||
|
auto& model = wxGetApp().plater()->model();
|
||||||
|
if (model.model_info == nullptr) {
|
||||||
|
model.model_info = std::make_shared<ModelInfo>();
|
||||||
|
}
|
||||||
|
return model.model_info;
|
||||||
|
}
|
||||||
|
|
||||||
AuFile::AuFile(wxWindow *parent, fs::path file_path, wxString file_name, AuxiliaryFolderType type, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
|
AuFile::AuFile(wxWindow *parent, fs::path file_path, wxString file_name, AuxiliaryFolderType type, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
|
||||||
{
|
{
|
||||||
m_type = type;
|
m_type = type;
|
||||||
|
@ -344,7 +356,7 @@ void AuFile::on_input_enter(wxCommandEvent &evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto existing = false;
|
auto existing = false;
|
||||||
auto dir = m_file_path.branch_path();
|
auto dir = m_file_path.parent_path();
|
||||||
auto new_fullname = new_file_name + m_file_path.extension().string();
|
auto new_fullname = new_file_name + m_file_path.extension().string();
|
||||||
|
|
||||||
|
|
||||||
|
@ -454,14 +466,12 @@ void AuFile::on_mouse_left_up(wxMouseEvent &evt)
|
||||||
|
|
||||||
void AuFile::on_set_cover()
|
void AuFile::on_set_cover()
|
||||||
{
|
{
|
||||||
if (wxGetApp().plater()->model().model_info == nullptr) { wxGetApp().plater()->model().model_info = std::make_shared<ModelInfo>(); }
|
|
||||||
|
|
||||||
fs::path path(into_path(m_file_name));
|
fs::path path(into_path(m_file_name));
|
||||||
wxGetApp().plater()->model().model_info->cover_file = path.string();
|
ensure_model_info()->cover_file = path.string();
|
||||||
//wxGetApp().plater()->model().model_info->cover_file = m_file_name.ToStdString();
|
//wxGetApp().plater()->model().model_info->cover_file = m_file_name.ToStdString();
|
||||||
|
|
||||||
auto full_path = m_file_path.branch_path();
|
auto full_path = m_file_path.parent_path();
|
||||||
auto full_root_path = full_path.branch_path();
|
auto full_root_path = full_path.parent_path();
|
||||||
auto full_root_path_str = encode_path(full_root_path.string().c_str());
|
auto full_root_path_str = encode_path(full_root_path.string().c_str());
|
||||||
auto dir = wxString::Format("%s/.thumbnails", full_root_path_str);
|
auto dir = wxString::Format("%s/.thumbnails", full_root_path_str);
|
||||||
|
|
||||||
|
@ -505,8 +515,8 @@ void AuFile::on_set_delete()
|
||||||
auto is_fine = fs::remove(bfs_path);
|
auto is_fine = fs::remove(bfs_path);
|
||||||
|
|
||||||
if (m_cover) {
|
if (m_cover) {
|
||||||
auto full_path = m_file_path.branch_path();
|
auto full_path = m_file_path.parent_path();
|
||||||
auto full_root_path = full_path.branch_path();
|
auto full_root_path = full_path.parent_path();
|
||||||
auto full_root_path_str = encode_path(full_root_path.string().c_str());
|
auto full_root_path_str = encode_path(full_root_path.string().c_str());
|
||||||
auto dir = wxString::Format("%s/.thumbnails", full_root_path_str);
|
auto dir = wxString::Format("%s/.thumbnails", full_root_path_str);
|
||||||
fs::path dir_path(dir.ToStdWstring());
|
fs::path dir_path(dir.ToStdWstring());
|
||||||
|
@ -520,8 +530,11 @@ void AuFile::on_set_delete()
|
||||||
if (fs::exists(fs::path(middle_img_path))) { fs::remove(fs::path(middle_img_path)); }
|
if (fs::exists(fs::path(middle_img_path))) { fs::remove(fs::path(middle_img_path)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxGetApp().plater()->model().model_info == nullptr) { wxGetApp().plater()->model().model_info = std::make_shared<ModelInfo>(); }
|
if (wxGetApp().plater()->model().model_info != nullptr) {
|
||||||
if (wxGetApp().plater()->model().model_info->cover_file == m_file_name) { wxGetApp().plater()->model().model_info->cover_file = ""; }
|
if (wxGetApp().plater()->model().model_info->cover_file == m_file_name) {
|
||||||
|
wxGetApp().plater()->model().model_info->cover_file = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_fine) {
|
if (is_fine) {
|
||||||
auto evt = wxCommandEvent(EVT_AUXILIARY_UPDATE_DELETE);
|
auto evt = wxCommandEvent(EVT_AUXILIARY_UPDATE_DELETE);
|
||||||
|
@ -669,6 +682,7 @@ void AuFolderPanel::update(std::vector<fs::path> paths)
|
||||||
}
|
}
|
||||||
m_gsizer_content->Layout();
|
m_gsizer_content->Layout();
|
||||||
Layout();
|
Layout();
|
||||||
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuFolderPanel::msw_rescale()
|
void AuFolderPanel::msw_rescale()
|
||||||
|
@ -820,9 +834,22 @@ void AuxiliaryPanel::init_bitmap()
|
||||||
|
|
||||||
void AuxiliaryPanel::init_tabpanel()
|
void AuxiliaryPanel::init_tabpanel()
|
||||||
{
|
{
|
||||||
auto m_side_tools = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(220), FromDIP(18)));
|
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Disabled),
|
||||||
|
std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
|
||||||
|
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
|
||||||
|
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
|
||||||
|
auto back_btn = new Button(this, _L("Back"), "assemble_return", wxBORDER_NONE | wxBU_LEFT | wxBU_EXACTFIT);
|
||||||
|
back_btn->SetSize(wxSize(FromDIP(220), FromDIP(18)));
|
||||||
|
back_btn->SetBackgroundColor(btn_bg_green);
|
||||||
|
back_btn->SetCornerRadius(0);
|
||||||
|
back_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxEvent& e) {
|
||||||
|
auto event = wxCommandEvent(EVT_AUXILIARY_DONE);
|
||||||
|
event.SetEventObject(m_parent);
|
||||||
|
wxPostEvent(m_parent, event);
|
||||||
|
});
|
||||||
|
|
||||||
wxBoxSizer *sizer_side_tools = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer *sizer_side_tools = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0);
|
sizer_side_tools->Add(back_btn, 1, wxEXPAND, 0);
|
||||||
m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
|
m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
|
||||||
m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF"));
|
m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF"));
|
||||||
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent &e) { ; });
|
m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent &e) { ; });
|
||||||
|
@ -872,20 +899,7 @@ bool AuxiliaryPanel::Show(bool show) { return wxPanel::Show(show); }
|
||||||
void AuxiliaryPanel::init_auxiliary()
|
void AuxiliaryPanel::init_auxiliary()
|
||||||
{
|
{
|
||||||
Model &model = wxGetApp().plater()->model();
|
Model &model = wxGetApp().plater()->model();
|
||||||
m_root_dir = encode_path(model.get_auxiliary_file_temp_path().c_str());
|
Reload(encode_path(model.get_auxiliary_file_temp_path().c_str()), {});
|
||||||
if (wxDirExists(m_root_dir)) {
|
|
||||||
fs::path path_to_del(m_root_dir.ToStdWstring());
|
|
||||||
try {
|
|
||||||
fs::remove_all(path_to_del);
|
|
||||||
} catch (...) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::path top_dir_path(m_root_dir.ToStdWstring());
|
|
||||||
fs::create_directory(top_dir_path);
|
|
||||||
|
|
||||||
for (auto folder : s_default_folders) create_folder(folder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuxiliaryPanel::on_import_file(wxCommandEvent &event)
|
void AuxiliaryPanel::on_import_file(wxCommandEvent &event)
|
||||||
|
@ -947,7 +961,7 @@ void AuxiliaryPanel::on_import_file(wxCommandEvent &event)
|
||||||
|
|
||||||
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
if (!fs::copy_file(src_bfs_path, fs::path(dir_path.ToStdWstring()), fs::copy_option::overwrite_if_exists, ec)) continue;
|
if (!fs::copy_file(src_bfs_path, fs::path(dir_path.ToStdWstring()), fs::copy_options::overwrite_existing, ec)) continue;
|
||||||
Slic3r::put_other_changes();
|
Slic3r::put_other_changes();
|
||||||
|
|
||||||
// add in file list
|
// add in file list
|
||||||
|
@ -987,76 +1001,22 @@ std::string AuxiliaryPanel::replaceSpace(std::string s, std::string ts, std::str
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuxiliaryPanel::Reload(wxString aux_path)
|
void AuxiliaryPanel::Reload(wxString aux_path, std::map<std::string, std::vector<json>> paths)
|
||||||
{
|
{
|
||||||
fs::path new_aux_path(aux_path.ToStdWstring());
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs::remove_all(fs::path(m_root_dir.ToStdWstring()));
|
|
||||||
} catch (...) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory " << m_root_dir.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_root_dir = aux_path;
|
m_root_dir = aux_path;
|
||||||
m_paths_list.clear();
|
m_paths_list.clear();
|
||||||
// Check new path. If not exist, create a new one.
|
|
||||||
if (!fs::exists(new_aux_path)) {
|
for (const auto & path : paths) {
|
||||||
fs::create_directory(new_aux_path);
|
m_paths_list[path.first] = std::vector<fs::path>{};
|
||||||
// Create default folders if they are not loaded
|
for (const auto & j : path.second) {
|
||||||
for (auto folder : s_default_folders) {
|
m_paths_list[path.first].push_back(j["_filepath"]);
|
||||||
wxString folder_path = aux_path + "/" + folder;
|
|
||||||
if (fs::exists(folder_path.ToStdWstring())) continue;
|
|
||||||
fs::create_directory(folder_path.ToStdWstring());
|
|
||||||
}
|
}
|
||||||
update_all_panel();
|
|
||||||
m_designer_panel->update_info();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load from new path
|
|
||||||
std::vector<fs::path> dir_cache;
|
|
||||||
fs::directory_iterator iter_end;
|
|
||||||
|
|
||||||
for (fs::directory_iterator iter(new_aux_path); iter != iter_end; iter++) {
|
|
||||||
wxString path = iter->path().generic_wstring();
|
|
||||||
dir_cache.push_back(iter->path());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto dir : dir_cache) {
|
|
||||||
for (fs::directory_iterator iter(dir); iter != iter_end; iter++) {
|
|
||||||
if (fs::is_directory(iter->path())) continue;
|
|
||||||
wxString file_path = iter->path().generic_wstring();
|
|
||||||
//auto file_path_str = encode_path(file_path.c_str());
|
|
||||||
|
|
||||||
for (auto folder : s_default_folders) {
|
|
||||||
auto idx = file_path.find(folder.ToStdString());
|
|
||||||
if (idx != std::string::npos) {
|
|
||||||
auto iter = m_paths_list.find(folder.ToStdString());
|
|
||||||
auto file_path_str = fs::path(file_path.ToStdWstring());
|
|
||||||
|
|
||||||
if (iter != m_paths_list.end()) {
|
|
||||||
m_paths_list[folder.ToStdString()].push_back(file_path_str);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
m_paths_list[folder.ToStdString()] = std::vector<fs::path>{file_path_str};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create default folders if they are not loaded
|
|
||||||
wxDataViewItemArray default_items;
|
|
||||||
for (auto folder : s_default_folders) {
|
|
||||||
wxString folder_path = aux_path + "/" + folder;
|
|
||||||
if (fs::exists(folder_path.ToStdWstring())) continue;
|
|
||||||
fs::create_directory(folder_path.ToStdWstring());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_all_panel();
|
update_all_panel();
|
||||||
update_all_cover();
|
update_all_cover();
|
||||||
m_designer_panel->update_info();
|
m_designer_panel->update_info();
|
||||||
|
m_tabpanel->SetSelection(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuxiliaryPanel::update_all_panel()
|
void AuxiliaryPanel::update_all_panel()
|
||||||
|
@ -1121,22 +1081,21 @@ void AuxiliaryPanel::update_all_cover()
|
||||||
m_imput_model_name->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
m_imput_model_name->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
||||||
m_sizer_model_name->Add(m_imput_model_name, 0, wxALIGN_CENTER, 0);
|
m_sizer_model_name->Add(m_imput_model_name, 0, wxALIGN_CENTER, 0);
|
||||||
|
|
||||||
/*
|
|
||||||
wxBoxSizer *m_sizer_license = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer *m_sizer_license = new wxBoxSizer(wxHORIZONTAL);
|
||||||
auto m_text_license = new wxStaticText(this, wxID_ANY, _L("License"), wxDefaultPosition, wxSize(120, -1), 0);
|
auto m_text_license = new wxStaticText(this, wxID_ANY, _L("License"), wxDefaultPosition, wxSize(180, -1), 0);
|
||||||
m_text_license->Wrap(-1);
|
m_text_license->Wrap(-1);
|
||||||
m_sizer_license->Add(m_text_license, 0, wxALIGN_CENTER, 0);
|
m_sizer_license->Add(m_text_license, 0, wxALIGN_CENTER, 0);
|
||||||
|
|
||||||
m_combo_license = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(450, -1), 0, NULL, wxCB_READONLY);
|
m_combo_license = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(450), -1), 0, NULL, wxCB_READONLY);
|
||||||
m_sizer_license->Add(m_combo_license, 0, wxALIGN_CENTER, 0);
|
m_sizer_license->Add(m_combo_license, 0, wxALIGN_CENTER, 0);
|
||||||
*/
|
|
||||||
m_sizer_body->Add( 0, 0, 0, wxTOP, FromDIP(50) );
|
m_sizer_body->Add( 0, 0, 0, wxTOP, FromDIP(50) );
|
||||||
m_sizer_body->Add(m_sizer_designer, 0, wxLEFT, FromDIP(50));
|
m_sizer_body->Add(m_sizer_designer, 0, wxLEFT, FromDIP(50));
|
||||||
m_sizer_body->Add( 0, 0, 0, wxTOP, FromDIP(20));
|
m_sizer_body->Add( 0, 0, 0, wxTOP, FromDIP(20));
|
||||||
m_sizer_body->Add(m_sizer_model_name, 0, wxLEFT, FromDIP(50));
|
m_sizer_body->Add(m_sizer_model_name, 0, wxLEFT, FromDIP(50));
|
||||||
//m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(20));
|
m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(20));
|
||||||
//m_sizer_body->Add(m_sizer_license, 0, wxLEFT, FromDIP(50));
|
m_sizer_body->Add(m_sizer_license, 0, wxLEFT, FromDIP(50));
|
||||||
//init_license_list();
|
init_license_list();
|
||||||
|
|
||||||
SetSizer(m_sizer_body);
|
SetSizer(m_sizer_body);
|
||||||
Layout();
|
Layout();
|
||||||
|
@ -1144,52 +1103,35 @@ void AuxiliaryPanel::update_all_cover()
|
||||||
|
|
||||||
m_input_designer->Bind(wxEVT_TEXT, &DesignerPanel::on_input_enter_designer, this);
|
m_input_designer->Bind(wxEVT_TEXT, &DesignerPanel::on_input_enter_designer, this);
|
||||||
m_imput_model_name->Bind(wxEVT_TEXT, &DesignerPanel::on_input_enter_model, this);
|
m_imput_model_name->Bind(wxEVT_TEXT, &DesignerPanel::on_input_enter_model, this);
|
||||||
//m_combo_license->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(DesignerPanel::on_select_license), NULL, this);
|
m_combo_license->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &DesignerPanel::on_select_license, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesignerPanel::~DesignerPanel()
|
DesignerPanel::~DesignerPanel()
|
||||||
{
|
{
|
||||||
//m_combo_license->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(DesignerPanel::on_select_license), NULL, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesignerPanel::init_license_list()
|
void DesignerPanel::init_license_list()
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
wxArrayString text_licese;
|
wxArrayString text_licese;
|
||||||
for (int i = 0; i < license_list.size(); i++) {
|
for (int i = 0; i < license_list.size(); i++) {
|
||||||
text_licese.Add(license_list[i]);
|
text_licese.Add(license_list[i]);
|
||||||
}
|
}
|
||||||
m_combo_license->Set(text_licese);
|
m_combo_license->Set(text_licese);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesignerPanel::on_select_license(wxCommandEvent&evt)
|
void DesignerPanel::on_select_license(wxCommandEvent&evt)
|
||||||
{
|
{
|
||||||
int selected = evt.GetInt();
|
int selected = evt.GetInt();
|
||||||
if (selected >= 0 && selected < license_list.size()) {
|
if (selected >= 0 && selected < license_list.size()) {
|
||||||
if (wxGetApp().plater()->model().model_info == nullptr) {
|
ensure_model_info()->license = license_list[selected];
|
||||||
wxGetApp().plater()->model().model_info = std::make_shared<ModelInfo>();
|
|
||||||
}
|
|
||||||
if (wxGetApp().plater()->model().model_info != nullptr) {
|
|
||||||
wxGetApp().plater()->model().model_info->license = license_list[selected];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesignerPanel::Show(bool show)
|
bool DesignerPanel::Show(bool show)
|
||||||
{
|
{
|
||||||
if ( wxGetApp().plater()->model().design_info != nullptr) {
|
if (show) update_info();
|
||||||
wxString text = wxString::FromUTF8(wxGetApp().plater()->model().design_info->Designer);
|
return wxPanel::Show(show);
|
||||||
m_input_designer->GetTextCtrl()->SetValue(text);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (wxGetApp().plater()->model().model_info != nullptr) {
|
|
||||||
wxString text = wxString::FromUTF8(wxGetApp().plater()->model().model_info->model_name);
|
|
||||||
m_imput_model_name->GetTextCtrl()->SetValue(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wxPanel::Show(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesignerPanel::on_input_enter_designer(wxCommandEvent &evt)
|
void DesignerPanel::on_input_enter_designer(wxCommandEvent &evt)
|
||||||
{
|
{
|
||||||
|
@ -1200,9 +1142,7 @@ void DesignerPanel::on_input_enter_designer(wxCommandEvent &evt)
|
||||||
void DesignerPanel::on_input_enter_model(wxCommandEvent &evt)
|
void DesignerPanel::on_input_enter_model(wxCommandEvent &evt)
|
||||||
{
|
{
|
||||||
auto text = evt.GetString();
|
auto text = evt.GetString();
|
||||||
if (wxGetApp().plater()->model().model_info) {
|
ensure_model_info()->model_name = std::string(text.ToUTF8().data());
|
||||||
wxGetApp().plater()->model().model_info->model_name = std::string(text.ToUTF8().data());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesignerPanel::update_info()
|
void DesignerPanel::update_info()
|
||||||
|
@ -1215,10 +1155,13 @@ void DesignerPanel::update_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxGetApp().plater()->model().model_info != nullptr) {
|
if (wxGetApp().plater()->model().model_info != nullptr) {
|
||||||
wxString text = wxString::FromUTF8(wxGetApp().plater()->model().model_info->model_name);
|
m_imput_model_name->GetTextCtrl()->SetValue(wxString::FromUTF8(wxGetApp().plater()->model().model_info->model_name));
|
||||||
m_imput_model_name->GetTextCtrl()->SetValue(text);
|
if (!m_combo_license->SetStringSelection(wxString::FromUTF8(wxGetApp().plater()->model().model_info->license))) {
|
||||||
|
m_combo_license->SetSelection(0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_imput_model_name->GetTextCtrl()->SetValue(wxEmptyString);
|
m_imput_model_name->GetTextCtrl()->SetValue(wxEmptyString);
|
||||||
|
m_combo_license->SetSelection(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,6 +1169,7 @@ void DesignerPanel::msw_rescale()
|
||||||
{
|
{
|
||||||
m_input_designer->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
m_input_designer->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
||||||
m_imput_model_name->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
m_imput_model_name->GetTextCtrl()->SetSize(wxSize(FromDIP(450), -1));
|
||||||
|
m_combo_license->SetSize(wxSize(FromDIP(450), -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
|
@ -181,7 +181,7 @@ public:
|
||||||
|
|
||||||
::TextInput* m_input_designer {nullptr};
|
::TextInput* m_input_designer {nullptr};
|
||||||
::TextInput* m_imput_model_name {nullptr};
|
::TextInput* m_imput_model_name {nullptr};
|
||||||
//wxComboBox* m_combo_license {nullptr};
|
ComboBox* m_combo_license {nullptr};
|
||||||
bool Show(bool show) override;
|
bool Show(bool show) override;
|
||||||
void init_license_list();
|
void init_license_list();
|
||||||
void on_input_enter_designer(wxCommandEvent &evt);
|
void on_input_enter_designer(wxCommandEvent &evt);
|
||||||
|
@ -232,7 +232,7 @@ public:
|
||||||
void create_folder(wxString name = wxEmptyString);
|
void create_folder(wxString name = wxEmptyString);
|
||||||
std::string replaceSpace(std::string s, std::string ts, std::string ns);
|
std::string replaceSpace(std::string s, std::string ts, std::string ns);
|
||||||
void on_import_file(wxCommandEvent &event);
|
void on_import_file(wxCommandEvent &event);
|
||||||
void Reload(wxString aux_path);
|
void Reload(wxString aux_path, std::map<std::string, std::vector<json>> paths);
|
||||||
|
|
||||||
void update_all_panel();
|
void update_all_panel();
|
||||||
void update_all_cover();
|
void update_all_cover();
|
||||||
|
@ -242,6 +242,7 @@ wxDECLARE_EVENT(EVT_AUXILIARY_IMPORT, wxCommandEvent);
|
||||||
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_COVER, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_COVER, wxCommandEvent);
|
||||||
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_DELETE, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_DELETE, wxCommandEvent);
|
||||||
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_RENAME, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_AUXILIARY_UPDATE_RENAME, wxCommandEvent);
|
||||||
|
wxDECLARE_EVENT(EVT_AUXILIARY_DONE, wxCommandEvent);
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -661,9 +661,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_speed", "ironing_angle" })
|
for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_speed", "ironing_angle" })
|
||||||
toggle_line(el, has_ironing);
|
toggle_line(el, has_ironing);
|
||||||
|
|
||||||
// bool have_sequential_printing = (config->opt_enum<PrintSequence>("print_sequence") == PrintSequence::ByObject);
|
bool have_sequential_printing = (config->opt_enum<PrintSequence>("print_sequence") == PrintSequence::ByObject);
|
||||||
// for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" })
|
// for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" })
|
||||||
// toggle_field(el, have_sequential_printing);
|
// toggle_field(el, have_sequential_printing);
|
||||||
|
toggle_field("print_order", !have_sequential_printing);
|
||||||
|
|
||||||
bool have_ooze_prevention = config->opt_bool("ooze_prevention");
|
bool have_ooze_prevention = config->opt_bool("ooze_prevention");
|
||||||
toggle_field("standby_temperature_delta", have_ooze_prevention);
|
toggle_field("standby_temperature_delta", have_ooze_prevention);
|
||||||
|
@ -742,6 +743,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||||
apply(config, &new_conf);
|
apply(config, &new_conf);
|
||||||
}
|
}
|
||||||
toggle_line("timelapse_type", is_BBL_Printer);
|
toggle_line("timelapse_type", is_BBL_Printer);
|
||||||
|
|
||||||
|
|
||||||
|
bool have_small_area_infill_flow_compensation = config->opt_bool("small_area_infill_flow_compensation");
|
||||||
|
toggle_line("small_area_infill_flow_compensation_model", have_small_area_infill_flow_compensation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
|
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
|
||||||
|
|
|
@ -7304,10 +7304,10 @@ void GLCanvas3D::_render_overlays()
|
||||||
|
|
||||||
auto curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
|
auto curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
|
||||||
auto curr_print_seq = curr_plate->get_real_print_seq();
|
auto curr_print_seq = curr_plate->get_real_print_seq();
|
||||||
bool sequential_print = (curr_print_seq == PrintSequence::ByObject);
|
const Print* print = fff_print();
|
||||||
|
bool sequential_print = (curr_print_seq == PrintSequence::ByObject) || print->config().print_order == PrintOrder::AsObjectList;
|
||||||
std::vector<const ModelInstance*> sorted_instances;
|
std::vector<const ModelInstance*> sorted_instances;
|
||||||
if (sequential_print) {
|
if (sequential_print) {
|
||||||
const Print* print = fff_print();
|
|
||||||
if (print) {
|
if (print) {
|
||||||
for (const PrintObject *print_object : print->objects())
|
for (const PrintObject *print_object : print->objects())
|
||||||
{
|
{
|
||||||
|
|
|
@ -2656,7 +2656,7 @@ bool GUI_App::on_init_inner()
|
||||||
|
|
||||||
sidebar().obj_list()->init();
|
sidebar().obj_list()->init();
|
||||||
//sidebar().aux_list()->init_auxiliary();
|
//sidebar().aux_list()->init_auxiliary();
|
||||||
//mainframe->m_auxiliary->init_auxiliary();
|
mainframe->m_project->init_auxiliary();
|
||||||
|
|
||||||
// update_mode(); // !!! do that later
|
// update_mode(); // !!! do that later
|
||||||
SetTopWindow(mainframe);
|
SetTopWindow(mainframe);
|
||||||
|
|
|
@ -1545,26 +1545,6 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & itObject) {
|
if (type & itObject) {
|
||||||
int curr_obj_id = m_objects_model->GetIdByItem(event.GetItem());
|
|
||||||
PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list();
|
|
||||||
int from_plate = partplate_list.find_instance(curr_obj_id, 0);
|
|
||||||
if (from_plate == -1) {
|
|
||||||
event.Veto();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto curr_plate_seq = partplate_list.get_plate(from_plate)->get_print_seq();
|
|
||||||
if (curr_plate_seq == PrintSequence::ByDefault) {
|
|
||||||
auto curr_preset_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
|
||||||
if (curr_preset_config.has("print_sequence"))
|
|
||||||
curr_plate_seq = curr_preset_config.option<ConfigOptionEnum<PrintSequence>>("print_sequence")->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curr_plate_seq != PrintSequence::ByObject) {
|
|
||||||
//drag forbidden under bylayer mode
|
|
||||||
event.Veto();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dragged_data.init(m_objects_model->GetIdByItem(item), type);
|
m_dragged_data.init(m_objects_model->GetIdByItem(item), type);
|
||||||
}
|
}
|
||||||
else if (type & itVolume){
|
else if (type & itVolume){
|
||||||
|
|
|
@ -717,7 +717,12 @@ bool GLGizmoCut3D::render_reset_button(const std::string& label_id, const std::s
|
||||||
|
|
||||||
static double get_grabber_mean_size(const BoundingBoxf3& bb)
|
static double get_grabber_mean_size(const BoundingBoxf3& bb)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_FIXED_GRABBER
|
||||||
|
// Orca: make grabber larger
|
||||||
|
return 32. * GLGizmoBase::INV_ZOOM;
|
||||||
|
#else
|
||||||
return (bb.size().x() + bb.size().y() + bb.size().z()) / 30.;
|
return (bb.size().x() + bb.size().y() + bb.size().z()) / 30.;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
|
indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
|
||||||
|
@ -2503,13 +2508,13 @@ void GLGizmoCut3D::add_horizontal_shift(float shift)
|
||||||
|
|
||||||
void GLGizmoCut3D::render_color_marker(float size, const ImU32& color)
|
void GLGizmoCut3D::render_color_marker(float size, const ImU32& color)
|
||||||
{
|
{
|
||||||
ImGui::SameLine();
|
|
||||||
const float radius = 0.5f * size;
|
const float radius = 0.5f * size;
|
||||||
ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
|
ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
|
||||||
pos.x += size;
|
pos.x += radius;
|
||||||
pos.y += 1.25f * radius;
|
pos.y += 1.4f * radius;
|
||||||
ImGui::GetCurrentWindow()->DrawList->AddNgonFilled(pos, radius, color, 6);
|
ImGui::GetCurrentWindow()->DrawList->AddNgonFilled(pos, radius, color, 6);
|
||||||
m_imgui->text(" ");
|
m_imgui->text(" ");
|
||||||
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in_val, const float& init_val, float& in_tolerance)
|
void GLGizmoCut3D::render_groove_float_input(const std::string& label, float& in_val, const float& init_val, float& in_tolerance)
|
||||||
|
@ -2730,20 +2735,27 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors, floa
|
||||||
|
|
||||||
// render "After Cut" section
|
// render "After Cut" section
|
||||||
|
|
||||||
float label_width = 0;
|
ImVec2 label_size;
|
||||||
for (const wxString &label : {_L("Upper part"), _L("Lower part")}) {
|
for (const wxString &label : {_L("Upper part"), _L("Lower part")}) {
|
||||||
const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f);
|
const ImVec2 text_size = ImGuiWrapper::calc_text_size(label);
|
||||||
if (label_width < width)
|
if (label_size.x < text_size.x)
|
||||||
label_width = width;
|
label_size.x = text_size.x;
|
||||||
|
if (label_size.y < text_size.y)
|
||||||
|
label_size.y = text_size.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto render_part_action_line = [this, label_width, &connectors](const wxString &label, const wxString &suffix, bool &keep_part,
|
const float marker_size = label_size.y;
|
||||||
|
const float h_shift = marker_size + label_size.x + m_imgui->scaled(2.f);
|
||||||
|
|
||||||
|
auto render_part_action_line = [this, h_shift, marker_size, &connectors](const wxString &label, const wxString &suffix, bool &keep_part,
|
||||||
bool &place_on_cut_part, bool &rotate_part) {
|
bool &place_on_cut_part, bool &rotate_part) {
|
||||||
bool keep = true;
|
bool keep = true;
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
|
render_color_marker(marker_size, ImGuiWrapper::to_ImU32(suffix == "##upper" ? UPPER_PART_COLOR : LOWER_PART_COLOR));
|
||||||
m_imgui->text(label);
|
m_imgui->text(label);
|
||||||
|
|
||||||
ImGui::SameLine(label_width);
|
ImGui::SameLine(h_shift);
|
||||||
|
|
||||||
m_imgui->disabled_begin(!connectors.empty() || m_keep_as_parts);
|
m_imgui->disabled_begin(!connectors.empty() || m_keep_as_parts);
|
||||||
m_imgui->bbl_checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep);
|
m_imgui->bbl_checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep);
|
||||||
|
|
|
@ -51,6 +51,7 @@ static unsigned int GLOBAL_PLATE_INDEX = 0;
|
||||||
|
|
||||||
static const double LOGICAL_PART_PLATE_GAP = 1. / 5.;
|
static const double LOGICAL_PART_PLATE_GAP = 1. / 5.;
|
||||||
static const int PARTPLATE_ICON_SIZE = 16;
|
static const int PARTPLATE_ICON_SIZE = 16;
|
||||||
|
static const int PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE = 12;
|
||||||
static const int PARTPLATE_ICON_GAP_TOP = 3;
|
static const int PARTPLATE_ICON_GAP_TOP = 3;
|
||||||
static const int PARTPLATE_ICON_GAP_LEFT = 3;
|
static const int PARTPLATE_ICON_GAP_LEFT = 3;
|
||||||
static const int PARTPLATE_ICON_GAP_Y = 5;
|
static const int PARTPLATE_ICON_GAP_Y = 5;
|
||||||
|
@ -571,6 +572,42 @@ void PartPlate::calc_vertex_for_number(int index, bool one_number, GLModel &buff
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartPlate::calc_vertex_for_plate_name_edit_icon(GLTexture *texture, int index, PickingModel &model) {
|
||||||
|
model.reset();
|
||||||
|
|
||||||
|
auto bed_ext = get_extents(m_shape);
|
||||||
|
auto factor = bed_ext.size()(1) / 200.0;
|
||||||
|
wxCoord w, h;
|
||||||
|
h = int(factor * 16);
|
||||||
|
ExPolygon poly;
|
||||||
|
Vec2d p = bed_ext[3];
|
||||||
|
float offset_x = 1;
|
||||||
|
h = PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE;
|
||||||
|
p += Vec2d(0, PARTPLATE_TEXT_OFFSET_Y + h);
|
||||||
|
if (texture && texture->get_width() > 0 && texture->get_height()) {
|
||||||
|
w = int(factor * (texture->get_original_width() * 16) / texture->get_height()) + 1;
|
||||||
|
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + w), scale_(p(1) - h )});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + w + PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE), scale_(p(1) - h)});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + w + PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE), scale_(p(1))});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + w), scale_(p(1) )});
|
||||||
|
|
||||||
|
if (!init_model_from_poly(model.model, poly, GROUND_Z))
|
||||||
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x ), scale_(p(1) - h )});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x + PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE), scale_(p(1) - h)});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x + PARTPLATE_EDIT_PLATE_NAME_ICON_SIZE), scale_(p(1))});
|
||||||
|
poly.contour.append({scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x), scale_(p(1) )});
|
||||||
|
|
||||||
|
if (!init_model_from_poly(model.model, poly, GROUND_Z))
|
||||||
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
init_raycaster_from_model(model);
|
||||||
|
}
|
||||||
|
|
||||||
void PartPlate::calc_vertex_for_icons(int index, PickingModel &model)
|
void PartPlate::calc_vertex_for_icons(int index, PickingModel &model)
|
||||||
{
|
{
|
||||||
model.reset();
|
model.reset();
|
||||||
|
@ -975,6 +1012,13 @@ void PartPlate::render_icons(bool bottom, bool only_name, int hover_id)
|
||||||
render_icon_texture(m_lock_icon.model, m_partplate_list->m_lockopen_texture);
|
render_icon_texture(m_lock_icon.model, m_partplate_list->m_lockopen_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hover_id == 6) {
|
||||||
|
render_icon_texture(m_plate_name_edit_icon.model, m_partplate_list->m_plate_name_edit_hovered_texture);
|
||||||
|
show_tooltip(_u8L("Edit current plate name"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
render_icon_texture(m_plate_name_edit_icon.model, m_partplate_list->m_plate_name_edit_texture);
|
||||||
|
|
||||||
if (m_partplate_list->render_plate_settings) {
|
if (m_partplate_list->render_plate_settings) {
|
||||||
if (hover_id == 5) {
|
if (hover_id == 5) {
|
||||||
if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty())
|
if (get_bed_type() == BedType::btDefault && get_print_seq() == PrintSequence::ByDefault && get_first_layer_print_sequence().empty())
|
||||||
|
@ -1272,6 +1316,9 @@ void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas)
|
||||||
register_model_for_picking(canvas, m_lock_icon, picking_id_component(4));
|
register_model_for_picking(canvas, m_lock_icon, picking_id_component(4));
|
||||||
if (m_partplate_list->render_plate_settings)
|
if (m_partplate_list->render_plate_settings)
|
||||||
register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5));
|
register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5));
|
||||||
|
|
||||||
|
canvas.remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||||
|
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
int PartPlate::picking_id_component(int idx) const
|
int PartPlate::picking_id_component(int idx) const
|
||||||
|
@ -1781,7 +1828,12 @@ void PartPlate::generate_plate_name_texture()
|
||||||
poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x), scale_(p(1) - PARTPLATE_TEXT_OFFSET_Y) });
|
poly.contour.append({ scale_(p(0) + PARTPLATE_ICON_GAP_LEFT + offset_x), scale_(p(1) - PARTPLATE_TEXT_OFFSET_Y) });
|
||||||
|
|
||||||
if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z))
|
if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z))
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
|
||||||
|
|
||||||
|
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
|
||||||
|
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||||
|
calc_vertex_for_plate_name_edit_icon(&m_name_texture, 0, m_plate_name_edit_icon);
|
||||||
|
register_model_for_picking(*canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||||
}
|
}
|
||||||
void PartPlate::set_plate_name(const std::string& name)
|
void PartPlate::set_plate_name(const std::string& name)
|
||||||
{
|
{
|
||||||
|
@ -3124,6 +3176,20 @@ void PartPlateList::generate_icon_textures()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (m_plate_name_edit_texture.get_id() == 0)
|
||||||
|
{
|
||||||
|
file_name = path + (m_is_dark ? "plate_name_edit_dark.svg" : "plate_name_edit.svg");
|
||||||
|
if (!m_plate_name_edit_texture.load_from_svg_file(file_name, true, false, false, icon_size)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":load file %1% failed") % file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (m_plate_name_edit_hovered_texture.get_id() == 0)
|
||||||
|
{
|
||||||
|
file_name = path + (m_is_dark ? "plate_name_edit_hover_dark.svg" : "plate_name_edit_hover.svg");
|
||||||
|
if (!m_plate_name_edit_hovered_texture.load_from_svg_file(file_name, true, false, false, icon_size)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":load file %1% failed") % file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string text_str = "01";
|
std::string text_str = "01";
|
||||||
wxFont* font = find_font(text_str,32);
|
wxFont* font = find_font(text_str,32);
|
||||||
|
@ -3161,7 +3227,8 @@ void PartPlateList::release_icon_textures()
|
||||||
m_plate_settings_texture.reset();
|
m_plate_settings_texture.reset();
|
||||||
m_plate_settings_texture.reset();
|
m_plate_settings_texture.reset();
|
||||||
m_plate_settings_hovered_texture.reset();
|
m_plate_settings_hovered_texture.reset();
|
||||||
|
m_plate_name_edit_texture.reset();
|
||||||
|
m_plate_name_edit_hovered_texture.reset();
|
||||||
for (int i = 0;i < MAX_PLATE_COUNT; i++) {
|
for (int i = 0;i < MAX_PLATE_COUNT; i++) {
|
||||||
m_idx_textures[i].reset();
|
m_idx_textures[i].reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ private:
|
||||||
PickingModel m_orient_icon;
|
PickingModel m_orient_icon;
|
||||||
PickingModel m_lock_icon;
|
PickingModel m_lock_icon;
|
||||||
PickingModel m_plate_settings_icon;
|
PickingModel m_plate_settings_icon;
|
||||||
|
PickingModel m_plate_name_edit_icon;
|
||||||
GLModel m_plate_idx_icon;
|
GLModel m_plate_idx_icon;
|
||||||
GLTexture m_texture;
|
GLTexture m_texture;
|
||||||
|
|
||||||
|
@ -169,6 +170,7 @@ private:
|
||||||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox);
|
void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox);
|
||||||
void calc_height_limit();
|
void calc_height_limit();
|
||||||
void calc_vertex_for_number(int index, bool one_number, GLModel &buffer);
|
void calc_vertex_for_number(int index, bool one_number, GLModel &buffer);
|
||||||
|
void calc_vertex_for_plate_name_edit_icon(GLTexture *texture, int index, PickingModel &model);
|
||||||
void calc_vertex_for_icons(int index, PickingModel &model);
|
void calc_vertex_for_icons(int index, PickingModel &model);
|
||||||
// void calc_vertex_for_icons_background(int icon_count, GLModel &buffer);
|
// void calc_vertex_for_icons_background(int icon_count, GLModel &buffer);
|
||||||
void render_background(bool force_default_color = false);
|
void render_background(bool force_default_color = false);
|
||||||
|
|
|
@ -62,6 +62,11 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos,
|
||||||
|
|
||||||
Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this);
|
Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this);
|
||||||
|
|
||||||
|
m_auxiliary = new AuxiliaryPanel(this);
|
||||||
|
m_auxiliary->Hide();
|
||||||
|
main_sizer->Add(m_auxiliary, wxSizerFlags().Expand().Proportion(1));
|
||||||
|
Bind(EVT_AUXILIARY_DONE, [this](wxCommandEvent& e) { update_model_data();});
|
||||||
|
|
||||||
SetSizer(main_sizer);
|
SetSizer(main_sizer);
|
||||||
Layout();
|
Layout();
|
||||||
Fit();
|
Fit();
|
||||||
|
@ -91,38 +96,39 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
|
||||||
std::string model_author;
|
std::string model_author;
|
||||||
std::string cover_file;
|
std::string cover_file;
|
||||||
std::string description;
|
std::string description;
|
||||||
std::map<std::string, std::vector<json>> files;
|
|
||||||
|
|
||||||
std::string p_name;
|
std::string p_name;
|
||||||
std::string p_author;
|
std::string p_author;
|
||||||
std::string p_description;
|
std::string p_description;
|
||||||
std::string p_cover_file;
|
std::string p_cover_file;
|
||||||
|
|
||||||
|
std::map<std::string, std::vector<json>> files;
|
||||||
|
|
||||||
Model model = wxGetApp().plater()->model();
|
Model model = wxGetApp().plater()->model();
|
||||||
|
|
||||||
license = model.model_info->license;
|
auto model_info = model.model_info;
|
||||||
model_name = model.model_info->model_name;
|
if (model_info != nullptr) {
|
||||||
cover_file = model.model_info->cover_file;
|
license = model_info->license;
|
||||||
description = model.model_info->description;
|
model_name = model_info->model_name;
|
||||||
update_type = model.model_info->origin;
|
cover_file = model_info->cover_file;
|
||||||
|
description = model_info->description;
|
||||||
|
update_type = model_info->origin;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!model_info->copyright.empty()) {
|
||||||
|
json copy_right = json::parse(model_info->copyright);
|
||||||
|
|
||||||
try {
|
if (copy_right.is_array()) {
|
||||||
if (!model.model_info->copyright.empty()) {
|
for (auto it = copy_right.begin(); it != copy_right.end(); it++) {
|
||||||
json copy_right = json::parse(model.model_info->copyright);
|
if ((*it).contains("author")) {
|
||||||
|
model_author = (*it)["author"].get<std::string>();
|
||||||
if (copy_right.is_array()) {
|
}
|
||||||
for (auto it = copy_right.begin(); it != copy_right.end(); it++) {
|
|
||||||
if ((*it).contains("author")) {
|
|
||||||
model_author = (*it)["author"].get<std::string>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (...) {
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model_author.empty() && model.design_info != nullptr)
|
if (model_author.empty() && model.design_info != nullptr)
|
||||||
model_author = model.design_info->Designer;
|
model_author = model.design_info->Designer;
|
||||||
|
@ -134,12 +140,44 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
|
||||||
p_author = model.profile_info->ProfileUserName;
|
p_author = model.profile_info->ProfileUserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
//file info
|
// file info
|
||||||
std::string file_path = encode_path(wxGetApp().plater()->model().get_auxiliary_file_temp_path().c_str());
|
std::string file_path = encode_path(wxGetApp().plater()->model().get_auxiliary_file_temp_path().c_str());
|
||||||
if (!file_path.empty()) {
|
if (!file_path.empty()) {
|
||||||
files = Reload(file_path);
|
files = Reload(file_path);
|
||||||
|
wxGetApp().CallAfter([this, file_path, files] { m_auxiliary->Reload(file_path, files); });
|
||||||
|
} else {
|
||||||
|
clear_model_info();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
bool has_content = false;
|
||||||
|
for (const string& v : {
|
||||||
|
update_type,
|
||||||
|
license,
|
||||||
|
model_name,
|
||||||
|
model_author,
|
||||||
|
cover_file,
|
||||||
|
description,
|
||||||
|
p_name,
|
||||||
|
p_author,
|
||||||
|
p_description,
|
||||||
|
p_cover_file,
|
||||||
|
}) {
|
||||||
|
if (!v.empty()) {
|
||||||
|
has_content = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_content) {
|
||||||
|
for (const auto & file : files) {
|
||||||
|
if (!file.second.empty()) {
|
||||||
|
has_content = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_content) {
|
||||||
|
// Nothing to show, just return
|
||||||
clear_model_info();
|
clear_model_info();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -180,6 +218,7 @@ void ProjectPanel::on_reload(wxCommandEvent& evt)
|
||||||
|
|
||||||
void ProjectPanel::msw_rescale()
|
void ProjectPanel::msw_rescale()
|
||||||
{
|
{
|
||||||
|
m_auxiliary->msw_rescale();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectPanel::on_size(wxSizeEvent &event)
|
void ProjectPanel::on_size(wxSizeEvent &event)
|
||||||
|
@ -215,6 +254,9 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
|
||||||
else if (strCmd == "request_3mf_info") {
|
else if (strCmd == "request_3mf_info") {
|
||||||
m_web_init_completed = true;
|
m_web_init_completed = true;
|
||||||
}
|
}
|
||||||
|
else if (strCmd == "edit_project_info") {
|
||||||
|
show_info_editor(true);
|
||||||
|
}
|
||||||
else if (strCmd == "debug_info") {
|
else if (strCmd == "debug_info") {
|
||||||
//wxString msg = j["msg"];
|
//wxString msg = j["msg"];
|
||||||
//OutputDebugString(wxString::Format("Model_Web: msg = %s \r\n", msg));
|
//OutputDebugString(wxString::Format("Model_Web: msg = %s \r\n", msg));
|
||||||
|
@ -227,14 +269,24 @@ void ProjectPanel::OnScriptMessage(wxWebViewEvent& evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectPanel::show_info_editor(bool show)
|
||||||
|
{
|
||||||
|
m_browser->Show(!show);
|
||||||
|
m_auxiliary->Show(show);
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectPanel::update_model_data()
|
void ProjectPanel::update_model_data()
|
||||||
{
|
{
|
||||||
Model model = wxGetApp().plater()->model();
|
Model model = wxGetApp().plater()->model();
|
||||||
|
show_info_editor(false);
|
||||||
clear_model_info();
|
clear_model_info();
|
||||||
|
|
||||||
|
m_auxiliary->init_auxiliary();
|
||||||
|
|
||||||
//basics info
|
//basics info
|
||||||
if (model.model_info == nullptr)
|
//if (model.model_info == nullptr)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
auto event = wxCommandEvent(EVT_PROJECT_RELOAD);
|
auto event = wxCommandEvent(EVT_PROJECT_RELOAD);
|
||||||
event.SetEventObject(this);
|
event.SetEventObject(this);
|
||||||
|
@ -258,7 +310,6 @@ std::map<std::string, std::vector<json>> ProjectPanel::Reload(wxString aux_path)
|
||||||
{
|
{
|
||||||
std::vector<fs::path> dir_cache;
|
std::vector<fs::path> dir_cache;
|
||||||
fs::directory_iterator iter_end;
|
fs::directory_iterator iter_end;
|
||||||
wxString m_root_dir;
|
|
||||||
std::map<std::string, std::vector<json>> m_paths_list;
|
std::map<std::string, std::vector<json>> m_paths_list;
|
||||||
|
|
||||||
const static std::array<wxString, 5> s_default_folders = {
|
const static std::array<wxString, 5> s_default_folders = {
|
||||||
|
@ -276,24 +327,16 @@ std::map<std::string, std::vector<json>> ProjectPanel::Reload(wxString aux_path)
|
||||||
|
|
||||||
fs::path new_aux_path(aux_path.ToStdWstring());
|
fs::path new_aux_path(aux_path.ToStdWstring());
|
||||||
|
|
||||||
try {
|
|
||||||
fs::remove_all(fs::path(m_root_dir.ToStdWstring()));
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Failed removing the auxiliary directory" << m_root_dir.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_root_dir = aux_path;
|
|
||||||
// Check new path. If not exist, create a new one.
|
// Check new path. If not exist, create a new one.
|
||||||
if (!fs::exists(new_aux_path)) {
|
if (!fs::exists(new_aux_path)) {
|
||||||
fs::create_directory(new_aux_path);
|
fs::create_directory(new_aux_path);
|
||||||
// Create default folders if they are not loaded
|
}
|
||||||
for (auto folder : s_default_folders) {
|
|
||||||
wxString folder_path = aux_path + "/" + folder;
|
// Create default folders if they are not loaded
|
||||||
if (fs::exists(folder_path.ToStdWstring())) continue;
|
for (auto folder : s_default_folders) {
|
||||||
fs::create_directory(folder_path.ToStdWstring());
|
wxString folder_path = aux_path + "/" + folder;
|
||||||
}
|
if (fs::exists(folder_path.ToStdWstring())) continue;
|
||||||
return m_paths_list;
|
fs::create_directory(folder_path.ToStdWstring());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load from new path
|
// Load from new path
|
||||||
|
@ -321,6 +364,7 @@ std::map<std::string, std::vector<json>> ProjectPanel::Reload(wxString aux_path)
|
||||||
wxStat(file_name, &strucStat);
|
wxStat(file_name, &strucStat);
|
||||||
wxFileOffset filelen = strucStat.st_size;
|
wxFileOffset filelen = strucStat.st_size;
|
||||||
|
|
||||||
|
pfile_obj["_filepath"] = file_path;
|
||||||
pfile_obj["filename"] = wxGetApp().url_encode(file_path_obj.filename().string().c_str());
|
pfile_obj["filename"] = wxGetApp().url_encode(file_path_obj.filename().string().c_str());
|
||||||
pfile_obj["size"] = formatBytes((unsigned long)filelen);
|
pfile_obj["size"] = formatBytes((unsigned long)filelen);
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
#include "libslic3r/ProjectTask.hpp"
|
#include "libslic3r/ProjectTask.hpp"
|
||||||
#include "wxExtensions.hpp"
|
#include "wxExtensions.hpp"
|
||||||
|
#include "Auxiliary.hpp"
|
||||||
|
|
||||||
#define AUFILE_GREY700 wxColour(107, 107, 107)
|
#define AUFILE_GREY700 wxColour(107, 107, 107)
|
||||||
#define AUFILE_GREY500 wxColour(158, 158, 158)
|
#define AUFILE_GREY500 wxColour(158, 158, 158)
|
||||||
|
@ -63,10 +64,13 @@ private:
|
||||||
bool m_reload_already = {false};
|
bool m_reload_already = {false};
|
||||||
|
|
||||||
wxWebView* m_browser = {nullptr};
|
wxWebView* m_browser = {nullptr};
|
||||||
|
AuxiliaryPanel* m_auxiliary{nullptr};
|
||||||
wxString m_project_home_url;
|
wxString m_project_home_url;
|
||||||
wxString m_root_dir;
|
wxString m_root_dir;
|
||||||
static inline int m_sequence_id = 8000;
|
static inline int m_sequence_id = 8000;
|
||||||
|
|
||||||
|
void show_info_editor(bool show);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL);
|
ProjectPanel(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxTAB_TRAVERSAL);
|
||||||
|
@ -81,6 +85,7 @@ public:
|
||||||
void msw_rescale();
|
void msw_rescale();
|
||||||
void update_model_data();
|
void update_model_data();
|
||||||
void clear_model_info();
|
void clear_model_info();
|
||||||
|
void init_auxiliary() { m_auxiliary->init_auxiliary(); }
|
||||||
|
|
||||||
bool Show(bool show);
|
bool Show(bool show);
|
||||||
void OnScriptMessage(wxWebViewEvent& evt);
|
void OnScriptMessage(wxWebViewEvent& evt);
|
||||||
|
|
|
@ -1324,8 +1324,11 @@ void Selection::scale_legacy(const Vec3d& scale, TransformationType transformati
|
||||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||||
|
|
||||||
v.set_instance_scaling_factor(new_scale);
|
v.set_instance_scaling_factor(new_scale);
|
||||||
|
// Restore mirror state
|
||||||
|
v.set_instance_mirror(m_cache.volumes_data[i].get_instance_transform().get_mirror());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const auto mirror = v.get_instance_mirror();
|
||||||
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
||||||
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
||||||
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
||||||
|
@ -1334,16 +1337,24 @@ void Selection::scale_legacy(const Vec3d& scale, TransformationType transformati
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
v.set_instance_scaling_factor(scale);
|
v.set_instance_scaling_factor(scale);
|
||||||
|
// Restore mirror state
|
||||||
|
v.set_instance_mirror(mirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the instance assemble transform
|
// update the instance assemble transform
|
||||||
ModelObject* object = m_model->objects[v.object_idx()];
|
ModelObject* object = m_model->objects[v.object_idx()];
|
||||||
Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
|
Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
|
||||||
|
const auto mirror = assemble_transform.get_mirror();
|
||||||
assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
|
assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
|
||||||
|
assemble_transform.set_mirror(mirror);
|
||||||
object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
|
object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
|
||||||
}
|
}
|
||||||
else if (is_single_volume() || is_single_modifier())
|
else if (is_single_volume() || is_single_modifier()) {
|
||||||
|
const auto mirror = v.get_volume_transformation().get_mirror();
|
||||||
v.set_volume_scaling_factor(scale);
|
v.set_volume_scaling_factor(scale);
|
||||||
|
// Restore mirror state
|
||||||
|
v.set_volume_mirror(mirror);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
|
@ -1354,6 +1365,8 @@ void Selection::scale_legacy(const Vec3d& scale, TransformationType transformati
|
||||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||||
|
|
||||||
v.set_instance_scaling_factor(new_scale);
|
v.set_instance_scaling_factor(new_scale);
|
||||||
|
// Restore mirror state
|
||||||
|
v.set_instance_mirror(m_cache.volumes_data[i].get_instance_transform().get_mirror());
|
||||||
}
|
}
|
||||||
else if (m_mode == Volume) {
|
else if (m_mode == Volume) {
|
||||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||||
|
@ -1364,6 +1377,8 @@ void Selection::scale_legacy(const Vec3d& scale, TransformationType transformati
|
||||||
v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||||
}
|
}
|
||||||
v.set_volume_scaling_factor(new_scale);
|
v.set_volume_scaling_factor(new_scale);
|
||||||
|
// Restore mirror state
|
||||||
|
v.set_volume_mirror(m_cache.volumes_data[i].get_volume_transform().get_mirror());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1989,6 +1989,14 @@ void TabPrint::build()
|
||||||
optgroup->append_single_option_line("reduce_crossing_wall");
|
optgroup->append_single_option_line("reduce_crossing_wall");
|
||||||
optgroup->append_single_option_line("max_travel_detour_distance");
|
optgroup->append_single_option_line("max_travel_detour_distance");
|
||||||
|
|
||||||
|
optgroup = page->new_optgroup(L("Small Area Infill Flow Compensation (experimental)"), L"param_advanced");
|
||||||
|
optgroup->append_single_option_line("small_area_infill_flow_compensation");
|
||||||
|
Option option = optgroup->get_option("small_area_infill_flow_compensation_model");
|
||||||
|
option.opt.full_width = true;
|
||||||
|
option.opt.is_code = true;
|
||||||
|
option.opt.height = 15;
|
||||||
|
optgroup->append_single_option_line(option);
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Bridging"), L"param_advanced");
|
optgroup = page->new_optgroup(L("Bridging"), L"param_advanced");
|
||||||
optgroup->append_single_option_line("bridge_flow");
|
optgroup->append_single_option_line("bridge_flow");
|
||||||
optgroup->append_single_option_line("internal_bridge_flow");
|
optgroup->append_single_option_line("internal_bridge_flow");
|
||||||
|
@ -2198,6 +2206,7 @@ void TabPrint::build()
|
||||||
optgroup = page->new_optgroup(L("Special mode"), L"param_special");
|
optgroup = page->new_optgroup(L("Special mode"), L"param_special");
|
||||||
optgroup->append_single_option_line("slicing_mode");
|
optgroup->append_single_option_line("slicing_mode");
|
||||||
optgroup->append_single_option_line("print_sequence", "sequent-print");
|
optgroup->append_single_option_line("print_sequence", "sequent-print");
|
||||||
|
optgroup->append_single_option_line("print_order");
|
||||||
optgroup->append_single_option_line("spiral_mode", "spiral-vase");
|
optgroup->append_single_option_line("spiral_mode", "spiral-vase");
|
||||||
optgroup->append_single_option_line("spiral_mode_smooth", "spiral-vase#smooth");
|
optgroup->append_single_option_line("spiral_mode_smooth", "spiral-vase#smooth");
|
||||||
optgroup->append_single_option_line("spiral_mode_max_xy_smoothing", "spiral-vase#max-xy-smoothing");
|
optgroup->append_single_option_line("spiral_mode_max_xy_smoothing", "spiral-vase#max-xy-smoothing");
|
||||||
|
@ -2218,7 +2227,7 @@ void TabPrint::build()
|
||||||
optgroup->append_single_option_line("gcode_comments");
|
optgroup->append_single_option_line("gcode_comments");
|
||||||
optgroup->append_single_option_line("gcode_label_objects");
|
optgroup->append_single_option_line("gcode_label_objects");
|
||||||
optgroup->append_single_option_line("exclude_object");
|
optgroup->append_single_option_line("exclude_object");
|
||||||
Option option = optgroup->get_option("filename_format");
|
option = optgroup->get_option("filename_format");
|
||||||
// option.opt.full_width = true;
|
// option.opt.full_width = true;
|
||||||
option.opt.is_code = true;
|
option.opt.is_code = true;
|
||||||
option.opt.multiline = true;
|
option.opt.multiline = true;
|
||||||
|
|
951
src/spline/spline.h
Normal file
951
src/spline/spline.h
Normal file
|
@ -0,0 +1,951 @@
|
||||||
|
/*
|
||||||
|
* spline.h
|
||||||
|
*
|
||||||
|
* simple cubic spline interpolation library without external
|
||||||
|
* dependencies
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* Copyright (C) 2011, 2014, 2016, 2021 Tino Kluge (ttk448 at gmail.com)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TK_SPLINE_H
|
||||||
|
#define TK_SPLINE_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#ifdef HAVE_SSTREAM
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#endif // HAVE_SSTREAM
|
||||||
|
|
||||||
|
// not ideal but disable unused-function warnings
|
||||||
|
// (we get them because we have implementations in the header file,
|
||||||
|
// and this is because we want to be able to quickly separate them
|
||||||
|
// into a cpp file if necessary)
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// unnamed namespace only because the implementation is in this
|
||||||
|
// header file and we don't want to export symbols to the obj files
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace tk
|
||||||
|
{
|
||||||
|
|
||||||
|
// spline interpolation
|
||||||
|
class spline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// spline types
|
||||||
|
enum spline_type {
|
||||||
|
linear = 10, // linear interpolation
|
||||||
|
cspline = 30, // cubic splines (classical C^2)
|
||||||
|
cspline_hermite = 31 // cubic hermite splines (local, only C^1)
|
||||||
|
};
|
||||||
|
|
||||||
|
// boundary condition type for the spline end-points
|
||||||
|
enum bd_type {
|
||||||
|
first_deriv = 1,
|
||||||
|
second_deriv = 2,
|
||||||
|
not_a_knot = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<double> m_x,m_y; // x,y coordinates of points
|
||||||
|
// interpolation parameters
|
||||||
|
// f(x) = a_i + b_i*(x-x_i) + c_i*(x-x_i)^2 + d_i*(x-x_i)^3
|
||||||
|
// where a_i = y_i, or else it won't go through grid points
|
||||||
|
std::vector<double> m_b,m_c,m_d; // spline coefficients
|
||||||
|
double m_c0; // for left extrapolation
|
||||||
|
spline_type m_type;
|
||||||
|
bd_type m_left, m_right;
|
||||||
|
double m_left_value, m_right_value;
|
||||||
|
bool m_made_monotonic;
|
||||||
|
void set_coeffs_from_b(); // calculate c_i, d_i from b_i
|
||||||
|
size_t find_closest(double x) const; // closest idx so that m_x[idx]<=x
|
||||||
|
|
||||||
|
public:
|
||||||
|
// default constructor: set boundary condition to be zero curvature
|
||||||
|
// at both ends, i.e. natural splines
|
||||||
|
spline(): m_type(cspline),
|
||||||
|
m_left(second_deriv), m_right(second_deriv),
|
||||||
|
m_left_value(0.0), m_right_value(0.0), m_made_monotonic(false)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
spline(const std::vector<double>& X, const std::vector<double>& Y,
|
||||||
|
spline_type type = cspline,
|
||||||
|
bool make_monotonic = false,
|
||||||
|
bd_type left = second_deriv, double left_value = 0.0,
|
||||||
|
bd_type right = second_deriv, double right_value = 0.0
|
||||||
|
):
|
||||||
|
m_type(type),
|
||||||
|
m_left(left), m_right(right),
|
||||||
|
m_left_value(left_value), m_right_value(right_value),
|
||||||
|
m_made_monotonic(false) // false correct here: make_monotonic() sets it
|
||||||
|
{
|
||||||
|
this->set_points(X,Y,m_type);
|
||||||
|
if(make_monotonic) {
|
||||||
|
this->make_monotonic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// modify boundary conditions: if called it must be before set_points()
|
||||||
|
void set_boundary(bd_type left, double left_value,
|
||||||
|
bd_type right, double right_value);
|
||||||
|
|
||||||
|
// set all data points (cubic_spline=false means linear interpolation)
|
||||||
|
void set_points(const std::vector<double>& x,
|
||||||
|
const std::vector<double>& y,
|
||||||
|
spline_type type=cspline);
|
||||||
|
|
||||||
|
// adjust coefficients so that the spline becomes piecewise monotonic
|
||||||
|
// where possible
|
||||||
|
// this is done by adjusting slopes at grid points by a non-negative
|
||||||
|
// factor and this will break C^2
|
||||||
|
// this can also break boundary conditions if adjustments need to
|
||||||
|
// be made at the boundary points
|
||||||
|
// returns false if no adjustments have been made, true otherwise
|
||||||
|
bool make_monotonic();
|
||||||
|
|
||||||
|
// evaluates the spline at point x
|
||||||
|
double operator() (double x) const;
|
||||||
|
double deriv(int order, double x) const;
|
||||||
|
|
||||||
|
// solves for all x so that: spline(x) = y
|
||||||
|
std::vector<double> solve(double y, bool ignore_extrapolation=true) const;
|
||||||
|
|
||||||
|
// returns the input data points
|
||||||
|
std::vector<double> get_x() const { return m_x; }
|
||||||
|
std::vector<double> get_y() const { return m_y; }
|
||||||
|
double get_x_min() const { assert(!m_x.empty()); return m_x.front(); }
|
||||||
|
double get_x_max() const { assert(!m_x.empty()); return m_x.back(); }
|
||||||
|
|
||||||
|
#ifdef HAVE_SSTREAM
|
||||||
|
// spline info string, i.e. spline type, boundary conditions etc.
|
||||||
|
std::string info() const;
|
||||||
|
#endif // HAVE_SSTREAM
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
|
||||||
|
// band matrix solver
|
||||||
|
class band_matrix
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector< std::vector<double> > m_upper; // upper band
|
||||||
|
std::vector< std::vector<double> > m_lower; // lower band
|
||||||
|
public:
|
||||||
|
band_matrix() {}; // constructor
|
||||||
|
band_matrix(int dim, int n_u, int n_l); // constructor
|
||||||
|
~band_matrix() {}; // destructor
|
||||||
|
void resize(int dim, int n_u, int n_l); // init with dim,n_u,n_l
|
||||||
|
int dim() const; // matrix dimension
|
||||||
|
int num_upper() const
|
||||||
|
{
|
||||||
|
return (int)m_upper.size()-1;
|
||||||
|
}
|
||||||
|
int num_lower() const
|
||||||
|
{
|
||||||
|
return (int)m_lower.size()-1;
|
||||||
|
}
|
||||||
|
// access operator
|
||||||
|
double & operator () (int i, int j); // write
|
||||||
|
double operator () (int i, int j) const; // read
|
||||||
|
// we can store an additional diagonal (in m_lower)
|
||||||
|
double& saved_diag(int i);
|
||||||
|
double saved_diag(int i) const;
|
||||||
|
void lu_decompose();
|
||||||
|
std::vector<double> r_solve(const std::vector<double>& b) const;
|
||||||
|
std::vector<double> l_solve(const std::vector<double>& b) const;
|
||||||
|
std::vector<double> lu_solve(const std::vector<double>& b,
|
||||||
|
bool is_lu_decomposed=false);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
double get_eps();
|
||||||
|
|
||||||
|
std::vector<double> solve_cubic(double a, double b, double c, double d,
|
||||||
|
int newton_iter=0);
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// implementation part, which could be separated into a cpp file
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
// spline implementation
|
||||||
|
// -----------------------
|
||||||
|
|
||||||
|
void spline::set_boundary(spline::bd_type left, double left_value,
|
||||||
|
spline::bd_type right, double right_value)
|
||||||
|
{
|
||||||
|
assert(m_x.size()==0); // set_points() must not have happened yet
|
||||||
|
m_left=left;
|
||||||
|
m_right=right;
|
||||||
|
m_left_value=left_value;
|
||||||
|
m_right_value=right_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void spline::set_coeffs_from_b()
|
||||||
|
{
|
||||||
|
assert(m_x.size()==m_y.size());
|
||||||
|
assert(m_x.size()==m_b.size());
|
||||||
|
assert(m_x.size()>2);
|
||||||
|
size_t n=m_b.size();
|
||||||
|
if(m_c.size()!=n)
|
||||||
|
m_c.resize(n);
|
||||||
|
if(m_d.size()!=n)
|
||||||
|
m_d.resize(n);
|
||||||
|
|
||||||
|
for(size_t i=0; i<n-1; i++) {
|
||||||
|
const double h = m_x[i+1]-m_x[i];
|
||||||
|
// from continuity and differentiability condition
|
||||||
|
m_c[i] = ( 3.0*(m_y[i+1]-m_y[i])/h - (2.0*m_b[i]+m_b[i+1]) ) / h;
|
||||||
|
// from differentiability condition
|
||||||
|
m_d[i] = ( (m_b[i+1]-m_b[i])/(3.0*h) - 2.0/3.0*m_c[i] ) / h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for left extrapolation coefficients
|
||||||
|
m_c0 = (m_left==first_deriv) ? 0.0 : m_c[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void spline::set_points(const std::vector<double>& x,
|
||||||
|
const std::vector<double>& y,
|
||||||
|
spline_type type)
|
||||||
|
{
|
||||||
|
assert(x.size()==y.size());
|
||||||
|
assert(x.size()>=3);
|
||||||
|
// not-a-knot with 3 points has many solutions
|
||||||
|
if(m_left==not_a_knot || m_right==not_a_knot)
|
||||||
|
assert(x.size()>=4);
|
||||||
|
m_type=type;
|
||||||
|
m_made_monotonic=false;
|
||||||
|
m_x=x;
|
||||||
|
m_y=y;
|
||||||
|
int n = (int) x.size();
|
||||||
|
// check strict monotonicity of input vector x
|
||||||
|
for(int i=0; i<n-1; i++) {
|
||||||
|
assert(m_x[i]<m_x[i+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(type==linear) {
|
||||||
|
// linear interpolation
|
||||||
|
m_d.resize(n);
|
||||||
|
m_c.resize(n);
|
||||||
|
m_b.resize(n);
|
||||||
|
for(int i=0; i<n-1; i++) {
|
||||||
|
m_d[i]=0.0;
|
||||||
|
m_c[i]=0.0;
|
||||||
|
m_b[i]=(m_y[i+1]-m_y[i])/(m_x[i+1]-m_x[i]);
|
||||||
|
}
|
||||||
|
// ignore boundary conditions, set slope equal to the last segment
|
||||||
|
m_b[n-1]=m_b[n-2];
|
||||||
|
m_c[n-1]=0.0;
|
||||||
|
m_d[n-1]=0.0;
|
||||||
|
} else if(type==cspline) {
|
||||||
|
// classical cubic splines which are C^2 (twice cont differentiable)
|
||||||
|
// this requires solving an equation system
|
||||||
|
|
||||||
|
// setting up the matrix and right hand side of the equation system
|
||||||
|
// for the parameters b[]
|
||||||
|
int n_upper = (m_left == spline::not_a_knot) ? 2 : 1;
|
||||||
|
int n_lower = (m_right == spline::not_a_knot) ? 2 : 1;
|
||||||
|
internal::band_matrix A(n,n_upper,n_lower);
|
||||||
|
std::vector<double> rhs(n);
|
||||||
|
for(int i=1; i<n-1; i++) {
|
||||||
|
A(i,i-1)=1.0/3.0*(x[i]-x[i-1]);
|
||||||
|
A(i,i)=2.0/3.0*(x[i+1]-x[i-1]);
|
||||||
|
A(i,i+1)=1.0/3.0*(x[i+1]-x[i]);
|
||||||
|
rhs[i]=(y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]);
|
||||||
|
}
|
||||||
|
// boundary conditions
|
||||||
|
if(m_left == spline::second_deriv) {
|
||||||
|
// 2*c[0] = f''
|
||||||
|
A(0,0)=2.0;
|
||||||
|
A(0,1)=0.0;
|
||||||
|
rhs[0]=m_left_value;
|
||||||
|
} else if(m_left == spline::first_deriv) {
|
||||||
|
// b[0] = f', needs to be re-expressed in terms of c:
|
||||||
|
// (2c[0]+c[1])(x[1]-x[0]) = 3 ((y[1]-y[0])/(x[1]-x[0]) - f')
|
||||||
|
A(0,0)=2.0*(x[1]-x[0]);
|
||||||
|
A(0,1)=1.0*(x[1]-x[0]);
|
||||||
|
rhs[0]=3.0*((y[1]-y[0])/(x[1]-x[0])-m_left_value);
|
||||||
|
} else if(m_left == spline::not_a_knot) {
|
||||||
|
// f'''(x[1]) exists, i.e. d[0]=d[1], or re-expressed in c:
|
||||||
|
// -h1*c[0] + (h0+h1)*c[1] - h0*c[2] = 0
|
||||||
|
A(0,0) = -(x[2]-x[1]);
|
||||||
|
A(0,1) = x[2]-x[0];
|
||||||
|
A(0,2) = -(x[1]-x[0]);
|
||||||
|
rhs[0] = 0.0;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
if(m_right == spline::second_deriv) {
|
||||||
|
// 2*c[n-1] = f''
|
||||||
|
A(n-1,n-1)=2.0;
|
||||||
|
A(n-1,n-2)=0.0;
|
||||||
|
rhs[n-1]=m_right_value;
|
||||||
|
} else if(m_right == spline::first_deriv) {
|
||||||
|
// b[n-1] = f', needs to be re-expressed in terms of c:
|
||||||
|
// (c[n-2]+2c[n-1])(x[n-1]-x[n-2])
|
||||||
|
// = 3 (f' - (y[n-1]-y[n-2])/(x[n-1]-x[n-2]))
|
||||||
|
A(n-1,n-1)=2.0*(x[n-1]-x[n-2]);
|
||||||
|
A(n-1,n-2)=1.0*(x[n-1]-x[n-2]);
|
||||||
|
rhs[n-1]=3.0*(m_right_value-(y[n-1]-y[n-2])/(x[n-1]-x[n-2]));
|
||||||
|
} else if(m_right == spline::not_a_knot) {
|
||||||
|
// f'''(x[n-2]) exists, i.e. d[n-3]=d[n-2], or re-expressed in c:
|
||||||
|
// -h_{n-2}*c[n-3] + (h_{n-3}+h_{n-2})*c[n-2] - h_{n-3}*c[n-1] = 0
|
||||||
|
A(n-1,n-3) = -(x[n-1]-x[n-2]);
|
||||||
|
A(n-1,n-2) = x[n-1]-x[n-3];
|
||||||
|
A(n-1,n-1) = -(x[n-2]-x[n-3]);
|
||||||
|
rhs[0] = 0.0;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// solve the equation system to obtain the parameters c[]
|
||||||
|
m_c=A.lu_solve(rhs);
|
||||||
|
|
||||||
|
// calculate parameters b[] and d[] based on c[]
|
||||||
|
m_d.resize(n);
|
||||||
|
m_b.resize(n);
|
||||||
|
for(int i=0; i<n-1; i++) {
|
||||||
|
m_d[i]=1.0/3.0*(m_c[i+1]-m_c[i])/(x[i+1]-x[i]);
|
||||||
|
m_b[i]=(y[i+1]-y[i])/(x[i+1]-x[i])
|
||||||
|
- 1.0/3.0*(2.0*m_c[i]+m_c[i+1])*(x[i+1]-x[i]);
|
||||||
|
}
|
||||||
|
// for the right extrapolation coefficients (zero cubic term)
|
||||||
|
// f_{n-1}(x) = y_{n-1} + b*(x-x_{n-1}) + c*(x-x_{n-1})^2
|
||||||
|
double h=x[n-1]-x[n-2];
|
||||||
|
// m_c[n-1] is determined by the boundary condition
|
||||||
|
m_d[n-1]=0.0;
|
||||||
|
m_b[n-1]=3.0*m_d[n-2]*h*h+2.0*m_c[n-2]*h+m_b[n-2]; // = f'_{n-2}(x_{n-1})
|
||||||
|
if(m_right==first_deriv)
|
||||||
|
m_c[n-1]=0.0; // force linear extrapolation
|
||||||
|
|
||||||
|
} else if(type==cspline_hermite) {
|
||||||
|
// hermite cubic splines which are C^1 (cont. differentiable)
|
||||||
|
// and derivatives are specified on each grid point
|
||||||
|
// (here we use 3-point finite differences)
|
||||||
|
m_b.resize(n);
|
||||||
|
m_c.resize(n);
|
||||||
|
m_d.resize(n);
|
||||||
|
// set b to match 1st order derivative finite difference
|
||||||
|
for(int i=1; i<n-1; i++) {
|
||||||
|
const double h = m_x[i+1]-m_x[i];
|
||||||
|
const double hl = m_x[i]-m_x[i-1];
|
||||||
|
m_b[i] = -h/(hl*(hl+h))*m_y[i-1] + (h-hl)/(hl*h)*m_y[i]
|
||||||
|
+ hl/(h*(hl+h))*m_y[i+1];
|
||||||
|
}
|
||||||
|
// boundary conditions determine b[0] and b[n-1]
|
||||||
|
if(m_left==first_deriv) {
|
||||||
|
m_b[0]=m_left_value;
|
||||||
|
} else if(m_left==second_deriv) {
|
||||||
|
const double h = m_x[1]-m_x[0];
|
||||||
|
m_b[0]=0.5*(-m_b[1]-0.5*m_left_value*h+3.0*(m_y[1]-m_y[0])/h);
|
||||||
|
} else if(m_left == not_a_knot) {
|
||||||
|
// f''' continuous at x[1]
|
||||||
|
const double h0 = m_x[1]-m_x[0];
|
||||||
|
const double h1 = m_x[2]-m_x[1];
|
||||||
|
m_b[0]= -m_b[1] + 2.0*(m_y[1]-m_y[0])/h0
|
||||||
|
+ h0*h0/(h1*h1)*(m_b[1]+m_b[2]-2.0*(m_y[2]-m_y[1])/h1);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
if(m_right==first_deriv) {
|
||||||
|
m_b[n-1]=m_right_value;
|
||||||
|
m_c[n-1]=0.0;
|
||||||
|
} else if(m_right==second_deriv) {
|
||||||
|
const double h = m_x[n-1]-m_x[n-2];
|
||||||
|
m_b[n-1]=0.5*(-m_b[n-2]+0.5*m_right_value*h+3.0*(m_y[n-1]-m_y[n-2])/h);
|
||||||
|
m_c[n-1]=0.5*m_right_value;
|
||||||
|
} else if(m_right == not_a_knot) {
|
||||||
|
// f''' continuous at x[n-2]
|
||||||
|
const double h0 = m_x[n-2]-m_x[n-3];
|
||||||
|
const double h1 = m_x[n-1]-m_x[n-2];
|
||||||
|
m_b[n-1]= -m_b[n-2] + 2.0*(m_y[n-1]-m_y[n-2])/h1 + h1*h1/(h0*h0)
|
||||||
|
*(m_b[n-3]+m_b[n-2]-2.0*(m_y[n-2]-m_y[n-3])/h0);
|
||||||
|
// f'' continuous at x[n-1]: c[n-1] = 3*d[n-2]*h[n-2] + c[n-1]
|
||||||
|
m_c[n-1]=(m_b[n-2]+2.0*m_b[n-1])/h1-3.0*(m_y[n-1]-m_y[n-2])/(h1*h1);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
m_d[n-1]=0.0;
|
||||||
|
|
||||||
|
// parameters c and d are determined by continuity and differentiability
|
||||||
|
set_coeffs_from_b();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for left extrapolation coefficients
|
||||||
|
m_c0 = (m_left==first_deriv) ? 0.0 : m_c[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spline::make_monotonic()
|
||||||
|
{
|
||||||
|
assert(m_x.size()==m_y.size());
|
||||||
|
assert(m_x.size()==m_b.size());
|
||||||
|
assert(m_x.size()>2);
|
||||||
|
bool modified = false;
|
||||||
|
const int n=(int)m_x.size();
|
||||||
|
// make sure: input data monotonic increasing --> b_i>=0
|
||||||
|
// input data monotonic decreasing --> b_i<=0
|
||||||
|
for(int i=0; i<n; i++) {
|
||||||
|
int im1 = std::max(i-1, 0);
|
||||||
|
int ip1 = std::min(i+1, n-1);
|
||||||
|
if( ((m_y[im1]<=m_y[i]) && (m_y[i]<=m_y[ip1]) && m_b[i]<0.0) ||
|
||||||
|
((m_y[im1]>=m_y[i]) && (m_y[i]>=m_y[ip1]) && m_b[i]>0.0) ) {
|
||||||
|
modified=true;
|
||||||
|
m_b[i]=0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if input data is monotonic (b[i], b[i+1], avg have all the same sign)
|
||||||
|
// ensure a sufficient criteria for monotonicity is satisfied:
|
||||||
|
// sqrt(b[i]^2+b[i+1]^2) <= 3 |avg|, with avg=(y[i+1]-y[i])/h,
|
||||||
|
for(int i=0; i<n-1; i++) {
|
||||||
|
double h = m_x[i+1]-m_x[i];
|
||||||
|
double avg = (m_y[i+1]-m_y[i])/h;
|
||||||
|
if( avg==0.0 && (m_b[i]!=0.0 || m_b[i+1]!=0.0) ) {
|
||||||
|
modified=true;
|
||||||
|
m_b[i]=0.0;
|
||||||
|
m_b[i+1]=0.0;
|
||||||
|
} else if( (m_b[i]>=0.0 && m_b[i+1]>=0.0 && avg>0.0) ||
|
||||||
|
(m_b[i]<=0.0 && m_b[i+1]<=0.0 && avg<0.0) ) {
|
||||||
|
// input data is monotonic
|
||||||
|
double r = sqrt(m_b[i]*m_b[i]+m_b[i+1]*m_b[i+1])/std::fabs(avg);
|
||||||
|
if(r>3.0) {
|
||||||
|
// sufficient criteria for monotonicity: r<=3
|
||||||
|
// adjust b[i] and b[i+1]
|
||||||
|
modified=true;
|
||||||
|
m_b[i] *= (3.0/r);
|
||||||
|
m_b[i+1] *= (3.0/r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modified==true) {
|
||||||
|
set_coeffs_from_b();
|
||||||
|
m_made_monotonic=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the closest idx so that m_x[idx] <= x (return 0 if x<m_x[0])
|
||||||
|
size_t spline::find_closest(double x) const
|
||||||
|
{
|
||||||
|
std::vector<double>::const_iterator it;
|
||||||
|
it=std::upper_bound(m_x.begin(),m_x.end(),x); // *it > x
|
||||||
|
size_t idx = std::max( int(it-m_x.begin())-1, 0); // m_x[idx] <= x
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
double spline::operator() (double x) const
|
||||||
|
{
|
||||||
|
// polynomial evaluation using Horner's scheme
|
||||||
|
// TODO: consider more numerically accurate algorithms, e.g.:
|
||||||
|
// - Clenshaw
|
||||||
|
// - Even-Odd method by A.C.R. Newbery
|
||||||
|
// - Compensated Horner Scheme
|
||||||
|
size_t n=m_x.size();
|
||||||
|
size_t idx=find_closest(x);
|
||||||
|
|
||||||
|
double h=x-m_x[idx];
|
||||||
|
double interpol;
|
||||||
|
if(x<m_x[0]) {
|
||||||
|
// extrapolation to the left
|
||||||
|
interpol=(m_c0*h + m_b[0])*h + m_y[0];
|
||||||
|
} else if(x>m_x[n-1]) {
|
||||||
|
// extrapolation to the right
|
||||||
|
interpol=(m_c[n-1]*h + m_b[n-1])*h + m_y[n-1];
|
||||||
|
} else {
|
||||||
|
// interpolation
|
||||||
|
interpol=((m_d[idx]*h + m_c[idx])*h + m_b[idx])*h + m_y[idx];
|
||||||
|
}
|
||||||
|
return interpol;
|
||||||
|
}
|
||||||
|
|
||||||
|
double spline::deriv(int order, double x) const
|
||||||
|
{
|
||||||
|
assert(order>0);
|
||||||
|
size_t n=m_x.size();
|
||||||
|
size_t idx = find_closest(x);
|
||||||
|
|
||||||
|
double h=x-m_x[idx];
|
||||||
|
double interpol;
|
||||||
|
if(x<m_x[0]) {
|
||||||
|
// extrapolation to the left
|
||||||
|
switch(order) {
|
||||||
|
case 1:
|
||||||
|
interpol=2.0*m_c0*h + m_b[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
interpol=2.0*m_c0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interpol=0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(x>m_x[n-1]) {
|
||||||
|
// extrapolation to the right
|
||||||
|
switch(order) {
|
||||||
|
case 1:
|
||||||
|
interpol=2.0*m_c[n-1]*h + m_b[n-1];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
interpol=2.0*m_c[n-1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interpol=0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// interpolation
|
||||||
|
switch(order) {
|
||||||
|
case 1:
|
||||||
|
interpol=(3.0*m_d[idx]*h + 2.0*m_c[idx])*h + m_b[idx];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
interpol=6.0*m_d[idx]*h + 2.0*m_c[idx];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
interpol=6.0*m_d[idx];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
interpol=0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return interpol;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> spline::solve(double y, bool ignore_extrapolation) const
|
||||||
|
{
|
||||||
|
std::vector<double> x; // roots for the entire spline
|
||||||
|
std::vector<double> root; // roots for each piecewise cubic
|
||||||
|
const size_t n=m_x.size();
|
||||||
|
|
||||||
|
// left extrapolation
|
||||||
|
if(ignore_extrapolation==false) {
|
||||||
|
root = internal::solve_cubic(m_y[0]-y,m_b[0],m_c0,0.0,1);
|
||||||
|
for(size_t j=0; j<root.size(); j++) {
|
||||||
|
if(root[j]<0.0) {
|
||||||
|
x.push_back(m_x[0]+root[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force check if piecewise cubic has roots in their resp. segment
|
||||||
|
// TODO: make more efficient
|
||||||
|
for(size_t i=0; i<n-1; i++) {
|
||||||
|
root = internal::solve_cubic(m_y[i]-y,m_b[i],m_c[i],m_d[i],1);
|
||||||
|
for(size_t j=0; j<root.size(); j++) {
|
||||||
|
double h = (i>0) ? (m_x[i]-m_x[i-1]) : 0.0;
|
||||||
|
double eps = internal::get_eps()*512.0*std::min(h,1.0);
|
||||||
|
if( (-eps<=root[j]) && (root[j]<m_x[i+1]-m_x[i]) ) {
|
||||||
|
double new_root = m_x[i]+root[j];
|
||||||
|
if(x.size()>0 && x.back()+eps > new_root) {
|
||||||
|
x.back()=new_root; // avoid spurious duplicate roots
|
||||||
|
} else {
|
||||||
|
x.push_back(new_root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// right extrapolation
|
||||||
|
if(ignore_extrapolation==false) {
|
||||||
|
root = internal::solve_cubic(m_y[n-1]-y,m_b[n-1],m_c[n-1],0.0,1);
|
||||||
|
for(size_t j=0; j<root.size(); j++) {
|
||||||
|
if(0.0<=root[j]) {
|
||||||
|
x.push_back(m_x[n-1]+root[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_SSTREAM
|
||||||
|
std::string spline::info() const
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "type " << m_type << ", left boundary deriv " << m_left << " = ";
|
||||||
|
ss << m_left_value << ", right boundary deriv " << m_right << " = ";
|
||||||
|
ss << m_right_value << std::endl;
|
||||||
|
if(m_made_monotonic) {
|
||||||
|
ss << "(spline has been adjusted for piece-wise monotonicity)";
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
#endif // HAVE_SSTREAM
|
||||||
|
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
|
||||||
|
// band_matrix implementation
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
band_matrix::band_matrix(int dim, int n_u, int n_l)
|
||||||
|
{
|
||||||
|
resize(dim, n_u, n_l);
|
||||||
|
}
|
||||||
|
void band_matrix::resize(int dim, int n_u, int n_l)
|
||||||
|
{
|
||||||
|
assert(dim>0);
|
||||||
|
assert(n_u>=0);
|
||||||
|
assert(n_l>=0);
|
||||||
|
m_upper.resize(n_u+1);
|
||||||
|
m_lower.resize(n_l+1);
|
||||||
|
for(size_t i=0; i<m_upper.size(); i++) {
|
||||||
|
m_upper[i].resize(dim);
|
||||||
|
}
|
||||||
|
for(size_t i=0; i<m_lower.size(); i++) {
|
||||||
|
m_lower[i].resize(dim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int band_matrix::dim() const
|
||||||
|
{
|
||||||
|
if(m_upper.size()>0) {
|
||||||
|
return (int)m_upper[0].size();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// defines the new operator (), so that we can access the elements
|
||||||
|
// by A(i,j), index going from i=0,...,dim()-1
|
||||||
|
double & band_matrix::operator () (int i, int j)
|
||||||
|
{
|
||||||
|
int k=j-i; // what band is the entry
|
||||||
|
assert( (i>=0) && (i<dim()) && (j>=0) && (j<dim()) );
|
||||||
|
assert( (-num_lower()<=k) && (k<=num_upper()) );
|
||||||
|
// k=0 -> diagonal, k<0 lower left part, k>0 upper right part
|
||||||
|
if(k>=0) return m_upper[k][i];
|
||||||
|
else return m_lower[-k][i];
|
||||||
|
}
|
||||||
|
double band_matrix::operator () (int i, int j) const
|
||||||
|
{
|
||||||
|
int k=j-i; // what band is the entry
|
||||||
|
assert( (i>=0) && (i<dim()) && (j>=0) && (j<dim()) );
|
||||||
|
assert( (-num_lower()<=k) && (k<=num_upper()) );
|
||||||
|
// k=0 -> diagonal, k<0 lower left part, k>0 upper right part
|
||||||
|
if(k>=0) return m_upper[k][i];
|
||||||
|
else return m_lower[-k][i];
|
||||||
|
}
|
||||||
|
// second diag (used in LU decomposition), saved in m_lower
|
||||||
|
double band_matrix::saved_diag(int i) const
|
||||||
|
{
|
||||||
|
assert( (i>=0) && (i<dim()) );
|
||||||
|
return m_lower[0][i];
|
||||||
|
}
|
||||||
|
double & band_matrix::saved_diag(int i)
|
||||||
|
{
|
||||||
|
assert( (i>=0) && (i<dim()) );
|
||||||
|
return m_lower[0][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// LR-Decomposition of a band matrix
|
||||||
|
void band_matrix::lu_decompose()
|
||||||
|
{
|
||||||
|
int i_max,j_max;
|
||||||
|
int j_min;
|
||||||
|
double x;
|
||||||
|
|
||||||
|
// preconditioning
|
||||||
|
// normalize column i so that a_ii=1
|
||||||
|
for(int i=0; i<this->dim(); i++) {
|
||||||
|
assert(this->operator()(i,i)!=0.0);
|
||||||
|
this->saved_diag(i)=1.0/this->operator()(i,i);
|
||||||
|
j_min=std::max(0,i-this->num_lower());
|
||||||
|
j_max=std::min(this->dim()-1,i+this->num_upper());
|
||||||
|
for(int j=j_min; j<=j_max; j++) {
|
||||||
|
this->operator()(i,j) *= this->saved_diag(i);
|
||||||
|
}
|
||||||
|
this->operator()(i,i)=1.0; // prevents rounding errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauss LR-Decomposition
|
||||||
|
for(int k=0; k<this->dim(); k++) {
|
||||||
|
i_max=std::min(this->dim()-1,k+this->num_lower()); // num_lower not a mistake!
|
||||||
|
for(int i=k+1; i<=i_max; i++) {
|
||||||
|
assert(this->operator()(k,k)!=0.0);
|
||||||
|
x=-this->operator()(i,k)/this->operator()(k,k);
|
||||||
|
this->operator()(i,k)=-x; // assembly part of L
|
||||||
|
j_max=std::min(this->dim()-1,k+this->num_upper());
|
||||||
|
for(int j=k+1; j<=j_max; j++) {
|
||||||
|
// assembly part of R
|
||||||
|
this->operator()(i,j)=this->operator()(i,j)+x*this->operator()(k,j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// solves Ly=b
|
||||||
|
std::vector<double> band_matrix::l_solve(const std::vector<double>& b) const
|
||||||
|
{
|
||||||
|
assert( this->dim()==(int)b.size() );
|
||||||
|
std::vector<double> x(this->dim());
|
||||||
|
int j_start;
|
||||||
|
double sum;
|
||||||
|
for(int i=0; i<this->dim(); i++) {
|
||||||
|
sum=0;
|
||||||
|
j_start=std::max(0,i-this->num_lower());
|
||||||
|
for(int j=j_start; j<i; j++) sum += this->operator()(i,j)*x[j];
|
||||||
|
x[i]=(b[i]*this->saved_diag(i)) - sum;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
// solves Rx=y
|
||||||
|
std::vector<double> band_matrix::r_solve(const std::vector<double>& b) const
|
||||||
|
{
|
||||||
|
assert( this->dim()==(int)b.size() );
|
||||||
|
std::vector<double> x(this->dim());
|
||||||
|
int j_stop;
|
||||||
|
double sum;
|
||||||
|
for(int i=this->dim()-1; i>=0; i--) {
|
||||||
|
sum=0;
|
||||||
|
j_stop=std::min(this->dim()-1,i+this->num_upper());
|
||||||
|
for(int j=i+1; j<=j_stop; j++) sum += this->operator()(i,j)*x[j];
|
||||||
|
x[i]=( b[i] - sum ) / this->operator()(i,i);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> band_matrix::lu_solve(const std::vector<double>& b,
|
||||||
|
bool is_lu_decomposed)
|
||||||
|
{
|
||||||
|
assert( this->dim()==(int)b.size() );
|
||||||
|
std::vector<double> x,y;
|
||||||
|
if(is_lu_decomposed==false) {
|
||||||
|
this->lu_decompose();
|
||||||
|
}
|
||||||
|
y=this->l_solve(b);
|
||||||
|
x=this->r_solve(y);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// machine precision of a double, i.e. the successor of 1 is 1+eps
|
||||||
|
double get_eps()
|
||||||
|
{
|
||||||
|
//return std::numeric_limits<double>::epsilon(); // __DBL_EPSILON__
|
||||||
|
return 2.2204460492503131e-16; // 2^-52
|
||||||
|
}
|
||||||
|
|
||||||
|
// solutions for a + b*x = 0
|
||||||
|
std::vector<double> solve_linear(double a, double b)
|
||||||
|
{
|
||||||
|
std::vector<double> x; // roots
|
||||||
|
if(b==0.0) {
|
||||||
|
if(a==0.0) {
|
||||||
|
// 0*x = 0
|
||||||
|
x.resize(1);
|
||||||
|
x[0] = 0.0; // any x solves it but we need to pick one
|
||||||
|
return x;
|
||||||
|
} else {
|
||||||
|
// 0*x + ... = 0, no solution
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x.resize(1);
|
||||||
|
x[0] = -a/b;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// solutions for a + b*x + c*x^2 = 0
|
||||||
|
std::vector<double> solve_quadratic(double a, double b, double c,
|
||||||
|
int newton_iter=0)
|
||||||
|
{
|
||||||
|
if(c==0.0) {
|
||||||
|
return solve_linear(a,b);
|
||||||
|
}
|
||||||
|
// rescale so that we solve x^2 + 2p x + q = (x+p)^2 + q - p^2 = 0
|
||||||
|
double p=0.5*b/c;
|
||||||
|
double q=a/c;
|
||||||
|
double discr = p*p-q;
|
||||||
|
const double eps=0.5*internal::get_eps();
|
||||||
|
double discr_err = (6.0*(p*p)+3.0*fabs(q)+fabs(discr))*eps;
|
||||||
|
|
||||||
|
std::vector<double> x; // roots
|
||||||
|
if(fabs(discr)<=discr_err) {
|
||||||
|
// discriminant is zero --> one root
|
||||||
|
x.resize(1);
|
||||||
|
x[0] = -p;
|
||||||
|
} else if(discr<0) {
|
||||||
|
// no root
|
||||||
|
} else {
|
||||||
|
// two roots
|
||||||
|
x.resize(2);
|
||||||
|
x[0] = -p - sqrt(discr);
|
||||||
|
x[1] = -p + sqrt(discr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// improve solution via newton steps
|
||||||
|
for(size_t i=0; i<x.size(); i++) {
|
||||||
|
for(int k=0; k<newton_iter; k++) {
|
||||||
|
double f = (c*x[i] + b)*x[i] + a;
|
||||||
|
double f1 = 2.0*c*x[i] + b;
|
||||||
|
// only adjust if slope is large enough
|
||||||
|
if(fabs(f1)>1e-8) {
|
||||||
|
x[i] -= f/f1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// solutions for the cubic equation: a + b*x +c*x^2 + d*x^3 = 0
|
||||||
|
// this is a naive implementation of the analytic solution without
|
||||||
|
// optimisation for speed or numerical accuracy
|
||||||
|
// newton_iter: number of newton iterations to improve analytical solution
|
||||||
|
// see also
|
||||||
|
// gsl: gsl_poly_solve_cubic() in solve_cubic.c
|
||||||
|
// octave: roots.m - via eigenvalues of the Frobenius companion matrix
|
||||||
|
std::vector<double> solve_cubic(double a, double b, double c, double d,
|
||||||
|
int newton_iter)
|
||||||
|
{
|
||||||
|
if(d==0.0) {
|
||||||
|
return solve_quadratic(a,b,c,newton_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to normalised form: a + bx + cx^2 + x^3 = 0
|
||||||
|
if(d!=1.0) {
|
||||||
|
a/=d;
|
||||||
|
b/=d;
|
||||||
|
c/=d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to depressed cubic: z^3 - 3pz - 2q = 0
|
||||||
|
// via substitution: z = x + c/3
|
||||||
|
std::vector<double> z; // roots of the depressed cubic
|
||||||
|
double p = -(1.0/3.0)*b + (1.0/9.0)*(c*c);
|
||||||
|
double r = 2.0*(c*c)-9.0*b;
|
||||||
|
double q = -0.5*a - (1.0/54.0)*(c*r);
|
||||||
|
double discr=p*p*p-q*q; // discriminant
|
||||||
|
// calculating numerical round-off errors with assumptions:
|
||||||
|
// - each operation is precise but each intermediate result x
|
||||||
|
// when stored has max error of x*eps
|
||||||
|
// - only multiplication with a power of 2 introduces no new error
|
||||||
|
// - a,b,c,d and some fractions (e.g. 1/3) have rounding errors eps
|
||||||
|
// - p_err << |p|, q_err << |q|, ... (this is violated in rare cases)
|
||||||
|
// would be more elegant to use boost::numeric::interval<double>
|
||||||
|
const double eps = internal::get_eps();
|
||||||
|
double p_err = eps*((3.0/3.0)*fabs(b)+(4.0/9.0)*(c*c)+fabs(p));
|
||||||
|
double r_err = eps*(6.0*(c*c)+18.0*fabs(b)+fabs(r));
|
||||||
|
double q_err = 0.5*fabs(a)*eps + (1.0/54.0)*fabs(c)*(r_err+fabs(r)*3.0*eps)
|
||||||
|
+ fabs(q)*eps;
|
||||||
|
double discr_err = (p*p) * (3.0*p_err + fabs(p)*2.0*eps)
|
||||||
|
+ fabs(q) * (2.0*q_err + fabs(q)*eps) + fabs(discr)*eps;
|
||||||
|
|
||||||
|
// depending on the discriminant we get different solutions
|
||||||
|
if(fabs(discr)<=discr_err) {
|
||||||
|
// discriminant zero: one or two real roots
|
||||||
|
if(fabs(p)<=p_err) {
|
||||||
|
// p and q are zero: single root
|
||||||
|
z.resize(1);
|
||||||
|
z[0] = 0.0; // triple root
|
||||||
|
} else {
|
||||||
|
z.resize(2);
|
||||||
|
z[0] = 2.0*q/p; // single root
|
||||||
|
z[1] = -0.5*z[0]; // double root
|
||||||
|
}
|
||||||
|
} else if(discr>0) {
|
||||||
|
// three real roots: via trigonometric solution
|
||||||
|
z.resize(3);
|
||||||
|
double ac = (1.0/3.0) * acos( q/(p*sqrt(p)) );
|
||||||
|
double sq = 2.0*sqrt(p);
|
||||||
|
z[0] = sq * cos(ac);
|
||||||
|
z[1] = sq * cos(ac-2.0*M_PI/3.0);
|
||||||
|
z[2] = sq * cos(ac-4.0*M_PI/3.0);
|
||||||
|
} else if (discr<0.0) {
|
||||||
|
// single real root: via Cardano's fromula
|
||||||
|
z.resize(1);
|
||||||
|
double sgnq = (q >= 0 ? 1 : -1);
|
||||||
|
double basis = fabs(q) + sqrt(-discr);
|
||||||
|
double C = sgnq * pow(basis, 1.0/3.0); // c++11 has std::cbrt()
|
||||||
|
z[0] = C + p/C;
|
||||||
|
}
|
||||||
|
for(size_t i=0; i<z.size(); i++) {
|
||||||
|
// convert depressed cubic roots to original cubic: x = z - c/3
|
||||||
|
z[i] -= (1.0/3.0)*c;
|
||||||
|
// improve solution via newton steps
|
||||||
|
for(int k=0; k<newton_iter; k++) {
|
||||||
|
double f = ((z[i] + c)*z[i] + b)*z[i] + a;
|
||||||
|
double f1 = (3.0*z[i] + 2.0*c)*z[i] + b;
|
||||||
|
// only adjust if slope is large enough
|
||||||
|
if(fabs(f1)>1e-8) {
|
||||||
|
z[i] -= f/f1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ensure if a=0 we get exactly x=0 as root
|
||||||
|
// TODO: remove this fudge
|
||||||
|
if(a==0.0) {
|
||||||
|
assert(z.size()>0); // cubic should always have at least one root
|
||||||
|
double xmin=fabs(z[0]);
|
||||||
|
size_t imin=0;
|
||||||
|
for(size_t i=1; i<z.size(); i++) {
|
||||||
|
if(xmin>fabs(z[i])) {
|
||||||
|
xmin=fabs(z[i]);
|
||||||
|
imin=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
z[imin]=0.0; // replace the smallest absolute value with 0
|
||||||
|
}
|
||||||
|
std::sort(z.begin(), z.end());
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace tk
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TK_SPLINE_H */
|
Loading…
Add table
Add a link
Reference in a new issue