Merge branch 'main' into VFA-Calibs

This commit is contained in:
Noisyfox 2025-04-05 14:50:12 +08:00 committed by GitHub
commit 4aafa7a90d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 1696 additions and 866 deletions

View file

@ -49,7 +49,7 @@ while getopts ":1j:bcdghirsu" opt; do
export CMAKE_BUILD_PARALLEL_LEVEL=1 export CMAKE_BUILD_PARALLEL_LEVEL=1
;; ;;
j ) j )
CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
;; ;;
b ) b )
BUILD_DEBUG="1" BUILD_DEBUG="1"

View file

@ -3453,8 +3453,8 @@ msgstr ""
#, possible-c-format, possible-boost-format #, possible-c-format, possible-boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
msgid "" msgid ""

View file

@ -3691,11 +3691,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"La temperatura recomanada del broquet d'aquest tipus de filament és de [%d, " "La temperatura recomanada del broquet d'aquest tipus de filament és de [%d, "
"%d] graus centígrads" "%d] graus Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"

View file

@ -3618,8 +3618,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Doporučená teplota trysky pro tento typ filamentu je [%d, %d]stupňů Celsia" "Doporučená teplota trysky pro tento typ filamentu je [%d, %d]stupňů Celsia"
@ -18139,7 +18139,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "Teplota podložky ostatních vrstev je nižší než teplota podložky první " #~ "Teplota podložky ostatních vrstev je nižší než teplota podložky první "

View file

@ -3732,10 +3732,10 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" 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 "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -20600,7 +20600,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "Die Betttemperatur der anderen Schicht ist um mehr als %d Grad Celsius " #~ "Die Betttemperatur der anderen Schicht ist um mehr als %d Grad Celsius "

View file

@ -3585,11 +3585,9 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" 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] " "The recommended nozzle temperature for this filament type is [%d, %d] "
"degrees centigrade" "degrees Celsius."
msgstr ""
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -17677,11 +17675,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "The bed temperature of other layers is lower than the bed temperature of " #~ "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." #~ "This may cause models to break free from the build plate during printing."
#~ msgid "" #~ msgid ""

View file

@ -3722,11 +3722,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"La temperatura recomendada de la boquilla para este tipo de filamento es de " "La temperatura recomendada de la boquilla para este tipo de filamento es de "
"[%d, %d] grados centígrados" "[%d, %d] grados Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -20194,7 +20194,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "La temperatura del lecho de la otra capa es inferior a la temperatura del " #~ "La temperatura del lecho de la otra capa es inferior a la temperatura del "

View file

@ -15,7 +15,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n==0 || n==1) ? 0 : 1;\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" msgid "Supports Painting"
msgstr "Peindre les supports" msgstr "Peindre les supports"
@ -3731,11 +3731,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"La température de buse recommandée pour ce type de filament est de [%d, %d] " "La température de buse recommandée pour ce type de filament est de [%d, %d] "
"degrés centigrades" "degrés Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -3823,10 +3823,10 @@ msgid ""
"YES - Keep Prime Tower\n" "YES - Keep Prime Tower\n"
"NO - Keep Adaptive Layer Height and Independent Support Layer Height" "NO - Keep Adaptive Layer Height and Independent Support Layer Height"
msgstr "" msgstr ""
"La tour de purge ne fonctionne pas lorsque la hauteur de couche adaptative " "La tour damorçage ne fonctionne pas lorsque la hauteur de couche adaptative "
"ou la hauteur de couche de support indépendante est activée. \n" "ou la hauteur de couche de support indépendante est activée. \n"
"Que souhaitez-vous conserver ? \n" "Que souhaitez-vous conserver ? \n"
"OUI - Conserver la tour de purge \n" "OUI - Conserver la tour damorçage \n"
"NON - Conserver la hauteur de la couche adaptative et la hauteur de la " "NON - Conserver la hauteur de la couche adaptative et la hauteur de la "
"couche de support indépendante" "couche de support indépendante"
@ -3836,10 +3836,10 @@ msgid ""
"YES - Keep Prime Tower\n" "YES - Keep Prime Tower\n"
"NO - Keep Adaptive Layer Height" "NO - Keep Adaptive Layer Height"
msgstr "" msgstr ""
"La tour de purge ne fonctionne pas lorsque la hauteur de couche adaptative " "La tour damorçage ne fonctionne pas lorsque la hauteur de couche adaptative "
"est activée. \n" "est activée. \n"
"Que souhaitez-vous conserver ? \n" "Que souhaitez-vous conserver ? \n"
"OUI - Conserver la tour de purge \n" "OUI - Conserver la tour damorçage \n"
"NON - Conserver la hauteur de la couche adaptative" "NON - Conserver la hauteur de la couche adaptative"
msgid "" msgid ""
@ -3848,7 +3848,7 @@ msgid ""
"YES - Keep Prime Tower\n" "YES - Keep Prime Tower\n"
"NO - Keep Independent Support Layer Height" "NO - Keep Independent Support Layer Height"
msgstr "" msgstr ""
"La tour de purge ne fonctionne pas lorsque la hauteur de la couche de " "La tour damorçage ne fonctionne pas lorsque la hauteur de la couche de "
"support indépendante est activée.\n" "support indépendante est activée.\n"
"Que souhaitez-vous conserver ?\n" "Que souhaitez-vous conserver ?\n"
"OUI - Garder la tour de purge\n" "OUI - Garder la tour de purge\n"
@ -4943,7 +4943,7 @@ msgid ""
"top/bottom/side views" "top/bottom/side views"
msgstr "" msgstr ""
"Passage automatique de la vue en plan à la vue en perspective lorsque lon " "Passage automatique de la vue en plan à la vue en perspective lorsque lon "
"passe dune vue de haut en bas ou de côté à une vue orthographique." "passe dune vue de haut en bas ou de côté à une vue orthographique"
msgid "Show &G-code Window" msgid "Show &G-code Window"
msgstr "Afficher la fenêtre du &G-code" 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 #, c-format, boost-format
msgid "%1$d object was loaded as a part of cut object." msgid "%1$d object was loaded as a part of cut object."
msgid_plural "%1$d objects were loaded as parts 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 lobjet coupé" msgstr[0] "%1$d objet a été chargé en tant que partie de lobjet coupé."
msgstr[1] "%1$d objets ont été chargés en tant que partie de lobjet coupé" msgstr[1] "%1$d objets ont été chargés en tant que partie de lobjet coupé."
msgid "ERROR" msgid "ERROR"
msgstr "ERREUR" msgstr "ERREUR"
@ -6775,7 +6775,7 @@ msgstr ""
"La plaque% d : %s n'est pas suggéré pour l'utilisation du filament " "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 %s(%s). Si vous souhaitez toujours effectuer ce travail "
"d'impression, veuillez régler la température du plateau de ce filament sur " "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" msgid "Switching the language requires application restart.\n"
msgstr "Le changement de langue nécessite le redémarrage de l'application.\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 " "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?" "model without prime tower. Are you sure you want to disable prime tower?"
msgstr "" msgstr ""
"Une tour de purge est requise pour le mode Timeplase fluide. Il peut y avoir " "Une tour damorçage est requise pour le mode Timeplase fluide. Il peut y "
"des défauts sur le modèle sans tour de purge. Êtes-vous sûr de vouloir la " "avoir des défauts sur le modèle sans tour de purge. Êtes-vous sûr de vouloir "
"désactiver ?" "la désactiver ?"
msgid "" msgid ""
"Prime tower is required for smooth timelapse. There may be flaws on the " "Prime tower is required for smooth timelapse. There may be flaws on the "
"model without prime tower. Do you want to enable prime tower?" "model without prime tower. Do you want to enable prime tower?"
msgstr "" msgstr ""
"Une tour de purge est requise pour un mode timelapse fluide. Il peut y avoir " "Une tour damorçage est requise pour un mode timelapse fluide. Il peut y "
"des défauts sur le modèle sans tour de purge. Voulez-vous activer la " "avoir des défauts sur le modèle sans tour de purge. Voulez-vous activer la "
"désactiver?" "désactiver?"
msgid "Still print by object?" msgid "Still print by object?"
@ -8124,7 +8124,7 @@ msgid "Multimaterial"
msgstr "Multi-matériaux" msgstr "Multi-matériaux"
msgid "Prime tower" msgid "Prime tower"
msgstr "Tour de purge" msgstr "Tour damorçage"
msgid "Filament for Features" msgid "Filament for Features"
msgstr "Filament pour les caractéristiques" msgstr "Filament pour les caractéristiques"
@ -9724,7 +9724,7 @@ msgstr ""
"de l'impression." "de l'impression."
msgid "Prime Tower" msgid "Prime Tower"
msgstr "Tour de purge" msgstr "Tour damorçage"
msgid " is too close to others, and collisions may be caused.\n" msgid " is too close to others, and collisions may be caused.\n"
msgstr "" msgstr ""
@ -9827,57 +9827,57 @@ msgid ""
"The prime tower is currently only supported for the Marlin, RepRap/Sprinter, " "The prime tower is currently only supported for the Marlin, RepRap/Sprinter, "
"RepRapFirmware and Repetier G-code flavors." "RepRapFirmware and Repetier G-code flavors."
msgstr "" msgstr ""
"La tour principale nest actuellement prise en charge que pour les versions " "La tour damorçage nest actuellement prise en charge que pour les versions "
"Marlin, RepRap/Sprinter, RepRapFirmware et Repetier G-code." "Marlin, RepRap/Sprinter, RepRapFirmware et Repetier G-code."
msgid "The prime tower is not supported in \"By object\" print." msgid "The prime tower is not supported in \"By object\" print."
msgstr "" msgstr ""
"La tour de purge n'est pas prise en charge dans l'impression \"Par objet\"." "La tour damorçage n'est pas prise en charge dans l'impression \"Par objet\"."
msgid "" msgid ""
"The prime tower is not supported when adaptive layer height is on. It " "The prime tower is not supported when adaptive layer height is on. It "
"requires that all objects have the same layer height." "requires that all objects have the same layer height."
msgstr "" msgstr ""
"La tour de purge n'est pas prise en charge lorsque la hauteur de couche " "La tour damorç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 " "adaptative est activée. Cela nécessite que tous les objets aient la même "
"hauteur de couche." "hauteur de couche."
msgid "The prime tower requires \"support gap\" to be multiple of layer height" msgid "The prime tower requires \"support gap\" to be multiple of layer height"
msgstr "" msgstr ""
"La tour de purge nécessite que \"l'écart de support\" soit un multiple de la " "La tour damorçage nécessite que \"l'écart de support\" soit un multiple de "
"hauteur de la couche" "la hauteur de la couche"
msgid "The prime tower requires that all objects have the same layer heights" msgid "The prime tower requires that all objects have the same layer heights"
msgstr "" msgstr ""
"La tour de purge nécessite que tous les objets aient la même hauteur de " "La tour damorçage nécessite que tous les objets aient la même hauteur de "
"couche" "couche"
msgid "" msgid ""
"The prime tower requires that all objects are printed over the same number " "The prime tower requires that all objects are printed over the same number "
"of raft layers" "of raft layers"
msgstr "" msgstr ""
"La tour de purge nécessite que tous les objets soient imprimés sur le même " "La tour damorçage nécessite que tous les objets soient imprimés sur le même "
"nombre de couche de radeau" "nombre de couche de radeau"
msgid "" msgid ""
"The prime tower is only supported for multiple objects if they are printed " "The prime tower is only supported for multiple objects if they are printed "
"with the same support_top_z_distance" "with the same support_top_z_distance"
msgstr "" msgstr ""
"La tour de purge nest prise en charge pour plusieurs objets que sils sont " "La tour damorçage nest prise en charge pour plusieurs objets que sils "
"imprimés avec la même valeur de support_top_z_distance." "sont imprimés avec la même valeur de support_top_z_distance."
msgid "" msgid ""
"The prime tower requires that all objects are sliced with the same layer " "The prime tower requires that all objects are sliced with the same layer "
"heights." "heights."
msgstr "" msgstr ""
"La tour de purge nécessite que tous les objets soient découpés avec la même " "La tour damorçage nécessite que tous les objets soient découpés avec la "
"hauteur de couche." "même hauteur de couche."
msgid "" msgid ""
"The prime tower is only supported if all objects have the same variable " "The prime tower is only supported if all objects have the same variable "
"layer height" "layer height"
msgstr "" msgstr ""
"La tour de purge n'est prise en charge que si tous les objets ont la même " "La tour damorçage n'est prise en charge que si tous les objets ont la même "
"hauteur de couche variable" "hauteur de couche variable"
msgid "" msgid ""
@ -9906,8 +9906,8 @@ msgstr ""
msgid "" msgid ""
"The prime tower requires that support has the same layer height with object." "The prime tower requires that support has the same layer height with object."
msgstr "" msgstr ""
"La tour de purge nécessite que le support ait la même hauteur de couche avec " "La tour damorçage nécessite que le support ait la même hauteur de couche "
"l'objet." "avec l'objet."
msgid "" msgid ""
"Organic support tree tip diameter must not be smaller than support material " "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 " "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 " "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 " "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 damorçage est "
"requise en mode lisse pour essuyer la buse." "requise en mode lisse pour essuyer la buse."
msgid "Traditional" msgid "Traditional"
@ -14623,10 +14623,10 @@ msgstr ""
"PAUSE pour déclencher laction de changement manuel de filament." "PAUSE pour déclencher laction de changement manuel de filament."
msgid "Purge in prime tower" msgid "Purge in prime tower"
msgstr "Purge dans la tour de purge" msgstr "Purge dans la tour damorçage"
msgid "Purge remaining filament into prime tower" 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 damorçage"
msgid "Enable filament ramming" msgid "Enable filament ramming"
msgstr "Activer le pilonnage du filament" msgstr "Activer le pilonnage du filament"
@ -14952,8 +14952,8 @@ msgid ""
msgstr "" msgstr ""
"La couche de support utilise la hauteur de la couche indépendamment de la " "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 " "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 " "temps d'impression. Cette option ne sera pas valide lorsque la tour "
"sera activée." "damorçage sera activée."
msgid "Threshold angle" msgid "Threshold angle"
msgstr "Angle de seuil" msgstr "Angle de seuil"
@ -15305,13 +15305,13 @@ msgstr ""
"purge multiplié par les volumes de purge dans le tableau." "purge multiplié par les volumes de purge dans le tableau."
msgid "Prime volume" msgid "Prime volume"
msgstr "Premier volume" msgstr "Volume damorçage"
msgid "The volume of material to prime extruder on tower." msgid "The volume of material to prime extruder on tower."
msgstr "Le volume de matériau pour amorcer l'extrudeur sur la tour." msgstr "Le volume de matériau pour amorcer l'extrudeur sur la tour."
msgid "Width of prime tower" msgid "Width of prime tower"
msgstr "Largeur de la tour de purge" msgstr "Largeur de la tour damorçage"
msgid "Wipe tower rotation angle" msgid "Wipe tower rotation angle"
msgstr "Angle de rotation de la tour dessuyage" msgstr "Angle de rotation de la tour dessuyage"
@ -15405,7 +15405,7 @@ msgstr ""
"matériaux de remplissage des objets. Cela peut réduire la quantité de " "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 " "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. " "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 damorçage est activée."
msgid "" msgid ""
"Purging after filament change will be done inside objects' support. This may " "Purging after filament change will be done inside objects' support. This may "
@ -15414,7 +15414,7 @@ msgid ""
msgstr "" msgstr ""
"La purge après le changement de filament se fera à l'intérieur du support " "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 " "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 damorçage est activée."
msgid "" msgid ""
"This object will be used to purge the nozzle after a filament change to save " "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 " "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 " "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 " "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 damorçage est activée."
msgid "Maximal bridging distance" msgid "Maximal bridging distance"
msgstr "Distance de pont maximale" msgstr "Distance de pont maximale"
@ -20773,7 +20773,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "La température du plateau des autres couches est inférieure à la " #~ "La température du plateau des autres couches est inférieure à la "

