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
;;
j )
CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
;;
b )
BUILD_DEBUG="1"

View file

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

View file

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

View file

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

View file

@ -3732,10 +3732,10 @@ msgstr ""
#, c-format, boost-format
msgid ""
"Recommended nozzle temperature of this filament type is [%d, %d] degree "
"centigrade"
"The recommended nozzle temperature for this filament type is [%d, %d] "
"degrees Celsius."
msgstr ""
"Die empfohlene Düsentemperatur für diesen Filamenttyp beträgt [%d, %d] °C"
"Die empfohlene Düsentemperatur für diesen Filamenttyp beträgt [%d, %d] °C."
msgid ""
"Too small max volumetric speed.\n"
@ -20600,7 +20600,7 @@ msgstr ""
#, c-format, boost-format
#~ msgid ""
#~ "Bed temperature of other layer is lower than bed temperature of initial "
#~ "layer for more than %d degree centigrade.\n"
#~ "layer for more than %d degrees Celsius.\n"
#~ "This may cause model broken free from build plate during printing"
#~ msgstr ""
#~ "Die Betttemperatur der anderen Schicht ist um mehr als %d Grad Celsius "

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

@ -442,6 +442,10 @@ public:
};
float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance));
// ORCA: Clamp resulting speed to lowest of calculated speed based on the overhang values and the current speed
// Fixes bug where resulting overhang speed is higher than the current speed due to (for example) volumetric flow limits.
extrusion_speed = std::min(extrusion_speed, original_speed);
if(slowdown_for_curled_edges) {
float curled_speed = calculate_speed(artificial_distance_to_curled_lines);
extrusion_speed = std::min(curled_speed, extrusion_speed); // adjust extrusion speed based on what is smallest - the calculated overhang speed or the artificial curled speed

View file

@ -478,6 +478,16 @@ Transform3d Transformation::get_rotation_matrix() const
return extract_rotation_matrix(m_matrix);
}
Vec3d Transformation::get_rotation_by_quaternion() const
{
Matrix3d rotation_matrix = m_matrix.matrix().block(0, 0, 3, 3);
Eigen::Quaterniond quaternion(rotation_matrix);
quaternion.normalize();
Vec3d temp_rotation = quaternion.matrix().eulerAngles(2, 1, 0);
std::swap(temp_rotation(0), temp_rotation(2));
return temp_rotation;
}
void Transformation::set_rotation(const Vec3d& rotation)
{
const Vec3d offset = get_offset();
@ -839,6 +849,17 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
return curMat;
}
Transformation generate_transform(const Vec3d& x_dir, const Vec3d& y_dir, const Vec3d& z_dir, const Vec3d& origin) {
Matrix3d m;
m.col(0) = x_dir.normalized();
m.col(1) = y_dir.normalized();
m.col(2) = z_dir.normalized();
Transform3d mm(m);
Transformation tran(mm);
tran.set_offset(origin);
return tran;
}
bool is_point_inside_polygon_corner(const Point &a, const Point &b, const Point &c, const Point &query_point) {
// Cast all input points into int64_t to prevent overflows when points are close to max values of coord_t.
const Vec2i64 a_i64 = a.cast<int64_t>();

View file

@ -421,6 +421,7 @@ public:
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
Vec3d get_rotation() const;
Vec3d get_rotation_by_quaternion() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
@ -545,6 +546,7 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation)
}
Transformation mat_around_a_point_rotate(const Transformation& innMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian);
Transformation generate_transform(const Vec3d &x_dir, const Vec3d &y_dir, const Vec3d &z_dir, const Vec3d &origin);
/**
* Checks if a given point is inside a corner of a polygon.

View file

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

View file

@ -410,8 +410,8 @@ public:
return global_config.option<T>(config_option);
}
ModelVolume* add_volume(const TriangleMesh &mesh);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART);
ModelVolume* add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry = true);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART, bool modify_to_center_geometry = true);
ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID);
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART);
@ -1244,11 +1244,13 @@ public:
m_assemble_initialized = true;
m_assemble_transformation = transformation;
}
void set_assemble_from_transform(Transform3d& transform) {
void set_assemble_from_transform(const Transform3d& transform) {
m_assemble_initialized = true;
m_assemble_transformation.set_matrix(transform);
}
Vec3d get_assemble_offset() const {return m_assemble_transformation.get_offset(); }
void set_assemble_offset(const Vec3d& offset) { m_assemble_transformation.set_offset(offset); }
void set_assemble_rotation(const Vec3d &rotation) { m_assemble_transformation.set_rotation(rotation); }
void rotate_assemble(double angle, const Vec3d& axis) {
m_assemble_transformation.set_rotation(m_assemble_transformation.get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix()));
}

View file

@ -895,8 +895,13 @@ int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_suppo
}
//BBS: add outline drawing logic
void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, const GUI::Size& cnv_size,
std::function<bool(const GLVolume&)> filter_func) const
void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
bool disable_cullface,
const Transform3d & view_matrix,
const Transform3d& projection_matrix,
const GUI::Size& cnv_size,
std::function<bool(const GLVolume &)> filter_func,
bool partly_inside_enable) const
{
GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func);
if (to_render.empty())
@ -964,7 +969,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
//shader->set_uniform("print_volume.xy_data", m_render_volume.data);
//shader->set_uniform("print_volume.z_data", m_render_volume.zs);
if (volume.first->partly_inside) {
if (volume.first->partly_inside && partly_inside_enable) {
//only partly inside volume need to be painted with boundary check
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
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;
// Render the volumes by OpenGL.
//BBS: add outline drawing logic
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, const GUI::Size& cnv_size,
std::function<bool(const GLVolume &)> filter_func = std::function<bool(const GLVolume &)>()) const;
void render(ERenderType type,
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
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) {
wxString msg_text = _(L("Nozzle may be blocked when the temperature is out of recommended range.\n"
"Please make sure whether to use the temperature to print.\n\n"));
msg_text += wxString::Format(_L("Recommended nozzle temperature of this filament type is [%d, %d] degree centigrade"), temperature_range_low, temperature_range_high);
msg_text += wxString::Format(_L("The recommended nozzle temperature for this filament type is [%d, %d] degrees Celsius."), temperature_range_low, temperature_range_high);
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@ -113,7 +113,7 @@ void ConfigManipulation::check_nozzle_temperature_initial_layer_range(DynamicPri
{
wxString msg_text = _(L("Nozzle may be blocked when the temperature is out of recommended range.\n"
"Please make sure whether to use the temperature to print.\n\n"));
msg_text += wxString::Format(_L("Recommended nozzle temperature of this filament type is [%d, %d] degree centigrade"), temperature_range_low, temperature_range_high);
msg_text += wxString::Format(_L("The recommended nozzle temperature for this filament type is [%d, %d] degrees Celsius."), temperature_range_low, temperature_range_high);
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
is_msg_dlg_already_exist = true;
dialog.ShowModal();

View file

@ -14,7 +14,6 @@
#include "libslic3r/Technologies.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "3DBed.hpp"
#include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "GLShader.hpp"
@ -1168,6 +1167,13 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
load_arrange_settings();
m_selection.set_volumes(&m_volumes.volumes);
m_assembly_view_desc["object_selection_caption"] = _L("Left mouse button");
m_assembly_view_desc["object_selection"] = _L("object selection");
m_assembly_view_desc["part_selection_caption"] = "Alt +" + _L("Left mouse button");
m_assembly_view_desc["part_selection"] = _L("part selectiont");
m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys");
m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects");
}
GLCanvas3D::~GLCanvas3D()
@ -1939,7 +1945,11 @@ void GLCanvas3D::render(bool only_init)
/* assemble render*/
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
//BBS: add outline logic
if (m_show_world_axes) {
m_axes.render();
}
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
_render_selection();
//_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
_render_plane();
//BBS: add outline logic insteadof selection under assemble view
@ -2147,6 +2157,9 @@ void GLCanvas3D::update_plate_thumbnails()
void GLCanvas3D::select_all()
{
if (!m_gizmos.is_allow_select_all()) {
return;
}
m_selection.add_all();
m_dirty = true;
}
@ -2262,16 +2275,10 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
void GLCanvas3D::mirror_selection(Axis axis)
{
TransformationType transformation_type;
if (wxGetApp().obj_manipul()->is_local_coordinates())
transformation_type.set_local();
else if (wxGetApp().obj_manipul()->is_instance_coordinates())
transformation_type.set_instance();
//transformation_type.set_world();
transformation_type.set_relative();
m_selection.setup_cache();
m_selection.mirror(axis, transformation_type);
do_mirror(L("Mirror Object"));
// BBS
//wxGetApp().obj_manipul()->set_dirty();
@ -4073,9 +4080,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
GLGizmosManager::EType c = m_gizmos.get_current_type();
if (current_printer_technology() == ptFFF &&
(fff_print()->config().print_sequence == PrintSequence::ByObject)) {
if (c == GLGizmosManager::EType::Move ||
c == GLGizmosManager::EType::Scale ||
c == GLGizmosManager::EType::Rotate )
if (can_sequential_clearance_show_in_gizmo())
update_sequential_clearance();
} else {
if (c == GLGizmosManager::EType::Move ||
@ -4178,11 +4183,22 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
int volume_idx = get_first_hover_volume_idx();
bool already_selected = m_selection.contains_volume(volume_idx);
bool ctrl_down = evt.CmdDown();
bool alt_down = evt.AltDown();
Selection::IndicesList curr_idxs = m_selection.get_volume_idxs();
if (already_selected && ctrl_down)
m_selection.remove(volume_idx);
else if (alt_down) {
Selection::EMode mode = Selection::Volume;
if (already_selected) {
std::vector<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 {
m_selection.add(volume_idx, !ctrl_down, true);
m_mouse.drag.move_requires_threshold = !already_selected;
@ -4660,11 +4676,19 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
}
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@ -4771,11 +4795,17 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@ -4786,24 +4816,25 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
if (m_canvas_type != CanvasAssembleView) {
// Fixes sinking/flying instances
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
for (const std::pair<int, int> &i : done) {
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);
// 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);
m_selection.translate(i.first, 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);
}
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@ -4852,12 +4883,14 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@ -5213,6 +5246,17 @@ void GLCanvas3D::mouse_up_cleanup()
m_canvas->ReleaseMouse();
}
bool GLCanvas3D::can_sequential_clearance_show_in_gizmo() {
switch (m_gizmos.get_current_type()) {
case GLGizmosManager::EType::Move:
case GLGizmosManager::EType::Scale:
case GLGizmosManager::EType::Rotate: {
return true;
}
}
return false;
}
void GLCanvas3D::update_sequential_clearance()
{
if (current_printer_technology() != ptFFF || (fff_print()->config().print_sequence == PrintSequence::ByLayer))
@ -7269,6 +7313,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
ECanvasType canvas_type = this->m_canvas_type;
bool partly_inside_enable = canvas_type == ECanvasType::CanvasAssembleView ? false : true;
if (shader != nullptr) {
shader->start_using();
@ -7312,7 +7357,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else {
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
}
});
},
partly_inside_enable);
}
}
else {
@ -7346,7 +7392,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else {
return true;
}
});
},
partly_inside_enable);
if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) {
const GLGizmosManager& gm = get_gizmos_manager();
shader->stop_using();
@ -7414,19 +7461,11 @@ void GLCanvas3D::_render_sequential_clearance()
{
if (m_gizmos.is_dragging())
return;
switch (m_gizmos.get_current_type())
{
case GLGizmosManager::EType::Flatten:
case GLGizmosManager::EType::Cut:
// case GLGizmosManager::EType::Hollow:
// case GLGizmosManager::EType::SlaSupports:
case GLGizmosManager::EType::FdmSupports:
case GLGizmosManager::EType::Seam: { return; }
default: { break; }
}
auto type = m_gizmos.get_current_type();
if (type == GLGizmosManager::EType::Undefined
|| can_sequential_clearance_show_in_gizmo()) {
m_sequential_print_clearance.render();
}
}
#if ENABLE_RENDER_SELECTION_CENTER
@ -8171,6 +8210,7 @@ void GLCanvas3D::_render_return_toolbar() const
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->reload_scene(true);
}
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(1);
@ -8370,8 +8410,45 @@ void GLCanvas3D::_render_paint_toolbar() const
ImGui::PopStyleColor();
}
float GLCanvas3D::_show_assembly_tooltip_information(float caption_max, float x, float y) const
{
ImGuiWrapper *imgui = wxGetApp().imgui();
ImTextureID normal_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP);
ImTextureID hover_id = m_gizmos.get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER);
caption_max += imgui->calc_text_size(": "sv).x + 35.f;
float scale = get_scale();
ImVec2 button_size = ImVec2(25 * scale, 25 * scale); // ORCA: Use exact resolution will prevent blur on icon
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y});
ImGui::ImageButton3(normal_id, hover_id, button_size);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip2(ImVec2(x, y));
auto draw_text_with_caption = [this, &imgui, & caption_max](const wxString &caption, const wxString &text) {
imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption);
ImGui::SameLine(caption_max);
imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text);
};
for (const auto &t : std::array<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
void GLCanvas3D::_render_assemble_control() const
void GLCanvas3D::_render_assemble_control()
{
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
GLVolume::explosion_ratio = m_explosion_ratio = 1.0;
@ -8392,8 +8469,8 @@ void GLCanvas3D::_render_assemble_control() const
const float text_padding = 7.0f;
const float text_size_x = std::max(imgui->calc_text_size(_L("Reset direction")).x + 2 * ImGui::GetStyle().FramePadding.x,
std::max(imgui->calc_text_size(_L("Explosion Ratio")).x, imgui->calc_text_size(_L("Section View")).x));
const float slider_width = 75.0f;
const float value_size = imgui->calc_text_size(std::string_view{"3.00"}).x + text_padding * 2;
const float slider_width = 60.0f;
const float value_size = imgui->calc_text_size("3.00"sv).x + text_padding * 2;
const float item_spacing = imgui->get_item_spacing().x;
ImVec2 window_padding = ImGui::GetStyle().WindowPadding;
@ -8401,7 +8478,19 @@ void GLCanvas3D::_render_assemble_control() const
imgui->begin(_L("Assemble Control"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
ImGui::AlignTextToFramePadding();
float tip_icon_size;
{
float caption_max = 0.f;
for (const auto &t : std::array<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();
if (clp_dist == 0.f) {
@ -8415,32 +8504,76 @@ void GLCanvas3D::_render_assemble_control() const
});
}
}
ImGui::SameLine(window_padding.x + text_size_x + item_spacing);
same_line_width += (text_size_x + item_spacing);
ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(slider_width);
bool view_slider_changed = imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true);
ImGui::SameLine(window_padding.x + text_size_x + slider_width + item_spacing * 2);
same_line_width += (slider_width + item_spacing);
ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(value_size);
bool view_input_changed = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
if (view_slider_changed || view_input_changed)
m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true);
}
same_line_width += (value_size + item_spacing * 2);
}
{
ImGui::SameLine(window_padding.x + text_size_x + slider_width + item_spacing * 6 + value_size);
auto temp_x = imgui->calc_text_size(_L("Explosion Ratio")).x;
ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(temp_x);
imgui->text(_L("Explosion Ratio"));
ImGui::SameLine(window_padding.x + 2 * text_size_x + slider_width + item_spacing * 7 + value_size);
same_line_width += (temp_x + item_spacing);
ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(slider_width);
bool explosion_slider_changed = imgui->bbl_slider_float_style("##ratio_slider", &m_explosion_ratio, 1.0f, 3.0f, "%1.2f");
ImGui::SameLine(window_padding.x + 2 * text_size_x + 2 * slider_width + item_spacing * 8 + value_size);
same_line_width += (slider_width + item_spacing);
ImGui::SameLine(same_line_width);
ImGui::PushItemWidth(value_size);
bool explosion_input_changed = ImGui::BBLDragFloat("##ratio_input", &m_explosion_ratio, 0.1f, 1.0f, 3.0f, "%1.2f");
same_line_width += (value_size + item_spacing*2);
}
{
ImGui::SameLine(same_line_width);
// input
std::vector<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();
ImGuiWrapper::pop_toolbar_style();

View file

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

View file

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

View file

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

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_return_toolbar(true);
m_canvas->enable_separator_toolbar(false);
//m_canvas->set_show_world_axes(true);//wait for GitHub users to see if they have this requirement
// BBS: set volume_selection_mode to Volume
m_canvas->get_selection().set_volume_selection_mode(Selection::Volume);
m_canvas->get_selection().lock_volume_selection_mode();
//same to 3d //m_canvas->get_selection().set_volume_selection_mode(Selection::Instance);
//m_canvas->get_selection().lock_volume_selection_mode();
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);

