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();