View file

@ -3620,8 +3620,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Az ajánlott fúvóka hőmérséklet ehhez a filament típushoz [%d, %d] Celsius-fok" "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 #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "A többi réteg asztalhőmérséklete több mint %d Celsius-fokkal alacsonyabb, " #~ "A többi réteg asztalhőmérséklete több mint %d Celsius-fokkal alacsonyabb, "

View file

@ -3725,11 +3725,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"La temperatura dell'ugello consigliata per questo filamento è [%d, %d] gradi " "La temperatura dell'ugello consigliata per questo filamento è [%d, %d] gradi "
"centigradi" "Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -20244,11 +20244,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "The bed temperature of other layers is lower than the bed temperature of " #~ "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." #~ "This may cause models to break free from the build plate during printing."
#~ msgid "" #~ msgid ""

View file

@ -3579,8 +3579,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "このフィラメントで推奨ノズル温度は %d ~ %d ℃です。" msgstr "このフィラメントで推奨ノズル温度は %d ~ %d ℃です。"
msgid "" msgid ""
@ -17653,7 +17653,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "ベッド温度が1層目温度より %d ℃以上低いです。造形中プレートより離脱する可能" #~ "ベッド温度が1層目温度より %d ℃以上低いです。造形中プレートより離脱する可能"

View file

@ -3594,8 +3594,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "이 필라멘트 유형의 권장 노즐 온도는 [%d, %d]°C입니다" msgstr "이 필라멘트 유형의 권장 노즐 온도는 [%d, %d]°C입니다"
msgid "" msgid ""
@ -19244,7 +19244,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "다른 레이어의 베드 온도가 초기 레이어의 베드 온도보다 %d°C 이상 낮습니" #~ "다른 레이어의 베드 온도가 초기 레이어의 베드 온도보다 %d°C 이상 낮습니"

View file

@ -3657,11 +3657,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"De aanbevolen mondstuk temperatuur voor dit type filament is [%d, %d] graden " "De aanbevolen mondstuk temperatuur voor dit type filament is [%d, %d] graden "
"Celsius" "Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -18231,10 +18231,10 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ 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" #~ "dan de temperatuur voor de eerste laag.\n"
#~ "Hierdoor kan de print loskomen van het printbed gedurende de printtaak" #~ "Hierdoor kan de print loskomen van het printbed gedurende de printtaak"

View file

@ -3688,8 +3688,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Zalecana temperatura dyszy dla tego typu filamentu wynosi [%d, %d] stopni " "Zalecana temperatura dyszy dla tego typu filamentu wynosi [%d, %d] stopni "
"Celsjusza" "Celsjusza"
@ -21391,7 +21391,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "Temperatura podłoża innych warstw jest niższa niż temperatura podłoża " #~ "Temperatura podłoża innych warstw jest niższa niż temperatura podłoża "

View file