View file

@ -227,7 +227,71 @@ bool GLGizmoBase::render_combo(const std::string &label, const std::vector<std::
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_group_id(-1)
, m_state(Off)

View file

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

View file

@ -48,6 +48,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
void GLGizmoMove3D::data_changed(bool is_serializing) {
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
change_cs_by_selection();
}
bool GLGizmoMove3D::on_init()
@ -67,7 +68,11 @@ bool GLGizmoMove3D::on_init()
std::string GLGizmoMove3D::on_get_name() const
{
if (!on_is_activable() && m_state == EState::Off) {
return _u8L("Move") + ":\n" + _u8L("Please select at least one object.");
} else {
return _u8L("Move");
}
}
bool GLGizmoMove3D::on_is_activable() const
@ -75,13 +80,21 @@ bool GLGizmoMove3D::on_is_activable() const
return !m_parent.get_selection().is_empty();
}
void GLGizmoMove3D::on_set_state() {
if (get_state() == On) {
m_last_selected_obejct_idx = -1;
m_last_selected_volume_idx = -1;
change_cs_by_selection();
}
}
void GLGizmoMove3D::on_start_dragging()
{
assert(m_hover_id != -1);
m_displacement = Vec3d::Zero();
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_drag_position = m_grabbers[m_hover_id].matrix * m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center(2) = box.min(2);
@ -121,42 +134,38 @@ void GLGizmoMove3D::on_render()
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
const BoundingBoxf3& box = selection.get_bounding_box();
const Vec3d& center = box.center();
const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
m_bounding_box = box;
m_center = box_trafo.translation();
if (m_object_manipulation) {
m_object_manipulation->cs_center = box_trafo.translation();
}
const Transform3d base_matrix = box_trafo;
float space_size = 20.f *INV_ZOOM;
#if ENABLE_FIXED_GRABBER
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
const Vec3d zero = Vec3d::Zero();
// x axis
m_grabbers[0].center = { box.max.x() + space_size, center.y(), center.z() };
m_grabbers[0].center = {m_bounding_box.max.x() + space_size, 0, 0};
// y axis
m_grabbers[1].center = { center.x(), box.max.y() + space_size, center.z() };
m_grabbers[1].center = {0, m_bounding_box.max.y() + space_size,0};
// z axis
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + space_size };
m_grabbers[2].center = {0,0, m_bounding_box.max.z() + space_size};
for (int i = 0; i < 3; ++i) {
m_grabbers[i].color = AXES_COLOR[i];
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i];
}
#else
// x axis
m_grabbers[0].center = { box.max.x() + Offset, center.y(), center.z() };
m_grabbers[0].color = AXES_COLOR[0];
// y axis
m_grabbers[1].center = { center.x(), box.max.y() + Offset, center.z() };
m_grabbers[1].color = AXES_COLOR[1];
// z axis
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2];
#endif
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
auto render_grabber_connection = [this, &center](unsigned int id) {
auto render_grabber_connection = [this, &zero](unsigned int id) {
if (m_grabbers[id].enabled) {
//if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
m_grabber_connections[id].old_center = center;
m_grabber_connections[id].old_center = m_grabbers[id].center;
m_grabber_connections[id].model.reset();
GLModel::Geometry init_data;
@ -166,7 +175,7 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2);
// vertices
init_data.add_vertex((Vec3f)center.cast<float>());
init_data.add_vertex((Vec3f)zero.cast<float>());
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
// indices
@ -186,7 +195,7 @@ void GLGizmoMove3D::on_render()
if (shader != nullptr) {
shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
// draw axes
@ -199,6 +208,28 @@ void GLGizmoMove3D::on_render()
// draw grabbers
render_grabbers(box);
if (m_object_manipulation->is_instance_coordinates()) {
shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera();
Geometry::Transformation cur_tran;
if (auto mi = m_parent.get_selection().get_selected_single_intance()) {
cur_tran = mi->get_transformation();
} else {
cur_tran = selection.get_first_volume()->get_instance_transformation();
}
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * cur_tran.get_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
render_cross_mark(Vec3f::Zero(), true);
shader->stop_using();
}
}
}
void GLGizmoMove3D::on_register_raycasters_for_picking()
@ -245,5 +276,30 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
return projection;
}
void GLGizmoMove3D::change_cs_by_selection() {
int obejct_idx, volume_idx;
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
if (m_last_selected_obejct_idx == obejct_idx && m_last_selected_volume_idx == volume_idx) {
return;
}
m_last_selected_obejct_idx = obejct_idx;
m_last_selected_volume_idx = volume_idx;
if (m_parent.get_selection().is_multiple_full_object()) {
m_object_manipulation->set_use_object_cs(false);
}
else if (model_volume) {
m_object_manipulation->set_use_object_cs(true);
} else {
m_object_manipulation->set_use_object_cs(false);
}
if (m_object_manipulation->get_use_object_cs()) {
m_object_manipulation->set_coordinates_type(ECoordinatesType::Instance);
} else {
m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
}
}
} // namespace GUI
} // namespace Slic3r

