diff --git a/BuildLinux.sh b/BuildLinux.sh
index 44ed284427..382bdac733 100755
--- a/BuildLinux.sh
+++ b/BuildLinux.sh
@@ -49,7 +49,7 @@ while getopts ":1j:bcdghirsu" opt; do
export CMAKE_BUILD_PARALLEL_LEVEL=1
;;
j )
- CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
+ export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
;;
b )
BUILD_DEBUG="1"
diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot
index 156df7eca1..8f665dc04b 100644
--- a/localization/i18n/OrcaSlicer.pot
+++ b/localization/i18n/OrcaSlicer.pot
@@ -3453,8 +3453,8 @@ msgstr ""
#, possible-c-format, possible-boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
msgid ""
diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po
index 396f3eb28d..e288bd7d56 100644
--- a/localization/i18n/ca/OrcaSlicer_ca.po
+++ b/localization/i18n/ca/OrcaSlicer_ca.po
@@ -3691,11 +3691,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"La temperatura recomanada del broquet d'aquest tipus de filament és de [%d, "
-"%d] graus centígrads"
+"%d] graus Celsius."
msgid ""
"Too small max volumetric speed.\n"
diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po
index 8e0332584f..8f863368b0 100644
--- a/localization/i18n/cs/OrcaSlicer_cs.po
+++ b/localization/i18n/cs/OrcaSlicer_cs.po
@@ -3618,8 +3618,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Doporučená teplota trysky pro tento typ filamentu je [%d, %d]stupňů Celsia"
@@ -18139,7 +18139,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "Teplota podložky ostatních vrstev je nižší než teplota podložky první "
diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po
index 8b882ca4cb..18d314bec4 100644
--- a/localization/i18n/de/OrcaSlicer_de.po
+++ b/localization/i18n/de/OrcaSlicer_de.po
@@ -3732,10 +3732,10 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
-"Die empfohlene Düsentemperatur für diesen Filamenttyp beträgt [%d, %d] °C"
+"Die empfohlene Düsentemperatur für diesen Filamenttyp beträgt [%d, %d] °C."
msgid ""
"Too small max volumetric speed.\n"
@@ -20600,7 +20600,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "Die Betttemperatur der anderen Schicht ist um mehr als %d Grad Celsius "
diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po
index f95c11adee..6c3aa395e2 100644
--- a/localization/i18n/en/OrcaSlicer_en.po
+++ b/localization/i18n/en/OrcaSlicer_en.po
@@ -3585,11 +3585,9 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
-msgstr ""
"The recommended nozzle temperature for this filament type is [%d, %d] "
-"degrees centigrade"
+"degrees Celsius."
+msgstr ""
msgid ""
"Too small max volumetric speed.\n"
@@ -17677,11 +17675,11 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "The bed temperature of other layers is lower than the bed temperature of "
-#~ "the first layer by more than %d degrees centigrade.\n"
+#~ "the first layer by more than %d degrees Celsius.\n"
#~ "This may cause models to break free from the build plate during printing."
#~ msgid ""
diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po
index 7f33b41404..3c10b1fef7 100644
--- a/localization/i18n/es/OrcaSlicer_es.po
+++ b/localization/i18n/es/OrcaSlicer_es.po
@@ -3722,11 +3722,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"La temperatura recomendada de la boquilla para este tipo de filamento es de "
-"[%d, %d] grados centígrados"
+"[%d, %d] grados Celsius."
msgid ""
"Too small max volumetric speed.\n"
@@ -20194,7 +20194,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "La temperatura del lecho de la otra capa es inferior a la temperatura del "
diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po
index 021efd24b4..d4c1da224e 100644
--- a/localization/i18n/fr/OrcaSlicer_fr.po
+++ b/localization/i18n/fr/OrcaSlicer_fr.po
@@ -15,7 +15,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n==0 || n==1) ? 0 : 1;\n"
-"X-Generator: Poedit 3.5\n"
+"X-Generator: Poedit 3.6\n"
msgid "Supports Painting"
msgstr "Peindre les supports"
@@ -3731,11 +3731,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"La température de buse recommandée pour ce type de filament est de [%d, %d] "
-"degrés centigrades"
+"degrés Celsius."
msgid ""
"Too small max volumetric speed.\n"
@@ -3823,10 +3823,10 @@ msgid ""
"YES - Keep Prime Tower\n"
"NO - Keep Adaptive Layer Height and Independent Support Layer Height"
msgstr ""
-"La tour de purge ne fonctionne pas lorsque la hauteur de couche adaptative "
+"La tour d’amorçage ne fonctionne pas lorsque la hauteur de couche adaptative "
"ou la hauteur de couche de support indépendante est activée. \n"
"Que souhaitez-vous conserver ? \n"
-"OUI - Conserver la tour de purge \n"
+"OUI - Conserver la tour d’amorçage \n"
"NON - Conserver la hauteur de la couche adaptative et la hauteur de la "
"couche de support indépendante"
@@ -3836,10 +3836,10 @@ msgid ""
"YES - Keep Prime Tower\n"
"NO - Keep Adaptive Layer Height"
msgstr ""
-"La tour de purge ne fonctionne pas lorsque la hauteur de couche adaptative "
+"La tour d’amorçage ne fonctionne pas lorsque la hauteur de couche adaptative "
"est activée. \n"
"Que souhaitez-vous conserver ? \n"
-"OUI - Conserver la tour de purge \n"
+"OUI - Conserver la tour d’amorçage \n"
"NON - Conserver la hauteur de la couche adaptative"
msgid ""
@@ -3848,7 +3848,7 @@ msgid ""
"YES - Keep Prime Tower\n"
"NO - Keep Independent Support Layer Height"
msgstr ""
-"La tour de purge ne fonctionne pas lorsque la hauteur de la couche de "
+"La tour d’amorçage ne fonctionne pas lorsque la hauteur de la couche de "
"support indépendante est activée.\n"
"Que souhaitez-vous conserver ?\n"
"OUI - Garder la tour de purge\n"
@@ -4943,7 +4943,7 @@ msgid ""
"top/bottom/side views"
msgstr ""
"Passage automatique de la vue en plan à la vue en perspective lorsque l’on "
-"passe d’une vue de haut en bas ou de côté à une vue orthographique."
+"passe d’une vue de haut en bas ou de côté à une vue orthographique"
msgid "Show &G-code Window"
msgstr "Afficher la fenêtre du &G-code"
@@ -5892,8 +5892,8 @@ msgstr[1] "%1$d L'objets sont mis en couleur."
#, c-format, boost-format
msgid "%1$d object was loaded as a part of cut object."
msgid_plural "%1$d objects were loaded as parts of cut object"
-msgstr[0] "%1$d objet a été chargé en tant que partie de l’objet coupé"
-msgstr[1] "%1$d objets ont été chargés en tant que partie de l’objet coupé"
+msgstr[0] "%1$d objet a été chargé en tant que partie de l’objet coupé."
+msgstr[1] "%1$d objets ont été chargés en tant que partie de l’objet coupé."
msgid "ERROR"
msgstr "ERREUR"
@@ -6775,7 +6775,7 @@ msgstr ""
"La plaque% d : %s n'est pas suggéré pour l'utilisation du filament "
"d'impression %s(%s). Si vous souhaitez toujours effectuer ce travail "
"d'impression, veuillez régler la température du plateau de ce filament sur "
-"un nombre différent de zéro"
+"un nombre différent de zéro."
msgid "Switching the language requires application restart.\n"
msgstr "Le changement de langue nécessite le redémarrage de l'application.\n"
@@ -7864,16 +7864,16 @@ msgid ""
"Prime tower is required for smooth timelapse. There may be flaws on the "
"model without prime tower. Are you sure you want to disable prime tower?"
msgstr ""
-"Une tour de purge est requise pour le mode Timeplase fluide. Il peut y avoir "
-"des défauts sur le modèle sans tour de purge. Êtes-vous sûr de vouloir la "
-"désactiver ?"
+"Une tour d’amorçage est requise pour le mode Timeplase fluide. Il peut y "
+"avoir des défauts sur le modèle sans tour de purge. Êtes-vous sûr de vouloir "
+"la désactiver ?"
msgid ""
"Prime tower is required for smooth timelapse. There may be flaws on the "
"model without prime tower. Do you want to enable prime tower?"
msgstr ""
-"Une tour de purge est requise pour un mode timelapse fluide. Il peut y avoir "
-"des défauts sur le modèle sans tour de purge. Voulez-vous activer la "
+"Une tour d’amorçage est requise pour un mode timelapse fluide. Il peut y "
+"avoir des défauts sur le modèle sans tour de purge. Voulez-vous activer la "
"désactiver?"
msgid "Still print by object?"
@@ -8124,7 +8124,7 @@ msgid "Multimaterial"
msgstr "Multi-matériaux"
msgid "Prime tower"
-msgstr "Tour de purge"
+msgstr "Tour d’amorçage"
msgid "Filament for Features"
msgstr "Filament pour les caractéristiques"
@@ -9724,7 +9724,7 @@ msgstr ""
"de l'impression."
msgid "Prime Tower"
-msgstr "Tour de purge"
+msgstr "Tour d’amorçage"
msgid " is too close to others, and collisions may be caused.\n"
msgstr ""
@@ -9827,57 +9827,57 @@ msgid ""
"The prime tower is currently only supported for the Marlin, RepRap/Sprinter, "
"RepRapFirmware and Repetier G-code flavors."
msgstr ""
-"La tour principale n’est actuellement prise en charge que pour les versions "
+"La tour d’amorçage n’est actuellement prise en charge que pour les versions "
"Marlin, RepRap/Sprinter, RepRapFirmware et Repetier G-code."
msgid "The prime tower is not supported in \"By object\" print."
msgstr ""
-"La tour de purge n'est pas prise en charge dans l'impression \"Par objet\"."
+"La tour d’amorçage n'est pas prise en charge dans l'impression \"Par objet\"."
msgid ""
"The prime tower is not supported when adaptive layer height is on. It "
"requires that all objects have the same layer height."
msgstr ""
-"La tour de purge n'est pas prise en charge lorsque la hauteur de couche "
+"La tour d’amorçage n'est pas prise en charge lorsque la hauteur de couche "
"adaptative est activée. Cela nécessite que tous les objets aient la même "
"hauteur de couche."
msgid "The prime tower requires \"support gap\" to be multiple of layer height"
msgstr ""
-"La tour de purge nécessite que \"l'écart de support\" soit un multiple de la "
-"hauteur de la couche"
+"La tour d’amorçage nécessite que \"l'écart de support\" soit un multiple de "
+"la hauteur de la couche"
msgid "The prime tower requires that all objects have the same layer heights"
msgstr ""
-"La tour de purge nécessite que tous les objets aient la même hauteur de "
+"La tour d’amorçage nécessite que tous les objets aient la même hauteur de "
"couche"
msgid ""
"The prime tower requires that all objects are printed over the same number "
"of raft layers"
msgstr ""
-"La tour de purge nécessite que tous les objets soient imprimés sur le même "
+"La tour d’amorçage nécessite que tous les objets soient imprimés sur le même "
"nombre de couche de radeau"
msgid ""
"The prime tower is only supported for multiple objects if they are printed "
"with the same support_top_z_distance"
msgstr ""
-"La tour de purge n’est prise en charge pour plusieurs objets que s’ils sont "
-"imprimés avec la même valeur de support_top_z_distance."
+"La tour d’amorçage n’est prise en charge pour plusieurs objets que s’ils "
+"sont imprimés avec la même valeur de support_top_z_distance."
msgid ""
"The prime tower requires that all objects are sliced with the same layer "
"heights."
msgstr ""
-"La tour de purge nécessite que tous les objets soient découpés avec la même "
-"hauteur de couche."
+"La tour d’amorçage nécessite que tous les objets soient découpés avec la "
+"même hauteur de couche."
msgid ""
"The prime tower is only supported if all objects have the same variable "
"layer height"
msgstr ""
-"La tour de purge n'est prise en charge que si tous les objets ont la même "
+"La tour d’amorçage n'est prise en charge que si tous les objets ont la même "
"hauteur de couche variable"
msgid ""
@@ -9906,8 +9906,8 @@ msgstr ""
msgid ""
"The prime tower requires that support has the same layer height with object."
msgstr ""
-"La tour de purge nécessite que le support ait la même hauteur de couche avec "
-"l'objet."
+"La tour d’amorçage nécessite que le support ait la même hauteur de couche "
+"avec l'objet."
msgid ""
"Organic support tree tip diameter must not be smaller than support material "
@@ -14546,7 +14546,7 @@ msgstr ""
"une vidéo timelapse une fois l'impression terminée. Si le mode lisse est "
"sélectionné, l'extrudeur se déplace vers la goulotte d'évacuation à chaque "
"couche imprimée, puis prend un cliché. Étant donné que le filament fondu "
-"peut s'échapper de la buse pendant la prise de vue, une tour de purge est "
+"peut s'échapper de la buse pendant la prise de vue, une tour d’amorçage est "
"requise en mode lisse pour essuyer la buse."
msgid "Traditional"
@@ -14623,10 +14623,10 @@ msgstr ""
"PAUSE pour déclencher l’action de changement manuel de filament."
msgid "Purge in prime tower"
-msgstr "Purge dans la tour de purge"
+msgstr "Purge dans la tour d’amorçage"
msgid "Purge remaining filament into prime tower"
-msgstr "Purger le filament restant dans la tour de purge"
+msgstr "Purger le filament restant dans la tour d’amorçage"
msgid "Enable filament ramming"
msgstr "Activer le pilonnage du filament"
@@ -14952,8 +14952,8 @@ msgid ""
msgstr ""
"La couche de support utilise la hauteur de la couche indépendamment de la "
"couche objet. Cela permet de personnaliser l’écart de Z et de gagner du "
-"temps d'impression. Cette option ne sera pas valide lorsque la tour de purge "
-"sera activée."
+"temps d'impression. Cette option ne sera pas valide lorsque la tour "
+"d’amorçage sera activée."
msgid "Threshold angle"
msgstr "Angle de seuil"
@@ -15305,13 +15305,13 @@ msgstr ""
"purge multiplié par les volumes de purge dans le tableau."
msgid "Prime volume"
-msgstr "Premier volume"
+msgstr "Volume d’amorçage"
msgid "The volume of material to prime extruder on tower."
msgstr "Le volume de matériau pour amorcer l'extrudeur sur la tour."
msgid "Width of prime tower"
-msgstr "Largeur de la tour de purge"
+msgstr "Largeur de la tour d’amorçage"
msgid "Wipe tower rotation angle"
msgstr "Angle de rotation de la tour d’essuyage"
@@ -15405,7 +15405,7 @@ msgstr ""
"matériaux de remplissage des objets. Cela peut réduire la quantité de "
"déchets et le temps d'impression. Si les parois sont imprimées avec un "
"filament transparent, le remplissage de couleurs mélangées sera visible. "
-"Cela ne prendra effet que si la tour de purge est activée."
+"Cela ne prendra effet que si la tour d’amorçage est activée."
msgid ""
"Purging after filament change will be done inside objects' support. This may "
@@ -15414,7 +15414,7 @@ msgid ""
msgstr ""
"La purge après le changement de filament se fera à l'intérieur du support "
"des objets. Cela peut réduire la quantité de déchets et le temps "
-"d'impression. Cela ne prendra effet que si une tour de purge est activée."
+"d'impression. Cela ne prendra effet que si une tour d’amorçage est activée."
msgid ""
"This object will be used to purge the nozzle after a filament change to save "
@@ -15424,7 +15424,7 @@ msgstr ""
"Cet objet sera utilisé pour purger la buse après un changement de filament "
"afin d'économiser du filament et de réduire le temps d'impression. Les "
"couleurs des objets seront mélangées en conséquence. Cela ne prendra effet "
-"que si la tour de purge est activée."
+"que si la tour d’amorçage est activée."
msgid "Maximal bridging distance"
msgstr "Distance de pont maximale"
@@ -20773,7 +20773,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "La température du plateau des autres couches est inférieure à la "
diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po
index d708309afa..35e7a365d2 100644
--- a/localization/i18n/hu/OrcaSlicer_hu.po
+++ b/localization/i18n/hu/OrcaSlicer_hu.po
@@ -3620,8 +3620,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Az ajánlott fúvóka hőmérséklet ehhez a filament típushoz [%d, %d] Celsius-fok"
@@ -17907,7 +17907,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "A többi réteg asztalhőmérséklete több mint %d Celsius-fokkal alacsonyabb, "
diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po
index 40a2fa9f64..0ae825c9ec 100644
--- a/localization/i18n/it/OrcaSlicer_it.po
+++ b/localization/i18n/it/OrcaSlicer_it.po
@@ -3725,11 +3725,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"La temperatura dell'ugello consigliata per questo filamento è [%d, %d] gradi "
-"centigradi"
+"Celsius."
msgid ""
"Too small max volumetric speed.\n"
@@ -20244,11 +20244,11 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "The bed temperature of other layers is lower than the bed temperature of "
-#~ "the first layer by more than %d degrees centigrade.\n"
+#~ "the first layer by more than %d degrees Celsius.\n"
#~ "This may cause models to break free from the build plate during printing."
#~ msgid ""
diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po
index 432d9ca490..3d68f5408a 100644
--- a/localization/i18n/ja/OrcaSlicer_ja.po
+++ b/localization/i18n/ja/OrcaSlicer_ja.po
@@ -3579,8 +3579,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr "このフィラメントで推奨ノズル温度は %d ~ %d ℃です。"
msgid ""
@@ -17653,7 +17653,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "ベッド温度が1層目温度より %d ℃以上低いです。造形中プレートより離脱する可能"
diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po
index b65062afc2..5e500534b5 100644
--- a/localization/i18n/ko/OrcaSlicer_ko.po
+++ b/localization/i18n/ko/OrcaSlicer_ko.po
@@ -3594,8 +3594,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr "이 필라멘트 유형의 권장 노즐 온도는 [%d, %d]°C입니다"
msgid ""
@@ -19244,7 +19244,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "다른 레이어의 베드 온도가 초기 레이어의 베드 온도보다 %d°C 이상 낮습니"
diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po
index 0e0f7d5215..f81ff9df85 100644
--- a/localization/i18n/nl/OrcaSlicer_nl.po
+++ b/localization/i18n/nl/OrcaSlicer_nl.po
@@ -3657,11 +3657,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"De aanbevolen mondstuk temperatuur voor dit type filament is [%d, %d] graden "
-"Celsius"
+"Celsius."
msgid ""
"Too small max volumetric speed.\n"
@@ -18231,10 +18231,10 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
-#~ "De printbed temperatuur voor de overige lagen is %d graden celcius lager "
+#~ "De printbed temperatuur voor de overige lagen is %d graden Celcius lager "
#~ "dan de temperatuur voor de eerste laag.\n"
#~ "Hierdoor kan de print loskomen van het printbed gedurende de printtaak"
diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po
index 7cc55d166a..3c472a6ccb 100644
--- a/localization/i18n/pl/OrcaSlicer_pl.po
+++ b/localization/i18n/pl/OrcaSlicer_pl.po
@@ -3688,8 +3688,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Zalecana temperatura dyszy dla tego typu filamentu wynosi [%d, %d] stopni "
"Celsjusza"
@@ -21391,7 +21391,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "Temperatura podłoża innych warstw jest niższa niż temperatura podłoża "
diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
index 3161d3f894..553cd39496 100644
--- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
+++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po
@@ -1785,7 +1785,7 @@ msgid "Delete the selected object"
msgstr "Apagar o objeto selecionado"
msgid "Load..."
-msgstr "Carregar..."
+msgstr "Carregar…"
msgid "Cube"
msgstr "Cubo"
@@ -2458,7 +2458,7 @@ msgid "No printer"
msgstr "Sem impressora"
msgid "..."
-msgstr "..."
+msgstr "…"
msgid "Failed to connect to the server"
msgstr "Falha ao conectar ao servidor"
@@ -2486,7 +2486,7 @@ msgid "Please check the network connection of the printer and Orca."
msgstr "Por favor, verifique a conexão de rede da impressora e do Orca."
msgid "Connecting..."
-msgstr "Conectando..."
+msgstr "Conectando…"
msgid "?"
msgstr "?"
@@ -2525,7 +2525,7 @@ msgid "Retry"
msgstr "Tentar Novamente"
msgid "Calibrating AMS..."
-msgstr "Calibrando AMS..."
+msgstr "Calibrando AMS…"
msgid "A problem occurred during calibration. Click to view the solution."
msgstr "Ocorreu um problema durante a calibração. Clique para ver a solução."
@@ -2537,7 +2537,7 @@ msgid "Cancel calibration"
msgstr "Cancelar calibração"
msgid "Idling..."
-msgstr "Em espera..."
+msgstr "Em espera…"
msgid "Heat the nozzle"
msgstr "Aquecer o bico"
@@ -2594,7 +2594,7 @@ msgstr ""
"Não é possível auto-arranjar nessa placa."
msgid "Arranging..."
-msgstr "Organizando..."
+msgstr "Organizando…"
msgid "Arranging"
msgstr "Organizando"
@@ -2642,7 +2642,7 @@ msgstr ""
"Não é possível auto-orientar nessa placa."
msgid "Orienting..."
-msgstr "Orientando..."
+msgstr "Orientando…"
msgid "Orienting"
msgstr "Orientando"
@@ -3260,7 +3260,7 @@ msgid "Please save project and restart the program."
msgstr "Por favor, salve o projeto e reinicie o programa."
msgid "Processing G-Code from Previous file..."
-msgstr "Processando G-code do arquivo anterior..."
+msgstr "Processando G-code do arquivo anterior…"
msgid "Slicing complete"
msgstr "Fatiamento concluído"
@@ -3498,7 +3498,7 @@ msgid "No historical tasks!"
msgstr "Nenhuma tarefa no histórico!"
msgid "Loading..."
-msgstr "Carregando..."
+msgstr "Carregando…"
msgid "No AMS"
msgstr "Nenhum AMS"
@@ -3614,7 +3614,7 @@ msgid "Circular"
msgstr "Circular"
msgid "Load shape from STL..."
-msgstr "Carregar forma de STL..."
+msgstr "Carregar forma de STL…"
msgid "Settings"
msgstr "Configurações"
@@ -3686,11 +3686,11 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"A temperatura do bico recomendada para este tipo de filamento é [%d, %d] "
-"graus centígrados"
+"graus Celsius."
msgid ""
"Too small max volumetric speed.\n"
@@ -4991,7 +4991,7 @@ msgid "VFA"
msgstr "VFA"
msgid "More..."
-msgstr "Mais..."
+msgstr "Mais…"
msgid "Tutorial"
msgstr "Tutorial"
@@ -5169,7 +5169,7 @@ msgid "Please enter the IP of printer to connect."
msgstr "Por favor, digite o IP da impressora para conectar."
msgid "Initializing..."
-msgstr "Inicializando..."
+msgstr "Inicializando…"
msgid "Connection Failed. Please check the network and try again"
msgstr "Falha na conexão. Por favor, verifique a rede e tente novamente"
@@ -5220,7 +5220,7 @@ msgid "Information"
msgstr "Informação"
msgid "Playing..."
-msgstr "Reproduzindo..."
+msgstr "Reproduzindo…"
msgid "Year"
msgstr "Ano"
@@ -5277,7 +5277,7 @@ msgid "No printers."
msgstr "Nenhuma impressora."
msgid "Loading file list..."
-msgstr "Carregando lista de arquivos..."
+msgstr "Carregando lista de arquivos…"
msgid "No files"
msgstr "Sem arquivos"
@@ -5327,7 +5327,7 @@ msgid "Delete file"
msgstr "Excluir arquivo"
msgid "Fetching model information..."
-msgstr "Obtendo informações do modelo ..."
+msgstr "Obtendo informações do modelo…"
msgid "Failed to fetch model information from printer."
msgstr "Falha ao obter informação do modelo da impressora."
@@ -5355,7 +5355,7 @@ msgstr ""
"Título: %s\n"
msgid "Download waiting..."
-msgstr "Aguardando download..."
+msgstr "Aguardando download…"
msgid "Play"
msgstr "Reproduzir"
@@ -5368,7 +5368,7 @@ msgstr "Download concluído"
#, c-format, boost-format
msgid "Downloading %d%%..."
-msgstr "Baixando %d%%..."
+msgstr "Baixando %d%%…"
msgid ""
"Reconnecting the printer, the operation cannot be completed immediately, "
@@ -5515,10 +5515,10 @@ msgid "Are you sure you want to cancel this print?"
msgstr "Tem certeza de que deseja cancelar esta impressão?"
msgid "Downloading..."
-msgstr "Baixando..."
+msgstr "Baixando…"
msgid "Cloud Slicing..."
-msgstr "Fatiando na Nuvem..."
+msgstr "Fatiando na Nuvem…"
#, c-format, boost-format
msgid "In Cloud Slicing Queue, there are %s tasks ahead."
@@ -6438,13 +6438,13 @@ msgid "Importing Model"
msgstr "Importando Modelo"
msgid "prepare 3mf file..."
-msgstr "preparar o arquivo 3mf..."
+msgstr "preparar o arquivo 3mf…"
msgid "Download failed, unknown file format."
msgstr "Baixar falhou, formato de arquivo desconhecido."
msgid "downloading project ..."
-msgstr "baixando projeto..."
+msgstr "baixando projeto…"
msgid "Download failed, File size exception."
msgstr "Baixar falhou, erro no tamanho do arquivo."
@@ -7641,7 +7641,7 @@ msgid "Pin Code"
msgstr "Código PIN"
msgid "Binding..."
-msgstr "Vinculando..."
+msgstr "Vinculando…"
msgid "Please confirm on the printer screen"
msgstr "Confirme na tela da impressora"
@@ -9220,7 +9220,7 @@ msgid "Manual Setup"
msgstr "Configuração Manual"
msgid "connecting..."
-msgstr "conectando..."
+msgstr "conectando…"
msgid "Failed to connect to printer."
msgstr "Falha ao conectar à impressora."
@@ -16329,7 +16329,7 @@ msgstr ""
"Você ainda quer continuar com a calibração?"
msgid "Connecting to printer..."
-msgstr "Conectando à impressora..."
+msgstr "Conectando à impressora…"
msgid "The failed test result has been dropped."
msgstr "O resultado do teste falhado foi descartado."
@@ -16531,7 +16531,7 @@ msgstr ""
"imprime com:"
msgid "material with significant thermal shrinkage/expansion, such as..."
-msgstr "material com significativa contração/expansão térmica, como..."
+msgstr "material com significativa contração/expansão térmica, como…"
msgid "materials with inaccurate filament diameter"
msgstr "materiais com diâmetro de filamento impreciso"
diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po
index 40332ef2d5..dd0ba230ec 100644
--- a/localization/i18n/ru/OrcaSlicer_ru.po
+++ b/localization/i18n/ru/OrcaSlicer_ru.po
@@ -3726,8 +3726,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Рекомендуемая температура сопла для данного типа пластиковой нити составляет "
"[%d, %d] градусов Цельсия."
diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po
index 24db2da22a..4f75526535 100644
--- a/localization/i18n/sv/OrcaSlicer_sv.po
+++ b/localization/i18n/sv/OrcaSlicer_sv.po
@@ -3594,8 +3594,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Rekommenderad nozzel temperatur med denna filament typ är [%d, %d] grader "
"celius"
@@ -17712,7 +17712,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "Byggplattans temperatur för andra lager är mindre än temperaturen för "
diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po
index 39cd77fadf..7b66619601 100644
--- a/localization/i18n/tr/OrcaSlicer_tr.po
+++ b/localization/i18n/tr/OrcaSlicer_tr.po
@@ -3647,10 +3647,10 @@ msgstr ""
"Lütfen yazdırmak için sıcaklığı kullanıp kullanmayacağınızdan emin olun.\n"
"\n"
-#, c-format, boost-format
+#, fuzzy, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Bu filament tipinin tavsiye edilen Nozul sıcaklığı [%d, %d] derece "
"santigrattır"
diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po
index 5eb7391a94..7c175c9bf0 100644
--- a/localization/i18n/uk/OrcaSlicer_uk.po
+++ b/localization/i18n/uk/OrcaSlicer_uk.po
@@ -3687,8 +3687,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr ""
"Рекомендована температура сопла для цього типу нитки становить [%d, %d] "
"градусів Цельсія"
diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
index c982049ace..33a003a574 100644
--- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
+++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po
@@ -3523,8 +3523,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr "该耗材的推荐喷嘴温度是[%d, %d]摄氏度"
msgid ""
@@ -17804,7 +17804,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
-#~ "layer for more than %d degree centigrade.\n"
+#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "其它层的热床温度比首层热床温度低太多,超过了%d 摄氏度。\n"
diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
index 78b1821eca..f2a5a5d2ce 100644
--- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
+++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po
@@ -3527,8 +3527,8 @@ msgstr ""
#, c-format, boost-format
msgid ""
-"Recommended nozzle temperature of this filament type is [%d, %d] degree "
-"centigrade"
+"The recommended nozzle temperature for this filament type is [%d, %d] "
+"degrees Celsius."
msgstr "該線材的推薦噴嘴溫度是攝氏 [%d, %d] 度"
msgid ""
diff --git a/resources/images/toolbar_reset_zero.svg b/resources/images/toolbar_reset_zero.svg
new file mode 100644
index 0000000000..35c7469ab6
--- /dev/null
+++ b/resources/images/toolbar_reset_zero.svg
@@ -0,0 +1,5 @@
+
diff --git a/resources/images/toolbar_reset_zero_hover.svg b/resources/images/toolbar_reset_zero_hover.svg
new file mode 100644
index 0000000000..b2b03a214f
--- /dev/null
+++ b/resources/images/toolbar_reset_zero_hover.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index db803305fe..179c21248e 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -5384,7 +5384,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
ref_speed = EXTRUDER_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm;
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
- ref_speed = std::min(ref_speed, EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm);
+ ref_speed = std::min(ref_speed, EXTRUDER_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm);
}
if (sloped) {
ref_speed = std::min(ref_speed, m_config.scarf_joint_speed.get_abs_value(ref_speed));
diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp
index dd0065247d..62a01db11e 100644
--- a/src/libslic3r/GCode/ExtrusionProcessor.hpp
+++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp
@@ -442,6 +442,10 @@ public:
};
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance));
+ // ORCA: Clamp resulting speed to lowest of calculated speed based on the overhang values and the current speed
+ // Fixes bug where resulting overhang speed is higher than the current speed due to (for example) volumetric flow limits.
+ extrusion_speed = std::min(extrusion_speed, original_speed);
+
if(slowdown_for_curled_edges) {
float curled_speed = calculate_speed(artificial_distance_to_curled_lines);
extrusion_speed = std::min(curled_speed, extrusion_speed); // adjust extrusion speed based on what is smallest - the calculated overhang speed or the artificial curled speed
diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp
index 90e65f5103..69aff57c9a 100644
--- a/src/libslic3r/Geometry.cpp
+++ b/src/libslic3r/Geometry.cpp
@@ -478,6 +478,16 @@ Transform3d Transformation::get_rotation_matrix() const
return extract_rotation_matrix(m_matrix);
}
+Vec3d Transformation::get_rotation_by_quaternion() const
+{
+ Matrix3d rotation_matrix = m_matrix.matrix().block(0, 0, 3, 3);
+ Eigen::Quaterniond quaternion(rotation_matrix);
+ quaternion.normalize();
+ Vec3d temp_rotation = quaternion.matrix().eulerAngles(2, 1, 0);
+ std::swap(temp_rotation(0), temp_rotation(2));
+ return temp_rotation;
+}
+
void Transformation::set_rotation(const Vec3d& rotation)
{
const Vec3d offset = get_offset();
@@ -839,6 +849,17 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
return curMat;
}
+Transformation generate_transform(const Vec3d& x_dir, const Vec3d& y_dir, const Vec3d& z_dir, const Vec3d& origin) {
+ Matrix3d m;
+ m.col(0) = x_dir.normalized();
+ m.col(1) = y_dir.normalized();
+ m.col(2) = z_dir.normalized();
+ Transform3d mm(m);
+ Transformation tran(mm);
+ tran.set_offset(origin);
+ return tran;
+}
+
bool is_point_inside_polygon_corner(const Point &a, const Point &b, const Point &c, const Point &query_point) {
// Cast all input points into int64_t to prevent overflows when points are close to max values of coord_t.
const Vec2i64 a_i64 = a.cast();
diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp
index 0383aadb07..9560d7aa54 100644
--- a/src/libslic3r/Geometry.hpp
+++ b/src/libslic3r/Geometry.hpp
@@ -421,6 +421,7 @@ public:
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
Vec3d get_rotation() const;
+ Vec3d get_rotation_by_quaternion() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
@@ -545,6 +546,7 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation)
}
Transformation mat_around_a_point_rotate(const Transformation& innMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian);
+Transformation generate_transform(const Vec3d &x_dir, const Vec3d &y_dir, const Vec3d &z_dir, const Vec3d &origin);
/**
* Checks if a given point is inside a corner of a polygon.
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index d869a93350..699402c861 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -1167,23 +1167,27 @@ bool ModelObject::make_boolean(ModelObject *cut_object, const std::string &boole
return true;
}
-ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
+ModelVolume *ModelObject::add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry)
{
ModelVolume* v = new ModelVolume(this, mesh);
this->volumes.push_back(v);
- v->center_geometry_after_creation();
- this->invalidate_bounding_box();
+ if (modify_to_center_geometry) {
+ v->center_geometry_after_creation();
+ this->invalidate_bounding_box();
+ }
// BBS: backup
Slic3r::save_object_mesh(*this);
return v;
}
-ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/)
+ModelVolume *ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/, bool modify_to_center_geometry)
{
ModelVolume* v = new ModelVolume(this, std::move(mesh), type);
this->volumes.push_back(v);
- v->center_geometry_after_creation();
- this->invalidate_bounding_box();
+ if (modify_to_center_geometry) {
+ v->center_geometry_after_creation();
+ this->invalidate_bounding_box();
+ }
// BBS: backup
Slic3r::save_object_mesh(*this);
return v;
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 015a8b929f..c61b539e82 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -410,8 +410,8 @@ public:
return global_config.option(config_option);
}
- ModelVolume* add_volume(const TriangleMesh &mesh);
- ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART);
+ ModelVolume* add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry = true);
+ ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART, bool modify_to_center_geometry = true);
ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID);
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART);
@@ -1244,11 +1244,13 @@ public:
m_assemble_initialized = true;
m_assemble_transformation = transformation;
}
- void set_assemble_from_transform(Transform3d& transform) {
+ void set_assemble_from_transform(const Transform3d& transform) {
m_assemble_initialized = true;
m_assemble_transformation.set_matrix(transform);
}
+ Vec3d get_assemble_offset() const {return m_assemble_transformation.get_offset(); }
void set_assemble_offset(const Vec3d& offset) { m_assemble_transformation.set_offset(offset); }
+ void set_assemble_rotation(const Vec3d &rotation) { m_assemble_transformation.set_rotation(rotation); }
void rotate_assemble(double angle, const Vec3d& axis) {
m_assemble_transformation.set_rotation(m_assemble_transformation.get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix()));
}
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 598351fb89..6c74b837c5 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -895,8 +895,13 @@ int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_suppo
}
//BBS: add outline drawing logic
-void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, const GUI::Size& cnv_size,
- std::function filter_func) const
+void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
+ bool disable_cullface,
+ const Transform3d & view_matrix,
+ const Transform3d& projection_matrix,
+ const GUI::Size& cnv_size,
+ std::function filter_func,
+ bool partly_inside_enable) const
{
GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func);
if (to_render.empty())
@@ -964,7 +969,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
//shader->set_uniform("print_volume.xy_data", m_render_volume.data);
//shader->set_uniform("print_volume.z_data", m_render_volume.zs);
- if (volume.first->partly_inside) {
+ if (volume.first->partly_inside && partly_inside_enable) {
//only partly inside volume need to be painted with boundary check
shader->set_uniform("print_volume.type", static_cast(m_print_volume.type));
shader->set_uniform("print_volume.xy_data", m_print_volume.data);
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 8e39c0febd..c94fdecb42 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -471,8 +471,14 @@ public:
int get_selection_support_threshold_angle(bool&) const;
// Render the volumes by OpenGL.
//BBS: add outline drawing logic
- void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, const GUI::Size& cnv_size,
- std::function filter_func = std::function()) const;
+ void render(ERenderType type,
+ bool disable_cullface,
+ const Transform3d & view_matrix,
+ const Transform3d& projection_matrix,
+ const GUI::Size& cnv_size,
+ std::function filter_func = std::function(),
+ bool partly_inside_enable =true
+ ) const;
// Clear the geometry
void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index a62f37c437..35584dabfc 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -90,7 +90,7 @@ void ConfigManipulation::check_nozzle_temperature_range(DynamicPrintConfig *conf
if (config->opt_int("nozzle_temperature", 0) < temperature_range_low || config->opt_int("nozzle_temperature", 0) > temperature_range_high) {
wxString msg_text = _(L("Nozzle may be blocked when the temperature is out of recommended range.\n"
"Please make sure whether to use the temperature to print.\n\n"));
- msg_text += wxString::Format(_L("Recommended nozzle temperature of this filament type is [%d, %d] degree centigrade"), temperature_range_low, temperature_range_high);
+ msg_text += wxString::Format(_L("The recommended nozzle temperature for this filament type is [%d, %d] degrees Celsius."), temperature_range_low, temperature_range_high);
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@@ -113,7 +113,7 @@ void ConfigManipulation::check_nozzle_temperature_initial_layer_range(DynamicPri
{
wxString msg_text = _(L("Nozzle may be blocked when the temperature is out of recommended range.\n"
"Please make sure whether to use the temperature to print.\n\n"));
- msg_text += wxString::Format(_L("Recommended nozzle temperature of this filament type is [%d, %d] degree centigrade"), temperature_range_low, temperature_range_high);
+ msg_text += wxString::Format(_L("The recommended nozzle temperature for this filament type is [%d, %d] degrees Celsius."), temperature_range_low, temperature_range_high);
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true;
dialog.ShowModal();
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 974b2f7f92..a803a38fac 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -14,7 +14,6 @@
#include "libslic3r/Technologies.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PresetBundle.hpp"
-#include "3DBed.hpp"
#include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "GLShader.hpp"
@@ -1168,6 +1167,13 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
load_arrange_settings();
m_selection.set_volumes(&m_volumes.volumes);
+
+ m_assembly_view_desc["object_selection_caption"] = _L("Left mouse button");
+ m_assembly_view_desc["object_selection"] = _L("object selection");
+ m_assembly_view_desc["part_selection_caption"] = "Alt +" + _L("Left mouse button");
+ m_assembly_view_desc["part_selection"] = _L("part selectiont");
+ m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys");
+ m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects");
}
GLCanvas3D::~GLCanvas3D()
@@ -1939,7 +1945,11 @@ void GLCanvas3D::render(bool only_init)
/* assemble render*/
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
//BBS: add outline logic
+ if (m_show_world_axes) {
+ m_axes.render();
+ }
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
+ _render_selection();
//_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
_render_plane();
//BBS: add outline logic insteadof selection under assemble view
@@ -2147,6 +2157,9 @@ void GLCanvas3D::update_plate_thumbnails()
void GLCanvas3D::select_all()
{
+ if (!m_gizmos.is_allow_select_all()) {
+ return;
+ }
m_selection.add_all();
m_dirty = true;
}
@@ -2262,16 +2275,10 @@ std::vector GLCanvas3D::load_object(const Model& model, int obj_idx)
void GLCanvas3D::mirror_selection(Axis axis)
{
TransformationType transformation_type;
- if (wxGetApp().obj_manipul()->is_local_coordinates())
- transformation_type.set_local();
- else if (wxGetApp().obj_manipul()->is_instance_coordinates())
- transformation_type.set_instance();
-
+ //transformation_type.set_world();
transformation_type.set_relative();
-
m_selection.setup_cache();
m_selection.mirror(axis, transformation_type);
-
do_mirror(L("Mirror Object"));
// BBS
//wxGetApp().obj_manipul()->set_dirty();
@@ -4073,9 +4080,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
GLGizmosManager::EType c = m_gizmos.get_current_type();
if (current_printer_technology() == ptFFF &&
(fff_print()->config().print_sequence == PrintSequence::ByObject)) {
- if (c == GLGizmosManager::EType::Move ||
- c == GLGizmosManager::EType::Scale ||
- c == GLGizmosManager::EType::Rotate )
+ if (can_sequential_clearance_show_in_gizmo())
update_sequential_clearance();
} else {
if (c == GLGizmosManager::EType::Move ||
@@ -4178,11 +4183,22 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
int volume_idx = get_first_hover_volume_idx();
bool already_selected = m_selection.contains_volume(volume_idx);
bool ctrl_down = evt.CmdDown();
-
+ bool alt_down = evt.AltDown();
Selection::IndicesList curr_idxs = m_selection.get_volume_idxs();
if (already_selected && ctrl_down)
m_selection.remove(volume_idx);
+ else if (alt_down) {
+ Selection::EMode mode = Selection::Volume;
+ if (already_selected) {
+ std::vector volume_idxs;
+ for (auto idx : curr_idxs) { volume_idxs.emplace_back(idx); }
+ m_selection.remove_volumes(mode, volume_idxs);
+ }
+ std::vector add_volume_idxs;
+ add_volume_idxs.emplace_back(volume_idx);
+ m_selection.add_volumes(mode, add_volume_idxs, true);
+ }
else {
m_selection.add(volume_idx, !ctrl_down, true);
m_mouse.drag.move_requires_threshold = !already_selected;
@@ -4660,11 +4676,19 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
- if (selection_mode == Selection::Instance)
- model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
+ if (selection_mode == Selection::Instance) {
+ if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
+ model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
+ }
+ } else {
+ model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
+ }
+ }
else if (selection_mode == Selection::Volume) {
- if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
- model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
+ auto cur_mv = model_object->volumes[volume_idx];
+ if (cur_mv->get_transformation() != v->get_volume_transformation()) {
+ cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@@ -4771,11 +4795,17 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
- if (selection_mode == Selection::Instance)
- model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
+ if (selection_mode == Selection::Instance) {
+ if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
+ } else {
+ model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
+ }
+ }
else if (selection_mode == Selection::Volume) {
- if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
- model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
+ auto cur_mv = model_object->volumes[volume_idx];
+ if (cur_mv->get_transformation() != v->get_volume_transformation()) {
+ cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@@ -4786,23 +4816,24 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
+ if (m_canvas_type != CanvasAssembleView) {
+ // Fixes sinking/flying instances
+ for (const std::pair &i : done) {
+ ModelObject *m = m_model->objects[i.first];
- // Fixes sinking/flying instances
- for (const std::pair& i : done) {
- ModelObject* m = m_model->objects[i.first];
+ // BBS: don't call translate if the z is zero
+ const double shift_z = m->get_instance_min_z(i.second);
+ // leave sinking instances as sinking
+ if ((min_zs.find({i.first, i.second})->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
+ const Vec3d shift(0.0, 0.0, -shift_z);
+ m_selection.translate(i.first, i.second, shift);
+ m->translate_instance(i.second, shift);
+ // BBS: notify instance updates to part plater list
+ m_selection.notify_instance_update(i.first, i.second);
+ }
- //BBS: don't call translate if the z is zero
- const double shift_z = m->get_instance_min_z(i.second);
- // leave sinking instances as sinking
- if ((min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD)&&(shift_z != 0.0f)) {
- const Vec3d shift(0.0, 0.0, -shift_z);
- m_selection.translate(i.first, i.second, shift);
- m->translate_instance(i.second, shift);
- //BBS: notify instance updates to part plater list
- m_selection.notify_instance_update(i.first, i.second);
+ wxGetApp().obj_list()->update_info_items(static_cast(i.first));
}
-
- wxGetApp().obj_list()->update_info_items(static_cast(i.first));
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -4852,12 +4883,14 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
- if (selection_mode == Selection::Instance)
+ if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
+ }
else if (selection_mode == Selection::Volume) {
- if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
+ auto cur_mv = model_object->volumes[volume_idx];
+ if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
- model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
+ cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@@ -5213,6 +5246,17 @@ void GLCanvas3D::mouse_up_cleanup()
m_canvas->ReleaseMouse();
}
+bool GLCanvas3D::can_sequential_clearance_show_in_gizmo() {
+ switch (m_gizmos.get_current_type()) {
+ case GLGizmosManager::EType::Move:
+ case GLGizmosManager::EType::Scale:
+ case GLGizmosManager::EType::Rotate: {
+ return true;
+ }
+ }
+ return false;
+}
+
void GLCanvas3D::update_sequential_clearance()
{
if (current_printer_technology() != ptFFF || (fff_print()->config().print_sequence == PrintSequence::ByLayer))
@@ -7269,6 +7313,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
ECanvasType canvas_type = this->m_canvas_type;
+ bool partly_inside_enable = canvas_type == ECanvasType::CanvasAssembleView ? false : true;
if (shader != nullptr) {
shader->start_using();
@@ -7312,7 +7357,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
}
- });
+ },
+ partly_inside_enable);
}
}
else {
@@ -7346,7 +7392,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else {
return true;
}
- });
+ },
+ partly_inside_enable);
if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) {
const GLGizmosManager& gm = get_gizmos_manager();
shader->stop_using();
@@ -7414,19 +7461,11 @@ void GLCanvas3D::_render_sequential_clearance()
{
if (m_gizmos.is_dragging())
return;
-
- switch (m_gizmos.get_current_type())
- {
- case GLGizmosManager::EType::Flatten:
- case GLGizmosManager::EType::Cut:
- // case GLGizmosManager::EType::Hollow:
- // case GLGizmosManager::EType::SlaSupports:
- case GLGizmosManager::EType::FdmSupports:
- case GLGizmosManager::EType::Seam: { return; }
- default: { break; }
+ auto type = m_gizmos.get_current_type();
+ if (type == GLGizmosManager::EType::Undefined
+ || can_sequential_clearance_show_in_gizmo()) {
+ m_sequential_print_clearance.render();
}
-
- m_sequential_print_clearance.render();
}
#if ENABLE_RENDER_SELECTION_CENTER
@@ -8171,6 +8210,7 @@ void GLCanvas3D::_render_return_toolbar() const
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
const_cast(&m_gizmos)->reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().reset_all_states();
+ wxGetApp().plater()->get_view3D_canvas3D()->reload_scene(true);
}
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(1);
@@ -8370,8 +8410,45 @@ void GLCanvas3D::_render_paint_toolbar() const
ImGui::PopStyleColor();
}
+float GLCanvas3D::_show_assembly_tooltip_information(float caption_max, float x, float y) const
+{
+ ImGuiWrapper *imgui = wxGetApp().imgui();
+ ImTextureID normal_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
+ ImTextureID hover_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
+
+ caption_max += imgui->calc_text_size(": "sv).x + 35.f;
+
+ float scale = get_scale();
+ ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
+
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
+ ImGui::ImageButton3(normal_id, hover_id, button_size);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip2(ImVec2(x, y));
+ auto draw_text_with_caption = [this, &imgui, & caption_max](const wxString &caption, const wxString &text) {
+ imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
+ ImGui::SameLine(caption_max);
+ imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
+ };
+
+ for (const auto &t : std::array{"object_selection", "part_selection", "number_key"}) {
+ draw_text_with_caption(m_assembly_view_desc.at(t + "_caption") + ": ", m_assembly_view_desc.at(t));
+ }
+ ImGui::EndTooltip();
+ }
+ ImGui::PopStyleVar(2);
+ auto same_line_size = button_size.x * 1.8;//with an space size
+ ImGui::SameLine(same_line_size);
+ same_line_size = imgui->calc_text_size("|"sv).x + same_line_size + imgui->calc_text_size(" "sv).x;
+ imgui->text_colored(ImGuiWrapper::COL_ACTIVE, "|");
+ ImGui::SameLine(same_line_size);
+ return same_line_size;
+}
+
//BBS
-void GLCanvas3D::_render_assemble_control() const
+void GLCanvas3D::_render_assemble_control()
{
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
GLVolume::explosion_ratio = m_explosion_ratio = 1.0;
@@ -8392,8 +8469,8 @@ void GLCanvas3D::_render_assemble_control() const
const float text_padding = 7.0f;
const float text_size_x = std::max(imgui->calc_text_size(_L("Reset direction")).x + 2 * ImGui::GetStyle().FramePadding.x,
std::max(imgui->calc_text_size(_L("Explosion Ratio")).x, imgui->calc_text_size(_L("Section View")).x));
- const float slider_width = 75.0f;
- const float value_size = imgui->calc_text_size(std::string_view{"3.00"}).x + text_padding * 2;
+ const float slider_width = 60.0f;
+ const float value_size = imgui->calc_text_size("3.00"sv).x + text_padding * 2;
const float item_spacing = imgui->get_item_spacing().x;
ImVec2 window_padding = ImGui::GetStyle().WindowPadding;
@@ -8401,7 +8478,19 @@ void GLCanvas3D::_render_assemble_control() const
imgui->begin(_L("Assemble Control"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
ImGui::AlignTextToFramePadding();
-
+ float tip_icon_size;
+ {
+ float caption_max = 0.f;
+ for (const auto &t : std::array{"object_selection", "part_selection", "number_key"}) {
+ caption_max = std::max(caption_max, imgui->calc_text_size(m_assembly_view_desc.at(t + "_caption")).x);
+ }
+ const ImVec2 pos = ImGui::GetCursorScreenPos();
+ const float text_y =imgui->calc_text_size(_L("part selection")).y;
+ float get_cur_x = pos.x;
+ float get_cur_y = pos.y - ImGui::GetFrameHeight() - 4 * text_y;
+ tip_icon_size =_show_assembly_tooltip_information(caption_max, get_cur_x, get_cur_y);
+ }
+ float same_line_width = tip_icon_size;
{
float clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position();
if (clp_dist == 0.f) {
@@ -8415,32 +8504,76 @@ void GLCanvas3D::_render_assemble_control() const
});
}
}
-
- ImGui::SameLine(window_padding.x + text_size_x + item_spacing);
+ same_line_width += (text_size_x + item_spacing);
+ ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(slider_width);
bool view_slider_changed = imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
- ImGui::SameLine(window_padding.x + text_size_x + slider_width + item_spacing * 2);
+ same_line_width += (slider_width + item_spacing);
+ ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(value_size);
bool view_input_changed = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (view_slider_changed || view_input_changed)
m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true);
- }
+ same_line_width += (value_size + item_spacing * 2);
+ }
{
- ImGui::SameLine(window_padding.x + text_size_x + slider_width + item_spacing * 6 + value_size);
+ auto temp_x = imgui->calc_text_size(_L("Explosion Ratio")).x;
+ ImGui::SameLine(same_line_width);
+ ImGui::PushItemWidth(temp_x);
imgui->text(_L("Explosion Ratio"));
- ImGui::SameLine(window_padding.x + 2 * text_size_x + slider_width + item_spacing * 7 + value_size);
+ same_line_width += (temp_x + item_spacing);
+ ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(slider_width);
bool explosion_slider_changed = imgui->bbl_slider_float_style("##ratio_slider", &m_explosion_ratio, 1.0f, 3.0f, "%1.2f");
- ImGui::SameLine(window_padding.x + 2 * text_size_x + 2 * slider_width + item_spacing * 8 + value_size);
+ same_line_width += (slider_width + item_spacing);
+ ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(value_size);
bool explosion_input_changed = ImGui::BBLDragFloat("##ratio_input", &m_explosion_ratio, 0.1f, 1.0f, 3.0f, "%1.2f");
+ same_line_width += (value_size + item_spacing*2);
}
+ {
+ ImGui::SameLine(same_line_width);
+ // input
+ std::vector modes = {_u8L("Object"), _u8L("Part")};
+ int selection_idx = m_selection.get_volume_selection_mode() == Selection::Instance ? 0 : 1;
+ auto label = _u8L("Selection Mode") + ":" ;
+ auto label_width = imgui->calc_text_size(label).x ;
+ auto item_width = imgui->calc_text_size(_u8L("Object")).x * 2.5 + imgui->calc_text_size("xx"sv).x+ item_spacing;
+ //render imgui
+ ImGui::AlignTextToFramePadding();
+ ImGui::PushItemWidth(label_width);
+ imgui->text(label);
+ same_line_width += (label_width + item_spacing);
+ ImGui::SameLine(same_line_width);
+ ImGui::PushItemWidth(item_width);
+ size_t selection_out = selection_idx;
+ const char *selected_str = (selection_idx >= 0 && selection_idx < int(modes.size())) ? modes[selection_idx].c_str() : "";
+ ImGuiWrapper::push_combo_style(get_scale());
+ if (ImGui::BBLBeginCombo(("##" + label).c_str(), selected_str, 0)) {
+ for (size_t line_idx = 0; line_idx < modes.size(); ++line_idx) {
+ ImGui::PushID(int(line_idx));
+ if (ImGui::Selectable("", line_idx == selection_idx))
+ selection_out = line_idx;
+ ImGui::SameLine();
+ ImGui::Text("%s", modes[line_idx].c_str());
+ ImGui::PopID();
+ }
+ ImGui::EndCombo();
+ }
+ ImGuiWrapper::pop_combo_style();
+ if (selection_idx != selection_out) {//do
+ if (selection_out == 0) { m_selection.unlock_volume_selection_mode(); }
+ m_selection.set_volume_selection_mode(selection_out == 1 ? Selection::Volume : Selection::Instance);
+ if (selection_out == 1) { m_selection.lock_volume_selection_mode(); }
+ }
+ same_line_width += (label_width + item_width);
+ }
imgui->end();
ImGuiWrapper::pop_toolbar_style();
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index c2a5b9d00d..26c14fa75e 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -18,7 +18,7 @@
#include "Camera.hpp"
#include "SceneRaycaster.hpp"
#include "IMToolbar.hpp"
-
+#include "slic3r/GUI/3DBed.hpp"
#include "libslic3r/Slicing.hpp"
#include
@@ -512,6 +512,7 @@ private:
wxGLContext* m_context;
SceneRaycaster m_scene_raycaster;
Bed3D &m_bed;
+ std::map m_assembly_view_desc;
#if ENABLE_RETINA_GL
std::unique_ptr m_retina_helper;
#endif
@@ -611,8 +612,8 @@ private:
PrinterTechnology current_printer_technology() const;
-
-
+ bool m_show_world_axes{false};
+ Bed3D::Axes m_axes;
//BBS:record key botton frequency
int auto_orient_count = 0;
int auto_arrange_count = 0;
@@ -807,6 +808,7 @@ public:
void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); }
void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); }
+ void set_show_world_axes(bool flag) { m_show_world_axes = flag; }
void refresh_camera_scene_box();
void set_color_by(const std::string& value);
@@ -1111,6 +1113,7 @@ public:
m_sequential_print_clearance.set_polygons(polygons, height_polygons);
}
+ bool can_sequential_clearance_show_in_gizmo();
void update_sequential_clearance();
const Print* fff_print() const;
@@ -1189,7 +1192,8 @@ private:
// BBS
//void _render_view_toolbar() const;
void _render_paint_toolbar() const;
- void _render_assemble_control() const;
+ float _show_assembly_tooltip_information(float caption_max, float x, float y) const;
+ void _render_assemble_control();
void _render_assemble_info() const;
#if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target();
diff --git a/src/slic3r/GUI/GUI_Geometry.hpp b/src/slic3r/GUI/GUI_Geometry.hpp
index b18e4ae5a5..39faafb833 100644
--- a/src/slic3r/GUI/GUI_Geometry.hpp
+++ b/src/slic3r/GUI/GUI_Geometry.hpp
@@ -6,7 +6,7 @@ namespace GUI {
enum class ECoordinatesType : unsigned char
{
- World,
+ World = 0,
Instance,
Local
};
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 734729e734..e4e4989ac2 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -4759,6 +4759,9 @@ void ObjectList::select_all()
void ObjectList::select_item_all_children()
{
+ if (wxGetApp().plater() && !wxGetApp().plater()->canvas3D()->get_gizmos_manager().is_allow_select_all()) {
+ return;
+ }
wxDataViewItemArray sels;
// There is no selection before OR some object is selected => select all objects
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 25b333e281..978a0e3cab 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -823,10 +823,10 @@ bool AssembleView::init(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrint
m_canvas->enable_assemble_view_toolbar(false);
m_canvas->enable_return_toolbar(true);
m_canvas->enable_separator_toolbar(false);
-
+ //m_canvas->set_show_world_axes(true);//wait for GitHub users to see if they have this requirement
// BBS: set volume_selection_mode to Volume
- m_canvas->get_selection().set_volume_selection_mode(Selection::Volume);
- m_canvas->get_selection().lock_volume_selection_mode();
+ //same to 3d //m_canvas->get_selection().set_volume_selection_mode(Selection::Instance);
+ //m_canvas->get_selection().lock_volume_selection_mode();
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
index 089dd1d454..0b68e64150 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
@@ -227,7 +227,71 @@ bool GLGizmoBase::render_combo(const std::string &label, const std::vector &lines,
int &selection_idx, float label_width, float item_width);
-
+ void render_cross_mark(const Vec3f& target,bool is_single =false);
public:
GLGizmoBase(GLCanvas3D& parent,
const std::string& icon_filename,
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
index 6acf77a0f8..c82936650b 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
@@ -48,6 +48,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
void GLGizmoMove3D::data_changed(bool is_serializing) {
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
+ change_cs_by_selection();
}
bool GLGizmoMove3D::on_init()
@@ -67,7 +68,11 @@ bool GLGizmoMove3D::on_init()
std::string GLGizmoMove3D::on_get_name() const
{
- return _u8L("Move");
+ if (!on_is_activable() && m_state == EState::Off) {
+ return _u8L("Move") + ":\n" + _u8L("Please select at least one object.");
+ } else {
+ return _u8L("Move");
+ }
}
bool GLGizmoMove3D::on_is_activable() const
@@ -75,13 +80,21 @@ bool GLGizmoMove3D::on_is_activable() const
return !m_parent.get_selection().is_empty();
}
+void GLGizmoMove3D::on_set_state() {
+ if (get_state() == On) {
+ m_last_selected_obejct_idx = -1;
+ m_last_selected_volume_idx = -1;
+ change_cs_by_selection();
+ }
+}
+
void GLGizmoMove3D::on_start_dragging()
{
assert(m_hover_id != -1);
m_displacement = Vec3d::Zero();
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
- m_starting_drag_position = m_grabbers[m_hover_id].center;
+ m_starting_drag_position = m_grabbers[m_hover_id].matrix * m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center(2) = box.min(2);
@@ -121,42 +134,38 @@ void GLGizmoMove3D::on_render()
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
- const BoundingBoxf3& box = selection.get_bounding_box();
- const Vec3d& center = box.center();
+ const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
+ m_bounding_box = box;
+ m_center = box_trafo.translation();
+ if (m_object_manipulation) {
+ m_object_manipulation->cs_center = box_trafo.translation();
+ }
+ const Transform3d base_matrix = box_trafo;
float space_size = 20.f *INV_ZOOM;
-#if ENABLE_FIXED_GRABBER
+ for (int i = 0; i < 3; ++i) {
+ m_grabbers[i].matrix = base_matrix;
+ }
+
+ const Vec3d zero = Vec3d::Zero();
+
// x axis
- m_grabbers[0].center = { box.max.x() + space_size, center.y(), center.z() };
+ m_grabbers[0].center = {m_bounding_box.max.x() + space_size, 0, 0};
// y axis
- m_grabbers[1].center = { center.x(), box.max.y() + space_size, center.z() };
+ m_grabbers[1].center = {0, m_bounding_box.max.y() + space_size,0};
// z axis
- m_grabbers[2].center = { center.x(), center.y(), box.max.z() + space_size };
+ m_grabbers[2].center = {0,0, m_bounding_box.max.z() + space_size};
for (int i = 0; i < 3; ++i) {
m_grabbers[i].color = AXES_COLOR[i];
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i];
}
-#else
- // x axis
- m_grabbers[0].center = { box.max.x() + Offset, center.y(), center.z() };
- m_grabbers[0].color = AXES_COLOR[0];
-
- // y axis
- m_grabbers[1].center = { center.x(), box.max.y() + Offset, center.z() };
- m_grabbers[1].color = AXES_COLOR[1];
-
- // z axis
- m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
- m_grabbers[2].color = AXES_COLOR[2];
-#endif
-
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
- auto render_grabber_connection = [this, ¢er](unsigned int id) {
+ auto render_grabber_connection = [this, &zero](unsigned int id) {
if (m_grabbers[id].enabled) {
//if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
- m_grabber_connections[id].old_center = center;
+ m_grabber_connections[id].old_center = m_grabbers[id].center;
m_grabber_connections[id].model.reset();
GLModel::Geometry init_data;
@@ -166,7 +175,7 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2);
// vertices
- init_data.add_vertex((Vec3f)center.cast());
+ init_data.add_vertex((Vec3f)zero.cast());
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast());
// indices
@@ -186,7 +195,7 @@ void GLGizmoMove3D::on_render()
if (shader != nullptr) {
shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
- shader->set_uniform("view_model_matrix", camera.get_view_matrix());
+ shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
// draw axes
@@ -199,6 +208,28 @@ void GLGizmoMove3D::on_render()
// draw grabbers
render_grabbers(box);
+
+ if (m_object_manipulation->is_instance_coordinates()) {
+ shader = wxGetApp().get_shader("flat");
+ if (shader != nullptr) {
+ shader->start_using();
+ const Camera& camera = wxGetApp().plater()->get_camera();
+
+ Geometry::Transformation cur_tran;
+ if (auto mi = m_parent.get_selection().get_selected_single_intance()) {
+ cur_tran = mi->get_transformation();
+ } else {
+ cur_tran = selection.get_first_volume()->get_instance_transformation();
+ }
+
+ shader->set_uniform("view_model_matrix", camera.get_view_matrix() * cur_tran.get_matrix());
+ shader->set_uniform("projection_matrix", camera.get_projection_matrix());
+
+ render_cross_mark(Vec3f::Zero(), true);
+
+ shader->stop_using();
+ }
+ }
}
void GLGizmoMove3D::on_register_raycasters_for_picking()
@@ -245,5 +276,30 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
return projection;
}
+
+void GLGizmoMove3D::change_cs_by_selection() {
+ int obejct_idx, volume_idx;
+ ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
+ if (m_last_selected_obejct_idx == obejct_idx && m_last_selected_volume_idx == volume_idx) {
+ return;
+ }
+ m_last_selected_obejct_idx = obejct_idx;
+ m_last_selected_volume_idx = volume_idx;
+ if (m_parent.get_selection().is_multiple_full_object()) {
+ m_object_manipulation->set_use_object_cs(false);
+ }
+ else if (model_volume) {
+ m_object_manipulation->set_use_object_cs(true);
+ } else {
+ m_object_manipulation->set_use_object_cs(false);
+ }
+ if (m_object_manipulation->get_use_object_cs()) {
+ m_object_manipulation->set_coordinates_type(ECoordinatesType::Instance);
+ } else {
+ m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
+ }
+}
+
+
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
index 4d0b4581f0..df3abdddc7 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
@@ -16,6 +16,8 @@ class GLGizmoMove3D : public GLGizmoBase
static const double Offset;
Vec3d m_displacement{ Vec3d::Zero() };
+ Vec3d m_center{ Vec3d::Zero() };
+ BoundingBoxf3 m_bounding_box;
double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() };
@@ -57,6 +59,7 @@ protected:
bool on_init() override;
std::string on_get_name() const override;
bool on_is_activable() const override;
+ virtual void on_set_state() override;
void on_start_dragging() override;
void on_stop_dragging() override;
void on_dragging(const UpdateData& data) override;
@@ -68,6 +71,9 @@ protected:
private:
double calc_projection(const UpdateData& data) const;
+ void change_cs_by_selection(); //cs mean Coordinate System
+private:
+ int m_last_selected_obejct_idx, m_last_selected_volume_idx;
};
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
index 5b79edb95d..59c5f194ed 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
@@ -527,25 +527,6 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
return use_grabbers(mouse_event);
}
-void GLGizmoRotate3D::data_changed(bool is_serializing) {
- const Selection &selection = m_parent.get_selection();
- bool is_wipe_tower = selection.is_wipe_tower();
- if (is_wipe_tower) {
- DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
- float wipe_tower_rotation_angle =
- dynamic_cast(
- config.option("wipe_tower_rotation_angle"))
- ->value;
- set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
- m_gizmos[0].disable_grabber();
- m_gizmos[1].disable_grabber();
- } else {
- set_rotation(Vec3d::Zero());
- m_gizmos[0].enable_grabber();
- m_gizmos[1].enable_grabber();
- }
-}
-
bool GLGizmoRotate3D::on_init()
{
for (GLGizmoRotate& g : m_gizmos)
@@ -561,7 +542,57 @@ bool GLGizmoRotate3D::on_init()
std::string GLGizmoRotate3D::on_get_name() const
{
- return _u8L("Rotate");
+ if (!on_is_activable() && m_state == EState::Off) {
+ return _u8L("Rotate") + ":\n" + _u8L("Please select at least one object.");
+ } else {
+ return _u8L("Rotate");
+ }
+}
+
+void GLGizmoRotate3D::on_set_state()
+{
+ for (GLGizmoRotate &g : m_gizmos)
+ g.set_state(m_state);
+ if (get_state() == On) {
+ m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
+ } else {
+ m_last_volume = nullptr;
+ }
+}
+
+void GLGizmoRotate3D::data_changed(bool is_serializing) {
+ const Selection &selection = m_parent.get_selection();
+ const GLVolume * volume = selection.get_first_volume();
+ if (volume == nullptr) {
+ m_last_volume = nullptr;
+ return;
+ }
+ if (m_last_volume != volume) {
+ m_last_volume = volume;
+ Geometry::Transformation tran;
+ if (selection.is_single_full_instance()) {
+ tran = volume->get_instance_transformation();
+ } else {
+ tran = volume->get_volume_transformation();
+ }
+ m_object_manipulation->set_init_rotation(tran);
+ }
+
+ bool is_wipe_tower = selection.is_wipe_tower();
+ if (is_wipe_tower) {
+ DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
+ float wipe_tower_rotation_angle =
+ dynamic_cast(
+ config.option("wipe_tower_rotation_angle"))
+ ->value;
+ set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
+ m_gizmos[0].disable_grabber();
+ m_gizmos[1].disable_grabber();
+ } else {
+ set_rotation(Vec3d::Zero());
+ m_gizmos[0].enable_grabber();
+ m_gizmos[1].enable_grabber();
+ }
}
bool GLGizmoRotate3D::on_is_activable() const
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
index 769809df8d..8cbacde3c6 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
@@ -151,11 +151,9 @@ public:
protected:
bool on_init() override;
std::string on_get_name() const override;
- void on_set_state() override {
- for (GLGizmoRotate& g : m_gizmos)
- g.set_state(m_state);
- }
- void on_set_hover_id() override {
+ void on_set_state() override;
+ void on_set_hover_id() override
+ {
for (int i = 0; i < 3; ++i)
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
}
@@ -179,7 +177,7 @@ protected:
void on_render_input_window(float x, float y, float bottom_limit) override;
private:
-
+ const GLVolume *m_last_volume;
class RotoptimzeWindow
{
ImGuiWrapper *m_imgui = nullptr;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
index 8d2781e6a8..143d5b6669 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
@@ -5,7 +5,7 @@
#include
-#include
+#include
namespace Slic3r {
namespace GUI {
@@ -24,11 +24,11 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan
//BBS: GUI refactor: add obj manipulation
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id)
+ , m_scale(Vec3d::Ones())
+ , m_offset(Vec3d::Zero())
+ , m_snap_step(0.05)
//BBS: GUI refactor: add obj manipulation
, m_object_manipulation(obj_manipulation)
- , m_base_color(DEFAULT_BASE_COLOR)
- , m_drag_color(DEFAULT_DRAG_COLOR)
- , m_highlight_color(DEFAULT_HIGHLIGHT_COLOR)
{
m_grabber_connections[0].grabber_indices = { 0, 1 };
m_grabber_connections[1].grabber_indices = { 2, 3 };
@@ -39,6 +39,17 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
m_grabber_connections[6].grabber_indices = { 9, 6 };
}
+const Vec3d &GLGizmoScale3D::get_scale()
+{
+ if (m_object_manipulation) {
+ Vec3d cache_scale = m_object_manipulation->get_cache().scale.cwiseQuotient(Vec3d(100,100,100));
+ Vec3d temp_scale = cache_scale.cwiseProduct(m_scale);
+ m_object_manipulation->limit_scaling_ratio(temp_scale);
+ m_scale = temp_scale.cwiseQuotient(cache_scale);
+ }
+ return m_scale;
+}
+
std::string GLGizmoScale3D::get_tooltip() const
{
const Selection& selection = m_parent.get_selection();
@@ -70,77 +81,57 @@ std::string GLGizmoScale3D::get_tooltip() const
return "";
}
-static int constraint_id(int grabber_id)
-{
- static const std::vector id_map = { 1, 0, 3, 2, 5, 4, 8, 9, 6, 7 };
- return (0 <= grabber_id && grabber_id < (int)id_map.size()) ? id_map[grabber_id] : -1;
-}
-
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
{
if (mouse_event.Dragging()) {
if (m_dragging) {
// Apply new temporary scale factors
- Selection& selection = m_parent.get_selection();
TransformationType transformation_type;
- if (selection.is_single_full_instance()) {
- transformation_type.set_instance();
- } else if (selection.is_single_volume_or_modifier()) {
+ if (wxGetApp().obj_manipul()->is_local_coordinates())
transformation_type.set_local();
- }
+ else if (wxGetApp().obj_manipul()->is_instance_coordinates())
+ transformation_type.set_instance();
transformation_type.set_relative();
if (mouse_event.AltDown())
transformation_type.set_independent();
- selection.scale(m_scale, transformation_type);
- if (m_starting.ctrl_down && m_hover_id < 6) {
- // constrained scale:
- // uses the performed scale to calculate the new position of the constrained grabber
- // and from that calculates the offset (in world coordinates) to be applied to fullfill the constraint
- update_render_data();
- const Vec3d constraint_position = m_grabbers[constraint_id(m_hover_id)].center;
- // re-apply the scale because the selection always applies the transformations with respect to the initial state
- // set into on_start_dragging() with the call to selection.setup_cache()
- m_parent.get_selection().scale_and_translate(m_scale, m_starting.pivots[m_hover_id] - constraint_position, transformation_type);
- }
+ Selection& selection = m_parent.get_selection();
+ selection.scale_and_translate(get_scale(), get_offset(), transformation_type);
}
}
return use_grabbers(mouse_event);
}
+void GLGizmoScale3D::data_changed(bool is_serializing)
+{
+ const Selection &selection = m_parent.get_selection();
+ bool enable_scale_xyz = selection.is_single_full_instance() ||
+ selection.is_single_volume_or_modifier();
+ for (unsigned int i = 0; i < 6; ++i)
+ m_grabbers[i].enabled = enable_scale_xyz;
+
+ set_scale(Vec3d::Ones());
+
+ change_cs_by_selection();
+}
+
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
{
for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable;
}
-void GLGizmoScale3D::data_changed(bool is_serializing) {
- const Selection &selection = m_parent.get_selection();
- bool enable_scale_xyz = selection.is_single_full_instance() ||
- selection.is_single_volume_or_modifier();
- for (unsigned int i = 0; i < 6; ++i)
- m_grabbers[i].enabled = enable_scale_xyz;
-
- set_scale(Vec3d::Ones());
-}
-
bool GLGizmoScale3D::on_init()
{
- for (int i = 0; i < 10; ++i) {
+ for (int i = 0; i < 10; ++i)
+ {
m_grabbers.push_back(Grabber());
}
double half_pi = 0.5 * (double)PI;
- // x axis
- m_grabbers[0].angles(1) = half_pi;
- m_grabbers[1].angles(1) = half_pi;
-
- // y axis
- m_grabbers[2].angles(0) = half_pi;
- m_grabbers[3].angles(0) = half_pi;
// BBS
m_grabbers[4].enabled = false;
@@ -151,7 +142,11 @@ bool GLGizmoScale3D::on_init()
std::string GLGizmoScale3D::on_get_name() const
{
- return _u8L("Scale");
+ if (!on_is_activable() && m_state == EState::Off) {
+ return _u8L("Scale") + ":\n" + _u8L("Please select at least one object.");
+ } else {
+ return _u8L("Scale");
+ }
}
bool GLGizmoScale3D::on_is_activable() const
@@ -160,21 +155,48 @@ bool GLGizmoScale3D::on_is_activable() const
return !selection.is_empty() && !selection.is_wipe_tower();
}
+void GLGizmoScale3D::on_set_state() {
+ if (get_state() == On) {
+ m_last_selected_obejct_idx = -1;
+ m_last_selected_volume_idx = -1;
+ change_cs_by_selection();
+ }
+}
+
+static int constraint_id(int grabber_id)
+{
+ static const std::vector id_map = {1, 0, 3, 2, 5, 4, 8, 9, 6, 7};
+ return (0 <= grabber_id && grabber_id < (int) id_map.size()) ? id_map[grabber_id] : -1;
+}
+
void GLGizmoScale3D::on_start_dragging()
{
- assert(m_hover_id != -1);
- m_starting.drag_position = m_grabbers[m_hover_id].center;
- m_starting.plane_center = m_grabbers[4].center;
- m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
- m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
- m_starting.box = m_box;
+ if (m_hover_id != -1) {
+ auto grabbers_transform = m_grabbers_tran.get_matrix();
+ m_starting.drag_position = grabbers_transform * m_grabbers[m_hover_id].center;
+ m_starting.plane_center = grabbers_transform * m_grabbers[4].center; // plane_center = bottom center
+ m_starting.plane_nromal = (grabbers_transform * m_grabbers[5].center - grabbers_transform * m_grabbers[4].center).normalized();
+ m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
+ m_starting.box = m_bounding_box;
- m_starting.pivots[0] = m_grabbers[1].center;
- m_starting.pivots[1] = m_grabbers[0].center;
- m_starting.pivots[2] = m_grabbers[3].center;
- m_starting.pivots[3] = m_grabbers[2].center;
- m_starting.pivots[4] = m_grabbers[5].center;
- m_starting.pivots[5] = m_grabbers[4].center;
+ m_starting.center = m_center;
+ m_starting.instance_center = m_instance_center;
+
+ const Vec3d box_half_size = 0.5 * m_bounding_box.size();
+
+ m_starting.local_pivots[0] = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
+ m_starting.local_pivots[1] = Vec3d(-box_half_size.x(), 0.0, -box_half_size.z());
+ m_starting.local_pivots[2] = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
+ m_starting.local_pivots[3] = Vec3d(0.0, -box_half_size.y(), -box_half_size.z());
+ m_starting.local_pivots[4] = Vec3d(0.0, 0.0, box_half_size.z());
+ m_starting.local_pivots[5] = Vec3d(0.0, 0.0, -box_half_size.z());
+ for (size_t i = 0; i < 6; i++) {
+ m_starting.pivots[i] = grabbers_transform * m_starting.local_pivots[i]; // todo delete
+ }
+ m_starting.constraint_position = grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
+ m_scale = m_starting.scale = Vec3d::Ones() ;
+ m_offset = Vec3d::Zero();
+ }
}
void GLGizmoScale3D::on_stop_dragging()
@@ -185,26 +207,95 @@ void GLGizmoScale3D::on_stop_dragging()
void GLGizmoScale3D::on_dragging(const UpdateData& data)
{
- if (m_hover_id == 0 || m_hover_id == 1)
+ if ((m_hover_id == 0) || (m_hover_id == 1))
do_scale_along_axis(X, data);
- else if (m_hover_id == 2 || m_hover_id == 3)
+ else if ((m_hover_id == 2) || (m_hover_id == 3))
do_scale_along_axis(Y, data);
- else if (m_hover_id == 4 || m_hover_id == 5)
+ else if ((m_hover_id == 4) || (m_hover_id == 5))
do_scale_along_axis(Z, data);
else if (m_hover_id >= 6)
do_scale_uniform(data);
}
+void GLGizmoScale3D::update_grabbers_data()
+{
+ const Selection &selection = m_parent.get_selection();
+ const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
+ m_bounding_box = box;
+ m_center = box_trafo.translation();
+ m_grabbers_tran.set_matrix(box_trafo);
+ m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
+
+ const Vec3d box_half_size = 0.5 * m_bounding_box.size();
+ bool ctrl_down = wxGetKeyState(WXK_CONTROL);
+
+
+ bool single_instance = selection.is_single_full_instance();
+ bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
+
+ // x axis
+ m_grabbers[0].center = Vec3d(-(box_half_size.x()), 0.0, -box_half_size.z());
+ m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
+ m_grabbers[1].center = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
+ m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
+ // y axis
+ m_grabbers[2].center = Vec3d(0.0, -(box_half_size.y()), -box_half_size.z());
+ m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
+ m_grabbers[3].center = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
+ m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
+ // z axis do not show 4
+ m_grabbers[4].center = Vec3d(0.0, 0.0, -(box_half_size.z()));
+ m_grabbers[4].enabled = false;
+
+ m_grabbers[5].center = Vec3d(0.0, 0.0, box_half_size.z());
+ m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
+ // uniform
+ m_grabbers[6].center = Vec3d(-box_half_size.x(), -box_half_size.y(), -box_half_size.z());
+ m_grabbers[6].color = (ctrl_down && m_hover_id == 8) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
+ m_grabbers[7].center = Vec3d(box_half_size.x(), -box_half_size.y(), -box_half_size.z());
+ m_grabbers[7].color = (ctrl_down && m_hover_id == 9) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
+ m_grabbers[8].center = Vec3d(box_half_size.x(), box_half_size.y(), -box_half_size.z());
+ m_grabbers[8].color = (ctrl_down && m_hover_id == 6) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
+ m_grabbers[9].center = Vec3d(-box_half_size.x(), box_half_size.y(), -box_half_size.z());
+ m_grabbers[9].color = (ctrl_down && m_hover_id == 7) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
+ for (int i = 0; i < 6; ++i) {
+ //m_grabbers[i].color = AXES_COLOR[i / 2];
+ m_grabbers[i].hover_color = AXES_HOVER_COLOR[i / 2];
+ }
+ for (int i = 6; i < 10; ++i) {
+ //m_grabbers[i].color = GRABBER_UNIFORM_COL;
+ m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ m_grabbers[i].matrix = m_grabbers_tran.get_matrix();
+ }
+}
+
+
+void GLGizmoScale3D::change_cs_by_selection() {
+ int obejct_idx, volume_idx;
+ ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
+ if (m_last_selected_obejct_idx == obejct_idx && m_last_selected_volume_idx == volume_idx) { return; }
+ m_last_selected_obejct_idx = obejct_idx;
+ m_last_selected_volume_idx = volume_idx;
+ if (m_parent.get_selection().is_multiple_full_object()) {
+ m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
+ } else if (model_volume) {
+ m_object_manipulation->set_coordinates_type(ECoordinatesType::Local);
+ }
+}
+
void GLGizmoScale3D::on_render()
{
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
- update_render_data();
+ update_grabbers_data();
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
- const float grabber_mean_size = (float) ((m_box.size().x() + m_box.size().y() + m_box.size().z()) / 3.0);
+ const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
//draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat");
@@ -213,7 +304,7 @@ void GLGizmoScale3D::on_render()
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
//if (single_instance || single_volume) {
const Camera& camera = wxGetApp().plater()->get_camera();
- shader->set_uniform("view_model_matrix", camera.get_view_matrix());
+ shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_tran.get_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
render_grabbers_connection(4, 5, m_grabbers[4].color);
@@ -298,29 +389,53 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
double ratio = calc_ratio(data);
- if (ratio > 0.0) {
- Vec3d curr_scale = m_scale;
- curr_scale(axis) = m_starting.scale(axis) * ratio;
- m_scale = curr_scale;
+ if (ratio > 0.0)
+ {
+ m_scale(axis) = m_starting.scale(axis) * ratio;
+ if (m_starting.ctrl_down && abs(ratio-1.0f)>0.001) {
+ double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
+ if (m_hover_id == 2 * axis) {
+ local_offset *= -1.0;
+ }
+ Vec3d local_offset_vec;
+ switch (axis)
+ {
+ case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
+ case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break;}
+ case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break;
+ }
+ default: break;
+ }
+ if (m_object_manipulation->is_world_coordinates()) {
+ m_offset = local_offset_vec;
+ } else {//if (m_object_manipulation->is_instance_coordinates())
+ m_offset = m_grabbers_tran.get_matrix_no_offset() * local_offset_vec;
+ }
+ }
+ else
+ m_offset = Vec3d::Zero();
}
}
-void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
+void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{
- const double ratio = calc_ratio(data);
+ double ratio = calc_ratio(data);
if (ratio > 0.0)
+ {
m_scale = m_starting.scale * ratio;
+ m_offset = Vec3d::Zero();
+ }
}
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{
double ratio = 0.0;
- Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.plane_center;
-
+ Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.constraint_position : m_starting.plane_center; // plane_center = bottom center
Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm();
- if (len_starting_vec != 0.0) {
+ if (len_starting_vec != 0.0)
+ {
Vec3d mouse_dir = data.mouse_ray.unit_vector();
Vec3d plane_normal = m_starting.plane_nromal;
if (m_hover_id == 5) {
@@ -328,10 +443,16 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
Vec3d plane_vec = mouse_dir.cross(m_starting.plane_nromal);
plane_normal = plane_vec.cross(m_starting.plane_nromal);
}
-
+ plane_normal = plane_normal.normalized();
// finds the intersection of the mouse ray with the plane that the drag point moves
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection
- Vec3d inters = GetIntersectionOfRayAndPlane(data.mouse_ray.a, mouse_dir, m_starting.drag_position, plane_normal.normalized());
+ auto dot_value = (plane_normal.dot(mouse_dir));
+ auto angle = Geometry::rad2deg(acos(dot_value));
+ auto big_than_min_angle = abs(angle) < 95 && abs(angle) > 85;
+ if (big_than_min_angle) {
+ return 1;
+ }
+ Vec3d inters = GetIntersectionOfRayAndPlane(data.mouse_ray.a, mouse_dir, m_starting.drag_position, plane_normal);
Vec3d inters_vec = inters - m_starting.drag_position;
@@ -347,78 +468,5 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio;
}
-void GLGizmoScale3D::update_render_data()
-{
-
- const Selection& selection = m_parent.get_selection();
-
- bool single_instance = selection.is_single_full_instance();
- bool single_volume = selection.is_single_volume_or_modifier();
-
- m_box.reset();
- m_transform = Transform3d::Identity();
- Vec3d angles = Vec3d::Zero();
-
- if (single_instance) {
- // calculate bounding box in instance local reference system
- const Selection::IndicesList& idxs = selection.get_volume_idxs();
- for (unsigned int idx : idxs) {
- const GLVolume* vol = selection.get_volume(idx);
- m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
- }
-
- // gets transform from first selected volume
- const GLVolume* v = selection.get_first_volume();
- m_transform = v->get_instance_transformation().get_matrix();
- // gets angles from first selected volume
- angles = v->get_instance_rotation();
- }
- else if (single_volume) {
- const GLVolume* v = selection.get_first_volume();
- m_box = v->bounding_box();
- m_transform = v->world_matrix();
- angles = Geometry::extract_euler_angles(m_transform);
- }
- else
- m_box = selection.get_bounding_box();
-
- const Vec3d& center = m_box.center();
-
- // x axis
- m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z());
- m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
-
- // y axis
- m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z());
- m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
-
- // z axis do not show 4
- m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z());
- m_grabbers[4].enabled = false;
-
- m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z());
-
- // uniform
- m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z());
- m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z());
- m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z());
- m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z());
-
- for (int i = 0; i < 6; ++i) {
- m_grabbers[i].color = AXES_COLOR[i/2];
- m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2];
- }
-
- for (int i = 6; i < 10; ++i) {
- m_grabbers[i].color = GRABBER_UNIFORM_COL;
- m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
- }
-
- // sets grabbers orientation
- for (int i = 0; i < 10; ++i) {
- m_grabbers[i].angles = angles;
- }
-}
-
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp
index 77929bb538..6b46a596ba 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp
@@ -19,25 +19,28 @@ class GLGizmoScale3D : public GLGizmoBase
{
Vec3d scale;
Vec3d drag_position;
+ Vec3d constraint_position;
+ Vec3d center{Vec3d::Zero()};//sphere bounding box center
+ Vec3d instance_center{Vec3d::Zero()};
Vec3d plane_center; // keep the relative center position for scale in the bottom plane
- Vec3d plane_nromal; // keep the bottom plane
+ Vec3d plane_nromal; // keep the bottom plane
BoundingBoxf3 box;
- Vec3d pivots[6];
+ Vec3d pivots[6];// Vec3d constraint_position{Vec3d::Zero()};
+ Vec3d local_pivots[6];
bool ctrl_down;
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
};
- BoundingBoxf3 m_box;
- Transform3d m_transform;
- Vec3d m_scale{ Vec3d::Ones() };
- double m_snap_step{ 0.05 };
+ mutable BoundingBoxf3 m_bounding_box;
+ Geometry::Transformation m_grabbers_tran;//m_grabbers_transform
+ Vec3d m_center{Vec3d::Zero()};
+ Vec3d m_instance_center{Vec3d::Zero()};
+ Vec3d m_scale;
+ Vec3d m_offset;
+ double m_snap_step;
StartingData m_starting;
- ColorRGBA m_base_color;
- ColorRGBA m_drag_color;
- ColorRGBA m_highlight_color;
-
struct GrabberConnection
{
GLModel model;
@@ -58,9 +61,11 @@ public:
double get_snap_step(double step) const { return m_snap_step; }
void set_snap_step(double step) { m_snap_step = step; }
- const Vec3d& get_scale() const { return m_scale; }
+ const Vec3d &get_scale();
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
+ const Vec3d& get_offset() const { return m_offset; }
+
std::string get_tooltip() const override;
///
@@ -76,6 +81,7 @@ protected:
virtual bool on_init() override;
virtual std::string on_get_name() const override;
virtual bool on_is_activable() const override;
+ virtual void on_set_state() override;
virtual void on_start_dragging() override;
virtual void on_stop_dragging() override;
virtual void on_dragging(const UpdateData& data) override;
@@ -92,7 +98,10 @@ private:
void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const;
- void update_render_data();
+ void update_grabbers_data();
+ void change_cs_by_selection(); // cs mean Coordinate System
+private:
+ int m_last_selected_obejct_idx, m_last_selected_volume_idx;
};
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
index 63069b42b5..72c69dc0e9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
@@ -1024,20 +1024,6 @@ void GLGizmoText::show_tooltip_information(float x, float y)
ImGui::PopStyleVar(2);
}
-ModelVolume *GLGizmoText::get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const
-{
- if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) {
- const Selection &selection = m_parent.get_selection();
- const GLVolume * gl_volume = selection.get_first_volume();
- out_object_idx = gl_volume->object_idx();
- ModelObject *model_object = selection.get_model()->objects[out_object_idx];
- out_volume_idx = gl_volume->volume_idx();
- if (out_volume_idx < model_object->volumes.size())
- return model_object->volumes[out_volume_idx];
- }
- return nullptr;
-}
-
void GLGizmoText::reset_text_info()
{
m_font_name = "";
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 91918fa147..0a45b86d4d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -62,7 +62,9 @@ std::vector GLGizmosManager::get_selectable_idxs() const
out.reserve(m_gizmos.size());
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
for (size_t i = 0; i < m_gizmos.size(); ++i)
- if (m_gizmos[i]->get_sprite_id() == (unsigned int) Measure ||
+ if (m_gizmos[i]->get_sprite_id() == (unsigned int) Move ||
+ m_gizmos[i]->get_sprite_id() == (unsigned int) Rotate ||
+ m_gizmos[i]->get_sprite_id() == (unsigned int) Measure ||
m_gizmos[i]->get_sprite_id() == (unsigned int) Assembly ||
m_gizmos[i]->get_sprite_id() == (unsigned int) MmuSegmentation)
out.push_back(i);
@@ -247,6 +249,16 @@ bool GLGizmosManager::init_icon_textures()
else
return false;
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_reset_zero.svg", 14, 14, texture_id))
+ icon_list.insert(std::make_pair((int) IC_TOOLBAR_RESET_ZERO, texture_id));
+ else
+ return false;
+
+ if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_reset_zero_hover.svg", 14, 14, texture_id))
+ icon_list.insert(std::make_pair((int) IC_TOOLBAR_RESET_ZERO_HOVER, texture_id));
+ else
+ return false;
+
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_tooltip.svg", 25, 25, texture_id)) // ORCA: Use same resolution with gizmos to prevent blur on icon
icon_list.insert(std::make_pair((int)IC_TOOLBAR_TOOLTIP, texture_id));
else
@@ -371,6 +383,9 @@ void GLGizmosManager::update_assemble_view_data()
void GLGizmosManager::update_data()
{
if (!m_enabled) return;
+
+ const Selection& selection = m_parent.get_selection();
+
if (m_common_gizmos_data)
m_common_gizmos_data->update(get_current()
? get_current()->get_requirements()
@@ -381,8 +396,10 @@ void GLGizmosManager::update_data()
if (m_current != Flatten && !m_gizmos.empty()) m_gizmos[Flatten]->data_changed(m_serializing);
//BBS: GUI refactor: add object manipulation in gizmo
- m_object_manipulation.update_ui_from_settings();
- m_object_manipulation.UpdateAndShow(true);
+ if (!selection.is_empty()) {
+ m_object_manipulation.update_ui_from_settings();
+ m_object_manipulation.UpdateAndShow(true);
+ }
}
bool GLGizmosManager::is_running() const
@@ -461,6 +478,22 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
return false;
}
+bool GLGizmosManager::is_paint_gizmo()
+{
+ return m_current == EType::FdmSupports ||
+ m_current == EType::MmuSegmentation ||
+ m_current == EType::Seam;
+}
+
+bool GLGizmosManager::is_allow_select_all() {
+ if (m_current == Undefined || m_current == EType::Move||
+ m_current == EType::Rotate ||
+ m_current == EType::Scale) {
+ return true;
+ }
+ return false;
+}
+
ClippingPlane GLGizmosManager::get_clipping_plane() const
{
if (! m_common_gizmos_data
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index 06b0f69210..14654239c4 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -164,6 +164,8 @@ public:
enum MENU_ICON_NAME {
IC_TOOLBAR_RESET = 0,
IC_TOOLBAR_RESET_HOVER,
+ IC_TOOLBAR_RESET_ZERO,
+ IC_TOOLBAR_RESET_ZERO_HOVER,
IC_TOOLBAR_TOOLTIP,
IC_TOOLBAR_TOOLTIP_HOVER,
IC_NAME_COUNT,
@@ -261,6 +263,8 @@ public:
return nullptr;
}
+ bool is_paint_gizmo();
+ bool is_allow_select_all();
ClippingPlane get_clipping_plane() const;
ClippingPlane get_assemble_view_clipping_plane() const;
bool wants_reslice_supports_on_undo() const;
diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
index a1490ebc70..be2448e987 100644
--- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
+++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
@@ -6,8 +6,8 @@
//#include "I18N.hpp"
#include "GLGizmosManager.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
-
#include "slic3r/GUI/GUI_App.hpp"
+#include "slic3r/Utils/UndoRedo.hpp"
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/Model.hpp"
@@ -54,6 +54,24 @@ GizmoObjectManipulation::GizmoObjectManipulation(GLCanvas3D& glcanvas)
{
m_imperial_units = wxGetApp().app_config->get("use_inches") == "1";
m_new_unit_string = m_imperial_units ? L("in") : L("mm");
+
+ const wxString shift = "Shift+";
+ const wxString alt = GUI::shortkey_alt_prefix();
+ const wxString ctrl = GUI::shortkey_ctrl_prefix();
+ m_desc_move["part_selection_caption"] = alt + _L("Left mouse button");
+ m_desc_move["part_selection"] = _L("Part selection");
+ m_desc_move["snap_step_caption"] = shift + _L("Left mouse button");
+ m_desc_move["snap_step"] = _L("Fixed step drag");
+
+ m_desc_rotate["part_selection_caption"] = alt + _L("Left mouse button");
+ m_desc_rotate["part_selection"] = _L("Part selection");
+
+ m_desc_scale["part_selection_caption"] = alt + _L("Left mouse button");
+ m_desc_scale["part_selection"] = _L("Part selection");
+ m_desc_scale["snap_step_caption"] = shift + _L("Left mouse button");
+ m_desc_scale["snap_step"] = _L("Fixed step drag");
+ m_desc_scale["single_sided_caption"] = ctrl + _L("Left mouse button");
+ m_desc_scale["single_sided"] = _L("Single sided scaling");
}
void GizmoObjectManipulation::UpdateAndShow(const bool show)
@@ -74,31 +92,40 @@ void GizmoObjectManipulation::update_ui_from_settings()
update_buffered_value();
}
}
+void delete_negative_sign(Vec3d& value) {
+ for (size_t i = 0; i < value.size(); i++) {
+ if (abs(value[i]) < 0.001)
+ value[i] = 0.f;
+ }
+}
-void GizmoObjectManipulation::update_settings_value(const Selection& selection)
+void GizmoObjectManipulation::update_settings_value(const Selection &selection)
{
m_new_move_label_string = L("Position");
- m_new_rotate_label_string = L("Rotation");
+ m_new_rotate_label_string = L("Rotate (relative)");
+ m_new_rotation = Vec3d::Zero();
+ m_new_absolute_rotation = Vec3d::Zero();
m_new_scale_label_string = L("Scale ratios");
- m_coordinates_type = ECoordinatesType::World;
-
ObjectList* obj_list = wxGetApp().obj_list();
if (selection.is_single_full_instance()) {
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_first_volume();
m_new_position = volume->get_instance_offset();
-
- if (is_world_coordinates()) {
- m_new_rotate_label_string = L("Rotate");
- m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
- m_new_size = selection.get_scaled_instance_bounding_box().size();
- m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.;
- }
- else {
- m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
- m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
- m_new_scale = volume->get_instance_scaling_factor() * 100.;
+ auto rotation = volume->get_instance_transformation().get_rotation_by_quaternion();
+ m_new_absolute_rotation = rotation * (180. / M_PI);
+ delete_negative_sign(m_new_absolute_rotation);
+ if (is_world_coordinates()) {//for move and rotate
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_unscale_size = selection.get_unscaled_instance_bounding_box().size();
+ m_new_scale = m_new_size.cwiseQuotient(m_unscale_size) * 100.0;
+ }
+ else {//if (is_local_coordinates()) {//for scale
+ auto tran = selection.get_first_volume()->get_instance_transformation();
+ m_new_position = tran.get_matrix().inverse() * cs_center;
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_unscale_size = selection.get_full_unscaled_instance_local_bounding_box().size();
+ m_new_scale = m_new_size.cwiseQuotient(m_unscale_size) * 100.0;
}
m_new_enabled = true;
@@ -108,32 +135,48 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection)
else if (selection.is_single_full_object() && obj_list->is_selected(itObject)) {
const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center();
- m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(100., 100., 100.);
- m_new_size = box.size();
- m_new_rotate_label_string = L("Rotate");
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
m_new_scale_label_string = L("Scale");
m_new_enabled = true;
m_new_title_string = L("Object Operations");
- }
- else if (selection.is_single_modifier() || selection.is_single_volume()) {
- // the selection contains a single volume
- const GLVolume* volume = selection.get_first_volume();
- m_new_position = volume->get_volume_offset();
- m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
- m_new_scale = volume->get_volume_scaling_factor() * 100.;
- m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size()));
+ } else if (selection.is_single_volume_or_modifier()) {
+ const GLVolume *volume = selection.get_first_volume();
+ auto rotation = volume->get_volume_transformation().get_rotation_by_quaternion();
+ m_new_absolute_rotation = rotation * (180. / M_PI);
+ delete_negative_sign(m_new_absolute_rotation);
+ if (is_world_coordinates()) {//for move and rotate
+ const Geometry::Transformation trafo(volume->world_matrix());
+ const Vec3d &offset = trafo.get_offset();
+ m_new_position = offset;
+ m_new_scale = Vec3d(100.0, 100.0, 100.0);
+ m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ } else if (is_local_coordinates()) {//for scale
+ m_new_position = Vec3d::Zero();
+ m_new_scale = volume->get_volume_scaling_factor() * 100.0;
+ m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ } else {
+ m_new_position = volume->get_volume_offset();
+ m_new_scale_label_string = L("Scale");
+ m_new_scale = Vec3d(100.0, 100.0, 100.0);
+ m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ }
m_new_enabled = true;
m_new_title_string = L("Volume Operations");
- }
- else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
+ } else if (obj_list->is_connectors_item_selected() || obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
reset_settings_value();
m_new_move_label_string = L("Translate");
- m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale");
- m_new_size = selection.get_bounding_box().size();
+ m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
+ m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
m_new_enabled = true;
m_new_title_string = L("Group Operations");
+ } else if (selection.is_wipe_tower()) {
+ const BoundingBoxf3 &box = selection.get_bounding_box();
+ m_new_position = box.center();
}
else {
// No selection, reset the cache.
@@ -150,7 +193,7 @@ void GizmoObjectManipulation::update_buffered_value()
m_buffered_position = this->m_new_position;
m_buffered_rotation = this->m_new_rotation;
-
+ m_buffered_absolute_rotation = this->m_new_absolute_rotation;
m_buffered_scale = this->m_new_scale;
if (this->m_imperial_units)
@@ -176,6 +219,7 @@ void GizmoObjectManipulation::update_if_dirty()
};
update_label(m_cache.move_label_string, m_new_move_label_string);
update_label(m_cache.rotate_label_string, m_new_rotate_label_string);
+ update_label(m_cache.rotate_label_string, m_new_rotate_label_string);
update_label(m_cache.scale_label_string, m_new_scale_label_string);
enum ManipulationEditorKey
@@ -204,6 +248,7 @@ void GizmoObjectManipulation::update_if_dirty()
update(m_cache.scale, m_cache.scale_rounded, m_new_scale);
update(m_cache.size, m_cache.size_rounded, m_new_size);
update(m_cache.rotation, m_cache.rotation_rounded, m_new_rotation);
+ update(m_cache.absolute_rotation, m_cache.absolute_rotation_rounded, m_new_absolute_rotation);
}
update_reset_buttons_visibility();
@@ -216,8 +261,9 @@ void GizmoObjectManipulation::update_reset_buttons_visibility()
{
const Selection& selection = m_glcanvas.get_selection();
- if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
- const GLVolume* volume = selection.get_first_volume();
+ if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
+ const GLVolume * volume = selection.get_first_volume();
+
Vec3d rotation;
Vec3d scale;
double min_z = 0.;
@@ -231,8 +277,9 @@ void GizmoObjectManipulation::update_reset_buttons_visibility()
scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(volume);
}
- m_show_clear_rotation = !rotation.isApprox(Vec3d::Zero());
- m_show_clear_scale = !scale.isApprox(Vec3d::Ones(), EPSILON);
+ m_show_clear_rotation = !rotation.isApprox(m_init_rotation);
+ m_show_reset_0_rotation = !rotation.isApprox(Vec3d::Zero());
+ m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001;
m_show_drop_to_bed = (std::abs(min_z) > EPSILON);
}
}
@@ -242,6 +289,7 @@ void GizmoObjectManipulation::reset_settings_value()
{
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
+ m_new_absolute_rotation = Vec3d::Zero();
m_new_scale = Vec3d::Ones() * 100.;
m_new_size = Vec3d::Zero();
m_new_enabled = false;
@@ -262,11 +310,22 @@ void GizmoObjectManipulation::change_position_value(int axis, double value)
selection.setup_cache();
TransformationType trafo_type;
trafo_type.set_relative();
- if (selection.requires_local_axes()) {
+ switch (m_coordinates_type) {
+ case ECoordinatesType::Instance: {
trafo_type.set_instance();
+ break;
+ }
+ case ECoordinatesType::Local: {
+ trafo_type.set_local();
+ break;
+ }
+ default: {
+ break;
+ }
}
selection.translate(position - m_cache.position, trafo_type);
- m_glcanvas.do_move(L("Set Position"));
+ wxGetApp().plater()->take_snapshot("Set Position", UndoRedo::SnapshotType::GizmoAction);
+ m_glcanvas.do_move("");
m_cache.position = position;
m_cache.position_rounded(axis) = DBL_MAX;
@@ -287,38 +346,67 @@ void GizmoObjectManipulation::change_rotation_value(int axis, double value)
transformation_type.set_relative();
if (selection.is_single_full_instance())
transformation_type.set_independent();
-
if (is_local_coordinates())
transformation_type.set_local();
-
if (is_instance_coordinates())
transformation_type.set_instance();
selection.setup_cache();
- selection.rotate(
- (M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation),
- transformation_type);
- m_glcanvas.do_rotate(L("Set Orientation"));
+ selection.rotate((M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation), transformation_type);
+ wxGetApp().plater()->take_snapshot(_u8L("Set Orientation"), UndoRedo::SnapshotType::GizmoAction);
+ m_glcanvas.do_rotate("");
m_cache.rotation = rotation;
m_cache.rotation_rounded(axis) = DBL_MAX;
this->UpdateAndShow(true);
}
-void GizmoObjectManipulation::change_scale_value(int axis, double value)
-{
- if (std::abs(m_cache.scale_rounded(axis) - value) < EPSILON)
+void GizmoObjectManipulation::change_absolute_rotation_value(int axis, double value) {
+ if (std::abs(m_cache.absolute_rotation_rounded(axis) - value) < EPSILON)
return;
- Vec3d scale = m_cache.scale;
- if (scale[axis] != 0 && std::abs(m_cache.size[axis] * value / scale[axis]) > MAX_NUM) {
- scale[axis] *= MAX_NUM / m_cache.size[axis];
- }
- else {
- scale(axis) = value;
- }
+ Vec3d absolute_rotation = m_cache.absolute_rotation;
+ absolute_rotation(axis) = value;
- this->do_scale(axis, scale);
+ Selection &selection = m_glcanvas.get_selection();
+ TransformationType transformation_type;
+ transformation_type.set_relative();
+ if (selection.is_single_full_instance())
+ transformation_type.set_independent();
+ if (is_local_coordinates())
+ transformation_type.set_local();
+ if (is_instance_coordinates())
+ transformation_type.set_instance();
+
+ selection.setup_cache();
+ auto diff_rotation = transformation_type.absolute() ? absolute_rotation : absolute_rotation - m_cache.absolute_rotation;
+ selection.rotate((M_PI / 180.0) * diff_rotation, transformation_type);
+ wxGetApp().plater()->take_snapshot("set absolute orientation", UndoRedo::SnapshotType::GizmoAction);
+ m_glcanvas.do_rotate("");
+
+ m_cache.absolute_rotation = absolute_rotation;
+ m_cache.absolute_rotation_rounded(axis) = DBL_MAX;
+ this->UpdateAndShow(true);
+}
+
+void GizmoObjectManipulation::change_scale_value(int axis, double value)
+{
+ if (value <= 0.0)
+ return;
+ if (std::abs(m_cache.scale_rounded(axis) - value) < EPSILON) {
+ m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001;
+ return;
+ }
+ Vec3d scale = m_cache.scale;
+ scale(axis) = value;
+ Vec3d ref_scale = m_cache.scale;
+ const Selection &selection = m_glcanvas.get_selection();
+ if (selection.is_single_volume_or_modifier()) {
+ scale = scale.cwiseQuotient(ref_scale); // scale / ref_scale
+ ref_scale = Vec3d::Ones();
+ } else if (selection.is_single_full_instance())
+ ref_scale = 100 * Vec3d::Ones();
+ this->do_scale(axis, scale.cwiseQuotient(ref_scale));
m_cache.scale = scale;
m_cache.scale_rounded(axis) = DBL_MAX;
@@ -328,6 +416,8 @@ void GizmoObjectManipulation::change_scale_value(int axis, double value)
void GizmoObjectManipulation::change_size_value(int axis, double value)
{
+ if (value <= 0.0)
+ return;
if (std::abs(m_cache.size_rounded(axis) - value) < EPSILON)
return;
@@ -337,17 +427,17 @@ void GizmoObjectManipulation::change_size_value(int axis, double value)
const Selection& selection = m_glcanvas.get_selection();
Vec3d ref_size = m_cache.size;
- if (selection.is_single_volume() || selection.is_single_modifier()) {
- Vec3d instance_scale = wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->instances[0]->get_transformation().get_scaling_factor();
- ref_size = selection.get_first_volume()->bounding_box().size();
- ref_size = Vec3d(instance_scale[0] * ref_size[0], instance_scale[1] * ref_size[1], instance_scale[2] * ref_size[2]);
+ if (selection.is_single_volume_or_modifier()) {
+ size = size.cwiseQuotient(ref_size);
+ ref_size = Vec3d::Ones();
+ } else if (selection.is_single_full_instance()) {
+ if (is_world_coordinates())
+ ref_size = selection.get_full_unscaled_instance_bounding_box().size();
+ else
+ ref_size = selection.get_full_unscaled_instance_local_bounding_box().size();
}
- else if (selection.is_single_full_instance())
- ref_size = is_world_coordinates() ?
- selection.get_unscaled_instance_bounding_box().size() :
- wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size();
- this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
+ this->do_scale(axis, size.cwiseQuotient(ref_size));
m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX;
@@ -357,25 +447,33 @@ void GizmoObjectManipulation::change_size_value(int axis, double value)
void GizmoObjectManipulation::do_scale(int axis, const Vec3d &scale) const
{
Selection& selection = m_glcanvas.get_selection();
- Vec3d scaling_factor = scale;
- TransformationType transformation_type(TransformationType::World_Relative_Joint);
- if (selection.is_single_full_instance()) {
- transformation_type.set_absolute();
- if (! is_world_coordinates())
- transformation_type.set_local();
- }
+ TransformationType transformation_type;
+ if (is_local_coordinates())
+ transformation_type.set_local();
+ else if (is_instance_coordinates())
+ transformation_type.set_instance();
+ if (selection.is_single_volume_or_modifier() && !is_local_coordinates())
+ transformation_type.set_relative();
- // BBS: when select multiple objects, uniform scale can be deselected
- if (m_uniform_scale/* || selection.requires_uniform_scale()*/)
- scaling_factor = scale(axis) * Vec3d::Ones();
+ Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
+ limit_scaling_ratio(scaling_factor);
selection.setup_cache();
- selection.scale_legacy(scaling_factor * 0.01, transformation_type);
+ selection.scale(scaling_factor, transformation_type);
m_glcanvas.do_scale(L("Set Scale"));
}
-void GizmoObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
+
+void GizmoObjectManipulation::limit_scaling_ratio(Vec3d &scaling_factor) const{
+ for (size_t i = 0; i < scaling_factor.size(); i++) { // range protect //scaling_factor too big has problem
+ if (scaling_factor[i] * m_unscale_size[i] > MAX_NUM) {
+ scaling_factor[i] = MAX_NUM / m_unscale_size[i];
+ }
+ }
+}
+
+void GizmoObjectManipulation::on_change(const std::string &opt_key, int axis, double new_value)
{
if (!m_cache.is_valid())
return;
@@ -387,55 +485,42 @@ void GizmoObjectManipulation::on_change(const std::string& opt_key, int axis, do
change_position_value(axis, new_value);
else if (opt_key == "rotation")
change_rotation_value(axis, new_value);
+ else if (opt_key == "absolute_rotation")
+ change_absolute_rotation_value(axis, new_value);
else if (opt_key == "scale")
change_scale_value(axis, new_value);
else if (opt_key == "size")
change_size_value(axis, new_value);
}
-void GizmoObjectManipulation::set_uniform_scaling(const bool new_value)
-{
- const Selection &selection = m_glcanvas.get_selection();
- if (selection.is_single_full_instance() && is_world_coordinates() && !new_value) {
- // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
- // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
- const GLVolume* volume = selection.get_first_volume();
- // Is the angle close to a multiple of 90 degrees?
+bool GizmoObjectManipulation::render_combo(
+ ImGuiWrapper *imgui_wrapper, const std::string &label, const std::vector &lines, size_t &selection_idx, float label_width, float item_width)
+{
+ ImGui::AlignTextToFramePadding();
+ imgui_wrapper->text(label);
+ ImGui::SameLine(label_width);
+ ImGui::PushItemWidth(item_width);
- if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
- // Cannot apply scaling in the world coordinate system.
- // BBS: remove tilt prompt dialog
+ size_t selection_out = selection_idx;
- // Bake the rotation into the meshes of the object.
- wxGetApp().model().objects[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
- // Update the 3D scene, selections etc.
- wxGetApp().plater()->update();
- // Recalculate cached values at this panel, refresh the screen.
- this->UpdateAndShow(true);
+ const char *selected_str = (selection_idx >= 0 && selection_idx < int(lines.size())) ? lines[selection_idx].c_str() : "";
+ if (ImGui::BBLBeginCombo(("##" + label).c_str(), selected_str, 0)) {
+ for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
+ ImGui::PushID(int(line_idx));
+ if (ImGui::Selectable("", line_idx == selection_idx)) selection_out = line_idx;
+
+ ImGui::SameLine();
+ ImGui::Text("%s", lines[line_idx].c_str());
+ ImGui::PopID();
}
+
+ ImGui::EndCombo();
}
- m_uniform_scale = new_value;
-}
-void GizmoObjectManipulation::set_coordinates_type(ECoordinatesType type)
-{
- if (wxGetApp().get_mode() == comSimple)
- type = ECoordinatesType::World;
+ bool is_changed = selection_idx != selection_out;
+ selection_idx = selection_out;
- if (m_coordinates_type == type)
- return;
-
- m_coordinates_type = type;
- this->UpdateAndShow(true);
- GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
- canvas->get_gizmos_manager().update_data();
- canvas->set_as_dirty();
- canvas->request_extra_frame();
-}
-
-ECoordinatesType GizmoObjectManipulation::get_coordinates_type() const
-{
- return m_coordinates_type;
+ return is_changed;
}
void GizmoObjectManipulation::reset_position_value()
@@ -456,30 +541,45 @@ void GizmoObjectManipulation::reset_position_value()
return;
// Copy position values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
- m_glcanvas.do_move(L("Reset Position"));
+ wxGetApp().plater()->take_snapshot(_u8L("Reset Position"), UndoRedo::SnapshotType::GizmoAction);
+ m_glcanvas.do_move("");
UpdateAndShow(true);
}
-void GizmoObjectManipulation::reset_rotation_value()
+void GizmoObjectManipulation::reset_rotation_value(bool reset_relative)
{
- Selection& selection = m_glcanvas.get_selection();
-
- if (selection.is_single_volume() || selection.is_single_modifier()) {
- GLVolume* volume = const_cast(selection.get_first_volume());
- volume->set_volume_rotation(Vec3d::Zero());
- }
- else if (selection.is_single_full_instance()) {
- for (unsigned int idx : selection.get_volume_idxs()) {
- GLVolume* volume = const_cast(selection.get_volume(idx));
- volume->set_instance_rotation(Vec3d::Zero());
+ Selection &selection = m_glcanvas.get_selection();
+ selection.setup_cache();
+ if (selection.is_single_volume_or_modifier()) {
+ GLVolume * vol = const_cast(selection.get_first_volume());
+ Geometry::Transformation trafo = vol->get_volume_transformation();
+ if (reset_relative) {
+ auto offset = trafo.get_offset();
+ trafo.set_matrix(m_init_rotation_scale_tran);
+ trafo.set_offset(offset);
}
- }
- else
+ else {
+ trafo.reset_rotation();
+ }
+ vol->set_volume_transformation(trafo);
+ } else if (selection.is_single_full_instance()) {
+ Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation();
+ if (reset_relative) {
+ auto offset = trafo.get_offset();
+ trafo.set_matrix(m_init_rotation_scale_tran);
+ trafo.set_offset(offset);
+ } else {
+ trafo.reset_rotation();
+ }
+ for (unsigned int idx : selection.get_volume_idxs()) {
+ const_cast(selection.get_volume(idx))->set_instance_transformation(trafo);
+ }
+ } else
return;
+ // Synchronize instances/volumes.
- // Update rotation at the GLVolumes.
- selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
+ selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET);
selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
m_glcanvas.do_rotate(L("Reset Rotation"));
@@ -496,9 +596,37 @@ void GizmoObjectManipulation::reset_scale_value()
change_scale_value(2, 100.);
}
-static const char* label_values[2][3] = {
+void GizmoObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
+{
+ if (!use_uniform_scale)
+ // Recalculate cached values at this panel, refresh the screen.
+ this->UpdateAndShow(true);
+
+ m_uniform_scale = use_uniform_scale;
+ set_dirty();
+}
+
+void GizmoObjectManipulation::set_coordinates_type(ECoordinatesType type)
+{
+ /*if (wxGetApp().get_mode() == comSimple)
+ type = ECoordinatesType::World;*/
+
+ if (m_coordinates_type == type) return;
+
+ m_coordinates_type = type;
+ //m_word_local_combo->SetSelection((int) m_coordinates_type);
+ this->UpdateAndShow(true);
+ GLCanvas3D *canvas = wxGetApp().plater()->canvas3D();
+ canvas->get_gizmos_manager().update_data();
+ canvas->set_as_dirty();
+ canvas->request_extra_frame();
+
+}
+
+static const char* label_values[3][3] = {
{ "##position_x", "##position_y", "##position_z"},
-{ "##rotation_x", "##rotation_y", "##rotation_z"}
+{ "##rotation_x", "##rotation_y", "##rotation_z"},
+{ "##absolute_rotation_x", "##absolute_rotation_y", "##absolute_rotation_z"}
};
static const char* label_scale_values[2][3] = {
@@ -523,6 +651,23 @@ bool GizmoObjectManipulation::reset_button(ImGuiWrapper *imgui_wrapper, float ca
return pressed;
}
+bool GizmoObjectManipulation::reset_zero_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size)
+{
+ bool pressed = false;
+ ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_RESET_ZERO);
+ ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_RESET_ZERO_HOVER);
+
+ float font_size = ImGui::GetFontSize() * 1.1;
+ ImVec2 button_size = ImVec2(font_size, font_size);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+
+ pressed = ImGui::ImageButton3(normal_id, hover_id, button_size);
+
+ ImGui::PopStyleVar(1);
+ return pressed;
+}
+
float GizmoObjectManipulation::max_unit_size(int number, Vec3d &vec1, Vec3d &vec2,std::string str)
{
if (number <= 1) return -1;
@@ -546,6 +691,111 @@ bool GizmoObjectManipulation::reset_button(ImGuiWrapper *imgui_wrapper, float ca
return unit_size + 8.0;
}
+ bool GizmoObjectManipulation::bbl_checkbox(const wxString &label, bool &value)
+{
+ bool result;
+ bool b_value = value;
+ if (b_value) {
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ }
+ auto label_utf8 = into_u8(label);
+ result = ImGui::BBLCheckbox(label_utf8.c_str(), &value);
+
+ if (b_value) { ImGui::PopStyleColor(3); }
+ return result;
+}
+
+void GizmoObjectManipulation::show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
+{
+ ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
+ ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
+
+ caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
+
+ float scale = m_glcanvas.get_scale();
+ ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
+ ImGui::ImageButton3(normal_id, hover_id, button_size);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip2(ImVec2(x, y));
+ auto draw_text_with_caption = [this, &imgui_wrapper,& caption_max](const wxString &caption, const wxString &text) {
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
+ ImGui::SameLine(caption_max);
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
+ };
+
+ for (const auto &t : std::array{"part_selection", "snap_step"})
+ draw_text_with_caption(m_desc_move.at(t + "_caption") + ": ", m_desc_move.at(t));
+ ImGui::EndTooltip();
+ }
+ ImGui::PopStyleVar(2);
+}
+
+void GizmoObjectManipulation::show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
+{
+ ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
+ ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
+
+ caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
+
+ float scale = m_glcanvas.get_scale();
+ ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
+ ImGui::ImageButton3(normal_id, hover_id, button_size);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip2(ImVec2(x, y));
+ auto draw_text_with_caption = [this, &imgui_wrapper, &caption_max](const wxString &caption, const wxString &text) {
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
+ ImGui::SameLine(caption_max);
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
+ };
+
+ for (const auto &t : std::array{"part_selection"})
+ draw_text_with_caption(m_desc_rotate.at(t + "_caption") + ": ", m_desc_rotate.at(t));
+ ImGui::EndTooltip();
+ }
+ ImGui::PopStyleVar(2);
+}
+
+void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y)
+{
+ ImTextureID normal_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
+ ImTextureID hover_id = m_glcanvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
+
+ caption_max += imgui_wrapper->calc_text_size(": "sv).x + 35.f;
+
+ float scale = m_glcanvas.get_scale();
+ ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
+ ImGui::ImageButton3(normal_id, hover_id, button_size);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip2(ImVec2(x, y));
+ auto draw_text_with_caption = [this, &imgui_wrapper, &caption_max](const wxString &caption, const wxString &text) {
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
+ ImGui::SameLine(caption_max);
+ imgui_wrapper->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
+ };
+
+ for (const auto &t : std::array{"part_selection", "snap_step", "single_sided"})
+ draw_text_with_caption(m_desc_scale.at(t + "_caption") + ": ", m_desc_scale.at(t));
+ ImGui::EndTooltip();
+ }
+ ImGui::PopStyleVar(2);
+}
+
+void GizmoObjectManipulation::set_init_rotation(const Geometry::Transformation &value) {
+ m_init_rotation_scale_tran = value.get_matrix_no_offset();
+ m_init_rotation = value.get_rotation();
+}
+
void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit)
{
// BBS: GUI refactor: move gizmo to the right
@@ -584,13 +834,7 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
float space_size = imgui_wrapper->get_style_scaling() * 8;
float position_size = imgui_wrapper->calc_text_size(_L("Position")).x + space_size;
- auto position_title = _L("World coordinates");
- Selection& selection = m_glcanvas.get_selection();
- if(selection.is_single_modifier() || selection.is_single_volume())
- position_title = _L("Object coordinates");
-
- float World_size = imgui_wrapper->calc_text_size(position_title).x + space_size;
- float caption_max = std::max(position_size, World_size) + 2 * space_size;
+ float caption_max = imgui_wrapper->calc_text_size(_L("Object coordinates")).x + 2 * space_size;
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
// position
@@ -602,15 +846,34 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
Vec3d display_position = m_buffered_position;
// Rotation
- Vec3d rotation = this->m_buffered_rotation;
float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size;
int index = 1;
int index_unit = 1;
ImGui::AlignTextToFramePadding();
unsigned int current_active_id = ImGui::GetActiveID();
- ImGui::PushItemWidth(caption_max);
- imgui_wrapper->text(position_title);
+
+ Selection & selection = m_glcanvas.get_selection();
+ std::vector modes = {_u8L("World coordinates"), _u8L("Object coordinates")};//_u8L("Part coordinates")
+ if (selection.is_multiple_full_object() || selection.is_wipe_tower()) {
+ modes.pop_back();
+ }
+ size_t selection_idx = (int) m_coordinates_type;
+ if (selection_idx >= modes.size()) {
+ set_coordinates_type(ECoordinatesType::World);
+ selection_idx = 0;
+ }
+
+ float caption_cs_size = imgui_wrapper->calc_text_size(""sv).x;
+ float caption_size = caption_cs_size + 2 * space_size;
+ float combox_content_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x * 1.2 + imgui_wrapper->calc_text_size("xxx"sv).x + imgui_wrapper->scaled(3);
+ ImGuiWrapper::push_combo_style(m_glcanvas.get_scale());
+ bool combox_changed = false;
+ if (render_combo(imgui_wrapper, "", modes, selection_idx, caption_size, combox_content_size)) {
+ combox_changed = true;
+ }
+ ImGuiWrapper::pop_combo_style();
+ caption_max = combox_content_size - 4 * space_size;
ImGui::SameLine(caption_max + index * space_size);
ImGui::PushItemWidth(unit_size);
ImGui::TextAlignCenter("X");
@@ -636,15 +899,22 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
ImGui::BBLInputDouble(label_values[0][2], &display_position[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
imgui_wrapper->text(this->m_new_unit_string);
-
- for (int i = 0;i MAX_NUM)display_position[i] = MAX_NUM;
- if (display_position[i] < -MAX_NUM)display_position[i] = -MAX_NUM;
+ bool is_avoid_one_update{false};
+ if (combox_changed) {
+ combox_changed = false;
+ set_coordinates_type((ECoordinatesType) selection_idx);
+ UpdateAndShow(true);
+ is_avoid_one_update = true; // avoid update(current_active_id, "position", original_position
}
- m_buffered_position = display_position;
- update(current_active_id, "position", original_position, m_buffered_position);
+ if (!is_avoid_one_update) {
+ for (int i = 0; i < display_position.size(); i++) {
+ if (display_position[i] > MAX_NUM) display_position[i] = MAX_NUM;
+ if (display_position[i] < -MAX_NUM) display_position[i] = -MAX_NUM;
+ }
+ m_buffered_position = display_position;
+ update(current_active_id, "position", original_position, m_buffered_position);
+ }
// the init position values are not zero, won't add reset button
// send focus to m_glcanvas
@@ -658,7 +928,14 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
}
}
if (!focued_on_text) m_glcanvas.handle_sidebar_focus_event("", false);
-
+ float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
+ float tip_caption_max = 0.f;
+ float total_text_max = 0.f;
+ for (const auto &t : std::array{"part_selection", "snap_step"}) {
+ tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_move[t + "_caption"]).x);
+ total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_move[t]).x);
+ }
+ show_move_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
m_last_active_item = current_active_id;
last_move_input_window_width = ImGui::GetWindowWidth();
imgui_wrapper->end();
@@ -703,7 +980,7 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
};
float space_size = imgui_wrapper->get_style_scaling() * 8;
- float position_size = imgui_wrapper->calc_text_size(_L("Rotation")).x + space_size;
+ float position_size = imgui_wrapper->calc_text_size(_L("Rotate (relative)")).x + space_size;
float World_size = imgui_wrapper->calc_text_size(_L("World coordinates")).x + space_size;
float caption_max = std::max(position_size, World_size) + 2 * space_size;
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
@@ -717,7 +994,7 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
Vec3d display_position = m_buffered_position;
// Rotation
Vec3d rotation = this->m_buffered_rotation;
-
+ Vec3d absolute_rotation = this->m_buffered_absolute_rotation;
float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size;
int index = 1;
int index_unit = 1;
@@ -740,30 +1017,50 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
index_unit = 1;
// ImGui::PushItemWidth(unit_size * 2);
+ bool is_relative_input = false;
ImGui::AlignTextToFramePadding();
- imgui_wrapper->text(_L("Rotation"));
+ imgui_wrapper->text(_L("Rotate (relative)"));
ImGui::SameLine(caption_max + index * space_size);
ImGui::PushItemWidth(unit_size);
- ImGui::BBLInputDouble(label_values[1][0], &rotation[0], 0.0f, 0.0f, "%.2f");
+ if (ImGui::BBLInputDouble(label_values[1][0], &rotation[0], 0.0f, 0.0f, "%.2f")) {
+ is_relative_input = true;
+ }
ImGui::SameLine(caption_max + unit_size + (++index) * space_size);
ImGui::PushItemWidth(unit_size);
- ImGui::BBLInputDouble(label_values[1][1], &rotation[1], 0.0f, 0.0f, "%.2f");
+ if (ImGui::BBLInputDouble(label_values[1][1], &rotation[1], 0.0f, 0.0f, "%.2f")) {
+ is_relative_input = true;
+ }
ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
ImGui::PushItemWidth(unit_size);
- ImGui::BBLInputDouble(label_values[1][2], &rotation[2], 0.0f, 0.0f, "%.2f");
+ if (ImGui::BBLInputDouble(label_values[1][2], &rotation[2], 0.0f, 0.0f, "%.2f")) {
+ is_relative_input = true;
+ }
ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
imgui_wrapper->text(_L("°"));
m_buffered_rotation = rotation;
- update(current_active_id, "rotation", this->m_new_rotation, m_buffered_rotation);
+ if (is_relative_input) {
+ m_last_rotate_type = RotateType::Relative;
+ }
+ if (m_last_rotate_type == RotateType::Relative) {
+ bool is_valid = update(current_active_id, "rotation", this->m_new_rotation, m_buffered_rotation) >= 0;
+ if (is_valid) {
+ m_last_rotate_type = RotateType::None;
+ }
+ }
if (m_show_clear_rotation) {
ImGui::SameLine(caption_max + 3 * unit_size + 4 * space_size + end_text_size);
- if (reset_button(imgui_wrapper, caption_max, unit_size, space_size, end_text_size)) { reset_rotation_value(); }
+ if (reset_button(imgui_wrapper, caption_max, unit_size, space_size, end_text_size)) {
+ reset_rotation_value(true);
+ }
+ if (ImGui::IsItemHovered()) {
+ float tooltip_size = imgui_wrapper->calc_text_size(_L("Reset current rotation to the value when open the rotation tool.")).x + 3 * space_size;
+ imgui_wrapper->tooltip(_u8L("Reset current rotation to the value when open the rotation tool."), tooltip_size);
+ }
} else {
ImGui::SameLine(caption_max + 3 * unit_size + 5 * space_size + end_text_size);
ImGui::InvisibleButton("", ImVec2(ImGui::GetFontSize(), ImGui::GetFontSize()));
}
-
// send focus to m_glcanvas
bool focued_on_text = false;
for (int j = 0; j < 3; j++) {
@@ -774,8 +1071,69 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe
break;
}
}
- if (!focued_on_text) m_glcanvas.handle_sidebar_focus_event("", false);
+ index = 1;
+ index_unit = 1;
+ ImGui::AlignTextToFramePadding();
+ imgui_wrapper->text(_L("Rotate (absolute)"));
+ ImGui::SameLine(caption_max + index * space_size);
+ ImGui::PushItemWidth(unit_size);
+ bool is_absolute_input = false;
+ if (ImGui::BBLInputDouble(label_values[2][0], &absolute_rotation[0], 0.0f, 0.0f, "%.2f")) {
+ is_absolute_input = true;
+ }
+ ImGui::SameLine(caption_max + unit_size + (++index) * space_size);
+ ImGui::PushItemWidth(unit_size);
+ if (ImGui::BBLInputDouble(label_values[2][1], &absolute_rotation[1], 0.0f, 0.0f, "%.2f")) {
+ is_absolute_input = true;
+ }
+ ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
+ ImGui::PushItemWidth(unit_size);
+ if (ImGui::BBLInputDouble(label_values[2][2], &absolute_rotation[2], 0.0f, 0.0f, "%.2f")) {
+ is_absolute_input = true;
+ }
+ ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size);
+ imgui_wrapper->text(_L("°"));
+ m_buffered_absolute_rotation = absolute_rotation;
+ if (is_absolute_input) {
+ m_last_rotate_type = RotateType::Absolute;
+ }
+ if (m_last_rotate_type == RotateType::Absolute) {
+ bool is_valid = update(current_active_id, "absolute_rotation", this->m_new_absolute_rotation, m_buffered_absolute_rotation) >= 0;
+ if (is_valid) {
+ m_last_rotate_type = RotateType::None;
+ }
+ }
+
+ if (m_show_reset_0_rotation) {
+ ImGui::SameLine(caption_max + 3 * unit_size + 4 * space_size + end_text_size);
+ if (reset_zero_button(imgui_wrapper, caption_max, unit_size, space_size, end_text_size)) { reset_rotation_value(false); }
+ if (ImGui::IsItemHovered()) {
+ float tooltip_size = imgui_wrapper->calc_text_size(_L("Reset current rotation to real zeros.")).x + 3 * space_size;
+ imgui_wrapper->tooltip(_L("Reset current rotation to real zeros."), tooltip_size);
+ }
+ }
+ // send focus to m_glcanvas
+ bool absolute_focued_on_text = false;
+ for (int j = 0; j < 3; j++) {
+ unsigned int id = ImGui::GetID(label_values[2][j]);
+ if (current_active_id == id) {
+ m_glcanvas.handle_sidebar_focus_event(label_values[2][j] + 2, true);
+ absolute_focued_on_text = true;
+ break;
+ }
+ }
+ if (!focued_on_text && !absolute_focued_on_text)
+ m_glcanvas.handle_sidebar_focus_event("", false);
+
+ float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
+ float tip_caption_max = 0.f;
+ float total_text_max = 0.f;
+ for (const auto &t : std::array{"part_selection"}) {
+ tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_move[t + "_caption"]).x);
+ total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_move[t]).x);
+ }
+ show_rotate_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
m_last_active_item = current_active_id;
last_rotate_input_window_width = ImGui::GetWindowWidth();
imgui_wrapper->end();
@@ -826,8 +1184,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
float space_size = imgui_wrapper->get_style_scaling() * 8;
float scale_size = imgui_wrapper->calc_text_size(_L("Scale")).x + space_size;
- float size_len = imgui_wrapper->calc_text_size(_L("Size")).x + space_size;
- float caption_max = std::max(scale_size, size_len) + 2 * space_size;
+ float caption_max = imgui_wrapper->calc_text_size(_L("Object coordinates")).x + 2 * space_size;
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
ImGui::AlignTextToFramePadding();
unsigned int current_active_id = ImGui::GetActiveID();
@@ -843,10 +1200,30 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
int index = 2;
int index_unit = 1;
- ImGui::PushItemWidth(caption_max);
- ImGui::Dummy(ImVec2(caption_max, -1));
- //imgui_wrapper->text(_L(" "));
- //ImGui::PushItemWidth(unit_size * 1.5);
+ Selection & selection = m_glcanvas.get_selection();
+ std::vector modes = {_u8L("World coordinates"), _u8L("Object coordinates"), _u8L("Part coordinates")};
+ if (selection.is_single_full_object()) { modes.pop_back(); }
+ if (selection.is_multiple_full_object()) {
+ modes.pop_back();
+ modes.pop_back();
+ }
+ size_t selection_idx = (int) m_coordinates_type;
+ if (selection_idx >= modes.size()) {
+ set_coordinates_type(ECoordinatesType::World);
+ selection_idx = 0;
+ }
+
+ float caption_cs_size = imgui_wrapper->calc_text_size(""sv).x;
+ float caption_size = caption_cs_size + 2 * space_size;
+ float combox_content_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x * 1.2 + imgui_wrapper->calc_text_size("xxx"sv).x + imgui_wrapper->scaled(3);
+ ImGuiWrapper::push_combo_style(m_glcanvas.get_scale());
+ bool combox_changed = false;
+ if (render_combo(imgui_wrapper, "", modes, selection_idx, caption_size, combox_content_size)) {
+ combox_changed = true;
+ }
+ ImGuiWrapper::pop_combo_style();
+ caption_max = combox_content_size - 4 * space_size;
+ //ImGui::Dummy(ImVec2(caption_max, -1));
ImGui::SameLine(caption_max + space_size);
ImGui::PushItemWidth(unit_size);
ImGui::TextAlignCenter("X");
@@ -874,7 +1251,9 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::BBLInputDouble(label_scale_values[0][2], &scale[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size);
imgui_wrapper->text(_L("%"));
- m_buffered_scale = scale;
+ if (scale.x() > 0 && scale.y() > 0 && scale.z() > 0) {
+ m_buffered_scale = scale;
+ }
if (m_show_clear_scale) {
ImGui::SameLine(caption_max + 3 * unit_size + 4 * space_size + end_text_size);
@@ -908,17 +1287,31 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
ImGui::BBLInputDouble(label_scale_values[1][2], &display_size[2], 0.0f, 0.0f, "%.2f");
ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size);
imgui_wrapper->text(this->m_new_unit_string);
-
- for (int i = 0;i MAX_NUM) display_size[i] = MAX_NUM;
+ for (int i = 0; i < display_size.size(); i++) {
+ if (std::abs(display_size[i]) > MAX_NUM) {
+ display_size[i] = MAX_NUM;
+ }
+ }
+ if (display_size.x() > 0 && display_size.y() > 0 && display_size.z() > 0) {
+ m_buffered_size = display_size;
}
- m_buffered_size = display_size;
- int size_sel = update(current_active_id, "size", original_size, m_buffered_size);
- ImGui::PopStyleVar(1);
-
ImGui::Separator();
+ ImGui::AlignTextToFramePadding();
+ bool is_avoid_one_update{false};
+ if (combox_changed) {
+ combox_changed = false;
+ set_coordinates_type((ECoordinatesType) selection_idx);
+ UpdateAndShow(true);
+ is_avoid_one_update = true;
+ }
+ auto uniform_scale_size =imgui_wrapper->calc_text_size(_L("uniform scale")).x;
+ ImGui::PushItemWidth(uniform_scale_size);
+ int size_sel{-1};
+ if (!is_avoid_one_update) {
+ size_sel = update(current_active_id, "size", original_size, m_buffered_size);
+ }
+ ImGui::PopStyleVar(1);
bool uniform_scale = this->m_uniform_scale;
// BBS: when select multiple objects, uniform scale can be deselected
@@ -959,9 +1352,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
}
}
-
-
-
//send focus to m_glcanvas
bool focued_on_text = false;
for (int i = 0; i < 2; i++)
@@ -977,7 +1367,14 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
}
if (!focued_on_text)
m_glcanvas.handle_sidebar_focus_event("", false);
-
+ float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
+ float tip_caption_max = 0.f;
+ float total_text_max = 0.f;
+ for (const auto &t : std::array{"part_selection", "snap_step", "single_sided"}) {
+ tip_caption_max = std::max(tip_caption_max, imgui_wrapper->calc_text_size(m_desc_scale[t + "_caption"]).x);
+ total_text_max = std::max(total_text_max, imgui_wrapper->calc_text_size(m_desc_scale[t]).x);
+ }
+ show_scale_tooltip_information(imgui_wrapper, tip_caption_max, x, get_cur_y);
m_last_active_item = current_active_id;
last_scale_input_window_width = ImGui::GetWindowWidth();
diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp
index 3a3dc145ce..2f8b03c160 100644
--- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp
+++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp
@@ -4,6 +4,7 @@
#include
#include "libslic3r/Point.hpp"
+#include "libslic3r/Geometry.hpp"
#include
#include "slic3r/GUI/GUI_Geometry.hpp"
@@ -30,6 +31,8 @@ public:
Vec3d position_rounded;
Vec3d rotation;
Vec3d rotation_rounded;
+ Vec3d absolute_rotation;
+ Vec3d absolute_rotation_rounded;
Vec3d scale;
Vec3d scale_rounded;
Vec3d size;
@@ -56,7 +59,7 @@ public:
Cache m_cache;
bool m_imperial_units { false };
-
+ bool m_use_object_cs{false};
// Mirroring buttons and their current state
//enum MirrorButtonState {
// mbHidden,
@@ -75,19 +78,28 @@ public:
std::string m_new_unit_string;
Vec3d m_new_position;
Vec3d m_new_rotation;
+ Vec3d m_new_absolute_rotation;
Vec3d m_new_scale;
Vec3d m_new_size;
+ Vec3d m_unscale_size;
Vec3d m_buffered_position;
Vec3d m_buffered_rotation;
+ Vec3d m_buffered_absolute_rotation;
Vec3d m_buffered_scale;
Vec3d m_buffered_size;
+ Vec3d cs_center;
bool m_new_enabled {true};
bool m_uniform_scale {true};
- ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
+ // Does the object manipulation panel work in World or Local coordinates?
+ ECoordinatesType m_coordinates_type{ECoordinatesType::World};
+ bool m_show_reset_0_rotation{false};
bool m_show_clear_rotation { false };
bool m_show_clear_scale { false };
bool m_show_drop_to_bed { false };
+ enum class RotateType { None, Relative, Absolute
+ };
+ RotateType m_last_rotate_type{RotateType::None}; // 0:no input 1:relative 2:absolute
protected:
float last_move_input_window_width = 0.0f;
@@ -108,21 +120,33 @@ public:
void set_uniform_scaling(const bool uniform_scale);
bool get_uniform_scaling() const { return m_uniform_scale; }
+ void set_use_object_cs(bool flag){ if (m_use_object_cs != flag) m_use_object_cs = flag; }
+ bool get_use_object_cs() { return m_use_object_cs; }
+ // Does the object manipulation panel work in World or Local coordinates?
+ void set_coordinates_type(ECoordinatesType type);
+ ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
+ bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
+ bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
+ bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
- void set_coordinates_type(ECoordinatesType type);
- ECoordinatesType get_coordinates_type() const;
- bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
- bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
- bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
-
+ const Cache& get_cache() {return m_cache; }
void reset_cache() { m_cache.reset(); }
+ void limit_scaling_ratio(Vec3d &scaling_factor) const;
void on_change(const std::string& opt_key, int axis, double new_value);
+ bool render_combo(ImGuiWrapper *imgui_wrapper, const std::string &label, const std::vector &lines, size_t &selection_idx, float label_width, float item_width);
void do_render_move_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit);
void do_render_rotate_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit);
void do_render_scale_input_window(ImGuiWrapper* imgui_wrapper, std::string window_name, float x, float y, float bottom_limit);
float max_unit_size(int number, Vec3d &vec1, Vec3d &vec2,std::string str);
bool reset_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size);
+ bool reset_zero_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size);
+ bool bbl_checkbox(const wxString &label, bool &value);
+
+ void show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
+ void show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
+ void show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
+ void set_init_rotation(const Geometry::Transformation &value);
private:
void reset_settings_value();
@@ -134,18 +158,24 @@ private:
//Show or hide mirror buttons
//void update_mirror_buttons_visibility();
- // change values
+ // change values
void change_position_value(int axis, double value);
void change_rotation_value(int axis, double value);
+ void change_absolute_rotation_value(int axis, double value);
void change_scale_value(int axis, double value);
void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const;
void reset_position_value();
- void reset_rotation_value();
+ void reset_rotation_value(bool reset_relative);
void reset_scale_value();
GLCanvas3D& m_glcanvas;
unsigned int m_last_active_item { 0 };
+ std::map m_desc_move;
+ std::map m_desc_rotate;
+ std::map m_desc_scale;
+ Vec3d m_init_rotation;
+ Transform3d m_init_rotation_scale_tran;
};
}}
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index 68f1387492..9b6d97443a 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -401,6 +401,39 @@ void Selection::remove_volumes(EMode mode, const std::vector& volu
this->set_bounding_boxes_dirty();
}
+ModelVolume *Selection::get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const
+{
+ if (is_single_volume() || is_single_modifier()) {
+ const GLVolume *gl_volume = get_first_volume();
+ out_object_idx = gl_volume->object_idx();
+ ModelObject *model_object = get_model()->objects[out_object_idx];
+ out_volume_idx = gl_volume->volume_idx();
+ if (out_volume_idx < model_object->volumes.size())
+ return model_object->volumes[out_volume_idx];
+ }
+ return nullptr;
+}
+
+ModelObject *Selection::get_selected_single_object(int &out_object_idx) const
+{
+ if (is_single_volume() || is_single_modifier() || is_single_full_object()) {
+ const GLVolume *gl_volume = get_first_volume();
+ out_object_idx = gl_volume->object_idx();
+ return get_model()->objects[out_object_idx];
+ }
+ return nullptr;
+}
+
+const ModelInstance *Selection::get_selected_single_intance() const
+{
+ int object_idx;
+ auto mo = get_selected_single_object(object_idx);
+ if (mo) {
+ return mo->instances[get_instance_idx()];
+ }
+ return nullptr;
+}
+
void Selection::add_curr_plate()
{
if (!m_valid)
@@ -910,17 +943,17 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
return *m_scaled_instance_bounding_box;
}
-const BoundingBoxf3& Selection::get_full_unscaled_instance_bounding_box() const
+const BoundingBoxf3 &Selection::get_full_unscaled_instance_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_unscaled_instance_bounding_box.has_value()) {
- std::optional* bbox = const_cast*>(&m_full_unscaled_instance_bounding_box);
- *bbox = BoundingBoxf3();
+ std::optional *bbox = const_cast *>(&m_full_unscaled_instance_bounding_box);
+ *bbox = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
- const GLVolume& volume = *(*m_volumes)[i];
- Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix();
+ const GLVolume &volume = *(*m_volumes)[i];
+ Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix();
trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
}
@@ -929,17 +962,17 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_bounding_box() const
return *m_full_unscaled_instance_bounding_box;
}
-const BoundingBoxf3& Selection::get_full_scaled_instance_bounding_box() const
+const BoundingBoxf3 &Selection::get_full_scaled_instance_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_scaled_instance_bounding_box.has_value()) {
- std::optional* bbox = const_cast*>(&m_full_scaled_instance_bounding_box);
- *bbox = BoundingBoxf3();
+ std::optional *bbox = const_cast *>(&m_full_scaled_instance_bounding_box);
+ *bbox = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
- const GLVolume& volume = *(*m_volumes)[i];
- Transform3d trafo = volume.get_instance_transformation().get_matrix() * volume.get_volume_transformation().get_matrix();
+ const GLVolume &volume = *(*m_volumes)[i];
+ Transform3d trafo = volume.get_instance_transformation().get_matrix() * volume.get_volume_transformation().get_matrix();
trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
}
@@ -948,17 +981,17 @@ const BoundingBoxf3& Selection::get_full_scaled_instance_bounding_box() const
return *m_full_scaled_instance_bounding_box;
}
-const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box() const
+const BoundingBoxf3 &Selection::get_full_unscaled_instance_local_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_unscaled_instance_local_bounding_box.has_value()) {
- std::optional* bbox = const_cast*>(&m_full_unscaled_instance_local_bounding_box);
- *bbox = BoundingBoxf3();
+ std::optional *bbox = const_cast *>(&m_full_unscaled_instance_local_bounding_box);
+ *bbox = BoundingBoxf3();
if (m_valid) {
for (unsigned int i : m_list) {
- const GLVolume& volume = *(*m_volumes)[i];
- Transform3d trafo = volume.get_volume_transformation().get_matrix();
+ const GLVolume &volume = *(*m_volumes)[i];
+ Transform3d trafo = volume.get_volume_transformation().get_matrix();
trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
}
@@ -967,22 +1000,20 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box()
return *m_full_unscaled_instance_local_bounding_box;
}
-const std::pair& Selection::get_bounding_box_in_current_reference_system() const
+const std::pair &Selection::get_bounding_box_in_current_reference_system() const
{
static int last_coordinates_type = -1;
assert(!is_empty());
ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
- if (m_mode == Instance && coordinates_type == ECoordinatesType::Local)
- coordinates_type = ECoordinatesType::World;
+ if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) coordinates_type = ECoordinatesType::World;
- if (last_coordinates_type != int(coordinates_type))
- const_cast>*>(&m_bounding_box_in_current_reference_system)->reset();
+ if (last_coordinates_type != int(coordinates_type)) const_cast> *>(&m_bounding_box_in_current_reference_system)->reset();
if (!m_bounding_box_in_current_reference_system.has_value()) {
- last_coordinates_type = int(coordinates_type);
- *const_cast>*>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type);
+ last_coordinates_type = int(coordinates_type);
+ *const_cast> *>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type);
}
return *m_bounding_box_in_current_reference_system;
@@ -994,11 +1025,19 @@ std::pair Selection::get_bounding_box_in_reference_s
// trafo to current reference system
//
Transform3d trafo;
- switch (type)
- {
- case ECoordinatesType::World: { trafo = Transform3d::Identity(); break; }
- case ECoordinatesType::Instance: { trafo = get_first_volume()->get_instance_transformation().get_matrix(); break; }
- case ECoordinatesType::Local: { trafo = get_first_volume()->world_matrix(); break; }
+ switch (type) {
+ case ECoordinatesType::World: {
+ trafo = Transform3d::Identity();
+ break;
+ }
+ case ECoordinatesType::Instance: {
+ trafo = get_first_volume()->get_instance_transformation().get_matrix();
+ break;
+ }
+ case ECoordinatesType::Local: {
+ trafo = get_first_volume()->world_matrix();
+ break;
+ }
}
//
@@ -1006,60 +1045,55 @@ std::pair Selection::get_bounding_box_in_reference_s
//
Geometry::Transformation t(trafo);
t.reset_scaling_factor();
- const Transform3d basis_trafo = t.get_matrix_no_offset();
- std::vector axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
- for (size_t i = 0; i < axes.size(); ++i) {
- axes[i] = basis_trafo * axes[i];
- }
+ const Transform3d basis_trafo = t.get_matrix_no_offset();
+ std::vector axes = {Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ()};
+ for (size_t i = 0; i < axes.size(); ++i) { axes[i] = basis_trafo * axes[i]; }
//
// calculate bounding box aligned to trafo basis
//
- Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX };
- Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX };
+ Vec3d min = {DBL_MAX, DBL_MAX, DBL_MAX};
+ Vec3d max = {-DBL_MAX, -DBL_MAX, -DBL_MAX};
for (unsigned int id : m_list) {
- const GLVolume& vol = *get_volume(id);
- const Transform3d vol_world_rafo = vol.world_matrix();
- const TriangleMesh* mesh = vol.convex_hull();
+ const GLVolume & vol = *get_volume(id);
+ const Transform3d vol_world_rafo = vol.world_matrix();
+ const TriangleMesh *mesh = vol.convex_hull();
if (mesh == nullptr)
mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
assert(mesh != nullptr);
- for (const stl_vertex& v : mesh->its.vertices) {
+ for (const stl_vertex &v : mesh->its.vertices) {
const Vec3d world_v = vol_world_rafo * v.cast();
for (int i = 0; i < 3; ++i) {
const double i_comp = world_v.dot(axes[i]);
- min(i) = std::min(min(i), i_comp);
- max(i) = std::max(max(i), i_comp);
+ min(i) = std::min(min(i), i_comp);
+ max(i) = std::max(max(i), i_comp);
}
}
}
- const Vec3d box_size = max - min;
- Vec3d half_box_size = 0.5 * box_size;
+ const Vec3d box_size = max - min;
+ Vec3d half_box_size = 0.5 * box_size;
Geometry::Transformation out_trafo(trafo);
- Vec3d center = 0.5 * (min + max);
+ Vec3d center = 0.5 * (min + max);
- // Fix for non centered volume
+ // Fix for non centered volume
// by move with calculated center(to volume center) and extend half box size
// e.g. for right aligned embossed text
- if (m_list.size() == 1 &&
- type == ECoordinatesType::Local) {
- const GLVolume& vol = *get_volume(*m_list.begin());
+ if (m_list.size() == 1 && type == ECoordinatesType::Local) {
+ const GLVolume & vol = *get_volume(*m_list.begin());
const Transform3d vol_world_trafo = vol.world_matrix();
- Vec3d world_zero = vol_world_trafo * Vec3d::Zero();
- for (size_t i = 0; i < 3; i++){
+ Vec3d world_zero = vol_world_trafo * Vec3d::Zero();
+ for (size_t i = 0; i < 3; i++) {
// move center to local volume zero
center[i] = world_zero.dot(axes[i]);
// extend half size to bigger distance from center
- half_box_size[i] = std::max(
- abs(center[i] - min[i]),
- abs(center[i] - max[i]));
+ half_box_size[i] = std::max(abs(center[i] - min[i]), abs(center[i] - max[i]));
}
}
-
+
const BoundingBoxf3 out_box(-half_box_size, half_box_size);
out_trafo.set_offset(basis_trafo * center);
- return { out_box, out_trafo.get_matrix_no_scaling_factor() };
+ return {out_box, out_trafo.get_matrix_no_scaling_factor()};
}
const std::pair Selection::get_bounding_sphere() const
@@ -1138,34 +1172,52 @@ void Selection::move_to_center(const Vec3d& displacement, bool local)
this->set_bounding_boxes_dirty();
}
-void Selection::translate(const Vec3d& displacement, TransformationType transformation_type)
+void Selection::translate(const Vec3d &displacement, TransformationType transformation_type)
{
- if (!m_valid)
- return;
-
- // Emboss use translate in local coordinate
- assert(transformation_type.relative() ||
- transformation_type.local());
+ if (!m_valid) return;
for (unsigned int i : m_list) {
- GLVolume& v = *(*m_volumes)[i];
- const VolumeCache& volume_data = m_cache.volumes_data[i];
+ GLVolume & v = *(*m_volumes)[i];
+ const VolumeCache &volume_data = m_cache.volumes_data[i];
if (m_mode == Instance && !is_wipe_tower()) {
assert(is_from_fully_selected_instance(i));
if (transformation_type.instance()) {
- const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
+ const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement);
- }
- else
+ } else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
- }
- else {
- if (transformation_type.local() && transformation_type.absolute()) {
- const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
- const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
- v.set_volume_offset(vol_trafo.get_offset() + inst_trafo.get_scaling_factor_matrix().inverse() * vol_trafo.get_rotation_matrix() * displacement);
+ } else {
+ if (v.is_wipe_tower) {//in world cs
+ int plate_idx = v.object_idx() - 1000;
+ BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx)->get_bounding_box();
+ Vec3d tower_size = v.bounding_box().size();
+ Vec3d tower_origin = m_cache.volumes_data[i].get_volume_position();
+ Vec3d actual_displacement = displacement;
+ const double margin = WIPE_TOWER_MARGIN;
+
+ actual_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() *
+ m_cache.volumes_data[i].get_instance_mirror_matrix())
+ .inverse() *
+ displacement;
+ if (tower_origin(0) + actual_displacement(0) - margin < plate_bbox.min(0)) {
+ actual_displacement(0) = plate_bbox.min(0) - tower_origin(0) + margin;
+ } else if (tower_origin(0) + actual_displacement(0) + tower_size(0) + margin > plate_bbox.max(0)) {
+ actual_displacement(0) = plate_bbox.max(0) - tower_origin(0) - tower_size(0) - margin;
+ }
+
+ if (tower_origin(1) + actual_displacement(1) - margin < plate_bbox.min(1)) {
+ actual_displacement(1) = plate_bbox.min(1) - tower_origin(1) + margin;
+ } else if (tower_origin(1) + actual_displacement(1) + tower_size(1) + margin > plate_bbox.max(1)) {
+ actual_displacement(1) = plate_bbox.max(1) - tower_origin(1) - tower_size(1) - margin;
+ }
+
+ v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + actual_displacement);
}
- else {
+ else if (transformation_type.local() && transformation_type.absolute()) {
+ const Geometry::Transformation &vol_trafo = volume_data.get_volume_transform();
+ const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
+ v.set_volume_offset(vol_trafo.get_offset() + inst_trafo.get_scaling_factor_matrix().inverse() * vol_trafo.get_rotation_matrix() * displacement);
+ } else {
Vec3d relative_disp = displacement;
if (transformation_type.world() && transformation_type.instance())
relative_disp = volume_data.get_instance_transform().get_scaling_factor_matrix().inverse() * relative_disp;
@@ -1181,12 +1233,14 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
-
- ensure_not_below_bed();
+ if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ ensure_not_below_bed();
+ }
set_bounding_boxes_dirty();
- wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ }
}
-
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type)
{
@@ -1287,7 +1341,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
#endif // !DISABLE_INSTANCES_SYNCH
set_bounding_boxes_dirty();
- wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ }
}
void Selection::flattening_rotate(const Vec3d& normal)
@@ -1320,96 +1376,6 @@ void Selection::flattening_rotate(const Vec3d& normal)
this->set_bounding_boxes_dirty();
}
-void Selection::scale_legacy(const Vec3d& scale, TransformationType transformation_type)
-{
- if (!m_valid)
- return;
-
- for (unsigned int i : m_list) {
- GLVolume &v = *(*m_volumes)[i];
- if (is_single_full_instance()) {
- if (transformation_type.relative()) {
- Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
- Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
- // extracts scaling factors from the composed transformation
- Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
- if (transformation_type.joint())
- 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);
- // Restore mirror state
- v.set_instance_mirror(m_cache.volumes_data[i].get_instance_transform().get_mirror());
- }
- 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)) {
- // 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.
- assert(Geometry::is_rotation_ninety_degrees(v.get_instance_rotation()));
- v.set_instance_scaling_factor((v.get_instance_transformation().get_rotation_matrix().matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs());
- }
- else
- v.set_instance_scaling_factor(scale);
- // Restore mirror state
- v.set_instance_mirror(mirror);
- }
-
- // update the instance assemble transform
- ModelObject* object = m_model->objects[v.object_idx()];
- 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_mirror(mirror);
- object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
- }
- else if (is_single_volume() || is_single_modifier()) {
- const auto mirror = v.get_volume_transformation().get_mirror();
- v.set_volume_scaling_factor(scale);
- // Restore mirror state
- v.set_volume_mirror(mirror);
- }
- else {
- Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
- if (m_mode == Instance) {
- Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
- // extracts scaling factors from the composed transformation
- Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
- if (transformation_type.joint())
- 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);
- // Restore mirror state
- v.set_instance_mirror(m_cache.volumes_data[i].get_instance_transform().get_mirror());
- }
- else if (m_mode == Volume) {
- Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
- // extracts scaling factors from the composed transformation
- Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
- if (transformation_type.joint()) {
- Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
- v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
- }
- v.set_volume_scaling_factor(new_scale);
- // Restore mirror state
- v.set_volume_mirror(m_cache.volumes_data[i].get_volume_transform().get_mirror());
- }
- }
- }
-
-#if !DISABLE_INSTANCES_SYNCH
- if (m_mode == Instance)
- // even if there is no rotation, we pass SyncRotationType::GENERAL to force
- // synchronize_unselected_instances() to apply the scale to the other instances
- synchronize_unselected_instances(SyncRotationType::GENERAL);
- else if (m_mode == Volume)
- synchronize_unselected_volumes();
-#endif // !DISABLE_INSTANCES_SYNCH
-
- ensure_on_bed();
- set_bounding_boxes_dirty();
- wxGetApp().plater()->canvas3D()->requires_check_outside_state();
-}
-
void Selection::scale(const Vec3d& scale, TransformationType transformation_type)
{
scale_and_translate(scale, Vec3d::Zero(), transformation_type);
@@ -1552,16 +1518,9 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
}
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
-void Selection::mirror(Axis axis, TransformationType transformation_type)
+void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type)
{
- const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
- scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
-}
-
-void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type)
-{
- if (!m_valid)
- return;
+ if (!m_valid) return;
Vec3d relative_scale = scale;
if (transformation_type.absolute()) {
@@ -1582,45 +1541,52 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
}
for (unsigned int i : m_list) {
- GLVolume& v = *(*m_volumes)[i];
- const VolumeCache& volume_data = m_cache.volumes_data[i];
- const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
+ GLVolume & v = *(*m_volumes)[i];
+ const VolumeCache & volume_data = m_cache.volumes_data[i];
+ const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
if (m_mode == Instance) {
if (transformation_type.instance()) {
const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset();
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
- Matrix3d inst_rotation, inst_scale;
+ Matrix3d inst_rotation, inst_scale;
inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale);
const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
- const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale);
- v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
- }
- else
- transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
- }
- else {
+ const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale);
+ v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo *
+ Geometry::translation_transform(-local_inst_pivot));
+ } else
+ transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale),
+ m_cache.dragging_center);
+ // update the instance assemble transform
+ ModelObject * object = m_model->objects[v.object_idx()];
+ Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
+ assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
+ object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
+ } else {
if (!is_single_volume_or_modifier()) {
assert(transformation_type.world());
- transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
- }
- else {
+ transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale),
+ m_cache.dragging_center);
+ } else {
transformation_type.set_independent();
Vec3d translation;
- if (transformation_type.local())
+ if (transformation_type.local()) {
translation = volume_data.get_volume_transform().get_matrix_no_offset().inverse() * inst_trafo.get_matrix_no_offset().inverse() * world_translation;
+ }
else if (transformation_type.instance())
translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
else
translation = world_translation;
- transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
+ transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale),
+ m_cache.dragging_center);
}
}
}
#if !DISABLE_INSTANCES_SYNCH
if (m_mode == Instance)
- // even if there is no rotation, we pass SyncRotationType::GENERAL to force
+ // even if there is no rotation, we pass SyncRotationType::GENERAL to force
// synchronize_unselected_instances() to apply the scale to the other instances
synchronize_unselected_instances(SyncRotationType::GENERAL);
else if (m_mode == Volume)
@@ -1629,7 +1595,16 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
ensure_on_bed();
set_bounding_boxes_dirty();
- wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ wxGetApp().plater()->canvas3D()->requires_check_outside_state();
+ }
+}
+
+void Selection::mirror(Axis axis, TransformationType transformation_type)
+{
+ const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
+ scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
+
}
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
@@ -1944,7 +1919,8 @@ void Selection::render(float scale_factor)
m_scale_factor = scale_factor;
// render cumulative bounding box of selected volumes
const auto& [box, trafo] = get_bounding_box_in_current_reference_system();
- render_bounding_box(box, trafo, ColorRGB::WHITE());
+ render_bounding_box(box, trafo,
+ wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView ? ColorRGB::YELLOW(): ColorRGB::WHITE());
render_synchronized_volumes();
}
@@ -1992,40 +1968,33 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif
glsafe(::glEnable(GL_DEPTH_TEST));
- const Transform3d base_matrix = Geometry::assemble_transform(get_bounding_box().center());
+ Vec3d center = get_bounding_box().center();
Transform3d orient_matrix = Transform3d::Identity();
if (!boost::starts_with(sidebar_field, "layer")) {
shader->set_uniform("emission_factor", 0.05f);
+ const auto &[box, box_trafo] = get_bounding_box_in_current_reference_system();
// BBS
- if (is_single_full_instance()/* && !wxGetApp().obj_manipul()->get_world_coordinates()*/) {
- if (!boost::starts_with(sidebar_field, "position")) {
- if (boost::starts_with(sidebar_field, "scale"))
+ if (is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
+ center = box_trafo.translation();
+ orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
+ } else if (is_single_volume_or_modifier()) {
+ if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
+ if (wxGetApp().obj_manipul()->is_local_coordinates()) {
+ orient_matrix = get_bounding_box_in_current_reference_system().second;
+ orient_matrix.translation() = Vec3d::Zero();
+ } else {
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
- else if (boost::starts_with(sidebar_field, "rotation")) {
- if (boost::ends_with(sidebar_field, "x"))
- orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
- else if (boost::ends_with(sidebar_field, "y")) {
- const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
- if (rotation.x() == 0.0)
- orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
- else
- orient_matrix.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()));
- }
+ center = box_trafo.translation();
}
}
- }
- else if (is_single_volume() || is_single_modifier()) {
- orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
- if (!boost::starts_with(sidebar_field, "position"))
- orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_rotation_matrix();
-
- }
- else {
- if (requires_local_axes())
+ } else {
+ if (requires_local_axes()) {
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
+ }
}
}
+ const Transform3d base_matrix = Geometry::assemble_transform(center);
if (!boost::starts_with(sidebar_field, "layer"))
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
@@ -2033,6 +2002,8 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif
render_sidebar_position_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "rotation"))
render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix);
+ else if (boost::starts_with(sidebar_field, "absolute_rotation"))
+ render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "scale") || boost::starts_with(sidebar_field, "size"))
//BBS: GUI refactor: add uniform_scale from gizmo
render_sidebar_scale_hints(sidebar_field, uniform_scale, *shader, base_matrix * orient_matrix);
@@ -3052,6 +3023,9 @@ void Selection::ensure_not_below_bed()
bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const
{
+ if (m_mode == Instance && wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView) {
+ return true;
+ }
struct SameInstance
{
int obj_idx;
@@ -3180,14 +3154,14 @@ void Selection::paste_objects_from_clipboard()
Vec3d displacement;
bool in_current = plate->intersects(bbox);
auto start_point = in_current ? bbox.center() : plate->get_build_volume().center();
+ auto start_offset = in_current ? src_object->instances.front()->get_offset() : plate->get_build_volume().center();
if (shift_all(0) != 0 || shift_all(1) != 0) {
// BBS: if multiple objects are selected, move them as a whole after copy
if (i == 0) empty_cell_all = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}, {bbox.size()(0)+1,bbox.size()(1)+1});
auto instance_shift = src_object->instances.front()->get_offset() - src_objects[0]->instances.front()->get_offset();
- displacement = {shift_all.x() + empty_cell_all.x()+instance_shift.x(), shift_all.y() + empty_cell_all.y()+instance_shift.y(), start_point(2)};
+ displacement = {shift_all.x() + empty_cell_all.x() + instance_shift.x(), shift_all.y() + empty_cell_all.y() + instance_shift.y(), start_offset(2)};
} else {
// BBS: if only one object is copied, find an empty cell to put it
- auto start_offset = in_current ? src_object->instances.front()->get_offset() : plate->get_build_volume().center();
auto point_offset = start_offset - start_point;
auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}, {bbox.size()(0)+1, bbox.size()(1)+1});
displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_offset(2)};
diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp
index 0e95b41009..0ad56930df 100644
--- a/src/slic3r/GUI/Selection.hpp
+++ b/src/slic3r/GUI/Selection.hpp
@@ -15,6 +15,7 @@ class Model;
class ModelObject;
class ModelVolume;
class ObjectID;
+class ModelInstance;
class GLVolume;
class GLArrow;
class GLCurvedArrow;
@@ -225,6 +226,9 @@ public:
void remove_volumes(EMode mode, const std::vector& volume_idxs);
//BBS
+ ModelVolume * get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const;
+ ModelObject * get_selected_single_object(int &out_object_idx) const;
+ const ModelInstance * get_selected_single_intance() const;
void add_curr_plate();
void add_object_from_idx(std::vector& object_idxs);
void remove_curr_plate();
@@ -326,20 +330,17 @@ public:
const std::pair get_bounding_sphere() const;
void setup_cache();
-
void translate(const Vec3d& displacement, TransformationType transformation_type);
void move_to_center(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
- [[deprecated("Only used by GizmoObjectManipulation")]]
- void scale_legacy(const Vec3d& scale, TransformationType transformation_type);
void scale(const Vec3d& scale, TransformationType transformation_type);
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_to_fit_print_volume(const BuildVolume& volume);
#else
void scale_to_fit_print_volume(const DynamicPrintConfig& config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
- void scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type);
+ void scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type);
void mirror(Axis axis, TransformationType transformation_type);
void translate(unsigned int object_idx, const Vec3d& displacement);
@@ -351,6 +352,7 @@ public:
//BBS: add partplate related logic
void notify_instance_update(int object_idx, int instance_idx);
// BBS
+ EMode get_volume_selection_mode(){ return m_volume_selection_mode;}
void set_volume_selection_mode(EMode mode) { if (!m_volume_selection_locked) m_volume_selection_mode = mode; }
void lock_volume_selection_mode() { m_volume_selection_locked = true; }
void unlock_volume_selection_mode() { m_volume_selection_locked = false; }
@@ -358,11 +360,11 @@ public:
void erase();
void render(float scale_factor = 1.0);
- //BBS: GUI refactor: add uniform scale from gizmo
- void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale);
#if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging);
#endif // ENABLE_RENDER_SELECTION_CENTER
+ //BBS: GUI refactor: add uniform scale from gizmo
+ void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale);
bool requires_local_axes() const;
@@ -405,7 +407,8 @@ private:
void set_bounding_boxes_dirty() {
m_bounding_box.reset();
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset();
- m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset();
+ m_full_unscaled_instance_bounding_box.reset();
+ m_full_scaled_instance_bounding_box.reset();
m_full_unscaled_instance_local_bounding_box.reset();
m_bounding_box_in_current_reference_system.reset();
m_bounding_sphere.reset();