@ -1785,7 +1785,7 @@ msgid "Delete the selected object"
msgstr "Apagar o objeto selecionado" msgstr "Apagar o objeto selecionado"
msgid "Load..." msgid "Load..."
msgstr "Carregar..." msgstr "Carregar"
msgid "Cube" msgid "Cube"
msgstr "Cubo" msgstr "Cubo"
@ -2458,7 +2458,7 @@ msgid "No printer"
msgstr "Sem impressora" msgstr "Sem impressora"
msgid "..." msgid "..."
msgstr "..." msgstr ""
msgid "Failed to connect to the server" msgid "Failed to connect to the server"
msgstr "Falha ao conectar ao servidor" 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." msgstr "Por favor, verifique a conexão de rede da impressora e do Orca."
msgid "Connecting..." msgid "Connecting..."
msgstr "Conectando..." msgstr "Conectando"
msgid "?" msgid "?"
msgstr "?" msgstr "?"
@ -2525,7 +2525,7 @@ msgid "Retry"
msgstr "Tentar Novamente" msgstr "Tentar Novamente"
msgid "Calibrating AMS..." msgid "Calibrating AMS..."
msgstr "Calibrando AMS..." msgstr "Calibrando AMS"
msgid "A problem occurred during calibration. Click to view the solution." 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." 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" msgstr "Cancelar calibração"
msgid "Idling..." msgid "Idling..."
msgstr "Em espera..." msgstr "Em espera"
msgid "Heat the nozzle" msgid "Heat the nozzle"
msgstr "Aquecer o bico" msgstr "Aquecer o bico"
@ -2594,7 +2594,7 @@ msgstr ""
"Não é possível auto-arranjar nessa placa." "Não é possível auto-arranjar nessa placa."
msgid "Arranging..." msgid "Arranging..."
msgstr "Organizando..." msgstr "Organizando"
msgid "Arranging" msgid "Arranging"
msgstr "Organizando" msgstr "Organizando"
@ -2642,7 +2642,7 @@ msgstr ""
"Não é possível auto-orientar nessa placa." "Não é possível auto-orientar nessa placa."
msgid "Orienting..." msgid "Orienting..."
msgstr "Orientando..." msgstr "Orientando"
msgid "Orienting" msgid "Orienting"
msgstr "Orientando" msgstr "Orientando"
@ -3260,7 +3260,7 @@ msgid "Please save project and restart the program."
msgstr "Por favor, salve o projeto e reinicie o programa." msgstr "Por favor, salve o projeto e reinicie o programa."
msgid "Processing G-Code from Previous file..." msgid "Processing G-Code from Previous file..."
msgstr "Processando G-code do arquivo anterior..." msgstr "Processando G-code do arquivo anterior"
msgid "Slicing complete" msgid "Slicing complete"
msgstr "Fatiamento concluído" msgstr "Fatiamento concluído"
@ -3498,7 +3498,7 @@ msgid "No historical tasks!"
msgstr "Nenhuma tarefa no histórico!" msgstr "Nenhuma tarefa no histórico!"
msgid "Loading..." msgid "Loading..."
msgstr "Carregando..." msgstr "Carregando"
msgid "No AMS" msgid "No AMS"
msgstr "Nenhum AMS" msgstr "Nenhum AMS"
@ -3614,7 +3614,7 @@ msgid "Circular"
msgstr "Circular" msgstr "Circular"
msgid "Load shape from STL..." msgid "Load shape from STL..."
msgstr "Carregar forma de STL..." msgstr "Carregar forma de STL"
msgid "Settings" msgid "Settings"
msgstr "Configurações" msgstr "Configurações"
@ -3686,11 +3686,11 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"A temperatura do bico recomendada para este tipo de filamento é [%d, %d] " "A temperatura do bico recomendada para este tipo de filamento é [%d, %d] "
"graus centígrados" "graus Celsius."
msgid "" msgid ""
"Too small max volumetric speed.\n" "Too small max volumetric speed.\n"
@ -4991,7 +4991,7 @@ msgid "VFA"
msgstr "VFA" msgstr "VFA"
msgid "More..." msgid "More..."
msgstr "Mais..." msgstr "Mais"
msgid "Tutorial" msgid "Tutorial"
msgstr "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." msgstr "Por favor, digite o IP da impressora para conectar."
msgid "Initializing..." msgid "Initializing..."
msgstr "Inicializando..." msgstr "Inicializando"
msgid "Connection Failed. Please check the network and try again" msgid "Connection Failed. Please check the network and try again"
msgstr "Falha na conexão. Por favor, verifique a rede e tente novamente" msgstr "Falha na conexão. Por favor, verifique a rede e tente novamente"
@ -5220,7 +5220,7 @@ msgid "Information"
msgstr "Informação" msgstr "Informação"
msgid "Playing..." msgid "Playing..."
msgstr "Reproduzindo..." msgstr "Reproduzindo"
msgid "Year" msgid "Year"
msgstr "Ano" msgstr "Ano"
@ -5277,7 +5277,7 @@ msgid "No printers."
msgstr "Nenhuma impressora." msgstr "Nenhuma impressora."
msgid "Loading file list..." msgid "Loading file list..."
msgstr "Carregando lista de arquivos..." msgstr "Carregando lista de arquivos"
msgid "No files" msgid "No files"
msgstr "Sem arquivos" msgstr "Sem arquivos"
@ -5327,7 +5327,7 @@ msgid "Delete file"
msgstr "Excluir arquivo" msgstr "Excluir arquivo"
msgid "Fetching model information..." msgid "Fetching model information..."
msgstr "Obtendo informações do modelo ..." msgstr "Obtendo informações do modelo"
msgid "Failed to fetch model information from printer." msgid "Failed to fetch model information from printer."
msgstr "Falha ao obter informação do modelo da impressora." msgstr "Falha ao obter informação do modelo da impressora."
@ -5355,7 +5355,7 @@ msgstr ""
"Título: %s\n" "Título: %s\n"
msgid "Download waiting..." msgid "Download waiting..."
msgstr "Aguardando download..." msgstr "Aguardando download"
msgid "Play" msgid "Play"
msgstr "Reproduzir" msgstr "Reproduzir"
@ -5368,7 +5368,7 @@ msgstr "Download concluído"
#, c-format, boost-format #, c-format, boost-format
msgid "Downloading %d%%..." msgid "Downloading %d%%..."
msgstr "Baixando %d%%..." msgstr "Baixando %d%%"
msgid "" msgid ""
"Reconnecting the printer, the operation cannot be completed immediately, " "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?" msgstr "Tem certeza de que deseja cancelar esta impressão?"
msgid "Downloading..." msgid "Downloading..."
msgstr "Baixando..." msgstr "Baixando"
msgid "Cloud Slicing..." msgid "Cloud Slicing..."
msgstr "Fatiando na Nuvem..." msgstr "Fatiando na Nuvem"
#, c-format, boost-format #, c-format, boost-format
msgid "In Cloud Slicing Queue, there are %s tasks ahead." msgid "In Cloud Slicing Queue, there are %s tasks ahead."
@ -6438,13 +6438,13 @@ msgid "Importing Model"
msgstr "Importando Modelo" msgstr "Importando Modelo"
msgid "prepare 3mf file..." msgid "prepare 3mf file..."
msgstr "preparar o arquivo 3mf..." msgstr "preparar o arquivo 3mf"
msgid "Download failed, unknown file format." msgid "Download failed, unknown file format."
msgstr "Baixar falhou, formato de arquivo desconhecido." msgstr "Baixar falhou, formato de arquivo desconhecido."
msgid "downloading project ..." msgid "downloading project ..."
msgstr "baixando projeto..." msgstr "baixando projeto"
msgid "Download failed, File size exception." msgid "Download failed, File size exception."
msgstr "Baixar falhou, erro no tamanho do arquivo." msgstr "Baixar falhou, erro no tamanho do arquivo."
@ -7641,7 +7641,7 @@ msgid "Pin Code"
msgstr "Código PIN" msgstr "Código PIN"
msgid "Binding..." msgid "Binding..."
msgstr "Vinculando..." msgstr "Vinculando"
msgid "Please confirm on the printer screen" msgid "Please confirm on the printer screen"
msgstr "Confirme na tela da impressora" msgstr "Confirme na tela da impressora"
@ -9220,7 +9220,7 @@ msgid "Manual Setup"
msgstr "Configuração Manual" msgstr "Configuração Manual"
msgid "connecting..." msgid "connecting..."
msgstr "conectando..." msgstr "conectando"
msgid "Failed to connect to printer." msgid "Failed to connect to printer."
msgstr "Falha ao conectar à impressora." msgstr "Falha ao conectar à impressora."
@ -16329,7 +16329,7 @@ msgstr ""
"Você ainda quer continuar com a calibração?" "Você ainda quer continuar com a calibração?"
msgid "Connecting to printer..." msgid "Connecting to printer..."
msgstr "Conectando à impressora..." msgstr "Conectando à impressora"
msgid "The failed test result has been dropped." msgid "The failed test result has been dropped."
msgstr "O resultado do teste falhado foi descartado." msgstr "O resultado do teste falhado foi descartado."
@ -16531,7 +16531,7 @@ msgstr ""
"imprime com:" "imprime com:"
msgid "material with significant thermal shrinkage/expansion, such as..." 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" msgid "materials with inaccurate filament diameter"
msgstr "materiais com diâmetro de filamento impreciso" msgstr "materiais com diâmetro de filamento impreciso"

View file

@ -3726,8 +3726,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Рекомендуемая температура сопла для данного типа пластиковой нити составляет " "Рекомендуемая температура сопла для данного типа пластиковой нити составляет "
"[%d, %d] градусов Цельсия." "[%d, %d] градусов Цельсия."

View file

@ -3594,8 +3594,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Rekommenderad nozzel temperatur med denna filament typ är [%d, %d] grader " "Rekommenderad nozzel temperatur med denna filament typ är [%d, %d] grader "
"celius" "celius"
@ -17712,7 +17712,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "Byggplattans temperatur för andra lager är mindre än temperaturen för " #~ "Byggplattans temperatur för andra lager är mindre än temperaturen för "

View file

@ -3647,10 +3647,10 @@ msgstr ""
"Lütfen yazdırmak için sıcaklığı kullanıp kullanmayacağınızdan emin olun.\n" "Lütfen yazdırmak için sıcaklığı kullanıp kullanmayacağınızdan emin olun.\n"
"\n" "\n"
#, c-format, boost-format #, fuzzy, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Bu filament tipinin tavsiye edilen Nozul sıcaklığı [%d, %d] derece " "Bu filament tipinin tavsiye edilen Nozul sıcaklığı [%d, %d] derece "
"santigrattır" "santigrattır"

View file

@ -3687,8 +3687,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "" msgstr ""
"Рекомендована температура сопла для цього типу нитки становить [%d, %d] " "Рекомендована температура сопла для цього типу нитки становить [%d, %d] "
"градусів Цельсія" "градусів Цельсія"

View file

@ -3523,8 +3523,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "该耗材的推荐喷嘴温度是[%d, %d]摄氏度" msgstr "该耗材的推荐喷嘴温度是[%d, %d]摄氏度"
msgid "" msgid ""
@ -17804,7 +17804,7 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
#~ msgid "" #~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial " #~ "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" #~ "This may cause model broken free from build plate during printing"
#~ msgstr "" #~ msgstr ""
#~ "其它层的热床温度比首层热床温度低太多,超过了%d 摄氏度。\n" #~ "其它层的热床温度比首层热床温度低太多,超过了%d 摄氏度。\n"

View file

@ -3527,8 +3527,8 @@ msgstr ""
#, c-format, boost-format #, c-format, boost-format
msgid "" msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree " "The recommended nozzle temperature for this filament type is [%d, %d] "
"centigrade" "degrees Celsius."
msgstr "該線材的推薦噴嘴溫度是攝氏 [%d, %d] 度" msgstr "該線材的推薦噴嘴溫度是攝氏 [%d, %d] 度"
msgid "" msgid ""

View file

@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6457 7C10.5448 7 10.4602 6.9247 10.4433 6.82524C10.1226 4.93741 8.47917 3.5 6.5 3.5C4.29086 3.5 2.5 5.29086 2.5 7.5C2.5 9.47929 3.93759 11.1228 5.82559 11.4434C5.92506 11.4603 6.00037 11.5448 6.00037 11.6457V12.7588C6.00037 12.8763 5.89925 12.9688 5.7827 12.9536C3.08405 12.6022 1 10.2945 1 7.5C1 4.46243 3.46243 2 6.5 2C9.29433 2 11.6019 4.08386 11.9536 6.78232C11.9688 6.89888 11.8763 7 11.7587 7H10.6457Z" fill="#FF6F00"/>
<path d="M11.1649 9.76271C11.0854 9.87751 10.9156 9.87751 10.8361 9.76271L8.61993 6.5639C8.52803 6.43126 8.62296 6.25 8.78433 6.25H13.2167C13.3781 6.25 13.473 6.43126 13.3811 6.5639L11.1649 9.76271Z" fill="#FF6F00"/>
<path d="M8.38678 7.61146C8.38678 8.48963 8.22064 9.15893 7.88836 9.61938C7.56082 10.0798 7.09326 10.31 6.48566 10.31C5.87807 10.31 5.40576 10.0822 5.06873 9.6265C4.73645 9.16605 4.57031 8.49438 4.57031 7.61146C4.57031 6.72855 4.73645 6.05687 5.06873 5.59643C5.40576 5.13598 5.87807 4.90576 6.48566 4.90576C7.09326 4.90576 7.56082 5.13598 7.88836 5.59643C8.22064 6.05687 8.38678 6.72855 8.38678 7.61146ZM5.85908 7.61146C5.85908 8.14786 5.90892 8.54659 6.00861 8.80767C6.11304 9.06874 6.27206 9.19928 6.48566 9.19928C6.69453 9.19928 6.8488 9.06874 6.94848 8.80767C7.04817 8.54184 7.09801 8.14311 7.09801 7.61146C7.09801 7.07982 7.04817 6.68346 6.94848 6.42238C6.8488 6.15656 6.69453 6.02364 6.48566 6.02364C6.27206 6.02364 6.11304 6.15181 6.00861 6.40814C5.90892 6.66447 5.85908 7.06558 5.85908 7.61146Z" fill="#FF6F00"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,4 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.2937 5.6687C9.71589 3.84914 8.01293 2.53076 6.00204 2.53076C3.51563 2.53076 1.5 4.54639 1.5 7.0328C1.5 9.27369 3.13722 11.1322 5.28073 11.4774C5.38062 11.4935 5.4564 11.5783 5.4564 11.6794V12.7916C5.4564 12.9091 5.35522 13.0016 5.23861 12.9868C2.28425 12.6118 0 10.0891 0 7.0328C0 3.71797 2.68721 1.03076 6.00204 1.03076C8.84765 1.03076 11.2307 3.01105 11.8484 5.6687H13.3662C13.5275 5.6687 13.6225 5.84996 13.5306 5.9826L11.0772 9.52371C10.9977 9.63851 10.8279 9.63851 10.7484 9.52371L8.29505 5.9826C8.20315 5.84996 8.29808 5.6687 8.45945 5.6687H10.2937Z" fill="#FF6F00"/>
<path d="M7.99414 7.03451C7.99414 7.96884 7.81738 8.68095 7.46384 9.17084C7.11537 9.66073 6.6179 9.90568 5.97144 9.90568C5.32499 9.90568 4.82247 9.66326 4.46389 9.17842C4.11036 8.68852 3.93359 7.97389 3.93359 7.03451C3.93359 6.09513 4.11036 5.38049 4.46389 4.8906C4.82247 4.40071 5.32499 4.15576 5.97144 4.15576C6.6179 4.15576 7.11537 4.40071 7.46384 4.8906C7.81738 5.38049 7.99414 6.09513 7.99414 7.03451ZM5.30479 7.03451C5.30479 7.60521 5.35782 8.02944 5.46387 8.30722C5.57498 8.58499 5.74417 8.72388 5.97144 8.72388C6.19366 8.72388 6.3578 8.58499 6.46386 8.30722C6.56992 8.02439 6.62295 7.60016 6.62295 7.03451C6.62295 6.46886 6.56992 6.04715 6.46386 5.76937C6.3578 5.48655 6.19366 5.34514 5.97144 5.34514C5.74417 5.34514 5.57498 5.4815 5.46387 5.75422C5.35782 6.02695 5.30479 6.45371 5.30479 7.03451Z" fill="#FF6F00"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -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; ref_speed = EXTRUDER_CONFIG(filament_max_volumetric_speed) / _mm3_per_mm;
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) { 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) { if (sloped) {
ref_speed = std::min(ref_speed, m_config.scarf_joint_speed.get_abs_value(ref_speed)); ref_speed = std::min(ref_speed, m_config.scarf_joint_speed.get_abs_value(ref_speed));

View file

@ -442,6 +442,10 @@ public:
}; };
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance)); 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) { if(slowdown_for_curled_edges) {
float curled_speed = calculate_speed(artificial_distance_to_curled_lines); 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 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

View file

@ -478,6 +478,16 @@ Transform3d Transformation::get_rotation_matrix() const
return extract_rotation_matrix(m_matrix); 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) void Transformation::set_rotation(const Vec3d& rotation)
{ {
const Vec3d offset = get_offset(); const Vec3d offset = get_offset();
@ -839,6 +849,17 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
return curMat; 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) { 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. // 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<int64_t>(); const Vec2i64 a_i64 = a.cast<int64_t>();

View file

@ -421,6 +421,7 @@ public:
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; } void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
Vec3d get_rotation() const; Vec3d get_rotation() const;
Vec3d get_rotation_by_quaternion() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; } double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const; 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 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. * Checks if a given point is inside a corner of a polygon.

View file

@ -1167,23 +1167,27 @@ bool ModelObject::make_boolean(ModelObject *cut_object, const std::string &boole
return true; 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); ModelVolume* v = new ModelVolume(this, mesh);
this->volumes.push_back(v); this->volumes.push_back(v);
if (modify_to_center_geometry) {
v->center_geometry_after_creation(); v->center_geometry_after_creation();
this->invalidate_bounding_box(); this->invalidate_bounding_box();
}
// BBS: backup // BBS: backup
Slic3r::save_object_mesh(*this); Slic3r::save_object_mesh(*this);
return v; 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); ModelVolume* v = new ModelVolume(this, std::move(mesh), type);
this->volumes.push_back(v); this->volumes.push_back(v);
if (modify_to_center_geometry) {
v->center_geometry_after_creation(); v->center_geometry_after_creation();
this->invalidate_bounding_box(); this->invalidate_bounding_box();
}
// BBS: backup // BBS: backup
Slic3r::save_object_mesh(*this); Slic3r::save_object_mesh(*this);
return v; return v;