View file

@ -16,6 +16,8 @@ class GLGizmoMove3D : public GLGizmoBase
static const double Offset;
Vec3d m_displacement{ Vec3d::Zero() };
Vec3d m_center{ Vec3d::Zero() };
BoundingBoxf3 m_bounding_box;
double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() };
@ -57,6 +59,7 @@ protected:
bool on_init() override;
std::string on_get_name() const override;
bool on_is_activable() const override;
virtual void on_set_state() override;
void on_start_dragging() override;
void on_stop_dragging() override;
void on_dragging(const UpdateData& data) override;
@ -68,6 +71,9 @@ protected:
private:
double calc_projection(const UpdateData& data) const;
void change_cs_by_selection(); //cs mean Coordinate System
private:
int m_last_selected_obejct_idx, m_last_selected_volume_idx;
};

View file

@ -527,25 +527,6 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
return use_grabbers(mouse_event);
}
void GLGizmoRotate3D::data_changed(bool is_serializing) {
const Selection &selection = m_parent.get_selection();
bool is_wipe_tower = selection.is_wipe_tower();
if (is_wipe_tower) {
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
float wipe_tower_rotation_angle =
dynamic_cast<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()
{
for (GLGizmoRotate& g : m_gizmos)
@ -561,7 +542,57 @@ bool GLGizmoRotate3D::on_init()
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");
}
}
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

View file

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

View file

@ -24,11 +24,11 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan
//BBS: GUI refactor: add obj manipulation
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_scale(Vec3d::Ones())
, m_offset(Vec3d::Zero())
, m_snap_step(0.05)
//BBS: GUI refactor: add obj manipulation
, m_object_manipulation(obj_manipulation)
, m_base_color(DEFAULT_BASE_COLOR)
, m_drag_color(DEFAULT_DRAG_COLOR)
, m_highlight_color(DEFAULT_HIGHLIGHT_COLOR)
{
m_grabber_connections[0].grabber_indices = { 0, 1 };
m_grabber_connections[1].grabber_indices = { 2, 3 };
@ -39,6 +39,17 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
m_grabber_connections[6].grabber_indices = { 9, 6 };
}
const Vec3d &GLGizmoScale3D::get_scale()
{
if (m_object_manipulation) {
Vec3d cache_scale = m_object_manipulation->get_cache().scale.cwiseQuotient(Vec3d(100,100,100));
Vec3d temp_scale = cache_scale.cwiseProduct(m_scale);
m_object_manipulation->limit_scaling_ratio(temp_scale);
m_scale = temp_scale.cwiseQuotient(cache_scale);
}
return m_scale;
}
std::string GLGizmoScale3D::get_tooltip() const
{
const Selection& selection = m_parent.get_selection();
@ -70,77 +81,57 @@ std::string GLGizmoScale3D::get_tooltip() const
return "";
}
static int constraint_id(int grabber_id)
{
static const std::vector<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)
{
if (mouse_event.Dragging()) {
if (m_dragging) {
// Apply new temporary scale factors
Selection& selection = m_parent.get_selection();
TransformationType transformation_type;
if (selection.is_single_full_instance()) {
transformation_type.set_instance();
} else if (selection.is_single_volume_or_modifier()) {
if (wxGetApp().obj_manipul()->is_local_coordinates())
transformation_type.set_local();
}
else if (wxGetApp().obj_manipul()->is_instance_coordinates())
transformation_type.set_instance();
transformation_type.set_relative();
if (mouse_event.AltDown())
transformation_type.set_independent();
selection.scale(m_scale, transformation_type);
if (m_starting.ctrl_down && m_hover_id < 6) {
// constrained scale:
// uses the performed scale to calculate the new position of the constrained grabber
// and from that calculates the offset (in world coordinates) to be applied to fullfill the constraint
update_render_data();
const Vec3d constraint_position = m_grabbers[constraint_id(m_hover_id)].center;
// re-apply the scale because the selection always applies the transformations with respect to the initial state
// set into on_start_dragging() with the call to selection.setup_cache()
m_parent.get_selection().scale_and_translate(m_scale, m_starting.pivots[m_hover_id] - constraint_position, transformation_type);
}
Selection& selection = m_parent.get_selection();
selection.scale_and_translate(get_scale(), get_offset(), transformation_type);
}
}
return use_grabbers(mouse_event);
}
void GLGizmoScale3D::data_changed(bool is_serializing)
{
const Selection &selection = m_parent.get_selection();
bool enable_scale_xyz = selection.is_single_full_instance() ||
selection.is_single_volume_or_modifier();
for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable_scale_xyz;
set_scale(Vec3d::Ones());
change_cs_by_selection();
}
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
{
for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable;
}
void GLGizmoScale3D::data_changed(bool is_serializing) {
const Selection &selection = m_parent.get_selection();
bool enable_scale_xyz = selection.is_single_full_instance() ||
selection.is_single_volume_or_modifier();
for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable_scale_xyz;
set_scale(Vec3d::Ones());
}
bool GLGizmoScale3D::on_init()
{
for (int i = 0; i < 10; ++i) {
for (int i = 0; i < 10; ++i)
{
m_grabbers.push_back(Grabber());
}
double half_pi = 0.5 * (double)PI;
// x axis
m_grabbers[0].angles(1) = half_pi;
m_grabbers[1].angles(1) = half_pi;
// y axis
m_grabbers[2].angles(0) = half_pi;
m_grabbers[3].angles(0) = half_pi;
// BBS
m_grabbers[4].enabled = false;
@ -151,7 +142,11 @@ bool GLGizmoScale3D::on_init()
std::string GLGizmoScale3D::on_get_name() const
{
if (!on_is_activable() && m_state == EState::Off) {
return _u8L("Scale") + ":\n" + _u8L("Please select at least one object.");
} else {
return _u8L("Scale");
}
}
bool GLGizmoScale3D::on_is_activable() const
@ -160,21 +155,48 @@ bool GLGizmoScale3D::on_is_activable() const
return !selection.is_empty() && !selection.is_wipe_tower();
}
void GLGizmoScale3D::on_set_state() {
if (get_state() == On) {
m_last_selected_obejct_idx = -1;
m_last_selected_volume_idx = -1;
change_cs_by_selection();
}
}
static int constraint_id(int grabber_id)
{
static const std::vector<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()
{
assert(m_hover_id != -1);
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.plane_center = m_grabbers[4].center;
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
if (m_hover_id != -1) {
auto grabbers_transform = m_grabbers_tran.get_matrix();
m_starting.drag_position = grabbers_transform * m_grabbers[m_hover_id].center;
m_starting.plane_center = grabbers_transform * m_grabbers[4].center; // plane_center = bottom center
m_starting.plane_nromal = (grabbers_transform * m_grabbers[5].center - grabbers_transform * m_grabbers[4].center).normalized();
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
m_starting.box = m_box;
m_starting.box = m_bounding_box;
m_starting.pivots[0] = m_grabbers[1].center;
m_starting.pivots[1] = m_grabbers[0].center;
m_starting.pivots[2] = m_grabbers[3].center;
m_starting.pivots[3] = m_grabbers[2].center;
m_starting.pivots[4] = m_grabbers[5].center;
m_starting.pivots[5] = m_grabbers[4].center;
m_starting.center = m_center;
m_starting.instance_center = m_instance_center;
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
m_starting.local_pivots[0] = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
m_starting.local_pivots[1] = Vec3d(-box_half_size.x(), 0.0, -box_half_size.z());
m_starting.local_pivots[2] = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
m_starting.local_pivots[3] = Vec3d(0.0, -box_half_size.y(), -box_half_size.z());
m_starting.local_pivots[4] = Vec3d(0.0, 0.0, box_half_size.z());
m_starting.local_pivots[5] = Vec3d(0.0, 0.0, -box_half_size.z());
for (size_t i = 0; i < 6; i++) {
m_starting.pivots[i] = grabbers_transform * m_starting.local_pivots[i]; // todo delete
}
m_starting.constraint_position = grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
m_scale = m_starting.scale = Vec3d::Ones() ;
m_offset = Vec3d::Zero();
}
}
void GLGizmoScale3D::on_stop_dragging()
@ -185,26 +207,95 @@ void GLGizmoScale3D::on_stop_dragging()
void GLGizmoScale3D::on_dragging(const UpdateData& data)
{
if (m_hover_id == 0 || m_hover_id == 1)
if ((m_hover_id == 0) || (m_hover_id == 1))
do_scale_along_axis(X, data);
else if (m_hover_id == 2 || m_hover_id == 3)
else if ((m_hover_id == 2) || (m_hover_id == 3))
do_scale_along_axis(Y, data);
else if (m_hover_id == 4 || m_hover_id == 5)
else if ((m_hover_id == 4) || (m_hover_id == 5))
do_scale_along_axis(Z, data);
else if (m_hover_id >= 6)
do_scale_uniform(data);
}
void GLGizmoScale3D::update_grabbers_data()
{
const Selection &selection = m_parent.get_selection();
const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
m_bounding_box = box;
m_center = box_trafo.translation();
m_grabbers_tran.set_matrix(box_trafo);
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
bool ctrl_down = wxGetKeyState(WXK_CONTROL);
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
// x axis
m_grabbers[0].center = Vec3d(-(box_half_size.x()), 0.0, -box_half_size.z());
m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = Vec3d(0.0, -(box_half_size.y()), -box_half_size.z());
m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis do not show 4
m_grabbers[4].center = Vec3d(0.0, 0.0, -(box_half_size.z()));
m_grabbers[4].enabled = false;
m_grabbers[5].center = Vec3d(0.0, 0.0, box_half_size.z());
m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = Vec3d(-box_half_size.x(), -box_half_size.y(), -box_half_size.z());
m_grabbers[6].color = (ctrl_down && m_hover_id == 8) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
m_grabbers[7].center = Vec3d(box_half_size.x(), -box_half_size.y(), -box_half_size.z());
m_grabbers[7].color = (ctrl_down && m_hover_id == 9) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
m_grabbers[8].center = Vec3d(box_half_size.x(), box_half_size.y(), -box_half_size.z());
m_grabbers[8].color = (ctrl_down && m_hover_id == 6) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
m_grabbers[9].center = Vec3d(-box_half_size.x(), box_half_size.y(), -box_half_size.z());
m_grabbers[9].color = (ctrl_down && m_hover_id == 7) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
for (int i = 0; i < 6; ++i) {
//m_grabbers[i].color = AXES_COLOR[i / 2];
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i / 2];
}
for (int i = 6; i < 10; ++i) {
//m_grabbers[i].color = GRABBER_UNIFORM_COL;
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
}
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = m_grabbers_tran.get_matrix();
}
}
void GLGizmoScale3D::change_cs_by_selection() {
int obejct_idx, volume_idx;
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
if (m_last_selected_obejct_idx == obejct_idx && m_last_selected_volume_idx == volume_idx) { return; }
m_last_selected_obejct_idx = obejct_idx;
m_last_selected_volume_idx = volume_idx;
if (m_parent.get_selection().is_multiple_full_object()) {
m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
} else if (model_volume) {
m_object_manipulation->set_coordinates_type(ECoordinatesType::Local);
}
}
void GLGizmoScale3D::on_render()
{
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
update_render_data();
update_grabbers_data();
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
const float grabber_mean_size = (float) ((m_box.size().x() + m_box.size().y() + m_box.size().z()) / 3.0);
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
//draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat");
@ -213,7 +304,7 @@ void GLGizmoScale3D::on_render()
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
//if (single_instance || single_volume) {
const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * m_grabbers_tran.get_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
render_grabbers_connection(4, 5, m_grabbers[4].color);
@ -298,29 +389,53 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
double ratio = calc_ratio(data);
if (ratio > 0.0) {
Vec3d curr_scale = m_scale;
curr_scale(axis) = m_starting.scale(axis) * ratio;
m_scale = curr_scale;
if (ratio > 0.0)
{
m_scale(axis) = m_starting.scale(axis) * ratio;
if (m_starting.ctrl_down && abs(ratio-1.0f)>0.001) {
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis) {
local_offset *= -1.0;
}
Vec3d local_offset_vec;
switch (axis)
{
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break;}
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break;
}
default: break;
}
if (m_object_manipulation->is_world_coordinates()) {
m_offset = local_offset_vec;
} else {//if (m_object_manipulation->is_instance_coordinates())
m_offset = m_grabbers_tran.get_matrix_no_offset() * local_offset_vec;
}
}
else
m_offset = Vec3d::Zero();
}
}
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{
const double ratio = calc_ratio(data);
double ratio = calc_ratio(data);
if (ratio > 0.0)
{
m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero();
}
}
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{
double ratio = 0.0;
Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.plane_center;
Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.constraint_position : m_starting.plane_center; // plane_center = bottom center
Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0) {
if (len_starting_vec != 0.0)
{
Vec3d mouse_dir = data.mouse_ray.unit_vector();
Vec3d plane_normal = m_starting.plane_nromal;
if (m_hover_id == 5) {
@ -328,10 +443,16 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
Vec3d plane_vec = mouse_dir.cross(m_starting.plane_nromal);
plane_normal = plane_vec.cross(m_starting.plane_nromal);
}
plane_normal = plane_normal.normalized();
// finds the intersection of the mouse ray with the plane that the drag point moves
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection
Vec3d inters = GetIntersectionOfRayAndPlane(data.mouse_ray.a, mouse_dir, m_starting.drag_position, plane_normal.normalized());
auto dot_value = (plane_normal.dot(mouse_dir));
auto angle = Geometry::rad2deg(acos(dot_value));
auto big_than_min_angle = abs(angle) < 95 && abs(angle) > 85;
if (big_than_min_angle) {
return 1;
}
Vec3d inters = GetIntersectionOfRayAndPlane(data.mouse_ray.a, mouse_dir, m_starting.drag_position, plane_normal);
Vec3d inters_vec = inters - m_starting.drag_position;
@ -347,78 +468,5 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio;
}
void GLGizmoScale3D::update_render_data()
{
const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_volume_or_modifier();
m_box.reset();
m_transform = Transform3d::Identity();
Vec3d angles = Vec3d::Zero();
if (single_instance) {
// calculate bounding box in instance local reference system
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) {
const GLVolume* vol = selection.get_volume(idx);
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
}
// gets transform from first selected volume
const GLVolume* v = selection.get_first_volume();
m_transform = v->get_instance_transformation().get_matrix();
// gets angles from first selected volume
angles = v->get_instance_rotation();
}
else if (single_volume) {
const GLVolume* v = selection.get_first_volume();
m_box = v->bounding_box();
m_transform = v->world_matrix();
angles = Geometry::extract_euler_angles(m_transform);
}
else
m_box = selection.get_bounding_box();
const Vec3d& center = m_box.center();
// x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z());
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
// y axis
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z());
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
// z axis do not show 4
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z());
m_grabbers[4].enabled = false;
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z());
// uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z());
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z());
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z());
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z());
for (int i = 0; i < 6; ++i) {
m_grabbers[i].color = AXES_COLOR[i/2];
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2];
}
for (int i = 6; i < 10; ++i) {
m_grabbers[i].color = GRABBER_UNIFORM_COL;
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
}
// sets grabbers orientation
for (int i = 0; i < 10; ++i) {
m_grabbers[i].angles = angles;
}
}
} // namespace GUI
} // namespace Slic3r