View file

@ -410,8 +410,8 @@ public:
return global_config.option<T>(config_option); return global_config.option<T>(config_option);
} }
ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry = true);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART); 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, ModelVolumeType type = ModelVolumeType::INVALID);
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART); 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_initialized = true;
m_assemble_transformation = transformation; 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_initialized = true;
m_assemble_transformation.set_matrix(transform); 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_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) { 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())); m_assemble_transformation.set_rotation(m_assemble_transformation.get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix()));
} }

View file

@ -895,8 +895,13 @@ int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_suppo
} }
//BBS: add outline drawing logic //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, void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
std::function<bool(const GLVolume&)> filter_func) const bool disable_cullface,
const Transform3d & view_matrix,
const Transform3d& projection_matrix,
const GUI::Size& cnv_size,
std::function<bool(const GLVolume &)> filter_func,
bool partly_inside_enable) const
{ {
GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func); GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func);
if (to_render.empty()) 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.xy_data", m_render_volume.data);
//shader->set_uniform("print_volume.z_data", m_render_volume.zs); //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 //only partly inside volume need to be painted with boundary check
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type)); shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
shader->set_uniform("print_volume.xy_data", m_print_volume.data); shader->set_uniform("print_volume.xy_data", m_print_volume.data);

View file

@ -471,8 +471,14 @@ public:
int get_selection_support_threshold_angle(bool&) const; int get_selection_support_threshold_angle(bool&) const;
// Render the volumes by OpenGL. // Render the volumes by OpenGL.
//BBS: add outline drawing logic //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, void render(ERenderType type,
std::function<bool(const GLVolume &)> filter_func = std::function<bool(const GLVolume &)>()) const; bool disable_cullface,
const Transform3d & view_matrix,
const Transform3d& projection_matrix,
const GUI::Size& cnv_size,
std::function<bool(const GLVolume &)> filter_func = std::function<bool(const GLVolume &)>(),
bool partly_inside_enable =true
) const;
// Clear the geometry // Clear the geometry
void clear() { for (auto *v : volumes) delete v; volumes.clear(); } void clear() { for (auto *v : volumes) delete v; volumes.clear(); }

View file

@ -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) { 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" 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")); "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); MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true; is_msg_dlg_already_exist = true;
dialog.ShowModal(); 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" 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")); "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); MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true; is_msg_dlg_already_exist = true;
dialog.ShowModal(); dialog.ShowModal();

View file

@ -14,7 +14,6 @@
#include "libslic3r/Technologies.hpp" #include "libslic3r/Technologies.hpp"
#include "libslic3r/Tesselate.hpp" #include "libslic3r/Tesselate.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "3DBed.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp" #include "BackgroundSlicingProcess.hpp"
#include "GLShader.hpp" #include "GLShader.hpp"
@ -1168,6 +1167,13 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
load_arrange_settings(); load_arrange_settings();
m_selection.set_volumes(&m_volumes.volumes); 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() GLCanvas3D::~GLCanvas3D()
@ -1939,7 +1945,11 @@ void GLCanvas3D::render(bool only_init)
/* assemble render*/ /* assemble render*/
else if (m_canvas_type == ECanvasType::CanvasAssembleView) { else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
//BBS: add outline logic //BBS: add outline logic
if (m_show_world_axes) {
m_axes.render();
}
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); _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_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
_render_plane(); _render_plane();
//BBS: add outline logic insteadof selection under assemble view //BBS: add outline logic insteadof selection under assemble view
@ -2147,6 +2157,9 @@ void GLCanvas3D::update_plate_thumbnails()
void GLCanvas3D::select_all() void GLCanvas3D::select_all()
{ {
if (!m_gizmos.is_allow_select_all()) {
return;
}
m_selection.add_all(); m_selection.add_all();
m_dirty = true; m_dirty = true;
} }
@ -2262,16 +2275,10 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
void GLCanvas3D::mirror_selection(Axis axis) void GLCanvas3D::mirror_selection(Axis axis)
{ {
TransformationType transformation_type; TransformationType transformation_type;
if (wxGetApp().obj_manipul()->is_local_coordinates()) //transformation_type.set_world();
transformation_type.set_local();
else if (wxGetApp().obj_manipul()->is_instance_coordinates())
transformation_type.set_instance();
transformation_type.set_relative(); transformation_type.set_relative();
m_selection.setup_cache(); m_selection.setup_cache();
m_selection.mirror(axis, transformation_type); m_selection.mirror(axis, transformation_type);
do_mirror(L("Mirror Object")); do_mirror(L("Mirror Object"));
// BBS // BBS
//wxGetApp().obj_manipul()->set_dirty(); //wxGetApp().obj_manipul()->set_dirty();
@ -4073,9 +4080,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
GLGizmosManager::EType c = m_gizmos.get_current_type(); GLGizmosManager::EType c = m_gizmos.get_current_type();
if (current_printer_technology() == ptFFF && if (current_printer_technology() == ptFFF &&
(fff_print()->config().print_sequence == PrintSequence::ByObject)) { (fff_print()->config().print_sequence == PrintSequence::ByObject)) {
if (c == GLGizmosManager::EType::Move || if (can_sequential_clearance_show_in_gizmo())
c == GLGizmosManager::EType::Scale ||
c == GLGizmosManager::EType::Rotate )
update_sequential_clearance(); update_sequential_clearance();
} else { } else {
if (c == GLGizmosManager::EType::Move || if (c == GLGizmosManager::EType::Move ||
@ -4178,11 +4183,22 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
int volume_idx = get_first_hover_volume_idx(); int volume_idx = get_first_hover_volume_idx();
bool already_selected = m_selection.contains_volume(volume_idx); bool already_selected = m_selection.contains_volume(volume_idx);
bool ctrl_down = evt.CmdDown(); bool ctrl_down = evt.CmdDown();
bool alt_down = evt.AltDown();
Selection::IndicesList curr_idxs = m_selection.get_volume_idxs(); Selection::IndicesList curr_idxs = m_selection.get_volume_idxs();
if (already_selected && ctrl_down) if (already_selected && ctrl_down)
m_selection.remove(volume_idx); m_selection.remove(volume_idx);
else if (alt_down) {
Selection::EMode mode = Selection::Volume;
if (already_selected) {
std::vector<unsigned int> volume_idxs;
for (auto idx : curr_idxs) { volume_idxs.emplace_back(idx); }
m_selection.remove_volumes(mode, volume_idxs);
}
std::vector<unsigned int> add_volume_idxs;
add_volume_idxs.emplace_back(volume_idx);
m_selection.add_volumes(mode, add_volume_idxs, true);
}
else { else {
m_selection.add(volume_idx, !ctrl_down, true); m_selection.add(volume_idx, !ctrl_down, true);
m_mouse.drag.move_requires_threshold = !already_selected; m_mouse.drag.move_requires_threshold = !already_selected;
@ -4660,11 +4676,19 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
// Move instances/volumes // Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) 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()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) { 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];
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup // BBS: backup
Slic3r::save_object_mesh(*model_object); Slic3r::save_object_mesh(*model_object);
} }
@ -4771,11 +4795,17 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes. // Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) 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()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) { 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];
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup // BBS: backup
Slic3r::save_object_mesh(*model_object); Slic3r::save_object_mesh(*model_object);
} }
@ -4786,24 +4816,25 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list //BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1); m_selection.notify_instance_update(-1, -1);
if (m_canvas_type != CanvasAssembleView) {
// Fixes sinking/flying instances // Fixes sinking/flying instances
for (const std::pair<int, int>& i : done) { for (const std::pair<int, int> &i : done) {
ModelObject* m = m_model->objects[i.first]; ModelObject *m = m_model->objects[i.first];
//BBS: don't call translate if the z is zero // BBS: don't call translate if the z is zero
const double shift_z = m->get_instance_min_z(i.second); const double shift_z = m->get_instance_min_z(i.second);
// leave sinking instances as sinking // 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)) { 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); const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift); m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift); m->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list // BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second); m_selection.notify_instance_update(i.first, i.second);
} }
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first)); wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
} }
}
//BBS: nofity object list to update //BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items(); 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 // Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { 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()); model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) { 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->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 // BBS: backup
Slic3r::save_object_mesh(*model_object); Slic3r::save_object_mesh(*model_object);
} }
@ -5213,6 +5246,17 @@ void GLCanvas3D::mouse_up_cleanup()
m_canvas->ReleaseMouse(); 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() void GLCanvas3D::update_sequential_clearance()
{ {
if (current_printer_technology() != ptFFF || (fff_print()->config().print_sequence == PrintSequence::ByLayer)) 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"); GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
ECanvasType canvas_type = this->m_canvas_type; ECanvasType canvas_type = this->m_canvas_type;
bool partly_inside_enable = canvas_type == ECanvasType::CanvasAssembleView ? false : true;
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
@ -7312,7 +7357,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else { else {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
} }
}); },
partly_inside_enable);
} }
} }
else { else {
@ -7346,7 +7392,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else { else {
return true; return true;
} }
}); },
partly_inside_enable);
if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) { if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) {
const GLGizmosManager& gm = get_gizmos_manager(); const GLGizmosManager& gm = get_gizmos_manager();
shader->stop_using(); shader->stop_using();
@ -7414,19 +7461,11 @@ void GLCanvas3D::_render_sequential_clearance()
{ {
if (m_gizmos.is_dragging()) if (m_gizmos.is_dragging())
return; return;
auto type = m_gizmos.get_current_type();
switch (m_gizmos.get_current_type()) if (type == GLGizmosManager::EType::Undefined
{ || can_sequential_clearance_show_in_gizmo()) {
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; }
}
m_sequential_print_clearance.render(); m_sequential_print_clearance.render();
}
} }
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
@ -8171,6 +8210,7 @@ void GLCanvas3D::_render_return_toolbar() const
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states(); const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().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::PopStyleColor(5);
ImGui::PopStyleVar(1); ImGui::PopStyleVar(1);
@ -8370,8 +8410,45 @@ void GLCanvas3D::_render_paint_toolbar() const
ImGui::PopStyleColor(); 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<std::string, 3>{"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 //BBS
void GLCanvas3D::_render_assemble_control() const void GLCanvas3D::_render_assemble_control()
{ {
if (m_canvas_type != ECanvasType::CanvasAssembleView) { if (m_canvas_type != ECanvasType::CanvasAssembleView) {
GLVolume::explosion_ratio = m_explosion_ratio = 1.0; 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_padding = 7.0f;
const float text_size_x = std::max(imgui->calc_text_size(_L("Reset direction")).x + 2 * ImGui::GetStyle().FramePadding.x, 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)); 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 slider_width = 60.0f;
const float value_size = imgui->calc_text_size(std::string_view{"3.00"}).x + text_padding * 2; const float value_size = imgui->calc_text_size("3.00"sv).x + text_padding * 2;
const float item_spacing = imgui->get_item_spacing().x; const float item_spacing = imgui->get_item_spacing().x;
ImVec2 window_padding = ImGui::GetStyle().WindowPadding; 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->begin(_L("Assemble Control"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
float tip_icon_size;
{
float caption_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"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(); float clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position();
if (clp_dist == 0.f) { if (clp_dist == 0.f) {
@ -8415,32 +8504,76 @@ void GLCanvas3D::_render_assemble_control() const
}); });
} }
} }
same_line_width += (text_size_x + item_spacing);
ImGui::SameLine(window_padding.x + text_size_x + item_spacing); ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(slider_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); 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); ImGui::PushItemWidth(value_size);
bool view_input_changed = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); 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) if (view_slider_changed || view_input_changed)
m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true); 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->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); ImGui::PushItemWidth(slider_width);
bool explosion_slider_changed = imgui->bbl_slider_float_style("##ratio_slider", &m_explosion_ratio, 1.0f, 3.0f, "%1.2f"); 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); ImGui::PushItemWidth(value_size);
bool explosion_input_changed = ImGui::BBLDragFloat("##ratio_input", &m_explosion_ratio, 0.1f, 1.0f, 3.0f, "%1.2f"); 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<std::string> 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(); imgui->end();
ImGuiWrapper::pop_toolbar_style(); ImGuiWrapper::pop_toolbar_style();

View file

@ -18,7 +18,7 @@
#include "Camera.hpp" #include "Camera.hpp"
#include "SceneRaycaster.hpp" #include "SceneRaycaster.hpp"
#include "IMToolbar.hpp" #include "IMToolbar.hpp"
#include "slic3r/GUI/3DBed.hpp"
#include "libslic3r/Slicing.hpp" #include "libslic3r/Slicing.hpp"
#include <float.h> #include <float.h>
@ -512,6 +512,7 @@ private:
wxGLContext* m_context; wxGLContext* m_context;
SceneRaycaster m_scene_raycaster; SceneRaycaster m_scene_raycaster;
Bed3D &m_bed; Bed3D &m_bed;
std::map<std::string, wxString> m_assembly_view_desc;
#if ENABLE_RETINA_GL #if ENABLE_RETINA_GL
std::unique_ptr<RetinaHelper> m_retina_helper; std::unique_ptr<RetinaHelper> m_retina_helper;
#endif #endif
@ -611,8 +612,8 @@ private:
PrinterTechnology current_printer_technology() const; PrinterTechnology current_printer_technology() const;
bool m_show_world_axes{false};
Bed3D::Axes m_axes;
//BBS:record key botton frequency //BBS:record key botton frequency
int auto_orient_count = 0; int auto_orient_count = 0;
int auto_arrange_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(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); }
void set_color_clip_plane_colors(const std::array<ColorRGBA, 2>& colors) { m_volumes.set_color_clip_plane_colors(colors); } void set_color_clip_plane_colors(const std::array<ColorRGBA, 2>& 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 refresh_camera_scene_box();
void set_color_by(const std::string& value); void set_color_by(const std::string& value);
@ -1111,6 +1113,7 @@ public:
m_sequential_print_clearance.set_polygons(polygons, height_polygons); m_sequential_print_clearance.set_polygons(polygons, height_polygons);
} }
bool can_sequential_clearance_show_in_gizmo();
void update_sequential_clearance(); void update_sequential_clearance();
const Print* fff_print() const; const Print* fff_print() const;
@ -1189,7 +1192,8 @@ private:
// BBS // BBS
//void _render_view_toolbar() const; //void _render_view_toolbar() const;
void _render_paint_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; void _render_assemble_info() const;
#if ENABLE_SHOW_CAMERA_TARGET #if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target(); void _render_camera_target();

View file

@ -6,7 +6,7 @@ namespace GUI {
enum class ECoordinatesType : unsigned char enum class ECoordinatesType : unsigned char
{ {
World, World = 0,
Instance, Instance,
Local Local
}; };

View file

@ -4759,6 +4759,9 @@ void ObjectList::select_all()
void ObjectList::select_item_all_children() void ObjectList::select_item_all_children()
{ {
if (wxGetApp().plater() && !wxGetApp().plater()->canvas3D()->get_gizmos_manager().is_allow_select_all()) {
return;
}
wxDataViewItemArray sels; wxDataViewItemArray sels;
// There is no selection before OR some object is selected => select all objects // There is no selection before OR some object is selected => select all objects

View file

@ -823,10 +823,10 @@ bool AssembleView::init(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrint
m_canvas->enable_assemble_view_toolbar(false); m_canvas->enable_assemble_view_toolbar(false);
m_canvas->enable_return_toolbar(true); m_canvas->enable_return_toolbar(true);
m_canvas->enable_separator_toolbar(false); 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 // BBS: set volume_selection_mode to Volume
m_canvas->get_selection().set_volume_selection_mode(Selection::Volume); //same to 3d //m_canvas->get_selection().set_volume_selection_mode(Selection::Instance);
m_canvas->get_selection().lock_volume_selection_mode(); //m_canvas->get_selection().lock_volume_selection_mode();
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);

View file

@ -227,7 +227,71 @@ bool GLGizmoBase::render_combo(const std::string &label, const std::vector<std::
return is_changed; return is_changed;
} }
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) void GLGizmoBase::render_cross_mark(const Vec3f &target, bool is_single)
{
const float half_length = 4.0f;
glsafe(::glLineWidth(2.0f));
auto render_line = [](const Vec3f& p1, const Vec3f& p2, const ColorRGBA& color) {
GLModel::Geometry init_data;
init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3};
init_data.color = color;
init_data.reserve_vertices(2);
init_data.reserve_indices(2);
// vertices
init_data.add_vertex(p1);
init_data.add_vertex(p2);
// indices
init_data.add_line(0, 1);
GLModel model;
model.init_from(std::move(init_data));
model.render();
};
// draw line for x axis
if (!is_single) {
render_line(
{target(0) - half_length, target(1), target(2)},
{target(0) + half_length, target(1), target(2)},
ColorRGBA::RED());
}
else {
render_line(
{target(0), target(1), target(2)},
{target(0) + half_length, target(1), target(2)},
ColorRGBA::RED());
}
// draw line for y axis
if (!is_single) {
render_line(
{target(0), target(1) - half_length, target(2)},
{target(0), target(1) + half_length, target(2)},
ColorRGBA::GREEN());
} else {
render_line(
{target(0), target(1), target(2)},
{target(0), target(1) + half_length, target(2)},
ColorRGBA::GREEN());
}
// draw line for z axis
if (!is_single) {
render_line(
{target(0), target(1), target(2) - half_length},
{target(0), target(1), target(2) + half_length},
ColorRGBA::BLUE());
} else {
render_line(
{target(0), target(1), target(2)},
{target(0), target(1), target(2) + half_length},
ColorRGBA::BLUE());
}
}
GLGizmoBase::GLGizmoBase(GLCanvas3D &parent, const std::string &icon_filename, unsigned int sprite_id)
: m_parent(parent) : m_parent(parent)
, m_group_id(-1) , m_group_id(-1)
, m_state(Off) , m_state(Off)

View file

@ -152,7 +152,7 @@ protected:
bool render_combo(const std::string &label, const std::vector<std::string> &lines, bool render_combo(const std::string &label, const std::vector<std::string> &lines,
int &selection_idx, float label_width, float item_width); int &selection_idx, float label_width, float item_width);
void render_cross_mark(const Vec3f& target,bool is_single =false);
public: public:
GLGizmoBase(GLCanvas3D& parent, GLGizmoBase(GLCanvas3D& parent,
const std::string& icon_filename, const std::string& icon_filename,

View file

@ -48,6 +48,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
void GLGizmoMove3D::data_changed(bool is_serializing) { void GLGizmoMove3D::data_changed(bool is_serializing) {
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower(); m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
change_cs_by_selection();
} }
bool GLGizmoMove3D::on_init() bool GLGizmoMove3D::on_init()
@ -67,7 +68,11 @@ bool GLGizmoMove3D::on_init()
std::string GLGizmoMove3D::on_get_name() const std::string GLGizmoMove3D::on_get_name() const
{ {
if (!on_is_activable() && m_state == EState::Off) {
return _u8L("Move") + ":\n" + _u8L("Please select at least one object.");
} else {
return _u8L("Move"); return _u8L("Move");
}
} }
bool GLGizmoMove3D::on_is_activable() const bool GLGizmoMove3D::on_is_activable() const
@ -75,13 +80,21 @@ bool GLGizmoMove3D::on_is_activable() const
return !m_parent.get_selection().is_empty(); 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() void GLGizmoMove3D::on_start_dragging()
{ {
assert(m_hover_id != -1); assert(m_hover_id != -1);
m_displacement = Vec3d::Zero(); m_displacement = Vec3d::Zero();
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); 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_center = box.center();
m_starting_box_bottom_center = box.center(); m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center(2) = box.min(2); m_starting_box_bottom_center(2) = box.min(2);
@ -121,42 +134,38 @@ void GLGizmoMove3D::on_render()
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
const BoundingBoxf3& box = selection.get_bounding_box(); const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
const Vec3d& center = box.center(); 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; 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 // 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 // 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 // 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) { for (int i = 0; i < 3; ++i) {
m_grabbers[i].color = AXES_COLOR[i]; m_grabbers[i].color = AXES_COLOR[i];
m_grabbers[i].hover_color = AXES_HOVER_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)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
auto render_grabber_connection = [this, &center](unsigned int id) { auto render_grabber_connection = [this, &zero](unsigned int id) {
if (m_grabbers[id].enabled) { if (m_grabbers[id].enabled) {
//if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { //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(); m_grabber_connections[id].model.reset();
GLModel::Geometry init_data; GLModel::Geometry init_data;
@ -166,7 +175,7 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2); init_data.reserve_indices(2);
// vertices // vertices
init_data.add_vertex((Vec3f)center.cast<float>()); init_data.add_vertex((Vec3f)zero.cast<float>());
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>()); init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
// indices // indices
@ -186,7 +195,7 @@ void GLGizmoMove3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
// draw axes // draw axes
@ -199,6 +208,28 @@ void GLGizmoMove3D::on_render()
// draw grabbers // draw grabbers
render_grabbers(box); 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() void GLGizmoMove3D::on_register_raycasters_for_picking()
@ -245,5 +276,30 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
return projection; 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 GUI
} // namespace Slic3r } // namespace Slic3r

View file

@ -16,6 +16,8 @@ class GLGizmoMove3D : public GLGizmoBase
static const double Offset; static const double Offset;
Vec3d m_displacement{ Vec3d::Zero() }; Vec3d m_displacement{ Vec3d::Zero() };
Vec3d m_center{ Vec3d::Zero() };
BoundingBoxf3 m_bounding_box;
double m_snap_step{ 1.0 }; double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() }; Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() }; Vec3d m_starting_box_center{ Vec3d::Zero() };
@ -57,6 +59,7 @@ protected:
bool on_init() override; bool on_init() override;
std::string on_get_name() const override; std::string on_get_name() const override;
bool on_is_activable() const override; bool on_is_activable() const override;
virtual void on_set_state() override;
void on_start_dragging() override; void on_start_dragging() override;
void on_stop_dragging() override; void on_stop_dragging() override;
void on_dragging(const UpdateData& data) override; void on_dragging(const UpdateData& data) override;
@ -68,6 +71,9 @@ protected:
private: private:
double calc_projection(const UpdateData& data) const; 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;
}; };