View file

@ -19,25 +19,28 @@ class GLGizmoScale3D : public GLGizmoBase
{
Vec3d scale;
Vec3d drag_position;
Vec3d constraint_position;
Vec3d center{Vec3d::Zero()};//sphere bounding box center
Vec3d instance_center{Vec3d::Zero()};
Vec3d plane_center; // keep the relative center position for scale in the bottom plane
Vec3d plane_nromal; // keep the bottom plane
BoundingBoxf3 box;
Vec3d pivots[6];
Vec3d pivots[6];// Vec3d constraint_position{Vec3d::Zero()};
Vec3d local_pivots[6];
bool ctrl_down;
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
};
BoundingBoxf3 m_box;
Transform3d m_transform;
Vec3d m_scale{ Vec3d::Ones() };
double m_snap_step{ 0.05 };
mutable BoundingBoxf3 m_bounding_box;
Geometry::Transformation m_grabbers_tran;//m_grabbers_transform
Vec3d m_center{Vec3d::Zero()};
Vec3d m_instance_center{Vec3d::Zero()};
Vec3d m_scale;
Vec3d m_offset;
double m_snap_step;
StartingData m_starting;
ColorRGBA m_base_color;
ColorRGBA m_drag_color;
ColorRGBA m_highlight_color;
struct GrabberConnection
{
GLModel model;
@ -58,9 +61,11 @@ public:
double get_snap_step(double step) const { return m_snap_step; }
void set_snap_step(double step) { m_snap_step = step; }
const Vec3d& get_scale() const { return m_scale; }
const Vec3d &get_scale();
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
const Vec3d& get_offset() const { return m_offset; }
std::string get_tooltip() const override;
/// <summary>
@ -76,6 +81,7 @@ protected:
virtual bool on_init() override;
virtual std::string on_get_name() const override;
virtual bool on_is_activable() const override;
virtual void on_set_state() override;
virtual void on_start_dragging() override;
virtual void on_stop_dragging() override;
virtual void on_dragging(const UpdateData& data) override;
@ -92,7 +98,10 @@ private:
void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const;
void update_render_data();
void update_grabbers_data();
void change_cs_by_selection(); // cs mean Coordinate System
private:
int m_last_selected_obejct_idx, m_last_selected_volume_idx;
};