View file

@ -527,25 +527,6 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
return use_grabbers(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<const ConfigOptionFloat *>(
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() bool GLGizmoRotate3D::on_init()
{ {
for (GLGizmoRotate& g : m_gizmos) for (GLGizmoRotate& g : m_gizmos)
@ -561,7 +542,57 @@ bool GLGizmoRotate3D::on_init()
std::string GLGizmoRotate3D::on_get_name() const std::string GLGizmoRotate3D::on_get_name() const
{ {
if (!on_is_activable() && m_state == EState::Off) {
return _u8L("Rotate") + ":\n" + _u8L("Please select at least one object.");
} else {
return _u8L("Rotate"); 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<const ConfigOptionFloat *>(
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 bool GLGizmoRotate3D::on_is_activable() const

View file

@ -151,11 +151,9 @@ public:
protected: protected:
bool on_init() override; bool on_init() override;
std::string on_get_name() const override; std::string on_get_name() const override;
void on_set_state() override { void on_set_state() override;
for (GLGizmoRotate& g : m_gizmos) void on_set_hover_id() override
g.set_state(m_state); {
}
void on_set_hover_id() override {
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); 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; void on_render_input_window(float x, float y, float bottom_limit) override;
private: private:
const GLVolume *m_last_volume;
class RotoptimzeWindow class RotoptimzeWindow
{ {
ImGuiWrapper *m_imgui = nullptr; ImGuiWrapper *m_imgui = nullptr;

View file

@ -24,11 +24,11 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan
//BBS: GUI refactor: add obj manipulation //BBS: GUI refactor: add obj manipulation
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation) GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id) : 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 //BBS: GUI refactor: add obj manipulation
, m_object_manipulation(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[0].grabber_indices = { 0, 1 };
m_grabber_connections[1].grabber_indices = { 2, 3 }; 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 }; 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 std::string GLGizmoScale3D::get_tooltip() const
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
@ -70,77 +81,57 @@ std::string GLGizmoScale3D::get_tooltip() const
return ""; return "";
} }
static int constraint_id(int grabber_id)
{
static const std::vector<int> 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) bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
{ {
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
if (m_dragging) { if (m_dragging) {
// Apply new temporary scale factors // Apply new temporary scale factors
Selection& selection = m_parent.get_selection();
TransformationType transformation_type; TransformationType transformation_type;
if (selection.is_single_full_instance()) { if (wxGetApp().obj_manipul()->is_local_coordinates())
transformation_type.set_instance();
} else if (selection.is_single_volume_or_modifier()) {
transformation_type.set_local(); transformation_type.set_local();
} else if (wxGetApp().obj_manipul()->is_instance_coordinates())
transformation_type.set_instance();
transformation_type.set_relative(); transformation_type.set_relative();
if (mouse_event.AltDown()) if (mouse_event.AltDown())
transformation_type.set_independent(); transformation_type.set_independent();
selection.scale(m_scale, transformation_type); Selection& selection = m_parent.get_selection();
if (m_starting.ctrl_down && m_hover_id < 6) { selection.scale_and_translate(get_scale(), get_offset(), transformation_type);
// 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);
}
} }
} }
return use_grabbers(mouse_event); 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) void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
{ {
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable; 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() bool GLGizmoScale3D::on_init()
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i)
{
m_grabbers.push_back(Grabber()); m_grabbers.push_back(Grabber());
} }
double half_pi = 0.5 * (double)PI; 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 // BBS
m_grabbers[4].enabled = false; m_grabbers[4].enabled = false;
@ -151,7 +142,11 @@ bool GLGizmoScale3D::on_init()
std::string GLGizmoScale3D::on_get_name() const std::string GLGizmoScale3D::on_get_name() const
{ {
if (!on_is_activable() && m_state == EState::Off) {
return _u8L("Scale") + ":\n" + _u8L("Please select at least one object.");
} else {
return _u8L("Scale"); return _u8L("Scale");
}
} }
bool GLGizmoScale3D::on_is_activable() const bool GLGizmoScale3D::on_is_activable() const
@ -160,21 +155,48 @@ bool GLGizmoScale3D::on_is_activable() const
return !selection.is_empty() && !selection.is_wipe_tower(); 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<int> 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() void GLGizmoScale3D::on_start_dragging()
{ {
assert(m_hover_id != -1); if (m_hover_id != -1) {
m_starting.drag_position = m_grabbers[m_hover_id].center; auto grabbers_transform = m_grabbers_tran.get_matrix();
m_starting.plane_center = m_grabbers[4].center; m_starting.drag_position = grabbers_transform * m_grabbers[m_hover_id].center;
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].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.ctrl_down = wxGetKeyState(WXK_CONTROL);
m_starting.box = m_box; m_starting.box = m_bounding_box;
m_starting.pivots[0] = m_grabbers[1].center; m_starting.center = m_center;
m_starting.pivots[1] = m_grabbers[0].center; m_starting.instance_center = m_instance_center;
m_starting.pivots[2] = m_grabbers[3].center;
m_starting.pivots[3] = m_grabbers[2].center; const Vec3d box_half_size = 0.5 * m_bounding_box.size();
m_starting.pivots[4] = m_grabbers[5].center;
m_starting.pivots[5] = m_grabbers[4].center; 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() void GLGizmoScale3D::on_stop_dragging()
@ -185,26 +207,95 @@ void GLGizmoScale3D::on_stop_dragging()
void GLGizmoScale3D::on_dragging(const UpdateData& data) 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); 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); 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); do_scale_along_axis(Z, data);
else if (m_hover_id >= 6) else if (m_hover_id >= 6)
do_scale_uniform(data); 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() void GLGizmoScale3D::on_render()
{ {
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
update_render_data(); update_grabbers_data();
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); 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 //draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat"); 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) // BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
//if (single_instance || single_volume) { //if (single_instance || single_volume) {
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (m_grabbers[4].enabled && m_grabbers[5].enabled) if (m_grabbers[4].enabled && m_grabbers[5].enabled)
render_grabbers_connection(4, 5, m_grabbers[4].color); 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) void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{ {
double ratio = calc_ratio(data); double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0)
Vec3d curr_scale = m_scale; {
curr_scale(axis) = m_starting.scale(axis) * ratio; m_scale(axis) = m_starting.scale(axis) * ratio;
m_scale = curr_scale; 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) if (ratio > 0.0)
{
m_scale = m_starting.scale * ratio; m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero();
}
} }
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{ {
double ratio = 0.0; 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; Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm(); 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 mouse_dir = data.mouse_ray.unit_vector();
Vec3d plane_normal = m_starting.plane_nromal; Vec3d plane_normal = m_starting.plane_nromal;
if (m_hover_id == 5) { 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); Vec3d plane_vec = mouse_dir.cross(m_starting.plane_nromal);
plane_normal = plane_vec.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 // 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 // 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; Vec3d inters_vec = inters - m_starting.drag_position;
@ -347,78 +468,5 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio; 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 GUI
} // namespace Slic3r } // namespace Slic3r

View file

@ -19,25 +19,28 @@ class GLGizmoScale3D : public GLGizmoBase
{ {
Vec3d scale; Vec3d scale;
Vec3d drag_position; 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_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; BoundingBoxf3 box;
Vec3d pivots[6]; Vec3d pivots[6];// Vec3d constraint_position{Vec3d::Zero()};
Vec3d local_pivots[6];
bool ctrl_down; 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(); } } 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; mutable BoundingBoxf3 m_bounding_box;
Transform3d m_transform; Geometry::Transformation m_grabbers_tran;//m_grabbers_transform
Vec3d m_scale{ Vec3d::Ones() }; Vec3d m_center{Vec3d::Zero()};
double m_snap_step{ 0.05 }; Vec3d m_instance_center{Vec3d::Zero()};
Vec3d m_scale;
Vec3d m_offset;
double m_snap_step;
StartingData m_starting; StartingData m_starting;
ColorRGBA m_base_color;
ColorRGBA m_drag_color;
ColorRGBA m_highlight_color;
struct GrabberConnection struct GrabberConnection
{ {
GLModel model; GLModel model;
@ -58,9 +61,11 @@ public:
double get_snap_step(double step) const { return m_snap_step; } double get_snap_step(double step) const { return m_snap_step; }
void set_snap_step(double step) { m_snap_step = 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; } 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; std::string get_tooltip() const override;
/// <summary> /// <summary>
@ -76,6 +81,7 @@ protected:
virtual bool on_init() override; virtual bool on_init() override;
virtual std::string on_get_name() const override; virtual std::string on_get_name() const override;
virtual bool on_is_activable() const override; virtual bool on_is_activable() const override;
virtual void on_set_state() override;
virtual void on_start_dragging() override; virtual void on_start_dragging() override;
virtual void on_stop_dragging() override; virtual void on_stop_dragging() override;
virtual void on_dragging(const UpdateData& data) override; virtual void on_dragging(const UpdateData& data) override;
@ -92,7 +98,10 @@ private:
void do_scale_uniform(const UpdateData& data); void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const; 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;
}; };

View file

@ -1024,20 +1024,6 @@ void GLGizmoText::show_tooltip_information(float x, float y)
ImGui::PopStyleVar(2); 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() void GLGizmoText::reset_text_info()
{ {
m_font_name = ""; m_font_name = "";

View file

@ -62,7 +62,9 @@ std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
out.reserve(m_gizmos.size()); out.reserve(m_gizmos.size());
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) { if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
for (size_t i = 0; i < m_gizmos.size(); ++i) 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) Assembly ||
m_gizmos[i]->get_sprite_id() == (unsigned int) MmuSegmentation) m_gizmos[i]->get_sprite_id() == (unsigned int) MmuSegmentation)
out.push_back(i); out.push_back(i);
@ -247,6 +249,16 @@ bool GLGizmosManager::init_icon_textures()
else else
return false; 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 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)); icon_list.insert(std::make_pair((int)IC_TOOLBAR_TOOLTIP, texture_id));
else else
@ -371,6 +383,9 @@ void GLGizmosManager::update_assemble_view_data()
void GLGizmosManager::update_data() void GLGizmosManager::update_data()
{ {
if (!m_enabled) return; if (!m_enabled) return;
const Selection& selection = m_parent.get_selection();
if (m_common_gizmos_data) if (m_common_gizmos_data)
m_common_gizmos_data->update(get_current() m_common_gizmos_data->update(get_current()
? get_current()->get_requirements() ? 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); if (m_current != Flatten && !m_gizmos.empty()) m_gizmos[Flatten]->data_changed(m_serializing);
//BBS: GUI refactor: add object manipulation in gizmo //BBS: GUI refactor: add object manipulation in gizmo
if (!selection.is_empty()) {
m_object_manipulation.update_ui_from_settings(); m_object_manipulation.update_ui_from_settings();
m_object_manipulation.UpdateAndShow(true); m_object_manipulation.UpdateAndShow(true);
}
} }
bool GLGizmosManager::is_running() const bool GLGizmosManager::is_running() const
@ -461,6 +478,22 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
return false; 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 ClippingPlane GLGizmosManager::get_clipping_plane() const
{ {
if (! m_common_gizmos_data if (! m_common_gizmos_data

View file

@ -164,6 +164,8 @@ public:
enum MENU_ICON_NAME { enum MENU_ICON_NAME {
IC_TOOLBAR_RESET = 0, IC_TOOLBAR_RESET = 0,
IC_TOOLBAR_RESET_HOVER, IC_TOOLBAR_RESET_HOVER,
IC_TOOLBAR_RESET_ZERO,
IC_TOOLBAR_RESET_ZERO_HOVER,
IC_TOOLBAR_TOOLTIP, IC_TOOLBAR_TOOLTIP,
IC_TOOLBAR_TOOLTIP_HOVER, IC_TOOLBAR_TOOLTIP_HOVER,
IC_NAME_COUNT, IC_NAME_COUNT,
@ -261,6 +263,8 @@ public:
return nullptr; return nullptr;
} }
bool is_paint_gizmo();
bool is_allow_select_all();
ClippingPlane get_clipping_plane() const; ClippingPlane get_clipping_plane() const;
ClippingPlane get_assemble_view_clipping_plane() const; ClippingPlane get_assemble_view_clipping_plane() const;
bool wants_reslice_supports_on_undo() const; bool wants_reslice_supports_on_undo() const;

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "libslic3r/Geometry.hpp"
#include <float.h> #include <float.h>
#include "slic3r/GUI/GUI_Geometry.hpp" #include "slic3r/GUI/GUI_Geometry.hpp"
@ -30,6 +31,8 @@ public:
Vec3d position_rounded; Vec3d position_rounded;
Vec3d rotation; Vec3d rotation;
Vec3d rotation_rounded; Vec3d rotation_rounded;
Vec3d absolute_rotation;
Vec3d absolute_rotation_rounded;
Vec3d scale; Vec3d scale;
Vec3d scale_rounded; Vec3d scale_rounded;
Vec3d size; Vec3d size;
@ -56,7 +59,7 @@ public:
Cache m_cache; Cache m_cache;
bool m_imperial_units { false }; bool m_imperial_units { false };
bool m_use_object_cs{false};
// Mirroring buttons and their current state // Mirroring buttons and their current state
//enum MirrorButtonState { //enum MirrorButtonState {
// mbHidden, // mbHidden,
@ -75,19 +78,28 @@ public:
std::string m_new_unit_string; std::string m_new_unit_string;
Vec3d m_new_position; Vec3d m_new_position;
Vec3d m_new_rotation; Vec3d m_new_rotation;
Vec3d m_new_absolute_rotation;
Vec3d m_new_scale; Vec3d m_new_scale;
Vec3d m_new_size; Vec3d m_new_size;
Vec3d m_unscale_size;
Vec3d m_buffered_position; Vec3d m_buffered_position;
Vec3d m_buffered_rotation; Vec3d m_buffered_rotation;
Vec3d m_buffered_absolute_rotation;
Vec3d m_buffered_scale; Vec3d m_buffered_scale;
Vec3d m_buffered_size; Vec3d m_buffered_size;
Vec3d cs_center;
bool m_new_enabled {true}; bool m_new_enabled {true};
bool m_uniform_scale {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_rotation { false };
bool m_show_clear_scale { false }; bool m_show_clear_scale { false };
bool m_show_drop_to_bed { 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: protected:
float last_move_input_window_width = 0.0f; float last_move_input_window_width = 0.0f;
@ -108,21 +120,33 @@ public:
void set_uniform_scaling(const bool uniform_scale); void set_uniform_scaling(const bool uniform_scale);
bool get_uniform_scaling() const { return m_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); void set_coordinates_type(ECoordinatesType type);
ECoordinatesType get_coordinates_type() const; ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; } bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; } bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; } 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 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); 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<std::string> &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_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_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); 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); 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_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: private:
void reset_settings_value(); void reset_settings_value();
@ -137,15 +161,21 @@ private:
// change values // change values
void change_position_value(int axis, double value); void change_position_value(int axis, double value);
void change_rotation_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_scale_value(int axis, double value);
void change_size_value(int axis, double value); void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const; void do_scale(int axis, const Vec3d &scale) const;
void reset_position_value(); void reset_position_value();
void reset_rotation_value(); void reset_rotation_value(bool reset_relative);
void reset_scale_value(); void reset_scale_value();
GLCanvas3D& m_glcanvas; GLCanvas3D& m_glcanvas;
unsigned int m_last_active_item { 0 }; unsigned int m_last_active_item { 0 };
std::map<std::string, wxString> m_desc_move;
std::map<std::string, wxString> m_desc_rotate;
std::map<std::string, wxString> m_desc_scale;
Vec3d m_init_rotation;
Transform3d m_init_rotation_scale_tran;
}; };
}} }}