View file

@ -1024,20 +1024,6 @@ void GLGizmoText::show_tooltip_information(float x, float y)
ImGui::PopStyleVar(2);
}
ModelVolume *GLGizmoText::get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const
{
if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) {
const Selection &selection = m_parent.get_selection();
const GLVolume * gl_volume = selection.get_first_volume();
out_object_idx = gl_volume->object_idx();
ModelObject *model_object = selection.get_model()->objects[out_object_idx];
out_volume_idx = gl_volume->volume_idx();
if (out_volume_idx < model_object->volumes.size())
return model_object->volumes[out_volume_idx];
}
return nullptr;
}
void GLGizmoText::reset_text_info()
{
m_font_name = "";

View file

@ -62,7 +62,9 @@ std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
out.reserve(m_gizmos.size());
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
for (size_t i = 0; i < m_gizmos.size(); ++i)
if (m_gizmos[i]->get_sprite_id() == (unsigned int) Measure ||
if (m_gizmos[i]->get_sprite_id() == (unsigned int) Move ||
m_gizmos[i]->get_sprite_id() == (unsigned int) Rotate ||
m_gizmos[i]->get_sprite_id() == (unsigned int) Measure ||
m_gizmos[i]->get_sprite_id() == (unsigned int) Assembly ||
m_gizmos[i]->get_sprite_id() == (unsigned int) MmuSegmentation)
out.push_back(i);
@ -247,6 +249,16 @@ bool GLGizmosManager::init_icon_textures()
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_reset_zero.svg", 14, 14, texture_id))
icon_list.insert(std::make_pair((int) IC_TOOLBAR_RESET_ZERO, texture_id));
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_reset_zero_hover.svg", 14, 14, texture_id))
icon_list.insert(std::make_pair((int) IC_TOOLBAR_RESET_ZERO_HOVER, texture_id));
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/toolbar_tooltip.svg", 25, 25, texture_id)) // ORCA: Use same resolution with gizmos to prevent blur on icon
icon_list.insert(std::make_pair((int)IC_TOOLBAR_TOOLTIP, texture_id));
else
@ -371,6 +383,9 @@ void GLGizmosManager::update_assemble_view_data()
void GLGizmosManager::update_data()
{
if (!m_enabled) return;
const Selection& selection = m_parent.get_selection();
if (m_common_gizmos_data)
m_common_gizmos_data->update(get_current()
? get_current()->get_requirements()
@ -381,8 +396,10 @@ void GLGizmosManager::update_data()
if (m_current != Flatten && !m_gizmos.empty()) m_gizmos[Flatten]->data_changed(m_serializing);
//BBS: GUI refactor: add object manipulation in gizmo
if (!selection.is_empty()) {
m_object_manipulation.update_ui_from_settings();
m_object_manipulation.UpdateAndShow(true);
}
}
bool GLGizmosManager::is_running() const
@ -461,6 +478,22 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
return false;
}
bool GLGizmosManager::is_paint_gizmo()
{
return m_current == EType::FdmSupports ||
m_current == EType::MmuSegmentation ||
m_current == EType::Seam;
}
bool GLGizmosManager::is_allow_select_all() {
if (m_current == Undefined || m_current == EType::Move||
m_current == EType::Rotate ||
m_current == EType::Scale) {
return true;
}
return false;
}
ClippingPlane GLGizmosManager::get_clipping_plane() const
{
if (! m_common_gizmos_data

View file

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

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
#include <memory>
#include "libslic3r/Point.hpp"
#include "libslic3r/Geometry.hpp"
#include <float.h>
#include "slic3r/GUI/GUI_Geometry.hpp"
@ -30,6 +31,8 @@ public:
Vec3d position_rounded;
Vec3d rotation;
Vec3d rotation_rounded;
Vec3d absolute_rotation;
Vec3d absolute_rotation_rounded;
Vec3d scale;
Vec3d scale_rounded;
Vec3d size;
@ -56,7 +59,7 @@ public:
Cache m_cache;
bool m_imperial_units { false };
bool m_use_object_cs{false};
// Mirroring buttons and their current state
//enum MirrorButtonState {
// mbHidden,
@ -75,19 +78,28 @@ public:
std::string m_new_unit_string;
Vec3d m_new_position;
Vec3d m_new_rotation;
Vec3d m_new_absolute_rotation;
Vec3d m_new_scale;
Vec3d m_new_size;
Vec3d m_unscale_size;
Vec3d m_buffered_position;
Vec3d m_buffered_rotation;
Vec3d m_buffered_absolute_rotation;
Vec3d m_buffered_scale;
Vec3d m_buffered_size;
Vec3d cs_center;
bool m_new_enabled {true};
bool m_uniform_scale {true};
ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
// Does the object manipulation panel work in World or Local coordinates?
ECoordinatesType m_coordinates_type{ECoordinatesType::World};
bool m_show_reset_0_rotation{false};
bool m_show_clear_rotation { false };
bool m_show_clear_scale { false };
bool m_show_drop_to_bed { false };
enum class RotateType { None, Relative, Absolute
};
RotateType m_last_rotate_type{RotateType::None}; // 0:no input 1:relative 2:absolute
protected:
float last_move_input_window_width = 0.0f;
@ -108,21 +120,33 @@ public:
void set_uniform_scaling(const bool uniform_scale);
bool get_uniform_scaling() const { return m_uniform_scale; }
void set_use_object_cs(bool flag){ if (m_use_object_cs != flag) m_use_object_cs = flag; }
bool get_use_object_cs() { return m_use_object_cs; }
// Does the object manipulation panel work in World or Local coordinates?
void set_coordinates_type(ECoordinatesType type);
ECoordinatesType get_coordinates_type() const;
ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
const Cache& get_cache() {return m_cache; }
void reset_cache() { m_cache.reset(); }
void limit_scaling_ratio(Vec3d &scaling_factor) const;
void on_change(const std::string& opt_key, int axis, double new_value);
bool render_combo(ImGuiWrapper *imgui_wrapper, const std::string &label, const std::vector<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_rotate_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit);
void do_render_scale_input_window(ImGuiWrapper* imgui_wrapper, std::string window_name, float x, float y, float bottom_limit);
float max_unit_size(int number, Vec3d &vec1, Vec3d &vec2,std::string str);
bool reset_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size);
bool reset_zero_button(ImGuiWrapper *imgui_wrapper, float caption_max, float unit_size, float space_size, float end_text_size);
bool bbl_checkbox(const wxString &label, bool &value);
void show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void set_init_rotation(const Geometry::Transformation &value);
private:
void reset_settings_value();
@ -137,15 +161,21 @@ private:
// change values
void change_position_value(int axis, double value);
void change_rotation_value(int axis, double value);
void change_absolute_rotation_value(int axis, double value);
void change_scale_value(int axis, double value);
void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const;
void reset_position_value();
void reset_rotation_value();
void reset_rotation_value(bool reset_relative);
void reset_scale_value();
GLCanvas3D& m_glcanvas;
unsigned int m_last_active_item { 0 };
std::map<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();
}
ModelVolume *Selection::get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const
{
if (is_single_volume() || is_single_modifier()) {
const GLVolume *gl_volume = get_first_volume();
out_object_idx = gl_volume->object_idx();
ModelObject *model_object = get_model()->objects[out_object_idx];
out_volume_idx = gl_volume->volume_idx();
if (out_volume_idx < model_object->volumes.size())
return model_object->volumes[out_volume_idx];
}
return nullptr;
}
ModelObject *Selection::get_selected_single_object(int &out_object_idx) const
{
if (is_single_volume() || is_single_modifier() || is_single_full_object()) {
const GLVolume *gl_volume = get_first_volume();
out_object_idx = gl_volume->object_idx();
return get_model()->objects[out_object_idx];
}
return nullptr;
}
const ModelInstance *Selection::get_selected_single_intance() const
{
int object_idx;
auto mo = get_selected_single_object(object_idx);
if (mo) {
return mo->instances[get_instance_idx()];
}
return nullptr;
}
void Selection::add_curr_plate()
{
if (!m_valid)
@ -910,16 +943,16 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
return *m_scaled_instance_bounding_box;
}
const BoundingBoxf3& Selection::get_full_unscaled_instance_bounding_box() const
const BoundingBoxf3 &Selection::get_full_unscaled_instance_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_unscaled_instance_bounding_box.has_value()) {
std::optional<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();
if (m_valid) {
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();
trafo.translation().z() += volume.get_sla_shift_z();
(*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;
}
const BoundingBoxf3& Selection::get_full_scaled_instance_bounding_box() const
const BoundingBoxf3 &Selection::get_full_scaled_instance_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_scaled_instance_bounding_box.has_value()) {
std::optional<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();
if (m_valid) {
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();
trafo.translation().z() += volume.get_sla_shift_z();
(*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;
}
const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box() const
const BoundingBoxf3 &Selection::get_full_unscaled_instance_local_bounding_box() const
{
assert(is_single_full_instance());
if (!m_full_unscaled_instance_local_bounding_box.has_value()) {
std::optional<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();
if (m_valid) {
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();
trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
@ -967,22 +1000,20 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box()
return *m_full_unscaled_instance_local_bounding_box;
}
const std::pair<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;
assert(!is_empty());
ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (m_mode == Instance && coordinates_type == ECoordinatesType::Local)
coordinates_type = ECoordinatesType::World;
if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) coordinates_type = ECoordinatesType::World;
if (last_coordinates_type != int(coordinates_type))
const_cast<std::optional<std::pair<BoundingBoxf3, Transform3d>>*>(&m_bounding_box_in_current_reference_system)->reset();
if (last_coordinates_type != int(coordinates_type)) 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()) {
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;
@ -994,11 +1025,19 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
// trafo to current reference system
//
Transform3d trafo;
switch (type)
{
case ECoordinatesType::World: { trafo = Transform3d::Identity(); break; }
case ECoordinatesType::Instance: { trafo = get_first_volume()->get_instance_transformation().get_matrix(); break; }
case ECoordinatesType::Local: { trafo = get_first_volume()->world_matrix(); break; }
switch (type) {
case ECoordinatesType::World: {
trafo = Transform3d::Identity();
break;
}
case ECoordinatesType::Instance: {
trafo = get_first_volume()->get_instance_transformation().get_matrix();
break;
}
case ECoordinatesType::Local: {
trafo = get_first_volume()->world_matrix();
break;
}
}
//
@ -1007,24 +1046,22 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
Geometry::Transformation t(trafo);
t.reset_scaling_factor();
const Transform3d basis_trafo = t.get_matrix_no_offset();
std::vector<Vec3d> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
for (size_t i = 0; i < axes.size(); ++i) {
axes[i] = basis_trafo * axes[i];
}
std::vector<Vec3d> axes = {Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ()};
for (size_t i = 0; i < axes.size(); ++i) { axes[i] = basis_trafo * axes[i]; }
//
// calculate bounding box aligned to trafo basis
//
Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX };
Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX };
Vec3d min = {DBL_MAX, DBL_MAX, DBL_MAX};
Vec3d max = {-DBL_MAX, -DBL_MAX, -DBL_MAX};
for (unsigned int id : m_list) {
const GLVolume& vol = *get_volume(id);
const GLVolume & vol = *get_volume(id);
const Transform3d vol_world_rafo = vol.world_matrix();
const TriangleMesh* mesh = vol.convex_hull();
const TriangleMesh *mesh = vol.convex_hull();
if (mesh == nullptr)
mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
assert(mesh != nullptr);
for (const stl_vertex& v : mesh->its.vertices) {
for (const stl_vertex &v : mesh->its.vertices) {
const Vec3d world_v = vol_world_rafo * v.cast<double>();
for (int i = 0; i < 3; ++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
// by move with calculated center(to volume center) and extend half box size
// e.g. for right aligned embossed text
if (m_list.size() == 1 &&
type == ECoordinatesType::Local) {
const GLVolume& vol = *get_volume(*m_list.begin());
if (m_list.size() == 1 && type == ECoordinatesType::Local) {
const GLVolume & vol = *get_volume(*m_list.begin());
const Transform3d vol_world_trafo = vol.world_matrix();
Vec3d world_zero = vol_world_trafo * Vec3d::Zero();
for (size_t i = 0; i < 3; i++){
for (size_t i = 0; i < 3; i++) {
// move center to local volume zero
center[i] = world_zero.dot(axes[i]);
// extend half size to bigger distance from center
half_box_size[i] = std::max(
abs(center[i] - min[i]),
abs(center[i] - max[i]));
half_box_size[i] = std::max(abs(center[i] - min[i]), abs(center[i] - max[i]));
}
}
const BoundingBoxf3 out_box(-half_box_size, half_box_size);
out_trafo.set_offset(basis_trafo * center);
return { out_box, out_trafo.get_matrix_no_scaling_factor() };
return {out_box, out_trafo.get_matrix_no_scaling_factor()};
}
const std::pair<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();
}
void Selection::translate(const Vec3d& displacement, TransformationType transformation_type)
void Selection::translate(const Vec3d &displacement, TransformationType transformation_type)
{
if (!m_valid)
return;
// Emboss use translate in local coordinate
assert(transformation_type.relative() ||
transformation_type.local());
if (!m_valid) return;
for (unsigned int i : m_list) {
GLVolume& v = *(*m_volumes)[i];
const VolumeCache& volume_data = m_cache.volumes_data[i];
GLVolume & v = *(*m_volumes)[i];
const VolumeCache &volume_data = m_cache.volumes_data[i];
if (m_mode == Instance && !is_wipe_tower()) {
assert(is_from_fully_selected_instance(i));
if (transformation_type.instance()) {
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement);
}
else
} else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
} else {
if (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()) {
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
if (tower_origin(1) + actual_displacement(1) - margin < plate_bbox.min(1)) {
actual_displacement(1) = plate_bbox.min(1) - tower_origin(1) + margin;
} else if (tower_origin(1) + actual_displacement(1) + tower_size(1) + margin > plate_bbox.max(1)) {
actual_displacement(1) = plate_bbox.max(1) - tower_origin(1) - tower_size(1) - margin;
}
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + actual_displacement);
}
else if (transformation_type.local() && transformation_type.absolute()) {
const Geometry::Transformation &vol_trafo = volume_data.get_volume_transform();
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
v.set_volume_offset(vol_trafo.get_offset() + inst_trafo.get_scaling_factor_matrix().inverse() * vol_trafo.get_rotation_matrix() * displacement);
}
else {
} else {
Vec3d relative_disp = displacement;
if (transformation_type.world() && transformation_type.instance())
relative_disp = volume_data.get_instance_transform().get_scaling_factor_matrix().inverse() * relative_disp;
@ -1181,12 +1233,14 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
ensure_not_below_bed();
}
set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
}
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type)
{
@ -1287,7 +1341,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
#endif // !DISABLE_INSTANCES_SYNCH
set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
}
void Selection::flattening_rotate(const Vec3d& normal)
@ -1320,96 +1376,6 @@ void Selection::flattening_rotate(const Vec3d& normal)
this->set_bounding_boxes_dirty();
}
void Selection::scale_legacy(const Vec3d& scale, TransformationType transformation_type)
{
if (!m_valid)
return;
for (unsigned int i : m_list) {
GLVolume &v = *(*m_volumes)[i];
if (is_single_full_instance()) {
if (transformation_type.relative()) {
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
Eigen::Matrix<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)
{
scale_and_translate(scale, Vec3d::Zero(), transformation_type);
@ -1552,16 +1518,9 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
}
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void Selection::mirror(Axis axis, TransformationType transformation_type)
void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type)
{
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
}
void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type)
{
if (!m_valid)
return;
if (!m_valid) return;
Vec3d relative_scale = scale;
if (transformation_type.absolute()) {
@ -1582,9 +1541,9 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
}
for (unsigned int i : m_list) {
GLVolume& v = *(*m_volumes)[i];
const VolumeCache& volume_data = m_cache.volumes_data[i];
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
GLVolume & v = *(*m_volumes)[i];
const VolumeCache & volume_data = m_cache.volumes_data[i];
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
if (m_mode == Instance) {
if (transformation_type.instance()) {
@ -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);
const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale);
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
}
else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
}
else {
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo *
Geometry::translation_transform(-local_inst_pivot));
} else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale),
m_cache.dragging_center);
// update the instance assemble transform
ModelObject * object = m_model->objects[v.object_idx()];
Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
} else {
if (!is_single_volume_or_modifier()) {
assert(transformation_type.world());
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
}
else {
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale),
m_cache.dragging_center);
} else {
transformation_type.set_independent();
Vec3d translation;
if (transformation_type.local())
if (transformation_type.local()) {
translation = volume_data.get_volume_transform().get_matrix_no_offset().inverse() * inst_trafo.get_matrix_no_offset().inverse() * world_translation;
}
else if (transformation_type.instance())
translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
else
translation = world_translation;
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale),
m_cache.dragging_center);
}
}
}
@ -1629,7 +1595,16 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_trans
ensure_on_bed();
set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
}
}
void Selection::mirror(Axis axis, TransformationType transformation_type)
{
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
}
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
@ -1944,7 +1919,8 @@ void Selection::render(float scale_factor)
m_scale_factor = scale_factor;
// render cumulative bounding box of selected volumes
const auto& [box, trafo] = get_bounding_box_in_current_reference_system();
render_bounding_box(box, trafo, ColorRGB::WHITE());
render_bounding_box(box, trafo,
wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView ? ColorRGB::YELLOW(): ColorRGB::WHITE());
render_synchronized_volumes();
}
@ -1992,40 +1968,33 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif
glsafe(::glEnable(GL_DEPTH_TEST));
const Transform3d base_matrix = Geometry::assemble_transform(get_bounding_box().center());
Vec3d center = get_bounding_box().center();
Transform3d orient_matrix = Transform3d::Identity();
if (!boost::starts_with(sidebar_field, "layer")) {
shader->set_uniform("emission_factor", 0.05f);
const auto &[box, box_trafo] = get_bounding_box_in_current_reference_system();
// BBS
if (is_single_full_instance()/* && !wxGetApp().obj_manipul()->get_world_coordinates()*/) {
if (!boost::starts_with(sidebar_field, "position")) {
if (boost::starts_with(sidebar_field, "scale"))
if (is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
center = box_trafo.translation();
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
else if (boost::starts_with(sidebar_field, "rotation")) {
if (boost::ends_with(sidebar_field, "x"))
} else if (is_single_volume_or_modifier()) {
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
if (wxGetApp().obj_manipul()->is_local_coordinates()) {
orient_matrix = get_bounding_box_in_current_reference_system().second;
orient_matrix.translation() = Vec3d::Zero();
} else {
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
else if (boost::ends_with(sidebar_field, "y")) {
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
if (rotation.x() == 0.0)
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
else
orient_matrix.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()));
center = box_trafo.translation();
}
}
}
}
else if (is_single_volume() || is_single_modifier()) {
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
if (!boost::starts_with(sidebar_field, "position"))
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_rotation_matrix();
}
else {
if (requires_local_axes())
} else {
if (requires_local_axes()) {
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
}
}
}
const Transform3d base_matrix = Geometry::assemble_transform(center);
if (!boost::starts_with(sidebar_field, "layer"))
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
@ -2033,6 +2002,8 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field, bool unif
render_sidebar_position_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "rotation"))
render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "absolute_rotation"))
render_sidebar_rotation_hints(sidebar_field, *shader, base_matrix * orient_matrix);
else if (boost::starts_with(sidebar_field, "scale") || boost::starts_with(sidebar_field, "size"))
//BBS: GUI refactor: add uniform_scale from gizmo
render_sidebar_scale_hints(sidebar_field, uniform_scale, *shader, base_matrix * orient_matrix);
@ -3052,6 +3023,9 @@ void Selection::ensure_not_below_bed()
bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const
{
if (m_mode == Instance && wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView) {
return true;
}
struct SameInstance
{
int obj_idx;
@ -3180,14 +3154,14 @@ void Selection::paste_objects_from_clipboard()
Vec3d displacement;
bool in_current = plate->intersects(bbox);
auto start_point = in_current ? bbox.center() : plate->get_build_volume().center();
auto start_offset = in_current ? src_object->instances.front()->get_offset() : plate->get_build_volume().center();
if (shift_all(0) != 0 || shift_all(1) != 0) {
// BBS: if multiple objects are selected, move them as a whole after copy
if (i == 0) empty_cell_all = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}, {bbox.size()(0)+1,bbox.size()(1)+1});
auto instance_shift = src_object->instances.front()->get_offset() - src_objects[0]->instances.front()->get_offset();
displacement = {shift_all.x() + empty_cell_all.x()+instance_shift.x(), shift_all.y() + empty_cell_all.y()+instance_shift.y(), start_point(2)};
displacement = {shift_all.x() + empty_cell_all.x() + instance_shift.x(), shift_all.y() + empty_cell_all.y() + instance_shift.y(), start_offset(2)};
} else {
// BBS: if only one object is copied, find an empty cell to put it
auto start_offset = in_current ? src_object->instances.front()->get_offset() : plate->get_build_volume().center();
auto point_offset = start_offset - start_point;
auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}, {bbox.size()(0)+1, bbox.size()(1)+1});
displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_offset(2)};