View file

@ -401,6 +401,39 @@ void Selection::remove_volumes(EMode mode, const std::vector<unsigned int>& volu
this->set_bounding_boxes_dirty(); 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() void Selection::add_curr_plate()
{ {
if (!m_valid) if (!m_valid)
@ -910,16 +943,16 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
return *m_scaled_instance_bounding_box; 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()); assert(is_single_full_instance());
if (!m_full_unscaled_instance_bounding_box.has_value()) { if (!m_full_unscaled_instance_bounding_box.has_value()) {
std::optional<BoundingBoxf3>* bbox = const_cast<std::optional<BoundingBoxf3>*>(&m_full_unscaled_instance_bounding_box); std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_unscaled_instance_bounding_box);
*bbox = BoundingBoxf3(); *bbox = BoundingBoxf3();
if (m_valid) { if (m_valid) {
for (unsigned int i : m_list) { for (unsigned int i : m_list) {
const GLVolume& volume = *(*m_volumes)[i]; const GLVolume &volume = *(*m_volumes)[i];
Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix(); 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(); trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo)); (*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
@ -929,16 +962,16 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_bounding_box() const
return *m_full_unscaled_instance_bounding_box; 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()); assert(is_single_full_instance());
if (!m_full_scaled_instance_bounding_box.has_value()) { if (!m_full_scaled_instance_bounding_box.has_value()) {
std::optional<BoundingBoxf3>* bbox = const_cast<std::optional<BoundingBoxf3>*>(&m_full_scaled_instance_bounding_box); std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_scaled_instance_bounding_box);
*bbox = BoundingBoxf3(); *bbox = BoundingBoxf3();
if (m_valid) { if (m_valid) {
for (unsigned int i : m_list) { for (unsigned int i : m_list) {
const GLVolume& volume = *(*m_volumes)[i]; const GLVolume &volume = *(*m_volumes)[i];
Transform3d trafo = volume.get_instance_transformation().get_matrix() * volume.get_volume_transformation().get_matrix(); Transform3d trafo = volume.get_instance_transformation().get_matrix() * volume.get_volume_transformation().get_matrix();
trafo.translation().z() += volume.get_sla_shift_z(); trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo)); (*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
@ -948,16 +981,16 @@ const BoundingBoxf3& Selection::get_full_scaled_instance_bounding_box() const
return *m_full_scaled_instance_bounding_box; 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()); assert(is_single_full_instance());
if (!m_full_unscaled_instance_local_bounding_box.has_value()) { if (!m_full_unscaled_instance_local_bounding_box.has_value()) {
std::optional<BoundingBoxf3>* bbox = const_cast<std::optional<BoundingBoxf3>*>(&m_full_unscaled_instance_local_bounding_box); std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_unscaled_instance_local_bounding_box);
*bbox = BoundingBoxf3(); *bbox = BoundingBoxf3();
if (m_valid) { if (m_valid) {
for (unsigned int i : m_list) { for (unsigned int i : m_list) {
const GLVolume& volume = *(*m_volumes)[i]; const GLVolume &volume = *(*m_volumes)[i];
Transform3d trafo = volume.get_volume_transformation().get_matrix(); Transform3d trafo = volume.get_volume_transformation().get_matrix();
trafo.translation().z() += volume.get_sla_shift_z(); trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo)); (*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; return *m_full_unscaled_instance_local_bounding_box;
} }
const std::pair<BoundingBoxf3, Transform3d>& Selection::get_bounding_box_in_current_reference_system() const const std::pair<BoundingBoxf3, Transform3d> &Selection::get_bounding_box_in_current_reference_system() const
{ {
static int last_coordinates_type = -1; static int last_coordinates_type = -1;
assert(!is_empty()); assert(!is_empty());
ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) coordinates_type = ECoordinatesType::World;
coordinates_type = ECoordinatesType::World;
if (last_coordinates_type != int(coordinates_type)) if (last_coordinates_type != int(coordinates_type)) const_cast<std::optional<std::pair<BoundingBoxf3, Transform3d>> *>(&m_bounding_box_in_current_reference_system)->reset();
const_cast<std::optional<std::pair<BoundingBoxf3, Transform3d>>*>(&m_bounding_box_in_current_reference_system)->reset();
if (!m_bounding_box_in_current_reference_system.has_value()) { if (!m_bounding_box_in_current_reference_system.has_value()) {
last_coordinates_type = int(coordinates_type); last_coordinates_type = int(coordinates_type);
*const_cast<std::optional<std::pair<BoundingBoxf3, Transform3d>>*>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type); *const_cast<std::optional<std::pair<BoundingBoxf3, Transform3d>> *>(&m_bounding_box_in_current_reference_system) = get_bounding_box_in_reference_system(coordinates_type);
} }
return *m_bounding_box_in_current_reference_system; return *m_bounding_box_in_current_reference_system;
@ -994,11 +1025,19 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
// trafo to current reference system // trafo to current reference system
// //
Transform3d trafo; Transform3d trafo;
switch (type) switch (type) {
{ case ECoordinatesType::World: {
case ECoordinatesType::World: { trafo = Transform3d::Identity(); break; } trafo = Transform3d::Identity();
case ECoordinatesType::Instance: { trafo = get_first_volume()->get_instance_transformation().get_matrix(); break; } break;
case ECoordinatesType::Local: { trafo = get_first_volume()->world_matrix(); break; } }
case ECoordinatesType::Instance: {
trafo = get_first_volume()->get_instance_transformation().get_matrix();
break;
}
case ECoordinatesType::Local: {
trafo = get_first_volume()->world_matrix();
break;
}
} }
// //
@ -1007,24 +1046,22 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
Geometry::Transformation t(trafo); Geometry::Transformation t(trafo);
t.reset_scaling_factor(); t.reset_scaling_factor();
const Transform3d basis_trafo = t.get_matrix_no_offset(); const Transform3d basis_trafo = t.get_matrix_no_offset();
std::vector<Vec3d> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() }; std::vector<Vec3d> axes = {Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ()};
for (size_t i = 0; i < axes.size(); ++i) { for (size_t i = 0; i < axes.size(); ++i) { axes[i] = basis_trafo * axes[i]; }
axes[i] = basis_trafo * axes[i];
}
// //
// calculate bounding box aligned to trafo basis // calculate bounding box aligned to trafo basis
// //
Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX }; Vec3d min = {DBL_MAX, DBL_MAX, DBL_MAX};
Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX }; Vec3d max = {-DBL_MAX, -DBL_MAX, -DBL_MAX};
for (unsigned int id : m_list) { for (unsigned int id : m_list) {
const GLVolume& vol = *get_volume(id); const GLVolume & vol = *get_volume(id);
const Transform3d vol_world_rafo = vol.world_matrix(); const Transform3d vol_world_rafo = vol.world_matrix();
const TriangleMesh* mesh = vol.convex_hull(); const TriangleMesh *mesh = vol.convex_hull();
if (mesh == nullptr) if (mesh == nullptr)
mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh(); mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
assert(mesh != nullptr); 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<double>(); const Vec3d world_v = vol_world_rafo * v.cast<double>();
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
const double i_comp = world_v.dot(axes[i]); const double i_comp = world_v.dot(axes[i]);
@ -1042,24 +1079,21 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
// Fix for non centered volume // Fix for non centered volume
// by move with calculated center(to volume center) and extend half box size // by move with calculated center(to volume center) and extend half box size
// e.g. for right aligned embossed text // e.g. for right aligned embossed text
if (m_list.size() == 1 && if (m_list.size() == 1 && type == ECoordinatesType::Local) {
type == ECoordinatesType::Local) { const GLVolume & vol = *get_volume(*m_list.begin());
const GLVolume& vol = *get_volume(*m_list.begin());
const Transform3d vol_world_trafo = vol.world_matrix(); const Transform3d vol_world_trafo = vol.world_matrix();
Vec3d world_zero = vol_world_trafo * Vec3d::Zero(); Vec3d world_zero = vol_world_trafo * Vec3d::Zero();
for (size_t i = 0; i < 3; i++){ for (size_t i = 0; i < 3; i++) {
// move center to local volume zero // move center to local volume zero
center[i] = world_zero.dot(axes[i]); center[i] = world_zero.dot(axes[i]);
// extend half size to bigger distance from center // extend half size to bigger distance from center
half_box_size[i] = std::max( half_box_size[i] = std::max(abs(center[i] - min[i]), abs(center[i] - max[i]));
abs(center[i] - min[i]),
abs(center[i] - max[i]));
} }
} }
const BoundingBoxf3 out_box(-half_box_size, half_box_size); const BoundingBoxf3 out_box(-half_box_size, half_box_size);
out_trafo.set_offset(basis_trafo * center); 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<Vec3d, double> Selection::get_bounding_sphere() const const std::pair<Vec3d, double> Selection::get_bounding_sphere() const
@ -1138,34 +1172,52 @@ void Selection::move_to_center(const Vec3d& displacement, bool local)
this->set_bounding_boxes_dirty(); 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) if (!m_valid) return;
return;
// Emboss use translate in local coordinate
assert(transformation_type.relative() ||
transformation_type.local());
for (unsigned int i : m_list) { for (unsigned int i : m_list) {
GLVolume& v = *(*m_volumes)[i]; GLVolume & v = *(*m_volumes)[i];
const VolumeCache& volume_data = m_cache.volumes_data[i]; const VolumeCache &volume_data = m_cache.volumes_data[i];
if (m_mode == Instance && !is_wipe_tower()) { if (m_mode == Instance && !is_wipe_tower()) {
assert(is_from_fully_selected_instance(i)); assert(is_from_fully_selected_instance(i));
if (transformation_type.instance()) { 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); 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); transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
} 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;
} }
else {
if (transformation_type.local() && transformation_type.absolute()) { if (tower_origin(1) + actual_displacement(1) - margin < plate_bbox.min(1)) {
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform(); actual_displacement(1) = plate_bbox.min(1) - tower_origin(1) + margin;
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); } 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 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); v.set_volume_offset(vol_trafo.get_offset() + inst_trafo.get_scaling_factor_matrix().inverse() * vol_trafo.get_rotation_matrix() * displacement);
} } else {
else {
Vec3d relative_disp = displacement; Vec3d relative_disp = displacement;
if (transformation_type.world() && transformation_type.instance()) if (transformation_type.world() && transformation_type.instance())
relative_disp = volume_data.get_instance_transform().get_scaling_factor_matrix().inverse() * relative_disp; 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) else if (m_mode == Volume)
synchronize_unselected_volumes(); synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
ensure_not_below_bed(); ensure_not_below_bed();
}
set_bounding_boxes_dirty(); set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state(); wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
} }
// Rotate an object around one of the axes. Only one rotation component is expected to be changing. // 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) 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 #endif // !DISABLE_INSTANCES_SYNCH
set_bounding_boxes_dirty(); set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state(); wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
} }
void Selection::flattening_rotate(const Vec3d& normal) void Selection::flattening_rotate(const Vec3d& normal)
@ -1320,96 +1376,6 @@ void Selection::flattening_rotate(const Vec3d& normal)
this->set_bounding_boxes_dirty(); 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<double, 3, 3, Eigen::DontAlign> 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<double, 3, 3, Eigen::DontAlign> 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<double, 3, 3, Eigen::DontAlign> 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) void Selection::scale(const Vec3d& scale, TransformationType transformation_type)
{ {
scale_and_translate(scale, Vec3d::Zero(), 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 #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); if (!m_valid) return;
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;
Vec3d relative_scale = scale; Vec3d relative_scale = scale;
if (transformation_type.absolute()) { if (transformation_type.absolute()) {
@ -1582,9 +1541,9 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
} }
for (unsigned int i : m_list) { for (unsigned int i : m_list) {
GLVolume& v = *(*m_volumes)[i]; GLVolume & v = *(*m_volumes)[i];
const VolumeCache& volume_data = m_cache.volumes_data[i]; const VolumeCache & volume_data = m_cache.volumes_data[i];
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform(); const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
if (m_mode == Instance) { if (m_mode == Instance) {
if (transformation_type.instance()) { if (transformation_type.instance()) {
@ -1594,26 +1553,33 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
inst_trafo.get_matrix().computeRotationScaling(&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 offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale); 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)); v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo *
} Geometry::translation_transform(-local_inst_pivot));
else } else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center); transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale),
} m_cache.dragging_center);
else { // 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()) { if (!is_single_volume_or_modifier()) {
assert(transformation_type.world()); 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); transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale),
} m_cache.dragging_center);
else { } else {
transformation_type.set_independent(); transformation_type.set_independent();
Vec3d translation; 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; 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()) else if (transformation_type.instance())
translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation; translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
else else
translation = world_translation; 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);
} }
} }
} }
@ -1629,7 +1595,16 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
ensure_on_bed(); ensure_on_bed();
set_bounding_boxes_dirty(); set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state(); 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) 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; m_scale_factor = scale_factor;
// render cumulative bounding box of selected volumes // render cumulative bounding box of selected volumes
const auto& [box, trafo] = get_bounding_box_in_current_reference_system(); 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(); render_synchronized_volumes();
} }
@ -1992,40 +1968,33 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif
glsafe(::glEnable(GL_DEPTH_TEST)); 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(); Transform3d orient_matrix = Transform3d::Identity();
if (!boost::starts_with(sidebar_field, "layer")) { if (!boost::starts_with(sidebar_field, "layer")) {
shader->set_uniform("emission_factor", 0.05f); shader->set_uniform("emission_factor", 0.05f);
const auto &[box, box_trafo] = get_bounding_box_in_current_reference_system();
// BBS // BBS
if (is_single_full_instance()/* && !wxGetApp().obj_manipul()->get_world_coordinates()*/) { if (is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
if (!boost::starts_with(sidebar_field, "position")) { center = box_trafo.translation();
if (boost::starts_with(sidebar_field, "scale"))
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix(); orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
else if (boost::starts_with(sidebar_field, "rotation")) { } else if (is_single_volume_or_modifier()) {
if (boost::ends_with(sidebar_field, "x")) 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(); orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
else if (boost::ends_with(sidebar_field, "y")) { center = box_trafo.translation();
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()));
} }
} }
} } else {
} if (requires_local_axes()) {
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())
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix(); 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")) if (!boost::starts_with(sidebar_field, "layer"))
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); 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); render_sidebar_position_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "rotation")) else if (boost::starts_with(sidebar_field, "rotation"))
render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix); 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")) else if (boost::starts_with(sidebar_field, "scale") || boost::starts_with(sidebar_field, "size"))
//BBS: GUI refactor: add uniform_scale from gizmo //BBS: GUI refactor: add uniform_scale from gizmo
render_sidebar_scale_hints(sidebar_field, uniform_scale, *shader, base_matrix * orient_matrix); 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 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 struct SameInstance
{ {
int obj_idx; int obj_idx;
@ -3180,14 +3154,14 @@ void Selection::paste_objects_from_clipboard()
Vec3d displacement; Vec3d displacement;
bool in_current = plate->intersects(bbox); bool in_current = plate->intersects(bbox);
auto start_point = in_current ? bbox.center() : plate->get_build_volume().center(); 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) { if (shift_all(0) != 0 || shift_all(1) != 0) {
// BBS: if multiple objects are selected, move them as a whole after copy // 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}); 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(); 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 { } else {
// BBS: if only one object is copied, find an empty cell to put it // 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 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}); 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)}; displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_offset(2)};

View file

@ -15,6 +15,7 @@ class Model;
class ModelObject; class ModelObject;
class ModelVolume; class ModelVolume;
class ObjectID; class ObjectID;
class ModelInstance;
class GLVolume; class GLVolume;
class GLArrow; class GLArrow;
class GLCurvedArrow; class GLCurvedArrow;
@ -225,6 +226,9 @@ public:
void remove_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs); void remove_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs);
//BBS //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_curr_plate();
void add_object_from_idx(std::vector<int>& object_idxs); void add_object_from_idx(std::vector<int>& object_idxs);
void remove_curr_plate(); void remove_curr_plate();
@ -326,20 +330,17 @@ public:
const std::pair<Vec3d, double> get_bounding_sphere() const; const std::pair<Vec3d, double> get_bounding_sphere() const;
void setup_cache(); void setup_cache();
void translate(const Vec3d& displacement, TransformationType transformation_type); void translate(const Vec3d& displacement, TransformationType transformation_type);
void move_to_center(const Vec3d& displacement, bool local = false); void move_to_center(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, TransformationType transformation_type); void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal); 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); void scale(const Vec3d& scale, TransformationType transformation_type);
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT #if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_to_fit_print_volume(const BuildVolume& volume); void scale_to_fit_print_volume(const BuildVolume& volume);
#else #else
void scale_to_fit_print_volume(const DynamicPrintConfig& config); void scale_to_fit_print_volume(const DynamicPrintConfig& config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT #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 mirror(Axis axis, TransformationType transformation_type);
void translate(unsigned int object_idx, const Vec3d& displacement); void translate(unsigned int object_idx, const Vec3d& displacement);
@ -351,6 +352,7 @@ public:
//BBS: add partplate related logic //BBS: add partplate related logic
void notify_instance_update(int object_idx, int instance_idx); void notify_instance_update(int object_idx, int instance_idx);
// BBS // 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 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 lock_volume_selection_mode() { m_volume_selection_locked = true; }
void unlock_volume_selection_mode() { m_volume_selection_locked = false; } void unlock_volume_selection_mode() { m_volume_selection_locked = false; }
@ -358,11 +360,11 @@ public:
void erase(); void erase();
void render(float scale_factor = 1.0); 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 #if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging); void render_center(bool gizmo_is_dragging);
#endif // ENABLE_RENDER_SELECTION_CENTER #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; bool requires_local_axes() const;
@ -405,7 +407,8 @@ private:
void set_bounding_boxes_dirty() { void set_bounding_boxes_dirty() {
m_bounding_box.reset(); m_bounding_box.reset();
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_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_full_unscaled_instance_local_bounding_box.reset();
m_bounding_box_in_current_reference_system.reset(); m_bounding_box_in_current_reference_system.reset();
m_bounding_sphere.reset(); m_bounding_sphere.reset();