View file

@ -15,6 +15,7 @@ class Model;
class ModelObject;
class ModelVolume;
class ObjectID;
class ModelInstance;
class GLVolume;
class GLArrow;
class GLCurvedArrow;
@ -225,6 +226,9 @@ public:
void remove_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs);
//BBS
ModelVolume * get_selected_single_volume(int &out_object_idx, int &out_volume_idx) const;
ModelObject * get_selected_single_object(int &out_object_idx) const;
const ModelInstance * get_selected_single_intance() const;
void add_curr_plate();
void add_object_from_idx(std::vector<int>& object_idxs);
void remove_curr_plate();
@ -326,20 +330,17 @@ public:
const std::pair<Vec3d, double> get_bounding_sphere() const;
void setup_cache();
void translate(const Vec3d& displacement, TransformationType transformation_type);
void move_to_center(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
[[deprecated("Only used by GizmoObjectManipulation")]]
void scale_legacy(const Vec3d& scale, TransformationType transformation_type);
void scale(const Vec3d& scale, TransformationType transformation_type);
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_to_fit_print_volume(const BuildVolume& volume);
#else
void scale_to_fit_print_volume(const DynamicPrintConfig& config);
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
void scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type);
void scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type);
void mirror(Axis axis, TransformationType transformation_type);
void translate(unsigned int object_idx, const Vec3d& displacement);
@ -351,6 +352,7 @@ public:
//BBS: add partplate related logic
void notify_instance_update(int object_idx, int instance_idx);
// BBS
EMode get_volume_selection_mode(){ return m_volume_selection_mode;}
void set_volume_selection_mode(EMode mode) { if (!m_volume_selection_locked) m_volume_selection_mode = mode; }
void lock_volume_selection_mode() { m_volume_selection_locked = true; }
void unlock_volume_selection_mode() { m_volume_selection_locked = false; }
@ -358,11 +360,11 @@ public:
void erase();
void render(float scale_factor = 1.0);
//BBS: GUI refactor: add uniform scale from gizmo
void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale);
#if ENABLE_RENDER_SELECTION_CENTER
void render_center(bool gizmo_is_dragging);
#endif // ENABLE_RENDER_SELECTION_CENTER
//BBS: GUI refactor: add uniform scale from gizmo
void render_sidebar_hints(const std::string& sidebar_field, bool uniform_scale);
bool requires_local_axes() const;
@ -405,7 +407,8 @@ private:
void set_bounding_boxes_dirty() {
m_bounding_box.reset();
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset();
m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset();
m_full_unscaled_instance_bounding_box.reset();
m_full_scaled_instance_bounding_box.reset();
m_full_unscaled_instance_local_bounding_box.reset();
m_bounding_box_in_current_reference_system.reset();
m_bounding_sphere.reset();