Fixed conflicts after merge with master

This commit is contained in:
enricoturri1966 2022-06-07 11:10:19 +02:00
commit cd6155293b
66 changed files with 7432 additions and 3894 deletions

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.5.0-alpha0
0.1.5 Added Ender-3 S1 Pro
min_slic3r_version = 2.4.1 min_slic3r_version = 2.4.1
0.1.4 Added Ender-3 Pro. Added M25 support for some printers. 0.1.4 Added Ender-3 Pro. Added M25 support for some printers.
min_slic3r_version = 2.4.0-rc min_slic3r_version = 2.4.0-rc

View File

@ -5,7 +5,7 @@
name = Creality name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded. # This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.1.4 config_version = 0.1.5
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -21,7 +21,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = ender3.svg bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3BLTOUCH] [printer_model:ENDER3BLTOUCH]
name = Creality Ender-3 BLTouch name = Creality Ender-3 BLTouch
@ -30,7 +30,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = ender3.svg bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3PRO] [printer_model:ENDER3PRO]
name = Creality Ender-3 Pro name = Creality Ender-3 Pro
@ -39,7 +39,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = ender3.svg bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3V2] [printer_model:ENDER3V2]
name = Creality Ender-3 V2 name = Creality Ender-3 V2
@ -48,7 +48,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3v2_bed.stl bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3S1] [printer_model:ENDER3S1]
name = Creality Ender-3 S1 name = Creality Ender-3 S1
@ -57,7 +57,16 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3v2_bed.stl bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3S1PRO]
name = Creality Ender-3 S1 Pro
variants = 0.4
technology = FFF
family = ENDER
bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER3MAX] [printer_model:ENDER3MAX]
name = Creality Ender-3 Max name = Creality Ender-3 Max
@ -66,7 +75,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10spro.svg bed_texture = cr10spro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER4] [printer_model:ENDER4]
name = Creality Ender-4 name = Creality Ender-4
@ -75,7 +84,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3v2_bed.stl bed_model = ender3v2_bed.stl
bed_texture = ender3v2.svg bed_texture = ender3v2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER5] [printer_model:ENDER5]
name = Creality Ender-5 name = Creality Ender-5
@ -84,7 +93,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = ender3.svg bed_texture = ender3.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER5PLUS] [printer_model:ENDER5PLUS]
name = Creality Ender-5 Plus name = Creality Ender-5 Plus
@ -93,7 +102,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender5plus_bed.stl bed_model = ender5plus_bed.stl
bed_texture = ender5plus.svg bed_texture = ender5plus.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER6] [printer_model:ENDER6]
name = Creality Ender-6 name = Creality Ender-6
@ -102,7 +111,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender6_bed.stl bed_model = ender6_bed.stl
bed_texture = ender6.svg bed_texture = ender6.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER7] [printer_model:ENDER7]
name = Creality Ender-7 name = Creality Ender-7
@ -111,7 +120,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender7_bed.stl bed_model = ender7_bed.stl
bed_texture = ender7.svg bed_texture = ender7.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER2] [printer_model:ENDER2]
name = Creality Ender-2 name = Creality Ender-2
@ -120,7 +129,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender2_bed.stl bed_model = ender2_bed.stl
bed_texture = ender2.svg bed_texture = ender2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:ENDER2PRO] [printer_model:ENDER2PRO]
name = Creality Ender-2 Pro name = Creality Ender-2 Pro
@ -129,7 +138,7 @@ technology = FFF
family = ENDER family = ENDER
bed_model = ender2pro_bed.stl bed_model = ender2pro_bed.stl
bed_texture = ender2pro.svg bed_texture = ender2pro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR5PRO] [printer_model:CR5PRO]
name = Creality CR-5 Pro name = Creality CR-5 Pro
@ -138,7 +147,7 @@ technology = FFF
family = CR family = CR
bed_model = cr5pro_bed.stl bed_model = cr5pro_bed.stl
bed_texture = cr5pro.svg bed_texture = cr5pro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR5PROH] [printer_model:CR5PROH]
name = Creality CR-5 Pro H name = Creality CR-5 Pro H
@ -147,7 +156,7 @@ technology = FFF
family = CR family = CR
bed_model = cr5pro_bed.stl bed_model = cr5pro_bed.stl
bed_texture = cr5pro.svg bed_texture = cr5pro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR6SE] [printer_model:CR6SE]
name = Creality CR-6 SE name = Creality CR-6 SE
@ -156,7 +165,7 @@ technology = FFF
family = CR family = CR
bed_model = cr6se_bed.stl bed_model = cr6se_bed.stl
bed_texture = cr6se.svg bed_texture = cr6se.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR6MAX] [printer_model:CR6MAX]
name = Creality CR-6 Max name = Creality CR-6 Max
@ -165,7 +174,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10s4_bed.stl bed_model = cr10s4_bed.stl
bed_texture = cr10s4.svg bed_texture = cr10s4.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10SMART] [printer_model:CR10SMART]
name = Creality CR-10 SMART name = Creality CR-10 SMART
@ -174,7 +183,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10spro.svg bed_texture = cr10spro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10MINI] [printer_model:CR10MINI]
name = Creality CR-10 Mini name = Creality CR-10 Mini
@ -183,7 +192,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10mini_bed.stl bed_model = cr10mini_bed.stl
bed_texture = cr10mini.svg bed_texture = cr10mini.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10MAX] [printer_model:CR10MAX]
name = Creality CR-10 Max name = Creality CR-10 Max
@ -192,7 +201,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10max_bed.stl bed_model = cr10max_bed.stl
bed_texture = cr10max.svg bed_texture = cr10max.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10] [printer_model:CR10]
name = Creality CR-10 name = Creality CR-10
@ -201,7 +210,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10_bed.stl bed_model = cr10_bed.stl
bed_texture = cr10.svg bed_texture = cr10.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10V2] [printer_model:CR10V2]
name = Creality CR-10 V2 name = Creality CR-10 V2
@ -210,7 +219,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10.svg bed_texture = cr10.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10V3] [printer_model:CR10V3]
name = Creality CR-10 V3 name = Creality CR-10 V3
@ -219,7 +228,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10.svg bed_texture = cr10.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10S] [printer_model:CR10S]
name = Creality CR-10 S name = Creality CR-10 S
@ -228,7 +237,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10_bed.stl bed_model = cr10_bed.stl
bed_texture = cr10.svg bed_texture = cr10.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10SPRO] [printer_model:CR10SPRO]
name = Creality CR-10 S Pro name = Creality CR-10 S Pro
@ -237,7 +246,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10spro.svg bed_texture = cr10spro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10SPROV2] [printer_model:CR10SPROV2]
name = Creality CR-10 S Pro V2 name = Creality CR-10 S Pro V2
@ -246,7 +255,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10v2_bed.stl bed_model = cr10v2_bed.stl
bed_texture = cr10.svg bed_texture = cr10.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10S4] [printer_model:CR10S4]
name = Creality CR-10 S4 name = Creality CR-10 S4
@ -255,7 +264,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10s4_bed.stl bed_model = cr10s4_bed.stl
bed_texture = cr10s4.svg bed_texture = cr10s4.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR10S5] [printer_model:CR10S5]
name = Creality CR-10 S5 name = Creality CR-10 S5
@ -264,7 +273,7 @@ technology = FFF
family = CR family = CR
bed_model = cr10s5_bed.stl bed_model = cr10s5_bed.stl
bed_texture = cr10s5.svg bed_texture = cr10s5.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR20] [printer_model:CR20]
name = Creality CR-20 name = Creality CR-20
@ -273,7 +282,7 @@ technology = FFF
family = CR family = CR
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = cr20.svg bed_texture = cr20.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR20PRO] [printer_model:CR20PRO]
name = Creality CR-20 Pro name = Creality CR-20 Pro
@ -282,7 +291,7 @@ technology = FFF
family = CR family = CR
bed_model = ender3_bed.stl bed_model = ender3_bed.stl
bed_texture = cr20.svg bed_texture = cr20.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR200B] [printer_model:CR200B]
name = Creality CR-200B name = Creality CR-200B
@ -291,7 +300,7 @@ technology = FFF
family = CR family = CR
bed_model = cr200b_bed.stl bed_model = cr200b_bed.stl
bed_texture = cr200b.svg bed_texture = cr200b.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:CR8] [printer_model:CR8]
name = Creality CR-8 name = Creality CR-8
@ -300,7 +309,7 @@ technology = FFF
family = CR family = CR
bed_model = cr8_bed.stl bed_model = cr8_bed.stl
bed_texture = cr8.svg bed_texture = cr8.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
#[printer_model:CRX] #[printer_model:CRX]
#name = Creality CR-X #name = Creality CR-X
@ -309,7 +318,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
#family = CR-X #family = CR-X
#bed_model = cr10v2_bed.stl #bed_model = cr10v2_bed.stl
#bed_texture = cr10spro.svg #bed_texture = cr10spro.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY #default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
#[printer_model:CRXPRO] #[printer_model:CRXPRO]
#name = Creality CR-X Pro #name = Creality CR-X Pro
@ -318,7 +327,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
#family = CR-X #family = CR-X
#bed_model = cr10v2_bed.stl #bed_model = cr10v2_bed.stl
#bed_texture = cr10spro.svg #bed_texture = cr10spro.svg
#default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY #default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
[printer_model:SERMOOND1] [printer_model:SERMOOND1]
name = Creality Sermoon-D1 name = Creality Sermoon-D1
@ -327,7 +336,7 @@ technology = FFF
family = SERMOON family = SERMOON
bed_model = sermoond1_bed.stl bed_model = sermoond1_bed.stl
bed_texture = sermoond1.svg bed_texture = sermoond1.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY; Verbatim PLA @CREALITY
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -842,6 +851,17 @@ filament_cost = 27.44
filament_density = 1.29 filament_density = 1.29
filament_colour = #C7F935 filament_colour = #C7F935
[filament:Verbatim PLA @CREALITY]
inherits = *PLA*
filament_vendor = Verbatim
temperature = 205
bed_temperature = 60
first_layer_temperature = 210
first_layer_bed_temperature = 60
filament_cost = 22.99
filament_density = 1.24
filament_colour = #001ca8
# Common printer preset # Common printer preset
[printer:*common*] [printer:*common*]
printer_technology = FFF printer_technology = FFF
@ -989,6 +1009,13 @@ max_print_height = 270
printer_model = ENDER3S1 printer_model = ENDER3S1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1
[printer:Creality Ender-3 S1 Pro]
inherits = *common*; *pauseprint*; *spriteextruder*
bed_shape = 5x0,215x0,215x220,5x220
max_print_height = 270
printer_model = ENDER3S1PRO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER3S1PRO
[printer:Creality Ender-3 Max] [printer:Creality Ender-3 Max]
inherits = *common*; *pauseprint* inherits = *common*; *pauseprint*
retract_length = 6 retract_length = 6

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1,4 +1,6 @@
min_slic3r_version = 2.3.1-beta min_slic3r_version = 2.5.0-alpha0
0.0.4 Improve Proton X profiles, Add Proton XE-750 printer
min_slic3r_version = 2.4.1
0.0.3 Set default filament profile. 0.0.3 Set default filament profile.
0.0.2 Improved start gcode, changed filename format 0.0.2 Improved start gcode, changed filename format
0.0.1 Initial version 0.0.1 Initial version

View File

@ -3,7 +3,7 @@
[vendor] [vendor]
# Vendor name will be shown by the Config Wizard. # Vendor name will be shown by the Config Wizard.
name = INAT name = INAT
config_version = 0.0.3 config_version = 0.0.4
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/INAT/ config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/INAT/
### ###
@ -24,9 +24,16 @@ technology = FFF
family = Proton family = Proton
default_materials = PLA @PROTON_X default_materials = PLA @PROTON_X
[printer_model:PROTON_XE750]
name = INAT Proton XE-750
variants = 0.4
technology = FFF
family = Proton
default_materials = PLA @PROTON_XE750
### ###
### QUALITY DEFINITIONS ### COMMON QUALITY DEFINITIONS
### ###
[print:*common*] [print:*common*]
@ -35,14 +42,15 @@ layer_height = 0.2
first_layer_height = 0.2 first_layer_height = 0.2
perimeters = 3 perimeters = 3
spiral_vase = 0 spiral_vase = 0
top_solid_layers = 4 top_solid_layers = 5
bottom_solid_layers = 3 bottom_solid_layers = 3
top_solid_min_thickness = 0.8 top_solid_min_thickness = 1
bottom_solid_min_thickness = 0.6 bottom_solid_min_thickness = 0.6
extra_perimeters = 1 extra_perimeters = 1
ensure_vertical_shell_thickness = 1 ensure_vertical_shell_thickness = 1
avoid_crossing_perimeters = 0 avoid_crossing_perimeters = 0
thin_walls = 0 thin_walls = 0
thick_bridges = 0
overhangs = 1 overhangs = 1
seam_position = aligned seam_position = aligned
external_perimeters_first = 0 external_perimeters_first = 0
@ -76,7 +84,9 @@ support_material_auto = 1
support_material_threshold = 0 support_material_threshold = 0
support_material_enforce_layers = 0 support_material_enforce_layers = 0
raft_layers = 0 raft_layers = 0
support_material_contact_distance = 0.2 support_material_style = grid
support_material_contact_distance = 0.25
support_material_bottom_contact_distance = 0.3
support_material_pattern = rectilinear support_material_pattern = rectilinear
support_material_with_sheath = 0 support_material_with_sheath = 0
support_material_spacing = 5 support_material_spacing = 5
@ -92,8 +102,8 @@ perimeter_speed = 60
small_perimeter_speed = 75% small_perimeter_speed = 75%
external_perimeter_speed = 50% external_perimeter_speed = 50%
infill_speed = 80 infill_speed = 80
solid_infill_speed = 100% solid_infill_speed = 80%
top_solid_infill_speed = 30 top_solid_infill_speed = 20
support_material_speed = 80 support_material_speed = 80
support_material_interface_speed = 100% support_material_interface_speed = 100%
bridge_speed = 60 bridge_speed = 60
@ -126,7 +136,7 @@ infill_overlap = 25%
bridge_flow_ratio = 1 bridge_flow_ratio = 1
slice_closing_radius = 0.049 slice_closing_radius = 0.049
resolution = 0 resolution = 0
xy_size_compensation = 0 xy_size_compensation = -0.05
elefant_foot_compensation = 0.3 elefant_foot_compensation = 0.3
clip_multipart_objects = 0 clip_multipart_objects = 0
#output #output
@ -138,47 +148,50 @@ gcode_label_objects = 0
output_filename_format = {input_filename_base}_{filament_type[0]}.gcode output_filename_format = {input_filename_base}_{filament_type[0]}.gcode
[print:0.2mm Standard @PROTON_X] [print:*common 0.2mm Standard @INAT*]
inherits = *common* inherits = *common*
[print:0.2mm Strong @PROTON_X] [print:*common 0.2mm Strong @INAT*]
inherits = *common* inherits = *common*
fill_density = 50% fill_density = 50%
perimeters = 6 perimeters = 6
[print:0.2mm Advanced Material @PROTON_X] [print:*common 0.2mm Advanced Material @INAT*]
inherits = *common* inherits = *common*
bottom_solid_layers = 5 bottom_solid_layers = 5
top_solid_layers = 6 top_solid_layers = 6
skirts = 0 skirts = 0
brim_width = 30 brim_width = 20
infill_speed = 60 infill_speed = 60
support_material_speed = 60 support_material_speed = 60
travel_speed = 100 travel_speed = 100
first_layer_speed = 20 first_layer_speed = 20
elefant_foot_compensation = 0 elefant_foot_compensation = 0
[print:0.12mm Fine @PROTON_X] [print:*common 0.12mm Fine @INAT*]
inherits = *common* inherits = *common*
layer_height = 0.12
bottom_solid_layers = 7 bottom_solid_layers = 7
top_solid_layers = 7 top_solid_layers = 7
infill_every_layers = 2 infill_every_layers = 2
perimeter_speed = 50 perimeter_speed = 50
infill_speed = 50 infill_speed = 50
[print:0.32mm Draft @PROTON_X] [print:*common 0.32mm Draft @INAT*]
inherits = *common* inherits = *common*
layer_height = 0.32
perimeter_speed = 80 perimeter_speed = 80
external_perimeter_speed = 75% external_perimeter_speed = 75%
infill_speed = 100 infill_speed = 100
top_solid_infill_speed = 60 top_solid_infill_speed = 60
fill_density = 15% fill_density = 15%
support_material_style = snug
### ###
### PRINTER DEFINITIONS ### COMMON PRINTER DEFINITIONS
### ###
[printer:*common*] [printer:*proton_x_common*]
printer_vendor = INAT s.r.o. printer_vendor = INAT s.r.o.
default_filament_profile = "PLA @PROTON_X" default_filament_profile = "PLA @PROTON_X"
#general #general
@ -206,14 +219,14 @@ machine_max_feedrate_z = 10,10
machine_max_feedrate_e = 100,100 machine_max_feedrate_e = 100,100
machine_max_acceleration_x = 500,500 machine_max_acceleration_x = 500,500
machine_max_acceleration_y = 500,500 machine_max_acceleration_y = 500,500
machine_max_acceleration_z = 100,100 machine_max_acceleration_z = 200,200
machine_max_acceleration_e = 2000,2000 machine_max_acceleration_e = 8000,8000
machine_max_acceleration_extruding = 1000,1000 machine_max_acceleration_extruding = 1000,1000
machine_max_acceleration_retracting = 1500,1500 machine_max_acceleration_retracting = 8000,8000
machine_max_jerk_x = 8,8 machine_max_jerk_x = 8,8
machine_max_jerk_y = 8,8 machine_max_jerk_y = 8,8
machine_max_jerk_z = 1,1 machine_max_jerk_z = 3,3
machine_max_jerk_e = 2.5,2.5 machine_max_jerk_e = 10,10
machine_min_extruding_rate = 5 machine_min_extruding_rate = 5
#extruder 1 #extruder 1
nozzle_diameter = 0.4 nozzle_diameter = 0.4
@ -233,24 +246,65 @@ wipe = 1
retract_before_wipe = 100% retract_before_wipe = 100%
[printer:Proton X Rail] [printer:*proton_xe750_common*]
inherits = *common* printer_vendor = INAT s.r.o.
printer_model = PROTON_X_RAIL default_filament_profile = "PLA @PROTON_XE750"
printer_variant = 0.4 #general
default_print_profile = 0.2mm Standard @PROTON_X printer_technology = FFF
gcode_flavor = marlin bed_shape = 0x0,600x0,600x500,0x500
machine_max_acceleration_y = 800,800 max_print_height = 750
z_offset = 0
[printer:Proton X Rod] extruders_count = 2
inherits = *common*
printer_model = PROTON_X_ROD
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_X
gcode_flavor = marlin gcode_flavor = marlin
silent_mode = 0
remaining_times = 1
use_relative_e_distances = 0
use_firmware_retraction = 0
use_volumetric_e = 0
variable_layer_height = 1
#gcodes
start_gcode = G28 ;Home\nG0 Z10 F1000\nG29\nG0 X0 Y0 Z30 F6000\nM84 E\nM0\nG1 Z15.0 F6000 ;Move the platform down 15mm\n
end_gcode = M400\nM104 S0\nM140 S0\nM107\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X R5\nG0 Y300 F2000\nM84\nG4 S180\nM81 S30\n
color_change_gcode = M600
#limits
machine_limits_usage = emit_to_gcode
machine_max_feedrate_x = 200,200
machine_max_feedrate_y = 200,200
machine_max_feedrate_z = 10,10
machine_max_feedrate_e = 100,100
machine_max_acceleration_x = 1500,1500
machine_max_acceleration_y = 1500,1500
machine_max_acceleration_z = 500,500
machine_max_acceleration_e = 20000,20000
machine_max_acceleration_extruding = 2000,2000
machine_max_acceleration_retracting = 8000,8000
machine_max_jerk_x = 12,12
machine_max_jerk_y = 12,12
machine_max_jerk_z = 3,3
machine_max_jerk_e = 20,20
machine_min_extruding_rate = 5
#extruder 1
nozzle_diameter = 0.4,0.4
min_layer_height = 0.05,0.05
max_layer_height = 0.33,0.33
extruder_offset = 0x0,0x0
retract_length = 1.5,1.5
retract_lift = 0.6,0.6
retract_lift_above = 0,0
retract_lift_below = 0,0
retract_speed = 45,45
deretract_speed = 0,0
retract_restart_extra = 0,0
retract_before_travel = 2,2
retract_layer_change = 0,0
wipe = 1,1
retract_before_wipe = 100%,100%
retract_length_toolchange = 37,37
extruder_colour = #33CC33;#3399FF
### ###
### MATERIAL DEFINITIONS ### COMMON MATERIAL DEFINITIONS
### ###
[filament:*common*] [filament:*common*]
@ -272,7 +326,7 @@ min_print_speed = 10
filament_soluble = 0 filament_soluble = 0
[filament:PLA @PROTON_X] [filament:*common PLA @INAT*]
inherits = *common* inherits = *common*
temperature = 210 temperature = 210
bed_temperature = 60 bed_temperature = 60
@ -281,11 +335,12 @@ first_layer_bed_temperature = 60
filament_type = PLA filament_type = PLA
filament_cost = 20 filament_cost = 20
filament_density = 1.25 filament_density = 1.25
fan_always_on = 1
min_fan_speed = 50 min_fan_speed = 50
max_fan_speed = 100 max_fan_speed = 100
[filament:PETG @PROTON_X] [filament:*common PETG @INAT*]
inherits = *common* inherits = *common*
temperature = 240 temperature = 240
bed_temperature = 80 bed_temperature = 80
@ -294,10 +349,11 @@ first_layer_bed_temperature = 80
filament_type = PETG filament_type = PETG
filament_cost = 25 filament_cost = 25
filament_density = 1.27 filament_density = 1.27
min_fan_speed = 0 fan_always_on = 1
min_fan_speed = 25
max_fan_speed = 50 max_fan_speed = 50
[filament:ABS @PROTON_X] [filament:*common ABS @INAT*]
inherits = *common* inherits = *common*
temperature = 235 temperature = 235
bed_temperature = 100 bed_temperature = 100
@ -309,7 +365,7 @@ filament_density = 1.01
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:ASA @PROTON_X] [filament:*common ASA @INAT*]
inherits = *common* inherits = *common*
temperature = 240 temperature = 240
bed_temperature = 110 bed_temperature = 110
@ -320,7 +376,7 @@ filament_cost = 22
filament_density = 1.07 filament_density = 1.07
cooling = 0 cooling = 0
[filament:TPE @PROTON_X] [filament:*common TPE @INAT*]
inherits = *common* inherits = *common*
temperature = 220 temperature = 220
bed_temperature = 40 bed_temperature = 40
@ -334,7 +390,7 @@ max_fan_speed = 50
filament_retract_length = 0.8 filament_retract_length = 0.8
filament_retract_speed = 25 filament_retract_speed = 25
[filament:HIPS @PROTON_X] [filament:*common HIPS @INAT*]
inherits = *common* inherits = *common*
temperature = 245 temperature = 245
bed_temperature = 100 bed_temperature = 100
@ -347,7 +403,7 @@ min_fan_speed = 0
max_fan_speed = 50 max_fan_speed = 50
filament_soluble = 1 filament_soluble = 1
[filament:Nylon @PROTON_X] [filament:*common Nylon @INAT*]
inherits = *common* inherits = *common*
temperature = 235 temperature = 235
bed_temperature = 130 bed_temperature = 130
@ -359,19 +415,19 @@ filament_density = 1.01
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:PC @PROTON_X] [filament:*common PC @INAT*]
inherits = *common* inherits = *common*
temperature = 270 temperature = 270
bed_temperature = 130 bed_temperature = 115
first_layer_temperature = 270 first_layer_temperature = 270
first_layer_bed_temperature = 130 first_layer_bed_temperature = 115
filament_type = PC filament_type = PC
filament_cost = 65 filament_cost = 65
filament_density = 1.19 filament_density = 1.19
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:CPE @PROTON_X] [filament:*common CPE @INAT*]
inherits = *common* inherits = *common*
temperature = 280 temperature = 280
bed_temperature = 90 bed_temperature = 90
@ -383,7 +439,7 @@ filament_density = 1.27
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:PEEK @PROTON_X] [filament:*common PEEK @INAT*]
inherits = *common* inherits = *common*
temperature = 440 temperature = 440
bed_temperature = 150 bed_temperature = 150
@ -395,7 +451,7 @@ filament_density = 1.3
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:PEI @PROTON_X] [filament:*common PEI @INAT*]
inherits = *common* inherits = *common*
temperature = 400 temperature = 400
bed_temperature = 150 bed_temperature = 150
@ -407,7 +463,7 @@ filament_density = 1.27
cooling = 0 cooling = 0
bridge_fan_speed = 0 bridge_fan_speed = 0
[filament:Polymaker PolyMide CoPA @PROTON_X] [filament:*common Polymaker PolyMide CoPA @INAT*]
inherits = *common* inherits = *common*
filament_vendor = Polymaker filament_vendor = Polymaker
temperature = 265 temperature = 265
@ -419,7 +475,7 @@ filament_cost = 93
filament_density = 1.12 filament_density = 1.12
cooling = 0 cooling = 0
[filament:Polymaker PolyMide PA6-CF @PROTON_X] [filament:*common Polymaker PolyMide PA6-CF @INAT*]
inherits = *common* inherits = *common*
filament_vendor = Polymaker filament_vendor = Polymaker
temperature = 300 temperature = 300
@ -431,7 +487,7 @@ filament_cost = 95
filament_density = 1.17 filament_density = 1.17
cooling = 0 cooling = 0
[filament:Polymaker PolyMide PA6-GF @PROTON_X] [filament:*common Polymaker PolyMide PA6-GF @INAT*]
inherits = *common* inherits = *common*
filament_vendor = Polymaker filament_vendor = Polymaker
temperature = 300 temperature = 300
@ -443,20 +499,21 @@ filament_cost = 95
filament_density = 1.2 filament_density = 1.2
cooling = 0 cooling = 0
[filament:Devil Design PETG @PROTON_X] [filament:*common Devil Design PETG @INAT*]
inherits = *common* inherits = *common*
filament_vendor = Devil Design filament_vendor = Devil Design
temperature = 250 temperature = 245
bed_temperature = 80 bed_temperature = 80
first_layer_temperature = 250 first_layer_temperature = 245
first_layer_bed_temperature = 80 first_layer_bed_temperature = 80
filament_type = PETG filament_type = PETG
filament_cost = 22 filament_cost = 22
filament_density = 1.23 filament_density = 1.23
min_fan_speed = 0 fan_always_on = 1
min_fan_speed = 25
max_fan_speed = 50 max_fan_speed = 50
[filament:Filament PM PETG FRJet @PROTON_X] [filament:*common Filament PM PETG FRJet @INAT*]
inherits = *common* inherits = *common*
filament_vendor = Filament PM filament_vendor = Filament PM
temperature = 250 temperature = 250
@ -467,3 +524,207 @@ filament_type = PETG
filament_cost = 45.5 filament_cost = 45.5
filament_density = 1.27 filament_density = 1.27
cooling = 0 cooling = 0
######
###### PROTON X PRINTERS
######
[printer:Proton X Rail]
inherits = *proton_x_common*
printer_model = PROTON_X_RAIL
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_X
gcode_flavor = marlin
machine_max_acceleration_x = 800,800
machine_max_acceleration_y = 800,800
machine_max_jerk_x = 10,10
machine_max_jerk_y = 10,10
[printer:Proton X Rod]
inherits = *proton_x_common*
printer_model = PROTON_X_ROD
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_X
gcode_flavor = marlin
[print:0.2mm Standard @PROTON_X]
inherits = *common 0.2mm Standard @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[print:0.2mm Strong @PROTON_X]
inherits = *common 0.2mm Strong @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[print:0.2mm Advanced Material @PROTON_X]
inherits = *common 0.2mm Advanced Material @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[print:0.12mm Fine @PROTON_X]
inherits = *common 0.12mm Fine @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[print:0.32mm Draft @PROTON_X]
inherits = *common 0.32mm Draft @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:PLA @PROTON_X]
inherits =*common PLA @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:PETG @PROTON_X]
inherits =*common PETG @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:ABS @PROTON_X]
inherits =*common ABS @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:ASA @PROTON_X]
inherits =*common ASA @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:TPE @PROTON_X]
inherits =*common TPE @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:HIPS @PROTON_X]
inherits =*common HIPS @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Nylon @PROTON_X]
inherits =*common Nylon @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:PC @PROTON_X]
inherits =*common PC @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:CPE @PROTON_X]
inherits =*common CPE @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:PEEK @PROTON_X]
inherits =*common PEEK @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:PEI @PROTON_X]
inherits =*common PEI @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Polymaker PolyMide CoPA @PROTON_X]
inherits =*common Polymaker PolyMide CoPA @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Polymaker PolyMide PA6-CF @PROTON_X]
inherits =*common Polymaker PolyMide PA6-CF @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Polymaker PolyMide PA6-GF @PROTON_X]
inherits =*common Polymaker PolyMide PA6-GF @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Devil Design PETG @PROTON_X]
inherits =*common Devil Design PETG @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
[filament:Filament PM PETG FRJet @PROTON_X]
inherits =*common Filament PM PETG FRJet @INAT*
compatible_printers = "Proton X Rail";"Proton X Rod"
######### #########
######### Proton XE 750 #########
######### #########
[printer:Proton XE-750]
inherits = *proton_xe750_common*
printer_model = PROTON_XE750
printer_variant = 0.4
default_print_profile = 0.2mm Standard @PROTON_XE750
gcode_flavor = marlin
[print:0.2mm Standard @PROTON_XE750]
inherits = *common 0.2mm Standard @INAT*
compatible_printers = "Proton XE-750"
[print:0.2mm Strong @PROTON_XE750]
inherits = *common 0.2mm Strong @INAT*
compatible_printers = "Proton XE-750"
[print:0.2mm Advanced Material @PROTON_XE750]
inherits = *common 0.2mm Advanced Material @INAT*
compatible_printers = "Proton XE-750"
[print:0.12mm Fine @PROTON_XE750]
inherits = *common 0.12mm Fine @INAT*
compatible_printers = "Proton XE-750"
[print:0.32mm Draft @PROTON_XE750]
inherits = *common 0.32mm Draft @INAT*
compatible_printers = "Proton XE-750"
[filament:*start_end_gcode @PROTON_XE750*]
start_filament_gcode = "; Filament start gcode BEGIN\nM104 S[temperature[current_extruder]]\nG4 S20\n; Filament start gcode END\n"
end_filament_gcode = "; Filament end gcode BEGIN\nG0 X-5 Y250 F10000\nM104 S{temperature[current_extruder] - 50}\n; Filament end gcode END\n"
compatible_printers = "Proton XE-750"
[filament:PLA @PROTON_XE750]
inherits =*common PLA @INAT*; *start_end_gcode @PROTON_XE750*
[filament:PETG @PROTON_XE750]
inherits =*common PETG @INAT*; *start_end_gcode @PROTON_XE750*
[filament:ABS @PROTON_XE750]
inherits =*common ABS @INAT*; *start_end_gcode @PROTON_XE750*
[filament:ASA @PROTON_XE750]
inherits =*common ASA @INAT*; *start_end_gcode @PROTON_XE750*
[filament:TPE @PROTON_XE750]
inherits =*common TPE @INAT*; *start_end_gcode @PROTON_XE750*
[filament:HIPS @PROTON_XE750]
inherits =*common HIPS @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Nylon @PROTON_XE750]
inherits =*common Nylon @INAT*; *start_end_gcode @PROTON_XE750*
[filament:PC @PROTON_XE750]
inherits =*common PC @INAT*; *start_end_gcode @PROTON_XE750*
[filament:CPE @PROTON_XE750]
inherits =*common CPE @INAT*; *start_end_gcode @PROTON_XE750*
[filament:PEEK @PROTON_XE750]
inherits =*common PEEK @INAT*; *start_end_gcode @PROTON_XE750*
[filament:PEI @PROTON_XE750]
inherits =*common PEI @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Polymaker PolyMide CoPA @PROTON_XE750]
inherits =*common Polymaker PolyMide CoPA @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Polymaker PolyMide PA6-CF @PROTON_XE750]
inherits =*common Polymaker PolyMide PA6-CF @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Polymaker PolyMide PA6-GF @PROTON_XE750]
inherits =*common Polymaker PolyMide PA6-GF @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Devil Design PETG @PROTON_XE750]
inherits =*common Devil Design PETG @INAT*; *start_end_gcode @PROTON_XE750*
[filament:Filament PM PETG FRJet @PROTON_XE750]
inherits =*common Filament PM PETG FRJet @INAT*; *start_end_gcode @PROTON_XE750*

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,11 +1,12 @@
#ifndef ASTAR_HPP #ifndef ASTAR_HPP
#define ASTAR_HPP #define ASTAR_HPP
#include <cmath> // std::isinf() is here
#include <unordered_map>
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "libslic3r/MutablePriorityQueue.hpp" #include "libslic3r/MutablePriorityQueue.hpp"
#include <unordered_map>
namespace Slic3r { namespace astar { namespace Slic3r { namespace astar {
// Input interface for the Astar algorithm. Specialize this struct for a // Input interface for the Astar algorithm. Specialize this struct for a
@ -34,6 +35,8 @@ template<class T> struct TracerTraits_
// Get the estimated distance heuristic from node 'n' to the destination. // Get the estimated distance heuristic from node 'n' to the destination.
// This is referred to as the h value in AStar context. // This is referred to as the h value in AStar context.
// If node 'n' is the goal, this function should return a negative value. // If node 'n' is the goal, this function should return a negative value.
// Note that this heuristic should be admissible (never bigger than the real
// cost) in order for Astar to work.
static float goal_heuristic(const T &tracer, const Node &n) static float goal_heuristic(const T &tracer, const Node &n)
{ {
return tracer.goal_heuristic(n); return tracer.goal_heuristic(n);
@ -50,131 +53,132 @@ template<class T> struct TracerTraits_
template<class T> template<class T>
using TracerNodeT = typename TracerTraits_<remove_cvref_t<T>>::Node; using TracerNodeT = typename TracerTraits_<remove_cvref_t<T>>::Node;
namespace detail { constexpr size_t Unassigned = size_t(-1);
// Helper functions dispatching calls through the TracerTraits_ interface
template<class T> using TracerTraits = TracerTraits_<remove_cvref_t<T>>; template<class Tracer>
struct QNode // Queue node. Keeps track of scores g, and h
template<class T, class Fn>
void foreach_reachable(const T &tracer, const TracerNodeT<T> &from, Fn &&fn)
{ {
TracerTraits<T>::foreach_reachable(tracer, from, fn); TracerNodeT<Tracer> node; // The actual node itself
} size_t queue_id; // Position in the open queue or Unassigned if closed
size_t parent; // unique id of the parent or Unassigned
template<class T> float g, h;
float trace_distance(const T &tracer, const TracerNodeT<T> &a, const TracerNodeT<T> &b) float f() const { return g + h; }
{
return TracerTraits<T>::distance(tracer, a, b);
}
template<class T> QNode(TracerNodeT<Tracer> n = {},
float goal_heuristic(const T &tracer, const TracerNodeT<T> &n) size_t p = Unassigned,
{ float gval = std::numeric_limits<float>::infinity(),
return TracerTraits<T>::goal_heuristic(tracer, n); float hval = 0.f)
} : node{std::move(n)}, parent{p}, queue_id{Unassigned}, g{gval}, h{hval}
{}
template<class T> };
size_t unique_id(const T &tracer, const TracerNodeT<T> &n)
{
return TracerTraits<T>::unique_id(tracer, n);
}
} // namespace astar_detail
// Run the AStar algorithm on a tracer implementation. // Run the AStar algorithm on a tracer implementation.
// The 'tracer' argument encapsulates the domain (grid, point cloud, etc...) // The 'tracer' argument encapsulates the domain (grid, point cloud, etc...)
// The 'source' argument is the starting node. // The 'source' argument is the starting node.
// The 'out' argument is the output iterator into which the output nodes are // The 'out' argument is the output iterator into which the output nodes are
// written. // written. For performance reasons, the order is reverse, from the destination
// Note that no destination node is given. The tracer's goal_heuristic() method // to the source -- (destination included, source is not).
// should return a negative value if a node is a destination node. // The 'cached_nodes' argument is an optional associative container to hold a
template<class Tracer, class It> // QNode entry for each visited node. Any compatible container can be used
bool search_route(const Tracer &tracer, const TracerNodeT<Tracer> &source, It out) // (like std::map or maps with different allocators, even a sufficiently large
// std::vector).
//
// Note that no destination node is given in the signature. The tracer's
// goal_heuristic() method should return a negative value if a node is a
// destination node.
template<class Tracer,
class It,
class NodeMap = std::unordered_map<size_t, QNode<Tracer>>>
bool search_route(const Tracer &tracer,
const TracerNodeT<Tracer> &source,
It out,
NodeMap &&cached_nodes = {})
{ {
using namespace detail; using Node = TracerNodeT<Tracer>;
using QNode = QNode<Tracer>;
using TracerTraits = TracerTraits_<remove_cvref_t<Tracer>>;
using Node = TracerNodeT<Tracer>; struct LessPred { // Comparison functor needed by the priority queue
enum class QueueType { Open, Closed, None }; NodeMap &m;
struct QNode // Queue node. Keeps track of scores g, and h
{
Node node; // The actual node itself
QueueType qtype = QueueType::None; // Which queue holds this node
float g = 0.f, h = 0.f;
float f() const { return g + h; }
};
// TODO: apply a linear memory allocator
using QMap = std::unordered_map<size_t, QNode>;
// The traversed nodes are stored here encapsulated in QNodes
QMap cached_nodes;
struct LessPred { // Comparison functor needed by MutablePriorityQueue
QMap &m;
bool operator ()(size_t node_a, size_t node_b) { bool operator ()(size_t node_a, size_t node_b) {
auto ait = m.find(node_a); return m[node_a].f() < m[node_b].f();
auto bit = m.find(node_b);
assert (ait != m.end() && bit != m.end());
return ait->second.f() < bit->second.f();
} }
}; };
auto qopen = auto qopen = make_mutable_priority_queue<size_t, true>(
make_mutable_priority_queue<size_t, false>([](size_t, size_t){}, [&cached_nodes](size_t el, size_t qidx) {
LessPred{cached_nodes}); cached_nodes[el].queue_id = qidx;
},
LessPred{cached_nodes});
auto qclosed = QNode initial{source, /*parent = */ Unassigned, /*g = */0.f};
make_mutable_priority_queue<size_t, false>([](size_t, size_t){}, size_t source_id = TracerTraits::unique_id(tracer, source);
LessPred{cached_nodes}); cached_nodes[source_id] = initial;
qopen.push(source_id);
QNode initial{source, QueueType::Open}; size_t goal_id = TracerTraits::goal_heuristic(tracer, source) < 0.f ?
cached_nodes.insert({unique_id(tracer, source), initial}); source_id :
qopen.push(unique_id(tracer, source)); Unassigned;
bool goal_reached = false; while (goal_id == Unassigned && !qopen.empty()) {
while (!goal_reached && !qopen.empty()) {
size_t q_id = qopen.top(); size_t q_id = qopen.top();
qopen.pop(); qopen.pop();
QNode q = cached_nodes.at(q_id); QNode &q = cached_nodes[q_id];
foreach_reachable(tracer, q.node, [&](const Node &nd) { // This should absolutely be initialized in the cache already
if (goal_reached) return goal_reached; assert(!std::isinf(q.g));
TracerTraits::foreach_reachable(tracer, q.node, [&](const Node &succ_nd) {
if (goal_id != Unassigned)
return true;
float h = TracerTraits::goal_heuristic(tracer, succ_nd);
float dst = TracerTraits::distance(tracer, q.node, succ_nd);
size_t succ_id = TracerTraits::unique_id(tracer, succ_nd);
QNode qsucc_nd{succ_nd, q_id, q.g + dst, h};
float h = goal_heuristic(tracer, nd);
if (h < 0.f) { if (h < 0.f) {
goal_reached = true; goal_id = succ_id;
cached_nodes[succ_id] = qsucc_nd;
} else { } else {
float dst = trace_distance(tracer, q.node, nd); // If succ_id is not in cache, it gets created with g = infinity
QNode qnd{nd, QueueType::None, q.g + dst, h}; QNode &prev_nd = cached_nodes[succ_id];
size_t qnd_id = unique_id(tracer, nd);
auto it = cached_nodes.find(qnd_id); if (qsucc_nd.g < prev_nd.g) {
// new route is better, apply it:
if (it == cached_nodes.end() || // Save the old queue id, it would be lost after the next line
(it->second.qtype != QueueType::None && qnd.f() < it->second.f())) { size_t queue_id = prev_nd.queue_id;
qnd.qtype = QueueType::Open;
cached_nodes.insert_or_assign(qnd_id, qnd); // The cache needs to be updated either way
qopen.push(qnd_id); prev_nd = qsucc_nd;
if (queue_id == decltype(qopen)::invalid_id())
// was in closed or unqueued, rescheduling
qopen.push(succ_id);
else // was in open, updating
qopen.update(queue_id);
} }
} }
return goal_reached; return goal_id != Unassigned;
}); });
q.qtype = QueueType::Closed;
cached_nodes.insert_or_assign(q_id, q);
qclosed.push(q_id);
// write the output
*out = q.node;
++out;
} }
return goal_reached; // Write the output, do not reverse. Clients can do so if they need to.
if (goal_id != Unassigned) {
const QNode *q = &cached_nodes[goal_id];
while (q->parent != Unassigned) {
assert(!std::isinf(q->g)); // Uninitialized nodes are NOT allowed
*out = q->node;
++out;
q = &cached_nodes[q->parent];
}
}
return goal_id != Unassigned;
} }
}} // namespace Slic3r::astar }} // namespace Slic3r::astar

View File

@ -230,8 +230,13 @@ static std::string appconfig_md5_hash_line(const std::string_view data)
return "# MD5 checksum " + md5_digest_str + "\n"; return "# MD5 checksum " + md5_digest_str + "\n";
}; };
struct ConfigFileInfo {
bool correct_checksum {false};
bool contains_null {false};
};
// Assume that the last line with the comment inside the config file contains a checksum and that the user didn't modify the config file. // Assume that the last line with the comment inside the config file contains a checksum and that the user didn't modify the config file.
static bool verify_config_file_checksum(boost::nowide::ifstream &ifs) static ConfigFileInfo check_config_file_and_verify_checksum(boost::nowide::ifstream &ifs)
{ {
auto read_whole_config_file = [&ifs]() -> std::string { auto read_whole_config_file = [&ifs]() -> std::string {
std::stringstream ss; std::stringstream ss;
@ -240,7 +245,8 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs)
}; };
ifs.seekg(0, boost::nowide::ifstream::beg); ifs.seekg(0, boost::nowide::ifstream::beg);
std::string whole_config = read_whole_config_file(); const std::string whole_config = read_whole_config_file();
const bool contains_null = whole_config.find_first_of('\0') != std::string::npos;
// The checksum should be on the last line in the config file. // The checksum should be on the last line in the config file.
if (size_t last_comment_pos = whole_config.find_last_of('#'); last_comment_pos != std::string::npos) { if (size_t last_comment_pos = whole_config.find_last_of('#'); last_comment_pos != std::string::npos) {
@ -249,9 +255,9 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs)
// When the checksum isn't found, the checksum was not saved correctly, it was removed or it is an older config file without the checksum. // When the checksum isn't found, the checksum was not saved correctly, it was removed or it is an older config file without the checksum.
// If the checksum is incorrect, then the file was either not saved correctly or modified. // If the checksum is incorrect, then the file was either not saved correctly or modified.
if (std::string_view(whole_config.c_str() + last_comment_pos, whole_config.size() - last_comment_pos) == appconfig_md5_hash_line({ whole_config.data(), last_comment_pos })) if (std::string_view(whole_config.c_str() + last_comment_pos, whole_config.size() - last_comment_pos) == appconfig_md5_hash_line({ whole_config.data(), last_comment_pos }))
return true; return {true, contains_null};
} }
return false; return {false, contains_null};
} }
#endif #endif
@ -269,14 +275,25 @@ std::string AppConfig::load(const std::string &path)
ifs.open(path); ifs.open(path);
#ifdef WIN32 #ifdef WIN32
// Verify the checksum of the config file without taking just for debugging purpose. // Verify the checksum of the config file without taking just for debugging purpose.
if (!verify_config_file_checksum(ifs)) const ConfigFileInfo config_file_info = check_config_file_and_verify_checksum(ifs);
BOOST_LOG_TRIVIAL(info) << "The configuration file " << path << if (!config_file_info.correct_checksum)
" has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit."; BOOST_LOG_TRIVIAL(info)
<< "The configuration file " << path
<< " has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit.";
if (!config_file_info.correct_checksum && config_file_info.contains_null) {
BOOST_LOG_TRIVIAL(info) << "The configuration file " + path + " is corrupted, because it is contains null characters.";
throw Slic3r::CriticalException("The configuration file contains null characters.");
}
ifs.seekg(0, boost::nowide::ifstream::beg); ifs.seekg(0, boost::nowide::ifstream::beg);
#endif #endif
pt::read_ini(ifs, tree); try {
} catch (pt::ptree_error& ex) { pt::read_ini(ifs, tree);
} catch (pt::ptree_error &ex) {
throw Slic3r::CriticalException(ex.what());
}
} catch (Slic3r::CriticalException &ex) {
#ifdef WIN32 #ifdef WIN32
// The configuration file is corrupted, try replacing it with the backup configuration. // The configuration file is corrupted, try replacing it with the backup configuration.
ifs.close(); ifs.close();
@ -284,29 +301,29 @@ std::string AppConfig::load(const std::string &path)
if (boost::filesystem::exists(backup_path)) { if (boost::filesystem::exists(backup_path)) {
// Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct. // Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct.
boost::nowide::ifstream backup_ifs(backup_path); boost::nowide::ifstream backup_ifs(backup_path);
if (!verify_config_file_checksum(backup_ifs)) { if (const ConfigFileInfo config_file_info = check_config_file_and_verify_checksum(backup_ifs); !config_file_info.correct_checksum || config_file_info.contains_null) {
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", path, backup_path); BOOST_LOG_TRIVIAL(error) << format(R"(Both "%1%" and "%2%" are corrupted. It isn't possible to restore configuration from the backup.)", path, backup_path);
backup_ifs.close(); backup_ifs.close();
boost::filesystem::remove(backup_path); boost::filesystem::remove(backup_path);
} else if (std::string error_message; copy_file(backup_path, path, error_message, false) != SUCCESS) { } else if (std::string error_message; copy_file(backup_path, path, error_message, false) != SUCCESS) {
BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", path, backup_path, error_message); BOOST_LOG_TRIVIAL(error) << format(R"(Configuration file "%1%" is corrupted. Failed to restore from backup "%2%": %3%)", path, backup_path, error_message);
backup_ifs.close(); backup_ifs.close();
boost::filesystem::remove(backup_path); boost::filesystem::remove(backup_path);
} else { } else {
BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", path, backup_path); BOOST_LOG_TRIVIAL(info) << format(R"(Configuration file "%1%" was corrupted. It has been successfully restored from the backup "%2%".)", path, backup_path);
// Try parse configuration file after restore from backup. // Try parse configuration file after restore from backup.
try { try {
ifs.open(path); ifs.open(path);
pt::read_ini(ifs, tree); pt::read_ini(ifs, tree);
recovered = true; recovered = true;
} catch (pt::ptree_error& ex) { } catch (pt::ptree_error& ex) {
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", path, ex.what()); BOOST_LOG_TRIVIAL(info) << format(R"(Failed to parse configuration file "%1%" after it has been restored from backup: %2%)", path, ex.what());
} }
} }
} else } else
#endif // WIN32 #endif // WIN32
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", path, ex.what()); BOOST_LOG_TRIVIAL(info) << format(R"(Failed to parse configuration file "%1%": %2%)", path, ex.what());
if (! recovered) { if (!recovered) {
// Report the initial error of parsing PrusaSlicer.ini. // Report the initial error of parsing PrusaSlicer.ini.
// Error while parsing config file. We'll customize the error message and rethrow to be displayed. // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
// ! But to avoid the use of _utf8 (related to use of wxWidgets) // ! But to avoid the use of _utf8 (related to use of wxWidgets)

View File

@ -1,20 +1,25 @@
#include "../Print.hpp" #include "../Print.hpp"
#include "../ShortestPath.hpp"
#include "FillLightning.hpp" #include "FillLightning.hpp"
#include "Lightning/Generator.hpp" #include "Lightning/Generator.hpp"
#include "../Surface.hpp"
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <numeric>
namespace Slic3r::FillLightning { namespace Slic3r::FillLightning {
Polylines Filler::fill_surface(const Surface *surface, const FillParams &params) void Filler::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out)
{ {
const Layer &layer = generator->getTreesForLayer(this->layer_id); const Layer &layer = generator->getTreesForLayer(this->layer_id);
return layer.convertToLines(to_polygons(surface->expolygon), generator->infilll_extrusion_width()); Polylines fill_lines = layer.convertToLines(to_polygons(expolygon), scaled<coord_t>(0.5 * this->spacing - this->overlap));
if (params.dont_connect() || fill_lines.size() <= 1) {
append(polylines_out, chain_polylines(std::move(fill_lines)));
} else
connect_infill(std::move(fill_lines), expolygon, polylines_out, this->spacing, params);
} }
void GeneratorDeleter::operator()(Generator *p) { void GeneratorDeleter::operator()(Generator *p) {

View File

@ -24,8 +24,13 @@ public:
Generator *generator { nullptr }; Generator *generator { nullptr };
protected: protected:
Fill* clone() const override { return new Filler(*this); } Fill* clone() const override { return new Filler(*this); }
// Perform the fill.
Polylines fill_surface(const Surface *surface, const FillParams &params) override; void _fill_surface_single(const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out) override;
// Let the G-code export reoder the infill lines. // Let the G-code export reoder the infill lines.
bool no_sort() const override { return false; } bool no_sort() const override { return false; }
}; };

View File

@ -176,7 +176,7 @@ protected:
const Point offset_loc = loc - m_grid_range.min; const Point offset_loc = loc - m_grid_range.min;
const size_t flat_idx = m_grid_size.x() * offset_loc.y() + offset_loc.x(); const size_t flat_idx = m_grid_size.x() * offset_loc.y() + offset_loc.x();
assert(offset_loc.x() >= 0 && offset_loc.y() >= 0); assert(offset_loc.x() >= 0 && offset_loc.y() >= 0);
assert(flat_idx < m_grid_size.y() * m_grid_size.x()); assert(flat_idx < size_t(m_grid_size.y() * m_grid_size.x()));
return flat_idx; return flat_idx;
} }
}; };

View File

@ -7,7 +7,6 @@
#include "../../ClipperUtils.hpp" #include "../../ClipperUtils.hpp"
#include "../../Layer.hpp" #include "../../Layer.hpp"
#include "../../Print.hpp" #include "../../Print.hpp"
#include "../../Surface.hpp"
/* Possible future tasks/optimizations,etc.: /* Possible future tasks/optimizations,etc.:
* - Improve connecting heuristic to favor connecting to shorter trees * - Improve connecting heuristic to favor connecting to shorter trees
@ -54,8 +53,6 @@ Generator::Generator(const PrintObject &print_object, const std::function<void()
void Generator::generateInitialInternalOverhangs(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback) void Generator::generateInitialInternalOverhangs(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
{ {
m_overhang_per_layer.resize(print_object.layers().size()); m_overhang_per_layer.resize(print_object.layers().size());
// FIXME: It can be adjusted to improve bonding between infill and perimeters.
const float infill_wall_offset = 0;// m_infill_extrusion_width;
Polygons infill_area_above; Polygons infill_area_above;
//Iterate from top to bottom, to subtract the overhang areas above from the overhang areas on the layer below, to get only overhang in the top layer where it is overhanging. //Iterate from top to bottom, to subtract the overhang areas above from the overhang areas on the layer below, to get only overhang in the top layer where it is overhanging.
@ -65,7 +62,7 @@ void Generator::generateInitialInternalOverhangs(const PrintObject &print_object
for (const LayerRegion* layerm : print_object.get_layer(layer_nr)->regions()) for (const LayerRegion* layerm : print_object.get_layer(layer_nr)->regions())
for (const Surface& surface : layerm->fill_surfaces.surfaces) for (const Surface& surface : layerm->fill_surfaces.surfaces)
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
append(infill_area_here, infill_wall_offset == 0 ? surface.expolygon : offset(surface.expolygon, infill_wall_offset)); infill_area_here.emplace_back(surface.expolygon);
//Remove the part of the infill area that is already supported by the walls. //Remove the part of the infill area that is already supported by the walls.
Polygons overhang = diff(offset(infill_area_here, -float(m_wall_supporting_radius)), infill_area_above); Polygons overhang = diff(offset(infill_area_here, -float(m_wall_supporting_radius)), infill_area_above);
@ -84,8 +81,6 @@ const Layer& Generator::getTreesForLayer(const size_t& layer_id) const
void Generator::generateTrees(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback) void Generator::generateTrees(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
{ {
m_lightning_layers.resize(print_object.layers().size()); m_lightning_layers.resize(print_object.layers().size());
// FIXME: It can be adjusted to improve bonding between infill and perimeters.
const coord_t infill_wall_offset = 0;// m_infill_extrusion_width;
std::vector<Polygons> infill_outlines(print_object.layers().size(), Polygons()); std::vector<Polygons> infill_outlines(print_object.layers().size(), Polygons());
@ -95,7 +90,7 @@ void Generator::generateTrees(const PrintObject &print_object, const std::functi
for (const LayerRegion *layerm : print_object.get_layer(layer_id)->regions()) for (const LayerRegion *layerm : print_object.get_layer(layer_id)->regions())
for (const Surface &surface : layerm->fill_surfaces.surfaces) for (const Surface &surface : layerm->fill_surfaces.surfaces)
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
append(infill_outlines[layer_id], infill_wall_offset == 0 ? surface.expolygon : offset(surface.expolygon, infill_wall_offset)); infill_outlines[layer_id].emplace_back(surface.expolygon);
} }
// For various operations its beneficial to quickly locate nearby features on the polygon: // For various operations its beneficial to quickly locate nearby features on the polygon:
@ -125,7 +120,8 @@ void Generator::generateTrees(const PrintObject &print_object, const std::functi
if (const BoundingBox &outlines_locator_bbox = outlines_locator.bbox(); outlines_locator_bbox.defined) if (const BoundingBox &outlines_locator_bbox = outlines_locator.bbox(); outlines_locator_bbox.defined)
below_outlines_bbox.merge(outlines_locator_bbox); below_outlines_bbox.merge(outlines_locator_bbox);
below_outlines_bbox.merge(get_extents(current_lightning_layer.tree_roots).inflated(SCALED_EPSILON)); if (!current_lightning_layer.tree_roots.empty())
below_outlines_bbox.merge(get_extents(current_lightning_layer.tree_roots).inflated(SCALED_EPSILON));
outlines_locator.set_bbox(below_outlines_bbox); outlines_locator.set_bbox(below_outlines_bbox);
outlines_locator.create(below_outlines, locator_cell_size); outlines_locator.create(below_outlines, locator_cell_size);

View File

@ -433,15 +433,14 @@ static unsigned int moveInside(const Polygons& polygons, Point& from, int distan
} }
#endif #endif
// Returns 'added someting'. Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_overlap) const
Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const
{ {
if (tree_roots.empty()) if (tree_roots.empty())
return {}; return {};
Polylines result_lines; Polylines result_lines;
for (const auto &tree : tree_roots) for (const auto &tree : tree_roots)
tree->convertToPolylines(result_lines, line_width); tree->convertToPolylines(result_lines, line_overlap);
return intersection_pl(result_lines, limit_to_outline); return intersection_pl(result_lines, limit_to_outline);
} }

View File

@ -80,7 +80,7 @@ public:
coord_t wall_supporting_radius coord_t wall_supporting_radius
); );
Polylines convertToLines(const Polygons& limit_to_outline, coord_t line_width) const; Polylines convertToLines(const Polygons& limit_to_outline, coord_t line_overlap) const;
coord_t getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location); coord_t getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location);

View File

@ -347,12 +347,12 @@ coord_t Node::prune(const coord_t& pruning_distance)
return max_distance_pruned; return max_distance_pruned;
} }
void Node::convertToPolylines(Polylines &output, const coord_t line_width) const void Node::convertToPolylines(Polylines &output, const coord_t line_overlap) const
{ {
Polylines result; Polylines result;
result.emplace_back(); result.emplace_back();
convertToPolylines(0, result); convertToPolylines(0, result);
removeJunctionOverlap(result, line_width); removeJunctionOverlap(result, line_overlap);
append(output, std::move(result)); append(output, std::move(result));
} }
@ -376,10 +376,10 @@ void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const
} }
} }
void Node::removeJunctionOverlap(Polylines &result_lines, const coord_t line_width) const void Node::removeJunctionOverlap(Polylines &result_lines, const coord_t line_overlap) const
{ {
const coord_t reduction = line_width / 2; // TODO make configurable? const coord_t reduction = line_overlap;
size_t res_line_idx = 0; size_t res_line_idx = 0;
while (res_line_idx < result_lines.size()) { while (res_line_idx < result_lines.size()) {
Polyline &polyline = result_lines[res_line_idx]; Polyline &polyline = result_lines[res_line_idx];
if (polyline.size() <= 1) { if (polyline.size() <= 1) {

View File

@ -46,7 +46,7 @@ public:
{ {
struct EnableMakeShared : public Node struct EnableMakeShared : public Node
{ {
EnableMakeShared(Arg&&...arg) : Node(std::forward<Arg>(arg)...) {} explicit EnableMakeShared(Arg&&...arg) : Node(std::forward<Arg>(arg)...) {}
}; };
return std::make_shared<EnableMakeShared>(std::forward<Arg>(arg)...); return std::make_shared<EnableMakeShared>(std::forward<Arg>(arg)...);
} }
@ -179,16 +179,16 @@ public:
*/ */
bool hasOffspring(const NodeSPtr& to_be_checked) const; bool hasOffspring(const NodeSPtr& to_be_checked) const;
protected:
Node() = delete; // Don't allow empty contruction Node() = delete; // Don't allow empty contruction
protected:
/*! /*!
* Construct a new node, either for insertion in a tree or as root. * Construct a new node, either for insertion in a tree or as root.
* \param p The physical location in the 2D layer that this node represents. * \param p The physical location in the 2D layer that this node represents.
* Connecting other nodes to this node indicates that a line segment should * Connecting other nodes to this node indicates that a line segment should
* be drawn between those two physical positions. * be drawn between those two physical positions.
*/ */
Node(const Point& p, const std::optional<Point>& last_grounding_location = std::nullopt); explicit Node(const Point& p, const std::optional<Point>& last_grounding_location = std::nullopt);
/*! /*!
* Copy this node and its entire sub-tree. * Copy this node and its entire sub-tree.
@ -239,7 +239,7 @@ public:
* *
* \param output all branches in this tree connected into polylines * \param output all branches in this tree connected into polylines
*/ */
void convertToPolylines(Polylines &output, coord_t line_width) const; void convertToPolylines(Polylines &output, coord_t line_overlap) const;
/*! If this was ever a direct child of the root, it'll have a previous grounding location. /*! If this was ever a direct child of the root, it'll have a previous grounding location.
* *
@ -260,7 +260,7 @@ protected:
*/ */
void convertToPolylines(size_t long_line_idx, Polylines &output) const; void convertToPolylines(size_t long_line_idx, Polylines &output) const;
void removeJunctionOverlap(Polylines &polylines, coord_t line_width) const; void removeJunctionOverlap(Polylines &polylines, coord_t line_overlap) const;
bool m_is_root; bool m_is_root;
Point m_p; Point m_p;

View File

@ -35,6 +35,8 @@
#include "SVG.hpp" #include "SVG.hpp"
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/task_scheduler_observer.h>
#include <tbb/enumerable_thread_specific.h>
// Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332. // Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332.
// We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB. // We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
@ -1488,6 +1490,32 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
print.throw_if_canceled(); print.throw_if_canceled();
} }
// For unknown reasons and in sporadic cases when GCode export is processing, some participating thread
// in tbb::parallel_pipeline has not set locales to "C", probably because this thread is newly spawned.
// So in this class method on_scheduler_entry is called for every thread before it starts participating
// in tbb::parallel_pipeline to ensure that locales are set correctly
// For tbb::parallel_pipeline, it seems that on_scheduler_entry is called for every layer and every filter.
// We ensure using thread-local storage that locales will be set to "C" just once for any participating thread.
class TBBLocalesSetter : public tbb::task_scheduler_observer
{
public:
TBBLocalesSetter() { this->observe(true); }
~TBBLocalesSetter() override { this->observe(false); };
void on_scheduler_entry(bool is_worker) override
{
if (bool &is_locales_sets = m_is_locales_sets.local(); !is_locales_sets) {
// Set locales of the worker thread to "C".
set_c_locales();
is_locales_sets = true;
}
}
private:
tbb::enumerable_thread_specific<bool, tbb::cache_aligned_allocator<bool>, tbb::ets_key_usage_type::ets_key_per_instance> m_is_locales_sets{false};
};
// Process all layers of all objects (non-sequential mode) with a parallel pipeline: // Process all layers of all objects (non-sequential mode) with a parallel pipeline:
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
// and export G-code into file. // and export G-code into file.
@ -1531,6 +1559,10 @@ void GCode::process_layers(
[&output_stream](std::string s) { output_stream.write(s); } [&output_stream](std::string s) { output_stream.write(s); }
); );
// It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
// Handler is unregistered when the destructor is called.
TBBLocalesSetter locales_setter;
// The pipeline elements are joined using const references, thus no copying is performed. // The pipeline elements are joined using const references, thus no copying is performed.
output_stream.find_replace_supress(); output_stream.find_replace_supress();
if (m_spiral_vase && m_find_replace) if (m_spiral_vase && m_find_replace)
@ -1584,6 +1616,10 @@ void GCode::process_layers(
[&output_stream](std::string s) { output_stream.write(s); } [&output_stream](std::string s) { output_stream.write(s); }
); );
// It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
// Handler is unregistered when the destructor is called.
TBBLocalesSetter locales_setter;
// The pipeline elements are joined using const references, thus no copying is performed. // The pipeline elements are joined using const references, thus no copying is performed.
output_stream.find_replace_supress(); output_stream.find_replace_supress();
if (m_spiral_vase && m_find_replace) if (m_spiral_vase && m_find_replace)

View File

@ -313,9 +313,60 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
return transform; return transform;
} }
void assemble_transform(Transform3d& transform, const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror)
{
transform = translation * rotation * scale * mirror;
}
Transform3d assemble_transform(const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror)
{
Transform3d transform;
assemble_transform(transform, translation, rotation, scale, mirror);
return transform;
}
void translation_transform(Transform3d& transform, const Vec3d& translation)
{
transform = Transform3d::Identity();
transform.translate(translation);
}
Transform3d translation_transform(const Vec3d& translation)
{
Transform3d transform;
translation_transform(transform, translation);
return transform;
}
void rotation_transform(Transform3d& transform, const Vec3d& rotation)
{
transform = Transform3d::Identity();
transform.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX()));
}
Transform3d rotation_transform(const Vec3d& rotation)
{
Transform3d transform;
rotation_transform(transform, rotation);
return transform;
}
void scale_transform(Transform3d& transform, const Vec3d& scale)
{
transform = Transform3d::Identity();
transform.scale(scale);
}
Transform3d scale_transform(const Vec3d& scale)
{
Transform3d transform;
scale_transform(transform, scale);
return transform;
}
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix) Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix)
{ {
// reference: http://www.gregslabaugh.net/publications/euler.pdf // reference: http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
Vec3d angles1 = Vec3d::Zero(); Vec3d angles1 = Vec3d::Zero();
Vec3d angles2 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero();
if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5) { if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5) {
@ -363,6 +414,54 @@ Vec3d extract_euler_angles(const Transform3d& transform)
return extract_euler_angles(m); return extract_euler_angles(m);
} }
#if ENABLE_WORLD_COORDINATE
Transform3d Transformation::get_offset_matrix() const
{
return assemble_transform(get_offset());
}
static Transform3d extract_rotation(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(rotation);
}
static Transform3d extract_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(scale);
}
static std::pair<Transform3d, Transform3d> extract_rotation_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return { Transform3d(rotation), Transform3d(scale) };
}
static bool contains_skew(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return !scale.isDiagonal();
}
Vec3d Transformation::get_rotation() const
{
return extract_euler_angles(extract_rotation(m_matrix));
}
Transform3d Transformation::get_rotation_matrix() const
{
return extract_rotation(m_matrix);
}
#else
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{ {
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
@ -400,12 +499,19 @@ void Transformation::set_offset(Axis axis, double offset)
m_dirty = true; m_dirty = true;
} }
} }
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_rotation(const Vec3d& rotation) void Transformation::set_rotation(const Vec3d& rotation)
{ {
#if ENABLE_WORLD_COORDINATE
const Vec3d offset = get_offset();
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
m_matrix.translation() = offset;
#else
set_rotation(X, rotation.x()); set_rotation(X, rotation.x());
set_rotation(Y, rotation.y()); set_rotation(Y, rotation.y());
set_rotation(Z, rotation.z()); set_rotation(Z, rotation.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_rotation(Axis axis, double rotation) void Transformation::set_rotation(Axis axis, double rotation)
@ -414,32 +520,106 @@ void Transformation::set_rotation(Axis axis, double rotation)
if (is_approx(std::abs(rotation), 2.0 * double(PI))) if (is_approx(std::abs(rotation), 2.0 * double(PI)))
rotation = 0.0; rotation = 0.0;
#if ENABLE_WORLD_COORDINATE
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
Vec3d angles = extract_euler_angles(curr_rotation);
angles[axis] = rotation;
const Vec3d offset = get_offset();
m_matrix = rotation_transform(angles) * scale;
m_matrix.translation() = offset;
#else
if (m_rotation(axis) != rotation) { if (m_rotation(axis) != rotation) {
m_rotation(axis) = rotation; m_rotation(axis) = rotation;
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
Vec3d Transformation::get_scaling_factor() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0), scale(1, 1), scale(2, 2) };
}
Transform3d Transformation::get_scaling_factor_matrix() const
{
return extract_scale(m_matrix);
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_scaling_factor(const Vec3d& scaling_factor) void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
{ {
#if ENABLE_WORLD_COORDINATE
assert(scaling_factor.x() > 0.0 && scaling_factor.y() > 0.0 && scaling_factor.z() > 0.0);
const Vec3d offset = get_offset();
m_matrix = extract_rotation(m_matrix) * scale_transform(scaling_factor);
m_matrix.translation() = offset;
#else
set_scaling_factor(X, scaling_factor.x()); set_scaling_factor(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor.y()); set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor.z()); set_scaling_factor(Z, scaling_factor.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_scaling_factor(Axis axis, double scaling_factor) void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
{ {
#if ENABLE_WORLD_COORDINATE
assert(scaling_factor > 0.0);
auto [rotation, scale] = extract_rotation_scale(m_matrix);
scale(axis, axis) = scaling_factor;
const Vec3d offset = get_offset();
m_matrix = rotation * scale;
m_matrix.translation() = offset;
#else
if (m_scaling_factor(axis) != std::abs(scaling_factor)) { if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
m_scaling_factor(axis) = std::abs(scaling_factor); m_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
Vec3d Transformation::get_mirror() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0) / std::abs(scale(0, 0)), scale(1, 1) / std::abs(scale(1, 1)), scale(2, 2) / std::abs(scale(2, 2)) };
}
Transform3d Transformation::get_mirror_matrix() const
{
const Vec3d scale = get_scaling_factor();
return scale_transform({ scale.x() / std::abs(scale.x()), scale.y() / std::abs(scale.y()), scale.z() / std::abs(scale.z()) });
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_mirror(const Vec3d& mirror) void Transformation::set_mirror(const Vec3d& mirror)
{ {
#if ENABLE_WORLD_COORDINATE
Vec3d copy(mirror);
const Vec3d abs_mirror = copy.cwiseAbs();
for (int i = 0; i < 3; ++i) {
if (abs_mirror(i) == 0.0)
copy(i) = 1.0;
else if (abs_mirror(i) != 1.0)
copy(i) /= abs_mirror(i);
}
const Vec3d curr_scale = get_scaling_factor();
const Vec3d signs = curr_scale.cwiseProduct(copy);
set_scaling_factor({
signs.x() < 0.0 ? std::abs(curr_scale.x()) * copy.x() : curr_scale.x(),
signs.y() < 0.0 ? std::abs(curr_scale.y()) * copy.y() : curr_scale.y(),
signs.z() < 0.0 ? std::abs(curr_scale.z()) * copy.z() : curr_scale.z()
});
#else
set_mirror(X, mirror.x()); set_mirror(X, mirror.x());
set_mirror(Y, mirror.y()); set_mirror(Y, mirror.y());
set_mirror(Z, mirror.z()); set_mirror(Z, mirror.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_mirror(Axis axis, double mirror) void Transformation::set_mirror(Axis axis, double mirror)
@ -450,12 +630,24 @@ void Transformation::set_mirror(Axis axis, double mirror)
else if (abs_mirror != 1.0) else if (abs_mirror != 1.0)
mirror /= abs_mirror; mirror /= abs_mirror;
#if ENABLE_WORLD_COORDINATE
const double curr_scale = get_scaling_factor(axis);
const double sign = curr_scale * mirror;
set_scaling_factor(axis, sign < 0.0 ? std::abs(curr_scale) * mirror : curr_scale);
#else
if (m_mirror(axis) != mirror) { if (m_mirror(axis) != mirror) {
m_mirror(axis) = mirror; m_mirror(axis) = mirror;
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
bool Transformation::has_skew() const
{
return contains_skew(m_matrix);
}
#else
void Transformation::set_from_transform(const Transform3d& transform) void Transformation::set_from_transform(const Transform3d& transform)
{ {
// offset // offset
@ -493,17 +685,62 @@ void Transformation::set_from_transform(const Transform3d& transform)
// if (!m_matrix.isApprox(transform)) // if (!m_matrix.isApprox(transform))
// std::cout << "something went wrong in extracting data from matrix" << std::endl; // std::cout << "something went wrong in extracting data from matrix" << std::endl;
} }
#endif // ENABLE_WORLD_COORDINATE
void Transformation::reset() void Transformation::reset()
{ {
#if !ENABLE_WORLD_COORDINATE
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
m_rotation = Vec3d::Zero(); m_rotation = Vec3d::Zero();
m_scaling_factor = Vec3d::Ones(); m_scaling_factor = Vec3d::Ones();
m_mirror = Vec3d::Ones(); m_mirror = Vec3d::Ones();
#endif // !ENABLE_WORLD_COORDINATE
m_matrix = Transform3d::Identity(); m_matrix = Transform3d::Identity();
#if !ENABLE_WORLD_COORDINATE
m_dirty = false; m_dirty = false;
#endif // !ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
void Transformation::reset_skew()
{
Matrix3d rotation;
Matrix3d scale;
m_matrix.computeRotationScaling(&rotation, &scale);
const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2));
scale(0, 0) = average_scale;
scale(1, 1) = average_scale;
scale(2, 2) = average_scale;
scale(0, 1) = 0.0;
scale(0, 2) = 0.0;
scale(1, 0) = 0.0;
scale(1, 2) = 0.0;
scale(2, 0) = 0.0;
scale(2, 1) = 0.0;
const Vec3d offset = get_offset();
m_matrix = rotation * scale;
m_matrix.translation() = offset;
}
Transform3d Transformation::get_matrix_no_offset() const
{
Transformation copy(*this);
copy.reset_offset();
return copy.get_matrix();
}
Transform3d Transformation::get_matrix_no_scaling_factor() const
{
Transformation copy(*this);
copy.reset_scaling_factor();
copy.reset_mirror();
return copy.get_matrix();
}
#else
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{ {
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) { if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
@ -520,12 +757,14 @@ const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rot
return m_matrix; return m_matrix;
} }
#endif // ENABLE_WORLD_COORDINATE
Transformation Transformation::operator * (const Transformation& other) const Transformation Transformation::operator * (const Transformation& other) const
{ {
return Transformation(get_matrix() * other.get_matrix()); return Transformation(get_matrix() * other.get_matrix());
} }
#if !ENABLE_WORLD_COORDINATE
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox) Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
{ {
Transformation out; Transformation out;
@ -571,8 +810,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z()))); out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1)); out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
} }
else else {
{
// General anisotropic scaling, general rotation. // General anisotropic scaling, general rotation.
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world. // Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
// Scale it to get the required size. // Scale it to get the required size.
@ -581,6 +819,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
return out; return out;
} }
#endif // !ENABLE_WORLD_COORDINATE
// For parsing a transformation matrix from 3MF / AMF. // For parsing a transformation matrix from 3MF / AMF.
Transform3d transform3d_from_string(const std::string& transform_str) Transform3d transform3d_from_string(const std::string& transform_str)
@ -619,7 +858,7 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{ {
const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis(); const Vec3d& axis = angle_axis.axis();
const double angle = angle_axis.angle(); const double angle = angle_axis.angle();
#ifndef NDEBUG #ifndef NDEBUG
if (std::abs(angle) > 1e-8) { if (std::abs(angle) > 1e-8) {

View File

@ -323,7 +323,8 @@ bool arrange(
// 4) rotate Y // 4) rotate Y
// 5) rotate Z // 5) rotate Z
// 6) translate // 6) translate
void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(),
const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
// Returns the transform obtained by assembling the given transformations in the following order: // Returns the transform obtained by assembling the given transformations in the following order:
// 1) mirror // 1) mirror
@ -332,7 +333,43 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
// 4) rotate Y // 4) rotate Y
// 5) rotate Z // 5) rotate Z
// 6) translate // 6) translate
Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(),
const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
// Sets the given transform by multiplying the given transformations in the following order:
// T = translation * rotation * scale * mirror
void assemble_transform(Transform3d& transform, const Transform3d& translation = Transform3d::Identity(),
const Transform3d& rotation = Transform3d::Identity(), const Transform3d& scale = Transform3d::Identity(),
const Transform3d& mirror = Transform3d::Identity());
// Returns the transform obtained by multiplying the given transformations in the following order:
// T = translation * rotation * scale * mirror
Transform3d assemble_transform(const Transform3d& translation = Transform3d::Identity(), const Transform3d& rotation = Transform3d::Identity(),
const Transform3d& scale = Transform3d::Identity(), const Transform3d& mirror = Transform3d::Identity());
// Sets the given transform by assembling the given translation
void translation_transform(Transform3d& transform, const Vec3d& translation);
// Returns the transform obtained by assembling the given translation
Transform3d translation_transform(const Vec3d& translation);
// Sets the given transform by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
void rotation_transform(Transform3d& transform, const Vec3d& rotation);
// Returns the transform obtained by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
Transform3d rotation_transform(const Vec3d& rotation);
// Sets the given transform by assembling the given scale factors
void scale_transform(Transform3d& transform, const Vec3d& scale);
// Returns the transform obtained by assembling the given scale factors
Transform3d scale_transform(const Vec3d& scale);
// Returns the euler angles extracted from the given rotation matrix // Returns the euler angles extracted from the given rotation matrix
// Warning -> The matrix should not contain any scale or shear !!! // Warning -> The matrix should not contain any scale or shear !!!
@ -344,6 +381,9 @@ Vec3d extract_euler_angles(const Transform3d& transform);
class Transformation class Transformation
{ {
#if ENABLE_WORLD_COORDINATE
Transform3d m_matrix{ Transform3d::Identity() };
#else
struct Flags struct Flags
{ {
bool dont_translate{ true }; bool dont_translate{ true };
@ -363,8 +403,26 @@ class Transformation
mutable Transform3d m_matrix{ Transform3d::Identity() }; mutable Transform3d m_matrix{ Transform3d::Identity() };
mutable Flags m_flags; mutable Flags m_flags;
mutable bool m_dirty{ false }; mutable bool m_dirty{ false };
#endif // ENABLE_WORLD_COORDINATE
public: public:
#if ENABLE_WORLD_COORDINATE
Transformation() = default;
explicit Transformation(const Transform3d& transform) : m_matrix(transform) {}
Vec3d get_offset() const { return m_matrix.translation(); }
double get_offset(Axis axis) const { return get_offset()[axis]; }
Transform3d get_offset_matrix() const;
void set_offset(const Vec3d& offset) { m_matrix.translation() = offset; }
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
Vec3d get_rotation() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
#else
Transformation(); Transformation();
explicit Transformation(const Transform3d& transform); explicit Transformation(const Transform3d& transform);
@ -376,47 +434,103 @@ public:
const Vec3d& get_rotation() const { return m_rotation; } const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); } double get_rotation(Axis axis) const { return m_rotation(axis); }
#endif // ENABLE_WORLD_COORDINATE
void set_rotation(const Vec3d& rotation); void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double rotation); void set_rotation(Axis axis, double rotation);
#if ENABLE_WORLD_COORDINATE
Vec3d get_scaling_factor() const;
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
Transform3d get_scaling_factor_matrix() const;
bool is_scaling_uniform() const {
const Vec3d scale = get_scaling_factor();
return std::abs(scale.x() - scale.y()) < 1e-8 && std::abs(scale.x() - scale.z()) < 1e-8;
}
#else
const Vec3d& get_scaling_factor() const { return m_scaling_factor; } const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
#endif // ENABLE_WORLD_COORDINATE
void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(const Vec3d& scaling_factor);
void set_scaling_factor(Axis axis, double scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor);
#if ENABLE_WORLD_COORDINATE
Vec3d get_mirror() const;
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
Transform3d get_mirror_matrix() const;
bool is_left_handed() const {
const Vec3d mirror = get_mirror();
return mirror.x() * mirror.y() * mirror.z() < 0.0;
}
#else
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
const Vec3d& get_mirror() const { return m_mirror; } const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); } double get_mirror(Axis axis) const { return m_mirror(axis); }
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; } bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
#endif // ENABLE_WORLD_COORDINATE
void set_mirror(const Vec3d& mirror); void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror); void set_mirror(Axis axis, double mirror);
#if ENABLE_WORLD_COORDINATE
bool has_skew() const;
#else
void set_from_transform(const Transform3d& transform); void set_from_transform(const Transform3d& transform);
#endif // ENABLE_WORLD_COORDINATE
void reset(); void reset();
#if ENABLE_WORLD_COORDINATE
void reset_offset() { set_offset(Vec3d::Zero()); }
void reset_rotation() { set_rotation(Vec3d::Zero()); }
void reset_scaling_factor() { set_scaling_factor(Vec3d::Ones()); }
void reset_mirror() { set_mirror(Vec3d::Ones()); }
void reset_skew();
const Transform3d& get_matrix() const { return m_matrix; }
Transform3d get_matrix_no_offset() const;
Transform3d get_matrix_no_scaling_factor() const;
void set_matrix(const Transform3d& transform) { m_matrix = transform; }
#else
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
#endif // ENABLE_WORLD_COORDINATE
Transformation operator * (const Transformation& other) const; Transformation operator * (const Transformation& other) const;
#if !ENABLE_WORLD_COORDINATE
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity // Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
// as possible in least squares norm in regard to the 8 corners of bbox. // as possible in least squares norm in regard to the 8 corners of bbox.
// Bounding box is expected to be centered around zero in all axes. // Bounding box is expected to be centered around zero in all axes.
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox); static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
#endif // !ENABLE_WORLD_COORDINATE
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); } #if ENABLE_WORLD_COORDINATE
explicit Transformation(int) : m_dirty(true) {} template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
template <class Archive> static void load_and_construct(Archive &ar, cereal::construct<Transformation> &construct) explicit Transformation(int) {}
{ template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary. {
construct(1); // Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror); construct(1);
} ar(construct.ptr()->m_matrix);
}
#else
template<class Archive> void serialize(Archive& ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
explicit Transformation(int) : m_dirty(true) {}
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
{
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
construct(1);
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
}
#endif // ENABLE_WORLD_COORDINATE
}; };
// For parsing a transformation matrix from 3MF / AMF. // For parsing a transformation matrix from 3MF / AMF.

View File

@ -43,6 +43,25 @@ std::string float_to_string_decimal_point(double value, int precision = -1);
//std::string float_to_string_decimal_point(float value, int precision = -1); //std::string float_to_string_decimal_point(float value, int precision = -1);
double string_to_double_decimal_point(const std::string_view str, size_t* pos = nullptr); double string_to_double_decimal_point(const std::string_view str, size_t* pos = nullptr);
// Set locales to "C".
inline void set_c_locales()
{
#ifdef _WIN32
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
std::setlocale(LC_ALL, "C");
#else
// We are leaking some memory here, because the newlocale() produced memory will never be released.
// This is not a problem though, as there will be a maximum one worker thread created per physical thread.
uselocale(newlocale(
#ifdef __APPLE__
LC_ALL_MASK
#else // some Unix / Linux / BSD
LC_ALL
#endif
, "C", nullptr));
#endif
}
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_LocalesUtils_hpp_ #endif // slic3r_LocalesUtils_hpp_

View File

@ -945,7 +945,11 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
if (this->instances.empty()) if (this->instances.empty())
throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances"); throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances");
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = this->instances.front()->get_transformation().get_matrix_no_offset();
#else
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true); const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) if (v->is_model_part())
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
@ -957,9 +961,15 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
{ {
BoundingBoxf3 bb; BoundingBoxf3 bb;
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = dont_translate ?
this->instances[instance_idx]->get_transformation().get_matrix_no_offset() :
this->instances[instance_idx]->get_transformation().get_matrix();
#else
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate); const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
for (ModelVolume *v : this->volumes) #endif // ENABLE_WORLD_COORDINATE
{ for (ModelVolume *v : this->volumes) {
if (v->is_model_part()) if (v->is_model_part())
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
} }
@ -1368,9 +1378,12 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
new_object->add_instance(*model_instance); new_object->add_instance(*model_instance);
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh)); ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh));
for (ModelInstance* model_instance : new_object->instances) for (ModelInstance* model_instance : new_object->instances) {
{ #if ENABLE_WORLD_COORDINATE
Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
#else
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset(); Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
#endif // ENABLE_WORLD_COORDINATE
model_instance->set_offset(model_instance->get_offset() + shift); model_instance->set_offset(model_instance->get_offset() + shift);
} }
@ -1412,9 +1425,11 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
assert(instance_idx < this->instances.size()); assert(instance_idx < this->instances.size());
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation(); const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
#if !ENABLE_WORLD_COORDINATE
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation())) if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation. // nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
return; return;
#endif // !ENABLE_WORLD_COORDINATE
bool left_handed = reference_trafo.is_left_handed(); bool left_handed = reference_trafo.is_left_handed();
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.)); bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));
@ -1432,8 +1447,18 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
// Adjust the meshes. // Adjust the meshes.
// Transformation to be applied to the meshes. // Transformation to be applied to the meshes.
#if ENABLE_WORLD_COORDINATE
Geometry::Transformation reference_trafo_mod = reference_trafo;
reference_trafo_mod.reset_offset();
if (uniform_scaling)
reference_trafo_mod.reset_scaling_factor();
if (!has_mirrorring)
reference_trafo_mod.reset_mirror();
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
#else
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0); Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix(); #endif // ENABLE_WORLD_COORDINATE
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
for (ModelVolume *model_volume : this->volumes) { for (ModelVolume *model_volume : this->volumes) {
const Geometry::Transformation volume_trafo = model_volume->get_transformation(); const Geometry::Transformation volume_trafo = model_volume->get_transformation();
bool volume_left_handed = volume_trafo.is_left_handed(); bool volume_left_handed = volume_trafo.is_left_handed();
@ -1442,7 +1467,17 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON; std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON;
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.; double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
// Transform the mesh. // Transform the mesh.
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0); #if ENABLE_WORLD_COORDINATE
Geometry::Transformation volume_trafo_mod = volume_trafo;
volume_trafo_mod.reset_offset();
if (volume_uniform_scaling)
volume_trafo_mod.reset_scaling_factor();
if (!volume_has_mirrorring)
volume_trafo_mod.reset_mirror();
Eigen::Matrix3d volume_trafo_3x3 = volume_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
#else
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
#endif // ENABLE_WORLD_COORDINATE
// Following method creates a new shared_ptr<TriangleMesh> // Following method creates a new shared_ptr<TriangleMesh>
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed); model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
// Reset the rotation, scaling and mirroring. // Reset the rotation, scaling and mirroring.
@ -1489,7 +1524,11 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
double min_z = DBL_MAX; double min_z = DBL_MAX;
const ModelInstance* inst = instances[instance_idx]; const ModelInstance* inst = instances[instance_idx];
#if ENABLE_WORLD_COORDINATE
const Transform3d mi = inst->get_matrix_no_offset();
#else
const Transform3d& mi = inst->get_matrix(true); const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) { for (const ModelVolume* v : volumes) {
if (!v->is_model_part()) if (!v->is_model_part())
@ -1510,7 +1549,11 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
double max_z = -DBL_MAX; double max_z = -DBL_MAX;
const ModelInstance* inst = instances[instance_idx]; const ModelInstance* inst = instances[instance_idx];
#if ENABLE_WORLD_COORDINATE
const Transform3d mi = inst->get_matrix_no_offset();
#else
const Transform3d& mi = inst->get_matrix(true); const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) { for (const ModelVolume* v : volumes) {
if (!v->is_model_part()) if (!v->is_model_part())
@ -1936,14 +1979,22 @@ void ModelVolume::convert_from_meters()
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
{ {
#if ENABLE_WORLD_COORDINATE
mesh->transform(dont_translate ? get_matrix_no_offset() : get_matrix());
#else
mesh->transform(get_matrix(dont_translate)); mesh->transform(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
} }
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
{ {
// Rotate around mesh origin. // Rotate around mesh origin.
TriangleMesh copy(mesh); TriangleMesh copy(mesh);
#if ENABLE_WORLD_COORDINATE
copy.transform(get_transformation().get_rotation_matrix());
#else
copy.transform(get_matrix(true, false, true, true)); copy.transform(get_matrix(true, false, true, true));
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 bbox = copy.bounding_box(); BoundingBoxf3 bbox = copy.bounding_box();
if (!empty(bbox)) { if (!empty(bbox)) {
@ -1968,12 +2019,20 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mes
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
{ {
#if ENABLE_WORLD_COORDINATE
return bbox.transformed(dont_translate ? get_matrix_no_offset() : get_matrix());
#else
return bbox.transformed(get_matrix(dont_translate)); return bbox.transformed(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
} }
Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
{ {
#if ENABLE_WORLD_COORDINATE
return dont_translate ? get_matrix_no_offset() * v : get_matrix() * v;
#else
return get_matrix(dont_translate) * v; return get_matrix(dont_translate) * v;
#endif // ENABLE_WORLD_COORDINATE
} }
void ModelInstance::transform_polygon(Polygon* polygon) const void ModelInstance::transform_polygon(Polygon* polygon) const

File diff suppressed because it is too large Load Diff

View File

@ -547,6 +547,10 @@ namespace cereal {
template<class Archive> void load(Archive& archive, Slic3r::Matrix2f &m) { archive.loadBinary((char*)m.data(), sizeof(float) * 4); } template<class Archive> void load(Archive& archive, Slic3r::Matrix2f &m) { archive.loadBinary((char*)m.data(), sizeof(float) * 4); }
template<class Archive> void save(Archive& archive, Slic3r::Matrix2f &m) { archive.saveBinary((char*)m.data(), sizeof(float) * 4); } template<class Archive> void save(Archive& archive, Slic3r::Matrix2f &m) { archive.saveBinary((char*)m.data(), sizeof(float) * 4); }
#if ENABLE_WORLD_COORDINATE
template<class Archive> void load(Archive& archive, Slic3r::Transform3d& m) { archive.loadBinary((char*)m.data(), sizeof(double) * 16); }
template<class Archive> void save(Archive& archive, const Slic3r::Transform3d& m) { archive.saveBinary((char*)m.data(), sizeof(double) * 16); }
#endif // ENABLE_WORLD_COORDINATE
} }
// To be able to use Vec<> and Mat<> in range based for loops: // To be able to use Vec<> and Mat<> in range based for loops:

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@
// Enable showing time estimate for travel moves in legend // Enable showing time estimate for travel moves in legend
#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1)
// Enable not killing focus in object manipulator fields when hovering over 3D scene // Enable not killing focus in object manipulator fields when hovering over 3D scene
#define ENABLE_OBJECT_MANIPULATOR_FOCUS (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_OBJECT_MANIPULATOR_FOCUS (0 && ENABLE_2_5_0_ALPHA1)
// Enable removal of wipe tower magic object_id equal to 1000 // Enable removal of wipe tower magic object_id equal to 1000
#define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1)
// Enable removal of legacy OpenGL calls // Enable removal of legacy OpenGL calls
@ -67,6 +67,8 @@
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
// Enable recalculating toolpaths when switching to/from volumetric rate visualization // Enable recalculating toolpaths when switching to/from volumetric rate visualization
#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1)
// Enable editing volumes transformation in world coordinates and instances in local coordinates
#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified camera control using mouse // Enable modified camera control using mouse
#define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified rectangle selection // Enable modified rectangle selection

View File

@ -15,6 +15,7 @@
#include "Thread.hpp" #include "Thread.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "LocalesUtils.hpp"
namespace Slic3r { namespace Slic3r {
@ -234,21 +235,8 @@ void name_tbb_thread_pool_threads_set_locale()
std::ostringstream name; std::ostringstream name;
name << "slic3r_tbb_" << range.begin(); name << "slic3r_tbb_" << range.begin();
set_current_thread_name(name.str().c_str()); set_current_thread_name(name.str().c_str());
// Set locales of the worker thread to "C". // Set locales of the worker thread to "C".
#ifdef _WIN32 set_c_locales();
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
std::setlocale(LC_ALL, "C");
#else
// We are leaking some memory here, because the newlocale() produced memory will never be released.
// This is not a problem though, as there will be a maximum one worker thread created per physical thread.
uselocale(newlocale(
#ifdef __APPLE__
LC_ALL_MASK
#else // some Unix / Linux / BSD
LC_ALL
#endif
, "C", nullptr));
#endif
} }
}); });
} }

View File

@ -85,6 +85,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_App.hpp GUI/GUI_App.hpp
GUI/GUI_Utils.cpp GUI/GUI_Utils.cpp
GUI/GUI_Utils.hpp GUI/GUI_Utils.hpp
GUI/GUI_Geometry.cpp
GUI/GUI_Geometry.hpp
GUI/I18N.cpp GUI/I18N.cpp
GUI/I18N.hpp GUI/I18N.hpp
GUI/MainFrame.cpp GUI/MainFrame.cpp
@ -129,6 +131,8 @@ set(SLIC3R_GUI_SOURCES
GUI/2DBed.hpp GUI/2DBed.hpp
GUI/3DBed.cpp GUI/3DBed.cpp
GUI/3DBed.hpp GUI/3DBed.hpp
GUI/CoordAxes.cpp
GUI/CoordAxes.hpp
GUI/Camera.cpp GUI/Camera.cpp
GUI/Camera.hpp GUI/Camera.hpp
GUI/wxExtensions.cpp GUI/wxExtensions.cpp

View File

@ -102,6 +102,7 @@ const float* GeometryBuffer::get_vertices_data() const
} }
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL #endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#if !ENABLE_WORLD_COORDINATE
const float Bed3D::Axes::DefaultStemRadius = 0.5f; const float Bed3D::Axes::DefaultStemRadius = 0.5f;
const float Bed3D::Axes::DefaultStemLength = 25.0f; const float Bed3D::Axes::DefaultStemLength = 25.0f;
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
@ -171,6 +172,7 @@ void Bed3D::Axes::render()
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
} }
#endif // !ENABLE_WORLD_COORDINATE
bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
{ {
@ -333,7 +335,11 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
out.max.z() = 0.0; out.max.z() = 0.0;
// extend to contain axes // extend to contain axes
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones()); out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
#if ENABLE_WORLD_COORDINATE
out.merge(out.min + Vec3d(-m_axes.get_tip_radius(), -m_axes.get_tip_radius(), out.max.z()));
#else
out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z())); out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
#endif // ENABLE_WORLD_COORDINATE
// extend to contain model, if any // extend to contain model, if any
BoundingBoxf3 model_bb = m_model.get_bounding_box(); BoundingBoxf3 model_bb = m_model.get_bounding_box();
if (model_bb.defined) { if (model_bb.defined) {
@ -531,7 +537,15 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
void Bed3D::render_axes() void Bed3D::render_axes()
{ {
if (m_build_volume.valid()) if (m_build_volume.valid())
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_axes.render(Transform3d::Identity(), 0.25f);
#else
m_axes.render(0.25f);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#else
m_axes.render(); m_axes.render();
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL

View File

@ -3,7 +3,11 @@
#include "GLTexture.hpp" #include "GLTexture.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#if ENABLE_WORLD_COORDINATE
#include "CoordAxes.hpp"
#else
#include "GLModel.hpp" #include "GLModel.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "libslic3r/BuildVolume.hpp" #include "libslic3r/BuildVolume.hpp"
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -44,6 +48,7 @@ public:
class Bed3D class Bed3D
{ {
#if !ENABLE_WORLD_COORDINATE
class Axes class Axes
{ {
public: public:
@ -67,6 +72,7 @@ class Bed3D
float get_total_length() const { return m_stem_length + DefaultTipLength; } float get_total_length() const { return m_stem_length + DefaultTipLength; }
void render(); void render();
}; };
#endif // !ENABLE_WORLD_COORDINATE
public: public:
enum class Type : unsigned char enum class Type : unsigned char
@ -107,7 +113,11 @@ private:
#if !ENABLE_LEGACY_OPENGL_REMOVAL #if !ENABLE_LEGACY_OPENGL_REMOVAL
unsigned int m_vbo_id{ 0 }; unsigned int m_vbo_id{ 0 };
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL #endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
CoordAxes m_axes;
#else
Axes m_axes; Axes m_axes;
#endif // ENABLE_WORLD_COORDINATE
float m_scale_factor{ 1.0f }; float m_scale_factor{ 1.0f };

View File

@ -432,14 +432,23 @@ public:
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; } const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); } void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
void set_instance_transformation(const Transform3d& transform) { m_instance_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
Vec3d get_instance_offset() const { return m_instance_transformation.get_offset(); }
#else
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); } const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); } double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
#else
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); } const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); } double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); } void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
@ -451,7 +460,11 @@ public:
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
#else
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); } const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); } double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
@ -459,26 +472,43 @@ public:
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; } const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); } void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
void set_volume_transformation(const Transform3d& transform) { m_volume_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
Vec3d get_volume_offset() const { return m_volume_transformation.get_offset(); }
#else
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); } const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); } double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
#else
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); } const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); } double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); } void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); } void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
#else
const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); } const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); } double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
#else
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); } const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); } double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }

View File

@ -0,0 +1,95 @@
#include "libslic3r/libslic3r.h"
#include "CoordAxes.hpp"
#include "GUI_App.hpp"
#include "3DScene.hpp"
#if ENABLE_LEGACY_OPENGL_REMOVAL
#include "Plater.hpp"
#include "Camera.hpp"
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#include <GL/glew.h>
#if ENABLE_WORLD_COORDINATE
namespace Slic3r {
namespace GUI {
const float CoordAxes::DefaultStemRadius = 0.5f;
const float CoordAxes::DefaultStemLength = 25.0f;
const float CoordAxes::DefaultTipRadius = 2.5f * CoordAxes::DefaultStemRadius;
const float CoordAxes::DefaultTipLength = 5.0f;
#if ENABLE_LEGACY_OPENGL_REMOVAL
void CoordAxes::render(const Transform3d& trafo, float emission_factor)
#else
void CoordAxes::render(float emission_factor)
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
{
#if ENABLE_LEGACY_OPENGL_REMOVAL
auto render_axis = [this](GLShaderProgram& shader, const Transform3d& transform) {
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d matrix = camera.get_view_matrix() * transform;
shader.set_uniform("view_model_matrix", matrix);
shader.set_uniform("projection_matrix", camera.get_projection_matrix());
shader.set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose());
m_arrow.render();
#else
auto render_axis = [this](const Transform3f& transform) {
glsafe(::glPushMatrix());
glsafe(::glMultMatrixf(transform.data()));
m_arrow.render();
glsafe(::glPopMatrix());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
};
if (!m_arrow.is_initialized())
m_arrow.init_from(stilized_arrow(16, m_tip_radius, m_tip_length, m_stem_radius, m_stem_length));
GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
if (curr_shader != nullptr)
curr_shader->stop_using();
shader->start_using();
shader->set_uniform("emission_factor", emission_factor);
// x axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::X());
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }));
#else
m_arrow.set_color(-1, ColorRGBA::X());
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast<float>());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// y axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::Y());
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }));
#else
m_arrow.set_color(-1, ColorRGBA::Y());
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast<float>());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// z axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::Z());
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin));
#else
m_arrow.set_color(-1, ColorRGBA::Z());
render_axis(Geometry::assemble_transform(m_origin).cast<float>());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
shader->stop_using();
if (curr_shader != nullptr)
curr_shader->start_using();
}
} // GUI
} // Slic3r
#endif // ENABLE_WORLD_COORDINATE

View File

@ -0,0 +1,64 @@
#ifndef slic3r_CoordAxes_hpp_
#define slic3r_CoordAxes_hpp_
#if ENABLE_WORLD_COORDINATE
#include "GLModel.hpp"
namespace Slic3r {
namespace GUI {
class CoordAxes
{
public:
static const float DefaultStemRadius;
static const float DefaultStemLength;
static const float DefaultTipRadius;
static const float DefaultTipLength;
private:
Vec3d m_origin{ Vec3d::Zero() };
float m_stem_radius{ DefaultStemRadius };
float m_stem_length{ DefaultStemLength };
float m_tip_radius{ DefaultTipRadius };
float m_tip_length{ DefaultTipLength };
GLModel m_arrow;
public:
const Vec3d& get_origin() const { return m_origin; }
void set_origin(const Vec3d& origin) { m_origin = origin; }
void set_stem_radius(float radius) {
m_stem_radius = radius;
m_arrow.reset();
}
void set_stem_length(float length) {
m_stem_length = length;
m_arrow.reset();
}
void set_tip_radius(float radius) {
m_tip_radius = radius;
m_arrow.reset();
}
void set_tip_length(float length) {
m_tip_length = length;
m_arrow.reset();
}
float get_stem_radius() const { return m_stem_radius; }
float get_stem_length() const { return m_stem_length; }
float get_tip_radius() const { return m_tip_radius; }
float get_tip_length() const { return m_tip_length; }
float get_total_length() const { return m_stem_length + m_tip_length; }
#if ENABLE_LEGACY_OPENGL_REMOVAL
void render(const Transform3d& trafo, float emission_factor = 0.0f);
#else
void render(float emission_factor = 0.0f);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
};
} // GUI
} // Slic3r
#endif // ENABLE_WORLD_COORDINATE
#endif // slic3r_CoordAxes_hpp_

View File

@ -1075,6 +1075,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
#if ENABLE_WORLD_COORDINATE
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
#endif // ENABLE_WORLD_COORDINATE
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
@ -2888,7 +2891,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
else else
displacement = multiplier * direction; displacement = multiplier * direction;
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
m_selection.translate(displacement, trafo_type);
#else
m_selection.translate(displacement); m_selection.translate(displacement);
#endif // ENABLE_WORLD_COORDINATE
m_dirty = true; m_dirty = true;
} }
); );
@ -3553,7 +3562,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
} }
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D, trafo_type);
#else
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D); m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
#endif // ENABLE_WORLD_COORDINATE
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects) if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
update_sequential_clearance(); update_sequential_clearance();
wxGetApp().obj_manipul()->set_dirty(); wxGetApp().obj_manipul()->set_dirty();
@ -3799,9 +3814,17 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) if (selection_mode == Selection::Instance)
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume) else if (selection_mode == Selection::Volume)
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
object_moved = true; object_moved = true;
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
@ -3881,8 +3904,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
int object_idx = v->object_idx(); int object_idx = v->object_idx();
if (object_idx == 1000) { // the wipe tower if (object_idx == 1000) { // the wipe tower
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
Vec3d offset = v->get_volume_offset(); const Vec3d offset = v->get_volume_offset();
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2)))); post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z())));
} }
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int object_idx = v->object_idx(); int object_idx = v->object_idx();
@ -3890,8 +3913,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue; continue;
int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx)); done.insert(std::pair<int, int>(object_idx, instance_idx));
@ -3899,12 +3922,20 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) { if (selection_mode == Selection::Instance) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation()); model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
else if (selection_mode == Selection::Volume) { else if (selection_mode == Selection::Volume) {
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation()); model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
@ -3954,12 +3985,12 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
Selection::EMode selection_mode = m_selection.get_mode(); Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes) { for (const GLVolume* v : m_volumes.volumes) {
int object_idx = v->object_idx(); const int object_idx = v->object_idx();
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue; continue;
int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx)); done.insert(std::pair<int, int>(object_idx, instance_idx));
@ -3967,13 +3998,22 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) { if (selection_mode == Selection::Instance) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor()); model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
else if (selection_mode == Selection::Volume) { else if (selection_mode == Selection::Volume) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor()); model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
@ -3982,10 +4022,10 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Fixes sinking/flying instances // Fixes sinking/flying instances
for (const std::pair<int, int>& i : done) { for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first]; ModelObject* m = m_model->objects[i.first];
double shift_z = m->get_instance_min_z(i.second); const double shift_z = m->get_instance_min_z(i.second);
// leave sinking instances as sinking // leave sinking instances as sinking
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) { if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) {
Vec3d shift(0.0, 0.0, -shift_z); const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift); m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift); m->translate_instance(i.second, shift);
} }
@ -4035,9 +4075,17 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) if (selection_mode == Selection::Instance)
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror()); model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume) else if (selection_mode == Selection::Volume)
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror()); model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror());
#endif // ENABLE_WORLD_COORDINATE
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
@ -4061,6 +4109,44 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
m_dirty = true; m_dirty = true;
} }
#if ENABLE_WORLD_COORDINATE
void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(snapshot_type));
std::set<std::pair<int, int>> done; // keeps track of modified instances
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
for (unsigned int id : idxs) {
const GLVolume* v = m_volumes.volumes[id];
int object_idx = v->object_idx();
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx));
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
model_object->invalidate_bounding_box();
}
}
post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW));
m_dirty = true;
}
#endif // ENABLE_WORLD_COORDINATE
void GLCanvas3D::update_gizmos_on_off_state() void GLCanvas3D::update_gizmos_on_off_state()
{ {
set_as_dirty(); set_as_dirty();

View File

@ -156,6 +156,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
#if ENABLE_WORLD_COORDINATE
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
#endif // ENABLE_WORLD_COORDINATE
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
@ -732,7 +735,11 @@ public:
void update_volumes_colors_by_extruder(); void update_volumes_colors_by_extruder();
#if ENABLE_WORLD_COORDINATE
bool is_dragging() const { return m_gizmos.is_dragging() || (m_moving && !m_mouse.scene_position.isApprox(m_mouse.drag.start_position_3D)); }
#else
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; } bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
#endif // ENABLE_WORLD_COORDINATE
void render(); void render();
// printable_only == false -> render also non printable volumes as grayed // printable_only == false -> render also non printable volumes as grayed
@ -800,6 +807,9 @@ public:
void do_rotate(const std::string& snapshot_type); void do_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type);
void do_mirror(const std::string& snapshot_type); void do_mirror(const std::string& snapshot_type);
#if ENABLE_WORLD_COORDINATE
void do_reset_skew(const std::string& snapshot_type);
#endif // ENABLE_WORLD_COORDINATE
void update_gizmos_on_off_state(); void update_gizmos_on_off_state();
void reset_all_gizmos() { m_gizmos.reset_all_states(); } void reset_all_gizmos() { m_gizmos.reset_all_states(); }

View File

@ -0,0 +1,9 @@
#include "libslic3r/libslic3r.h"
#include "GUI_Geometry.hpp"
namespace Slic3r {
namespace GUI {
} // namespace Slic3r
} // namespace GUI

View File

@ -0,0 +1,81 @@
#ifndef slic3r_GUI_Geometry_hpp_
#define slic3r_GUI_Geometry_hpp_
namespace Slic3r {
namespace GUI {
#if ENABLE_WORLD_COORDINATE
enum class ECoordinatesType : unsigned char
{
World,
Instance,
Local
};
class TransformationType
{
public:
enum Enum {
// Transforming in a world coordinate system
World = 0,
// Transforming in a instance coordinate system
Instance = 1,
// Transforming in a local coordinate system
Local = 2,
// Absolute transformations, allowed in local coordinate system only.
Absolute = 0,
// Relative transformations, allowed in both local and world coordinate system.
Relative = 4,
// For group selection, the transformation is performed as if the group made a single solid body.
Joint = 0,
// For group selection, the transformation is performed on each object independently.
Independent = 8,
World_Relative_Joint = World | Relative | Joint,
World_Relative_Independent = World | Relative | Independent,
Instance_Absolute_Joint = Instance | Absolute | Joint,
Instance_Absolute_Independent = Instance | Absolute | Independent,
Instance_Relative_Joint = Instance | Relative | Joint,
Instance_Relative_Independent = Instance | Relative | Independent,
Local_Absolute_Joint = Local | Absolute | Joint,
Local_Absolute_Independent = Local | Absolute | Independent,
Local_Relative_Joint = Local | Relative | Joint,
Local_Relative_Independent = Local | Relative | Independent,
};
TransformationType() : m_value(World) {}
TransformationType(Enum value) : m_value(value) {}
TransformationType& operator=(Enum value) { m_value = value; return *this; }
Enum operator()() const { return m_value; }
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
void set_world() { this->remove(Instance); this->remove(Local); }
void set_instance() { this->remove(Local); this->add(Instance); }
void set_local() { this->remove(Instance); this->add(Local); }
void set_absolute() { this->remove(Relative); }
void set_relative() { this->add(Relative); }
void set_joint() { this->remove(Independent); }
void set_independent() { this->add(Independent); }
bool world() const { return !this->has(Instance) && !this->has(Local); }
bool instance() const { return this->has(Instance); }
bool local() const { return this->has(Local); }
bool absolute() const { return !this->has(Relative); }
bool relative() const { return this->has(Relative); }
bool joint() const { return !this->has(Independent); }
bool independent() const { return this->has(Independent); }
private:
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); }
Enum m_value;
};
#endif // ENABLE_WORLD_COORDINATE
} // namespace Slic3r
} // namespace GUI
#endif // slic3r_GUI_Geometry_hpp_

View File

@ -1530,9 +1530,13 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
const BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx); const BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
// First (any) GLVolume of the selected instance. They all share the same instance matrix. // First (any) GLVolume of the selected instance. They all share the same instance matrix.
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_first_volume();
const Geometry::Transformation inst_transform = v->get_instance_transformation(); const Geometry::Transformation inst_transform = v->get_instance_transformation();
#if ENABLE_WORLD_COORDINATE
const Transform3d inv_inst_transform = inst_transform.get_matrix_no_offset().inverse();
#else
const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse(); const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse();
#endif // ENABLE_WORLD_COORDINATE
const Vec3d instance_offset = v->get_instance_offset(); const Vec3d instance_offset = v->get_instance_offset();
for (size_t i = 0; i < input_files.size(); ++i) { for (size_t i = 0; i < input_files.size(); ++i) {
@ -1580,9 +1584,15 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset; new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset;
if (from_galery) { if (from_galery) {
#if ENABLE_WORLD_COORDINATE
// Transform the new modifier to be aligned with the print bed.
new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
#else
// Transform the new modifier to be aligned with the print bed. // Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb)); new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position. // Set the modifier position.
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
const Vec3d offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - instance_offset; const Vec3d offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - instance_offset;
@ -1650,17 +1660,27 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type); ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type);
// First (any) GLVolume of the selected instance. They all share the same instance matrix. // First (any) GLVolume of the selected instance. They all share the same instance matrix.
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
// Transform the new modifier to be aligned with the print bed. // Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
#else
// Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position. // Set the modifier position.
auto offset = (type_name == "Slab") ? auto offset = (type_name == "Slab") ?
// Slab: Lift to print bed // Slab: Lift to print bed
Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) :
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset(); Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset();
#if ENABLE_WORLD_COORDINATE
new_volume->set_offset(v->get_instance_transformation().get_matrix_no_offset().inverse() * offset);
#else
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
#endif // ENABLE_WORLD_COORDINATE
const wxString name = _L("Generic") + "-" + _(type_name); const wxString name = _L("Generic") + "-" + _(type_name);
new_volume->name = into_u8(name); new_volume->name = into_u8(name);
@ -2545,7 +2565,13 @@ void ObjectList::part_selection_changed()
Sidebar& panel = wxGetApp().sidebar(); Sidebar& panel = wxGetApp().sidebar();
panel.Freeze(); panel.Freeze();
#if ENABLE_WORLD_COORDINATE
const ManipulationEditor* const editor = wxGetApp().obj_manipul()->get_focused_editor();
const std::string opt_key = (editor != nullptr) ? editor->get_full_opt_name() : "";
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, !opt_key.empty());
#else
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false); wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
#endif // ENABLE_WORLD_COORDINATE
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers); wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
@ -3263,8 +3289,12 @@ void ObjectList::update_selections()
return; return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
} }
#if ENABLE_WORLD_COORDINATE
else if (selection.is_single_volume_or_modifier()) {
#else
else if (selection.is_single_volume() || selection.is_any_modifier()) { else if (selection.is_single_volume() || selection.is_any_modifier()) {
const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin()); #endif // ENABLE_WORLD_COORDINATE
const auto gl_vol = selection.get_first_volume();
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx()) if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return; return;
} }

View File

@ -52,10 +52,17 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
#if ENABLE_WORLD_COORDINATE
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
temp->Select((int)ECoordinatesType::World);
#else
temp->Append(_L("World coordinates")); temp->Append(_L("World coordinates"));
temp->Append(_L("Local coordinates")); temp->Append(_L("Local coordinates"));
temp->SetSelection(0); temp->SetSelection(0);
temp->SetValue(temp->GetString(0)); temp->SetValue(temp->GetString(0));
#endif // ENABLE_WORLD_COORDINATE
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed.")); temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
return temp; return temp;
@ -81,8 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
// Set rescaled size // Set rescaled size
combo->SetSize(size); combo->SetSize(size);
#if ENABLE_WORLD_COORDINATE
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
#else
combo->Append(_L("World coordinates")); combo->Append(_L("World coordinates"));
combo->Append(_L("Local coordinates")); combo->Append(_L("Local coordinates"));
#endif // ENABLE_WORLD_COORDINATE
combo->SetValue(selection); combo->SetValue(selection);
#else #else
@ -101,6 +114,7 @@ static void set_font_and_background_style(wxWindow* win, const wxFont& font)
static const wxString axes_color_text[] = { "#990000", "#009900", "#000099" }; static const wxString axes_color_text[] = { "#990000", "#009900", "#000099" };
static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" }; static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" };
ObjectManipulation::ObjectManipulation(wxWindow* parent) : ObjectManipulation::ObjectManipulation(wxWindow* parent) :
OG_Settings(parent, true) OG_Settings(parent, true)
{ {
@ -157,8 +171,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// Add world local combobox // Add world local combobox
m_word_local_combo = create_word_local_combo(parent); m_word_local_combo = create_word_local_combo(parent);
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) { m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) {
#if ENABLE_WORLD_COORDINATE
this->set_coordinates_type(evt.GetString());
#else
this->set_world_coordinates(evt.GetSelection() != 1); this->set_world_coordinates(evt.GetSelection() != 1);
}), m_word_local_combo->GetId()); #endif // ENABLE_WORLD_COORDINATE
}), m_word_local_combo->GetId());
// Small trick to correct layouting in different view_mode : // Small trick to correct layouting in different view_mode :
// Show empty string of a same height as a m_word_local_combo, when m_word_local_combo is hidden // Show empty string of a same height as a m_word_local_combo, when m_word_local_combo is hidden
@ -264,8 +282,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) { if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin())); #endif // ENABLE_WORLD_COORDINATE
GLVolume* volume = const_cast<GLVolume*>(selection.get_first_volume());
volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis)); volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
} }
else if (selection.is_single_full_instance()) { else if (selection.is_single_full_instance()) {
@ -278,7 +300,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return; return;
// Update mirroring at the GLVolumes. // Update mirroring at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_mirror(L("Set Mirror")); canvas->do_mirror(L("Set Mirror"));
@ -327,28 +349,60 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) { #if ENABLE_WORLD_COORDINATE
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); if (selection.is_single_volume_or_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const double min_z = get_volume_min_z(*volume);
if (!is_world_coordinates()) {
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(*volume)); change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (get_volume_min_z(*volume) * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x()); change_position_value(0, diff.x());
change_position_value(1, diff.y()); change_position_value(1, diff.y());
change_position_value(2, diff.z()); change_position_value(2, diff.z());
#endif // ENABLE_WORLD_COORDINATE
} }
else if (selection.is_single_full_instance()) { else if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const double min_z = selection.get_scaled_instance_bounding_box().min.z();
if (!is_world_coordinates()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
#else
const ModelObjectPtrs& objects = wxGetApp().model().objects; const ModelObjectPtrs& objects = wxGetApp().model().objects;
const int idx = selection.get_object_idx(); const int idx = selection.get_object_idx();
if (0 <= idx && idx < static_cast<int>(objects.size())) { if (0 <= idx && idx < static_cast<int>(objects.size())) {
const ModelObject* mo = wxGetApp().model().objects[idx]; const ModelObject* mo = wxGetApp().model().objects[idx];
const double min_z = mo->bounding_box().min.z(); const double min_z = mo->bounding_box().min.z();
if (std::abs(min_z) > SINKING_Z_THRESHOLD) { if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
#endif // ENABLE_WORLD_COORDINATE
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z); change_position_value(2, m_cache.position.z() - min_z);
} }
#if !ENABLE_WORLD_COORDINATE
} }
#endif // !ENABLE_WORLD_COORDINATE
} }
}); });
editors_grid_sizer->Add(m_drop_to_bed_button); editors_grid_sizer->Add(m_drop_to_bed_button);
@ -365,21 +419,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) { #if ENABLE_WORLD_COORDINATE
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin())); if (selection.is_single_volume_or_modifier())
volume->set_volume_rotation(Vec3d::Zero()); #else
} if (selection.is_single_volume() || selection.is_single_modifier())
#endif // ENABLE_WORLD_COORDINATE
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
else if (selection.is_single_full_instance()) { else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) { for (unsigned int idx : selection.get_volume_idxs()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx)); const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
volume->set_instance_rotation(Vec3d::Zero());
} }
} }
else else
return; return;
// Update rotation at the GLVolumes. // Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Reset Rotation")); canvas->do_rotate(L("Reset Rotation"));
@ -397,11 +452,29 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_scale_button->SetToolTip(_L("Reset scale")); m_reset_scale_button->SetToolTip(_L("Reset scale"));
m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
#if ENABLE_WORLD_COORDINATE
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume_or_modifier())
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_scaling_factor(Vec3d::Ones());
else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) {
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_scaling_factor(Vec3d::Ones());
}
}
else
return;
canvas->do_scale(L("Reset scale"));
UpdateAndShow(true);
#else
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
change_scale_value(0, 100.); change_scale_value(0, 100.);
change_scale_value(1, 100.); change_scale_value(1, 100.);
change_scale_value(2, 100.); change_scale_value(2, 100.);
}); #endif // ENABLE_WORLD_COORDINATE
});
editors_grid_sizer->Add(m_reset_scale_button); editors_grid_sizer->Add(m_reset_scale_button);
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++) for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
@ -411,6 +484,25 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND); m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND);
#if ENABLE_WORLD_COORDINATE
m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew"));
m_main_grid_sizer->Add(m_skew_label, 1, wxEXPAND);
m_reset_skew_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_skew_button->SetToolTip(_L("Reset skew"));
m_reset_skew_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
selection.setup_cache();
selection.reset_skew();
canvas->do_reset_skew(L("Reset skew"));
UpdateAndShow(true);
}
});
m_main_grid_sizer->Add(m_reset_skew_button);
#endif // ENABLE_WORLD_COORDINATE
m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches")); m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches"));
m_check_inch->SetFont(wxGetApp().normal_font()); m_check_inch->SetFont(wxGetApp().normal_font());
@ -444,8 +536,27 @@ void ObjectManipulation::Show(const bool show)
if (show) { if (show) {
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only. // Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only.
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple; #if ENABLE_WORLD_COORDINATE
m_word_local_combo->Show(show_world_local_combo); const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
#ifdef __linux__
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), 1);
#else
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), wxNullBitmap, 1);
#endif // __linux__
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
else if (selection.is_single_full_instance() && m_word_local_combo->GetCount() > 2) {
m_word_local_combo->Delete(1);
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
#else
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
#endif // ENABLE_WORLD_COORDINATE
m_word_local_combo->Show(show_world_local_combo);
m_empty_str->Show(!show_world_local_combo); m_empty_str->Show(!show_world_local_combo);
} }
} }
@ -489,8 +600,7 @@ void ObjectManipulation::update_ui_from_settings()
} }
m_check_inch->SetValue(m_imperial_units); m_check_inch->SetValue(m_imperial_units);
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1")) if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1")) {
{
m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1"; m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1";
// update colors for edit-boxes // update colors for edit-boxes
int axis_id = 0; int axis_id = 0;
@ -522,33 +632,49 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_rotate_label_string = L("Rotation"); m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors"); m_new_scale_label_string = L("Scale factors");
#if !ENABLE_WORLD_COORDINATE
if (wxGetApp().get_mode() == comSimple) if (wxGetApp().get_mode() == comSimple)
m_world_coordinates = true; m_world_coordinates = true;
#endif // !ENABLE_WORLD_COORDINATE
ObjectList* obj_list = wxGetApp().obj_list(); ObjectList* obj_list = wxGetApp().obj_list();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
#if !ENABLE_WORLD_COORDINATE
m_new_position = volume->get_instance_offset(); m_new_position = volume->get_instance_offset();
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
if (m_world_coordinates && ! m_uniform_scale && if (m_world_coordinates && ! m_uniform_scale &&
! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { ! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling. // Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
m_uniform_scale = true; m_uniform_scale = true;
m_lock_bnt->SetLock(true); m_lock_bnt->SetLock(true);
} }
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
m_new_position = volume->get_instance_offset();
#else
if (m_world_coordinates) { if (m_world_coordinates) {
m_new_rotate_label_string = L("Rotate"); #endif // ENABLE_WORLD_COORDINATE
m_new_rotation = Vec3d::Zero(); m_new_rotate_label_string = L("Rotate");
m_new_size = selection.get_scaled_instance_bounding_box().size(); m_new_rotation = Vec3d::Zero();
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.; m_new_size = selection.get_scaled_instance_bounding_box().size();
} m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0;
}
else { else {
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); #if ENABLE_WORLD_COORDINATE
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); m_new_move_label_string = L("Translate");
m_new_scale = volume->get_instance_scaling_factor() * 100.; m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
#else
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
#endif // ENABLE_WORLD_COORDINATE
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
} }
m_new_enabled = true; m_new_enabled = true;
@ -557,19 +683,52 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center(); m_new_position = box.center();
m_new_rotation = Vec3d::Zero(); m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(100., 100., 100.); m_new_scale = Vec3d(100.0, 100.0, 100.0);
m_new_size = box.size(); m_new_size = box.size();
m_new_rotate_label_string = L("Rotate"); m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale"); m_new_scale_label_string = L("Scale");
m_new_enabled = true; m_new_enabled = true;
} }
#if ENABLE_WORLD_COORDINATE
else if (selection.is_single_volume_or_modifier()) {
#else
else if (selection.is_single_modifier() || selection.is_single_volume()) { else if (selection.is_single_modifier() || selection.is_single_volume()) {
#endif // ENABLE_WORLD_COORDINATE
// the selection contains a single volume // the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
const Geometry::Transformation trafo(volume->world_matrix());
const Vec3d& offset = trafo.get_offset();
m_new_position = offset;
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
else if (is_local_coordinates()) {
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size());
}
else {
#endif // ENABLE_WORLD_COORDINATE
m_new_position = volume->get_volume_offset(); m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_rotate_label_string = L("Rotate");
m_new_scale = volume->get_volume_scaling_factor() * 100.; m_new_rotation = Vec3d::Zero();
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size())); #if ENABLE_WORLD_COORDINATE
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
#else
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
#endif // ENABLE_WORLD_COORDINATE
m_new_enabled = true; m_new_enabled = true;
} }
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
@ -635,22 +794,26 @@ void ObjectManipulation::update_if_dirty()
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation); update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
} }
#if !ENABLE_WORLD_COORDINATE
if (selection.requires_uniform_scale()) { if (selection.requires_uniform_scale()) {
m_lock_bnt->SetLock(true); m_lock_bnt->SetLock(true);
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection")); m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
m_lock_bnt->disable(); m_lock_bnt->disable();
} }
else { else {
#endif // !ENABLE_WORLD_COORDINATE
m_lock_bnt->SetLock(m_uniform_scale); m_lock_bnt->SetLock(m_uniform_scale);
m_lock_bnt->SetToolTip(wxEmptyString); m_lock_bnt->SetToolTip(wxEmptyString);
m_lock_bnt->enable(); m_lock_bnt->enable();
#if !ENABLE_WORLD_COORDINATE
} }
{ {
int new_selection = m_world_coordinates ? 0 : 1; int new_selection = m_world_coordinates ? 0 : 1;
if (m_word_local_combo->GetSelection() != new_selection) if (m_word_local_combo->GetSelection() != new_selection)
m_word_local_combo->SetSelection(new_selection); m_word_local_combo->SetSelection(new_selection);
} }
#endif // !ENABLE_WORLD_COORDINATE
if (m_new_enabled) if (m_new_enabled)
m_og->enable(); m_og->enable();
@ -677,29 +840,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
bool show_rotation = false; bool show_rotation = false;
bool show_scale = false; bool show_scale = false;
bool show_drop_to_bed = false; bool show_drop_to_bed = false;
#if ENABLE_WORLD_COORDINATE
bool show_skew = false;
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
get_volume_min_z(*selection.get_first_volume());
show_drop_to_bed = std::abs(min_z) > EPSILON;
const GLVolume* volume = selection.get_first_volume();
Transform3d rotation = Transform3d::Identity();
Transform3d scale = Transform3d::Identity();
Geometry::Transformation skew;
#else
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
Vec3d rotation; Vec3d rotation;
Vec3d scale; Vec3d scale;
double min_z = 0.; double min_z = 0.0;
#endif // ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_instance_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int id : idxs) {
const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix());
if (world_trafo.has_skew()) {
skew = world_trafo;
break;
}
}
#else
rotation = volume->get_instance_rotation(); rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor(); scale = volume->get_instance_scaling_factor();
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z(); min_z = selection.get_scaled_instance_bounding_box().min.z();
#endif // ENABLE_WORLD_COORDINATE
} }
else { else {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_volume_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Geometry::Transformation world_trafo(volume->world_matrix());
if (world_trafo.has_skew())
skew = world_trafo;
#else
rotation = volume->get_volume_rotation(); rotation = volume->get_volume_rotation();
scale = volume->get_volume_scaling_factor(); scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(*volume); min_z = get_volume_min_z(*volume);
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
show_rotation = !rotation.isApprox(Transform3d::Identity());
show_scale = !scale.isApprox(Transform3d::Identity());
show_skew = skew.has_skew();
#else
show_rotation = !rotation.isApprox(Vec3d::Zero()); show_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones()); show_scale = !scale.isApprox(Vec3d::Ones());
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew] {
#else
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
#endif // ENABLE_WORLD_COORDINATE
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden // There is a case (under OSX), when this function is called after the Manipulation panel is hidden
// So, let check if Manipulation panel is still shown for this moment // So, let check if Manipulation panel is still shown for this moment
if (!this->IsShown()) if (!this->IsShown())
@ -707,6 +916,10 @@ void ObjectManipulation::update_reset_buttons_visibility()
m_reset_rotation_button->Show(show_rotation); m_reset_rotation_button->Show(show_rotation);
m_reset_scale_button->Show(show_scale); m_reset_scale_button->Show(show_scale);
m_drop_to_bed_button->Show(show_drop_to_bed); m_drop_to_bed_button->Show(show_drop_to_bed);
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->Show(show_skew);
m_skew_label->Show(show_skew);
#endif // ENABLE_WORLD_COORDINATE
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time // Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar(); Sidebar& panel = wxGetApp().sidebar();
@ -726,9 +939,17 @@ void ObjectManipulation::update_mirror_buttons_visibility()
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden}; std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
#if ENABLE_WORLD_COORDINATE
if (is_local_coordinates()) {
#else
if (!m_world_coordinates) { if (!m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); #endif // ENABLE_WORLD_COORDINATE
const GLVolume* volume = selection.get_first_volume();
Vec3d mirror; Vec3d mirror;
if (selection.is_single_full_instance()) if (selection.is_single_full_instance())
@ -792,6 +1013,19 @@ void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning
m_fix_throught_netfab_bitmap->SetToolTip(tooltip); m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
} }
#if ENABLE_WORLD_COORDINATE
wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
{
switch (type)
{
case ECoordinatesType::World: { return _L("World coordinates"); }
case ECoordinatesType::Instance: { return _L("Instance coordinates"); }
case ECoordinatesType::Local: { return _L("Local coordinates"); }
default: { assert(false); return _L("Unknown"); }
}
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::reset_settings_value() void ObjectManipulation::reset_settings_value()
{ {
m_new_position = Vec3d::Zero(); m_new_position = Vec3d::Zero();
@ -815,7 +1049,19 @@ void ObjectManipulation::change_position_value(int axis, double value)
auto canvas = wxGetApp().plater()->canvas3D(); auto canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
selection.setup_cache(); selection.setup_cache();
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
switch (get_coordinates_type())
{
case ECoordinatesType::Instance: { trafo_type.set_instance(); break; }
case ECoordinatesType::Local: { trafo_type.set_local(); break; }
default: { break; }
}
selection.translate(position - m_cache.position, trafo_type);
#else
selection.translate(position - m_cache.position, selection.requires_local_axes()); selection.translate(position - m_cache.position, selection.requires_local_axes());
#endif // ENABLE_WORLD_COORDINATE
canvas->do_move(L("Set Position")); canvas->do_move(L("Set Position"));
m_cache.position = position; m_cache.position = position;
@ -834,6 +1080,18 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
transformation_type.set_relative();
if (selection.is_single_full_instance())
transformation_type.set_independent();
if (is_local_coordinates())
transformation_type.set_local();
if (is_instance_coordinates())
transformation_type.set_instance();
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint); TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance() || selection.requires_local_axes()) if (selection.is_single_full_instance() || selection.requires_local_axes())
transformation_type.set_independent(); transformation_type.set_independent();
@ -842,6 +1100,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
// transformation_type.set_absolute(); // transformation_type.set_absolute();
transformation_type.set_local(); transformation_type.set_local();
} }
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache(); selection.setup_cache();
selection.rotate( selection.rotate(
@ -887,8 +1146,12 @@ void ObjectManipulation::change_size_value(int axis, double value)
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
Vec3d ref_size = m_cache.size; Vec3d ref_size = m_cache.size;
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) { if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); #endif // ENABLE_WORLD_COORDINATE
const GLVolume* v = selection.get_first_volume();
const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor()); const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor());
const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor()); const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size); const Vec3d local_change = local_size.cwiseQuotient(local_ref_size);
@ -897,11 +1160,19 @@ void ObjectManipulation::change_size_value(int axis, double value)
ref_size = Vec3d::Ones(); ref_size = Vec3d::Ones();
} }
else if (selection.is_single_full_instance()) else if (selection.is_single_full_instance())
ref_size = m_world_coordinates ? #if ENABLE_WORLD_COORDINATE
ref_size = is_world_coordinates() ?
#else
ref_size = m_world_coordinates ?
#endif // ENABLE_WORLD_COORDINATE
selection.get_unscaled_instance_bounding_box().size() : selection.get_unscaled_instance_bounding_box().size() :
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size(); wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size();
#if ENABLE_WORLD_COORDINATE
this->do_size(axis, size.cwiseQuotient(ref_size));
#else
this->do_scale(axis, size.cwiseQuotient(ref_size)); this->do_scale(axis, size.cwiseQuotient(ref_size));
#endif // ENABLE_WORLD_COORDINATE
m_cache.size = size; m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX; m_cache.size_rounded(axis) = DBL_MAX;
@ -911,8 +1182,22 @@ void ObjectManipulation::change_size_value(int axis, double value)
void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
{ {
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
#if !ENABLE_WORLD_COORDINATE
Vec3d scaling_factor = scale; Vec3d scaling_factor = scale;
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
if (!selection.is_single_full_instance() && !selection.is_single_volume_or_modifier())
transformation_type.set_relative();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint); TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
transformation_type.set_absolute(); transformation_type.set_absolute();
@ -922,12 +1207,31 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
if (m_uniform_scale || selection.requires_uniform_scale()) if (m_uniform_scale || selection.requires_uniform_scale())
scaling_factor = scale(axis) * Vec3d::Ones(); scaling_factor = scale(axis) * Vec3d::Ones();
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache(); selection.setup_cache();
selection.scale(scaling_factor, transformation_type); selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale")); wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
} }
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
selection.setup_cache();
selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value) void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
{ {
if (!m_cache.is_valid()) if (!m_cache.is_valid())
@ -962,17 +1266,26 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
} }
} }
void ObjectManipulation::set_uniform_scaling(const bool new_value) void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
{ {
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); #if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) { if (!use_uniform_scale)
// Recalculate cached values at this panel, refresh the screen.
this->UpdateAndShow(true);
m_uniform_scale = use_uniform_scale;
set_dirty();
#else
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. // Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
// Is the angle close to a multiple of 90 degrees? // Is the angle close to a multiple of 90 degrees?
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system. // Cannot apply scaling in the world coordinate system.
//wxMessageDialog dlg(GUI::wxGetApp().mainframe, //wxMessageDialog dlg(GUI::wxGetApp().mainframe,
MessageDialog dlg(GUI::wxGetApp().mainframe, MessageDialog dlg(GUI::wxGetApp().mainframe,
_L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n" _L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n"
"Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n" "Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n"
@ -980,7 +1293,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
_L("This operation is irreversible.\n" _L("This operation is irreversible.\n"
"Do you want to proceed?"), "Do you want to proceed?"),
SLIC3R_APP_NAME, SLIC3R_APP_NAME,
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION); wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES) { if (dlg.ShowModal() != wxID_YES) {
// Enforce uniform scaling. // Enforce uniform scaling.
m_lock_bnt->SetLock(true); m_lock_bnt->SetLock(true);
@ -994,9 +1307,29 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
this->UpdateAndShow(true); this->UpdateAndShow(true);
} }
} }
m_uniform_scale = new_value;
m_uniform_scale = use_uniform_scale;
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
{
if (wxGetApp().get_mode() == comSimple)
type = ECoordinatesType::World;
if (m_coordinates_type == type)
return;
m_coordinates_type = type;
this->UpdateAndShow(true);
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
canvas->get_gizmos_manager().update_data();
canvas->set_as_dirty();
canvas->request_extra_frame();
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::msw_rescale() void ObjectManipulation::msw_rescale()
{ {
const int em = wxGetApp().em_unit(); const int em = wxGetApp().em_unit();
@ -1014,6 +1347,9 @@ void ObjectManipulation::msw_rescale()
m_mirror_bitmap_hidden.msw_rescale(); m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale(); m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale(); m_reset_rotation_button->msw_rescale();
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->msw_rescale();
#endif /// ENABLE_WORLD_COORDINATE
m_drop_to_bed_button->msw_rescale(); m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale(); m_lock_bnt->msw_rescale();
@ -1053,6 +1389,9 @@ void ObjectManipulation::sys_color_changed()
m_mirror_bitmap_hidden.msw_rescale(); m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale(); m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale(); m_reset_rotation_button->msw_rescale();
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->msw_rescale();
#endif // ENABLE_WORLD_COORDINATE
m_drop_to_bed_button->msw_rescale(); m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale(); m_lock_bnt->msw_rescale();
@ -1060,6 +1399,19 @@ void ObjectManipulation::sys_color_changed()
m_mirror_buttons[id].first->msw_rescale(); m_mirror_buttons[id].first->msw_rescale();
} }
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(const wxString& type_string)
{
ECoordinatesType type = ECoordinatesType::World;
if (type_string == coordinate_type_str(ECoordinatesType::Instance))
type = ECoordinatesType::Instance;
else if (type_string == coordinate_type_str(ECoordinatesType::Local))
type = ECoordinatesType::Local;
this->set_coordinates_type(type);
}
#endif // ENABLE_WORLD_COORDINATE
static const char axes[] = { 'x', 'y', 'z' }; static const char axes[] = { 'x', 'y', 'z' };
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent, ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
const std::string& opt_key, const std::string& opt_key,
@ -1101,8 +1453,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
parent->set_focused_editor(nullptr); parent->set_focused_editor(nullptr);
#if ENABLE_OBJECT_MANIPULATOR_FOCUS #if ENABLE_OBJECT_MANIPULATOR_FOCUS
// if the widgets exchanging focus are both manipulator fields, call kill_focus // if the widgets loosing focus is a manipulator field, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr) if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
#else #else
if (!m_enter_pressed) if (!m_enter_pressed)
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS #endif // ENABLE_OBJECT_MANIPULATOR_FOCUS

View File

@ -5,6 +5,9 @@
#include "GUI_ObjectSettings.hpp" #include "GUI_ObjectSettings.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include <float.h> #include <float.h>
@ -57,6 +60,10 @@ public:
void set_value(const wxString& new_value); void set_value(const wxString& new_value);
void kill_focus(ObjectManipulation *parent); void kill_focus(ObjectManipulation *parent);
#if ENABLE_WORLD_COORDINATE
const std::string& get_full_opt_name() const { return m_full_opt_name; }
#endif // ENABLE_WORLD_COORDINATE
private: private:
double get_value(); double get_value();
}; };
@ -113,9 +120,12 @@ private:
wxStaticText* m_empty_str = nullptr; wxStaticText* m_empty_str = nullptr;
// Non-owning pointers to the reset buttons, so we can hide and show them. // Non-owning pointers to the reset buttons, so we can hide and show them.
ScalableButton* m_reset_scale_button = nullptr; ScalableButton* m_reset_scale_button{ nullptr };
ScalableButton* m_reset_rotation_button = nullptr; ScalableButton* m_reset_rotation_button{ nullptr };
ScalableButton* m_drop_to_bed_button = nullptr; #if ENABLE_WORLD_COORDINATE
ScalableButton* m_reset_skew_button{ nullptr };
#endif // ENABLE_WORLD_COORDINATE
ScalableButton* m_drop_to_bed_button{ nullptr };
wxCheckBox* m_check_inch {nullptr}; wxCheckBox* m_check_inch {nullptr};
@ -144,22 +154,35 @@ private:
Vec3d m_new_size; Vec3d m_new_size;
bool m_new_enabled {true}; bool m_new_enabled {true};
bool m_uniform_scale {true}; bool m_uniform_scale {true};
#if ENABLE_WORLD_COORDINATE
ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
#else
// Does the object manipulation panel work in World or Local coordinates? // Does the object manipulation panel work in World or Local coordinates?
bool m_world_coordinates = true; bool m_world_coordinates = true;
#endif // ENABLE_WORLD_COORDINATE
LockButton* m_lock_bnt{ nullptr }; LockButton* m_lock_bnt{ nullptr };
choice_ctrl* m_word_local_combo { nullptr }; choice_ctrl* m_word_local_combo { nullptr };
ScalableBitmap m_manifold_warning_bmp; ScalableBitmap m_manifold_warning_bmp;
wxStaticBitmap* m_fix_throught_netfab_bitmap; wxStaticBitmap* m_fix_throught_netfab_bitmap;
#if ENABLE_WORLD_COORDINATE
// Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor{ nullptr };
#else
#ifndef __APPLE__ #ifndef __APPLE__
// Currently focused editor (nullptr if none) // Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor {nullptr}; ManipulationEditor* m_focused_editor {nullptr};
#endif // __APPLE__ #endif // __APPLE__
#endif // ENABLE_WORLD_COORDINATE
wxFlexGridSizer* m_main_grid_sizer; wxFlexGridSizer* m_main_grid_sizer;
wxFlexGridSizer* m_labels_grid_sizer; wxFlexGridSizer* m_labels_grid_sizer;
#if ENABLE_WORLD_COORDINATE
wxStaticText* m_skew_label{ nullptr };
#endif // ENABLE_WORLD_COORDINATE
// sizers, used for msw_rescale // sizers, used for msw_rescale
wxBoxSizer* m_word_local_combo_sizer; wxBoxSizer* m_word_local_combo_sizer;
std::vector<wxBoxSizer*> m_rescalable_sizers; std::vector<wxBoxSizer*> m_rescalable_sizers;
@ -180,11 +203,19 @@ public:
// Called from the App to update the UI if dirty. // Called from the App to update the UI if dirty.
void update_if_dirty(); void update_if_dirty();
void set_uniform_scaling(const bool uniform_scale); void set_uniform_scaling(const bool use_uniform_scale);
bool get_uniform_scaling() const { return m_uniform_scale; } bool get_uniform_scaling() const { return m_uniform_scale; }
#if ENABLE_WORLD_COORDINATE
void set_coordinates_type(ECoordinatesType type);
ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
#else
// Does the object manipulation panel work in World or Local coordinates? // Does the object manipulation panel work in World or Local coordinates?
void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); } void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); }
bool get_world_coordinates() const { return m_world_coordinates; } bool get_world_coordinates() const { return m_world_coordinates; }
#endif // ENABLE_WORLD_COORDINATE
void reset_cache() { m_cache.reset(); } void reset_cache() { m_cache.reset(); }
#ifndef __APPLE__ #ifndef __APPLE__
@ -200,11 +231,23 @@ public:
void sys_color_changed(); void sys_color_changed();
void on_change(const std::string& opt_key, int axis, double new_value); void on_change(const std::string& opt_key, int axis, double new_value);
void set_focused_editor(ManipulationEditor* focused_editor) { void set_focused_editor(ManipulationEditor* focused_editor) {
#if ENABLE_WORLD_COORDINATE
m_focused_editor = focused_editor;
#else
#ifndef __APPLE__ #ifndef __APPLE__
m_focused_editor = focused_editor; m_focused_editor = focused_editor;
#endif // __APPLE__ #endif // __APPLE__
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_WORLD_COORDINATE
ManipulationEditor* get_focused_editor() { return m_focused_editor; }
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
static wxString coordinate_type_str(ECoordinatesType type);
#endif // ENABLE_WORLD_COORDINATE
private: private:
void reset_settings_value(); void reset_settings_value();
void update_settings_value(const Selection& selection); void update_settings_value(const Selection& selection);
@ -220,6 +263,11 @@ private:
void change_scale_value(int axis, double value); void change_scale_value(int axis, double value);
void change_size_value(int axis, double value); void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const; void do_scale(int axis, const Vec3d &scale) const;
#if ENABLE_WORLD_COORDINATE
void do_size(int axis, const Vec3d& scale) const;
void set_coordinates_type(const wxString& type_string);
#endif // ENABLE_WORLD_COORDINATE
}; };
}} }}

View File

@ -954,7 +954,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
} }
GCodeViewer::EViewType gcode_view_type = m_canvas->get_gcode_view_preview_type(); GCodeViewer::EViewType gcode_view_type = m_canvas->get_gcode_view_preview_type();
bool gcode_preview_data_valid = !m_gcode_result->moves.empty() && !m_canvas->get_gcode_layers_zs().empty(); bool gcode_preview_data_valid = !m_gcode_result->moves.empty();
// Collect colors per extruder. // Collect colors per extruder.
std::vector<std::string> colors; std::vector<std::string> colors;
@ -983,10 +983,11 @@ void Preview::load_print_as_fff(bool keep_z_range)
if (gcode_preview_data_valid) { if (gcode_preview_data_valid) {
// Load the real G-code preview. // Load the real G-code preview.
m_canvas->load_gcode_preview(*m_gcode_result, colors); m_canvas->load_gcode_preview(*m_gcode_result, colors);
m_left_sizer->Show(m_bottom_toolbar_panel);
m_left_sizer->Layout(); m_left_sizer->Layout();
Refresh(); Refresh();
zs = m_canvas->get_gcode_layers_zs(); zs = m_canvas->get_gcode_layers_zs();
if (!zs.empty())
m_left_sizer->Show(m_bottom_toolbar_panel);
m_loaded = true; m_loaded = true;
} }
else if (wxGetApp().is_editor()) { else if (wxGetApp().is_editor()) {

View File

@ -331,7 +331,11 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
wxGetApp().obj_manipul()->set_dirty(); wxGetApp().obj_manipul()->set_dirty();
m_parent.set_as_dirty(); m_parent.set_as_dirty();
return true; return true;
} else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) { }
else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
#if ENABLE_WORLD_COORDINATE
do_stop_dragging(is_leaving);
#else
for (auto &grabber : m_grabbers) grabber.dragging = false; for (auto &grabber : m_grabbers) grabber.dragging = false;
m_dragging = false; m_dragging = false;
@ -354,12 +358,41 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints // updates camera target constraints
m_parent.refresh_camera_scene_box(); m_parent.refresh_camera_scene_box();
#endif // ENABLE_WORLD_COORDINATE
return true; return true;
} }
} }
return false; return false;
} }
#if ENABLE_WORLD_COORDINATE
void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
{
for (auto& grabber : m_grabbers) grabber.dragging = false;
m_dragging = false;
// NOTE: This should be part of GLCanvas3D
// Reset hover_id when leave window
if (perform_mouse_cleanup) m_parent.mouse_up_cleanup();
on_stop_dragging();
// There is prediction that after draggign, data are changed
// Data are updated twice also by canvas3D::reload_scene.
// Should be fixed.
m_parent.get_gizmos_manager().update_data();
wxGetApp().obj_manipul()->set_dirty();
// Let the plater know that the dragging finished, so a delayed
// refresh of the scene with the background processing data should
// be performed.
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints
m_parent.refresh_camera_scene_box();
}
#endif // ENABLE_WORLD_COORDINATE
std::string GLGizmoBase::format(float value, unsigned int decimals) const std::string GLGizmoBase::format(float value, unsigned int decimals) const
{ {
return Slic3r::string_printf("%.*f", decimals, value); return Slic3r::string_printf("%.*f", decimals, value);

View File

@ -89,151 +89,156 @@ protected:
static GLModel s_cone; static GLModel s_cone;
#else #else
GLModel m_cube; GLModel m_cube;
#endif // ENABLE_GIZMO_GRABBER_REFACTOR #endif // ENABLE_GIZMO_GRABBER_REFACTOR
}; };
public: public:
enum EState enum EState
{ {
Off, Off,
On, On,
Num_States Num_States
}; };
struct UpdateData struct UpdateData
{ {
const Linef3& mouse_ray; const Linef3& mouse_ray;
const Point& mouse_pos; const Point& mouse_pos;
UpdateData(const Linef3& mouse_ray, const Point& mouse_pos) UpdateData(const Linef3& mouse_ray, const Point& mouse_pos)
: mouse_ray(mouse_ray), mouse_pos(mouse_pos) : mouse_ray(mouse_ray), mouse_pos(mouse_pos)
{} {}
}; };
protected: protected:
GLCanvas3D& m_parent; GLCanvas3D& m_parent;
int m_group_id; // TODO: remove only for rotate int m_group_id; // TODO: remove only for rotate
EState m_state; EState m_state;
int m_shortcut_key; int m_shortcut_key;
std::string m_icon_filename; std::string m_icon_filename;
unsigned int m_sprite_id; unsigned int m_sprite_id;
int m_hover_id; int m_hover_id;
bool m_dragging; bool m_dragging;
mutable std::vector<Grabber> m_grabbers; mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui; ImGuiWrapper* m_imgui;
bool m_first_input_window_render; bool m_first_input_window_render;
CommonGizmosDataPool* m_c; CommonGizmosDataPool* m_c;
public: public:
GLGizmoBase(GLCanvas3D& parent, GLGizmoBase(GLCanvas3D& parent,
const std::string& icon_filename, const std::string& icon_filename,
unsigned int sprite_id); unsigned int sprite_id);
virtual ~GLGizmoBase() = default; virtual ~GLGizmoBase() = default;
bool init() { return on_init(); } bool init() { return on_init(); }
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); } void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); } void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
std::string get_name(bool include_shortcut = true) const; std::string get_name(bool include_shortcut = true) const;
EState get_state() const { return m_state; } EState get_state() const { return m_state; }
void set_state(EState state) { m_state = state; on_set_state(); } void set_state(EState state) { m_state = state; on_set_state(); }
int get_shortcut_key() const { return m_shortcut_key; } int get_shortcut_key() const { return m_shortcut_key; }
const std::string& get_icon_filename() const { return m_icon_filename; } const std::string& get_icon_filename() const { return m_icon_filename; }
bool is_activable() const { return on_is_activable(); } bool is_activable() const { return on_is_activable(); }
bool is_selectable() const { return on_is_selectable(); } bool is_selectable() const { return on_is_selectable(); }
CommonGizmosDataID get_requirements() const { return on_get_requirements(); } CommonGizmosDataID get_requirements() const { return on_get_requirements(); }
virtual bool wants_enter_leave_snapshots() const { return false; } virtual bool wants_enter_leave_snapshots() const { return false; }
virtual std::string get_gizmo_entering_text() const { assert(false); return ""; } virtual std::string get_gizmo_entering_text() const { assert(false); return ""; }
virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; } virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; }
virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); } virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); }
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
unsigned int get_sprite_id() const { return m_sprite_id; } unsigned int get_sprite_id() const { return m_sprite_id; }
int get_hover_id() const { return m_hover_id; } int get_hover_id() const { return m_hover_id; }
void set_hover_id(int id); void set_hover_id(int id);
bool is_dragging() const { return m_dragging; } bool is_dragging() const { return m_dragging; }
// returns True when Gizmo changed its state // returns True when Gizmo changed its state
bool update_items_state(); bool update_items_state();
void render() { on_render(); } void render() { on_render(); }
void render_for_picking() { on_render_for_picking(); } void render_for_picking() { on_render_for_picking(); }
void render_input_window(float x, float y, float bottom_limit); void render_input_window(float x, float y, float bottom_limit);
/// <summary> /// <summary>
/// Mouse tooltip text /// Mouse tooltip text
/// </summary> /// </summary>
/// <returns>Text to be visible in mouse tooltip</returns> /// <returns>Text to be visible in mouse tooltip</returns>
virtual std::string get_tooltip() const { return ""; } virtual std::string get_tooltip() const { return ""; }
/// <summary> /// <summary>
/// Is called when data (Selection) is changed /// Is called when data (Selection) is changed
/// </summary> /// </summary>
virtual void data_changed(){}; virtual void data_changed(){};
/// <summary> /// <summary>
/// Implement when want to process mouse events in gizmo /// Implement when want to process mouse events in gizmo
/// Click, Right click, move, drag, ... /// Click, Right click, move, drag, ...
/// </summary> /// </summary>
/// <param name="mouse_event">Keep information about mouse click</param> /// <param name="mouse_event">Keep information about mouse click</param>
/// <returns>Return True when use the information and don't want to propagate it otherwise False.</returns> /// <returns>Return True when use the information and don't want to propagate it otherwise False.</returns>
virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; } virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; }
protected: protected:
virtual bool on_init() = 0; virtual bool on_init() = 0;
virtual void on_load(cereal::BinaryInputArchive& ar) {} virtual void on_load(cereal::BinaryInputArchive& ar) {}
virtual void on_save(cereal::BinaryOutputArchive& ar) const {} virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
virtual std::string on_get_name() const = 0; virtual std::string on_get_name() const = 0;
virtual void on_set_state() {} virtual void on_set_state() {}
virtual void on_set_hover_id() {} virtual void on_set_hover_id() {}
virtual bool on_is_activable() const { return true; } virtual bool on_is_activable() const { return true; }
virtual bool on_is_selectable() const { return true; } virtual bool on_is_selectable() const { return true; }
virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); } virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); }
virtual void on_enable_grabber(unsigned int id) {} virtual void on_enable_grabber(unsigned int id) {}
virtual void on_disable_grabber(unsigned int id) {} virtual void on_disable_grabber(unsigned int id) {}
// called inside use_grabbers // called inside use_grabbers
virtual void on_start_dragging() {} virtual void on_start_dragging() {}
virtual void on_stop_dragging() {} virtual void on_stop_dragging() {}
virtual void on_dragging(const UpdateData& data) {} virtual void on_dragging(const UpdateData& data) {}
virtual void on_render() = 0; virtual void on_render() = 0;
virtual void on_render_for_picking() = 0; virtual void on_render_for_picking() = 0;
virtual void on_render_input_window(float x, float y, float bottom_limit) {} virtual void on_render_input_window(float x, float y, float bottom_limit) {}
// Returns the picking color for the given id, based on the BASE_ID constant // Returns the picking color for the given id, based on the BASE_ID constant
// No check is made for clashing with other picking color (i.e. GLVolumes) // No check is made for clashing with other picking color (i.e. GLVolumes)
ColorRGBA picking_color_component(unsigned int id) const; ColorRGBA picking_color_component(unsigned int id) const;
void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers(float size) const; void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) const; void render_grabbers_for_picking(const BoundingBoxf3& box) const;
std::string format(float value, unsigned int decimals) const; std::string format(float value, unsigned int decimals) const;
// Mark gizmo as dirty to Re-Render when idle() // Mark gizmo as dirty to Re-Render when idle()
void set_dirty(); void set_dirty();
/// <summary> /// <summary>
/// function which /// function which
/// Set up m_dragging and call functions /// Set up m_dragging and call functions
/// on_start_dragging / on_dragging / on_stop_dragging /// on_start_dragging / on_dragging / on_stop_dragging
/// </summary> /// </summary>
/// <param name="mouse_event">Keep information about mouse click</param> /// <param name="mouse_event">Keep information about mouse click</param>
/// <returns>same as on_mouse</returns> /// <returns>same as on_mouse</returns>
bool use_grabbers(const wxMouseEvent &mouse_event); bool use_grabbers(const wxMouseEvent &mouse_event);
private:
// Flag for dirty visible state of Gizmo #if ENABLE_WORLD_COORDINATE
// When True then need new rendering void do_stop_dragging(bool perform_mouse_cleanup);
bool m_dirty; #endif // ENABLE_WORLD_COORDINATE
};
private:
} // namespace GUI // Flag for dirty visible state of Gizmo
} // namespace Slic3r // When True then need new rendering
bool m_dirty;
#endif // slic3r_GLGizmoBase_hpp_ };
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GLGizmoBase_hpp_

View File

@ -122,8 +122,8 @@ void GLGizmoCut::on_render()
// Z changed when move with cut plane // Z changed when move with cut plane
// X and Y changed when move with cutted object // X and Y changed when move with cutted object
bool is_changed = std::abs(diff.x()) > EPSILON || bool is_changed = std::abs(diff.x()) > EPSILON ||
std::abs(diff.y()) > EPSILON || std::abs(diff.y()) > EPSILON ||
std::abs(diff.z()) > EPSILON; std::abs(diff.z()) > EPSILON;
#endif // !ENABLE_GL_CORE_PROFILE #endif // !ENABLE_GL_CORE_PROFILE
m_old_center = plane_center; m_old_center = plane_center;
@ -132,7 +132,7 @@ void GLGizmoCut::on_render()
GLModel::Geometry init_data; GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 }; init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f }; init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f };
init_data.reserve_vertices(4); init_data.reserve_vertices(4);
init_data.reserve_indices(6); init_data.reserve_indices(6);
@ -344,7 +344,7 @@ void GLGizmoCut::perform_cut(const Selection& selection)
wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection"); wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection");
// m_cut_z is the distance from the bed. Subtract possible SLA elevation. // m_cut_z is the distance from the bed. Subtract possible SLA elevation.
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* first_glvolume = selection.get_first_volume();
const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z(); const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z();
if (0.0 < object_cut_z && object_cut_z < m_max_z) if (0.0 < object_cut_z && object_cut_z < m_max_z)
@ -397,7 +397,7 @@ BoundingBoxf3 GLGizmoCut::bounding_box() const
void GLGizmoCut::update_contours() void GLGizmoCut::update_contours()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* first_glvolume = selection.get_first_volume();
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box(); const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()]; const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];

View File

@ -1,437 +1,441 @@
#include "GLGizmoFdmSupports.hpp" #include "GLGizmoFdmSupports.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
//#include "slic3r/GUI/3DScene.hpp" //#include "slic3r/GUI/3DScene.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/format.hpp" #include "slic3r/GUI/format.hpp"
#include "slic3r/Utils/UndoRedo.hpp" #include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h> #include <GL/glew.h>
namespace Slic3r::GUI { namespace Slic3r::GUI {
void GLGizmoFdmSupports::on_shutdown() void GLGizmoFdmSupports::on_shutdown()
{ {
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
m_parent.toggle_model_objects_visibility(true); m_parent.toggle_model_objects_visibility(true);
} }
std::string GLGizmoFdmSupports::on_get_name() const std::string GLGizmoFdmSupports::on_get_name() const
{ {
return _u8L("Paint-on supports"); return _u8L("Paint-on supports");
} }
bool GLGizmoFdmSupports::on_init() bool GLGizmoFdmSupports::on_init()
{ {
m_shortcut_key = WXK_CONTROL_L; m_shortcut_key = WXK_CONTROL_L;
m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction"); m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Brush size") + ": "; m_desc["cursor_size"] = _L("Brush size") + ": ";
m_desc["cursor_type"] = _L("Brush shape") + ": "; m_desc["cursor_type"] = _L("Brush shape") + ": ";
m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
m_desc["enforce"] = _L("Enforce supports"); m_desc["enforce"] = _L("Enforce supports");
m_desc["block_caption"] = _L("Right mouse button") + ": "; m_desc["block_caption"] = _L("Right mouse button") + ": ";
m_desc["block"] = _L("Block supports"); m_desc["block"] = _L("Block supports");
m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": ";
m_desc["remove"] = _L("Remove selection"); m_desc["remove"] = _L("Remove selection");
m_desc["remove_all"] = _L("Remove all selection"); m_desc["remove_all"] = _L("Remove all selection");
m_desc["circle"] = _L("Circle"); m_desc["circle"] = _L("Circle");
m_desc["sphere"] = _L("Sphere"); m_desc["sphere"] = _L("Sphere");
m_desc["pointer"] = _L("Triangles"); m_desc["pointer"] = _L("Triangles");
m_desc["highlight_by_angle"] = _L("Highlight overhang by angle"); m_desc["highlight_by_angle"] = _L("Highlight overhang by angle");
m_desc["enforce_button"] = _L("Enforce"); m_desc["enforce_button"] = _L("Enforce");
m_desc["cancel"] = _L("Cancel"); m_desc["cancel"] = _L("Cancel");
m_desc["tool_type"] = _L("Tool type") + ": "; m_desc["tool_type"] = _L("Tool type") + ": ";
m_desc["tool_brush"] = _L("Brush"); m_desc["tool_brush"] = _L("Brush");
m_desc["tool_smart_fill"] = _L("Smart fill"); m_desc["tool_smart_fill"] = _L("Smart fill");
m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["smart_fill_angle"] = _L("Smart fill angle");
m_desc["split_triangles"] = _L("Split triangles"); m_desc["split_triangles"] = _L("Split triangles");
m_desc["on_overhangs_only"] = _L("On overhangs only"); m_desc["on_overhangs_only"] = _L("On overhangs only");
return true; return true;
} }
void GLGizmoFdmSupports::render_painter_gizmo() void GLGizmoFdmSupports::render_painter_gizmo()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
render_triangles(selection); render_triangles(selection);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut(); m_c->instances_hider()->render_cut();
render_cursor(); render_cursor();
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
return; return;
const float approx_height = m_imgui->scaled(23.f); const float approx_height = m_imgui->scaled(23.f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f);
const float autoset_slider_label_max_width = m_imgui->scaled(7.5f); const float autoset_slider_label_max_width = m_imgui->scaled(7.5f);
const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f); const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f);
const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x;
const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x;
const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f); const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f);
const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f); const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f);
const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f);
const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f); const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f);
const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f); const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.f; float total_text_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
} }
total_text_max += caption_max + m_imgui->scaled(1.f); total_text_max += caption_max + m_imgui->scaled(1.f);
caption_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left));
const float slider_icon_width = m_imgui->get_slider_icon_size().x; const float slider_icon_width = m_imgui->get_slider_icon_size().x;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width); window_width = std::max(window_width, button_width);
window_width = std::max(window_width, split_triangles_checkbox_width); window_width = std::max(window_width, split_triangles_checkbox_width);
window_width = std::max(window_width, on_overhangs_only_checkbox_width); window_width = std::max(window_width, on_overhangs_only_checkbox_width);
window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer); window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer);
window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill); window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill);
window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f));
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption);
ImGui::SameLine(caption_max); ImGui::SameLine(caption_max);
m_imgui->text(text); m_imgui->text(text);
}; };
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
ImGui::Separator(); ImGui::Separator();
float position_before_text_y = ImGui::GetCursorPos().y; float position_before_text_y = ImGui::GetCursorPos().y;
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width); m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
float position_after_text_y = ImGui::GetCursorPos().y; float position_after_text_y = ImGui::GetCursorPos().y;
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
"Degree sign to use in the respective slider in FDM supports gizmo," "Degree sign to use in the respective slider in FDM supports gizmo,"
"placed after the number with no whitespace in between."); "placed after the number with no whitespace in between.");
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
float slider_height = m_imgui->get_slider_float_height(); float slider_height = m_imgui->get_slider_float_height();
// Makes slider to be aligned to bottom of the multi-line text. // Makes slider to be aligned to bottom of the multi-line text.
float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height); float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height);
ImGui::SetCursorPosY(slider_start_position_y); ImGui::SetCursorPosY(slider_start_position_y);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when " wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when "
"the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]); "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]);
if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) { if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) {
m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg); m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg);
if (! m_parent.is_using_slope()) { if (! m_parent.is_using_slope()) {
m_parent.use_slope(true); m_parent.use_slope(true);
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
} }
// Restores the cursor position to be below the multi-line text. // Restores the cursor position to be below the multi-line text.
ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y)); ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y));
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f); m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f);
ImGui::NewLine(); ImGui::NewLine();
ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f)); ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f));
if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) { if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) {
select_facets_by_angle(m_highlight_by_angle_threshold_deg, false); select_facets_by_angle(m_highlight_by_angle_threshold_deg, false);
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
} }
ImGui::SameLine(window_width - buttons_width); ImGui::SameLine(window_width - buttons_width);
if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) { if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) {
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
} }
m_imgui->disabled_end(); m_imgui->disabled_end();
ImGui::Separator(); ImGui::Separator();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["tool_type"]); m_imgui->text(m_desc["tool_type"]);
float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f; float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f;
ImGui::SameLine(tool_type_offset); ImGui::SameLine(tool_type_offset);
ImGui::PushItemWidth(tool_type_radio_brush); ImGui::PushItemWidth(tool_type_radio_brush);
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH))
m_tool_type = ToolType::BRUSH; m_tool_type = ToolType::BRUSH;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width); m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width);
ImGui::SameLine(tool_type_offset + tool_type_radio_brush); ImGui::SameLine(tool_type_offset + tool_type_radio_brush);
ImGui::PushItemWidth(tool_type_radio_smart_fill); ImGui::PushItemWidth(tool_type_radio_smart_fill);
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL))
m_tool_type = ToolType::SMART_FILL; m_tool_type = ToolType::SMART_FILL;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width); m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width);
m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only); m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width); m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width);
ImGui::Separator(); ImGui::Separator();
if (m_tool_type == ToolType::BRUSH) { if (m_tool_type == ToolType::BRUSH) {
m_imgui->text(m_desc.at("cursor_type")); m_imgui->text(m_desc.at("cursor_type"));
ImGui::NewLine(); ImGui::NewLine();
float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f;
ImGui::SameLine(cursor_type_offset); ImGui::SameLine(cursor_type_offset);
ImGui::PushItemWidth(cursor_type_radio_sphere); ImGui::PushItemWidth(cursor_type_radio_sphere);
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
m_cursor_type = TriangleSelector::CursorType::SPHERE; m_cursor_type = TriangleSelector::CursorType::SPHERE;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width); m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width);
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere);
ImGui::PushItemWidth(cursor_type_radio_circle); ImGui::PushItemWidth(cursor_type_radio_circle);
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
m_cursor_type = TriangleSelector::CursorType::CIRCLE; m_cursor_type = TriangleSelector::CursorType::CIRCLE;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width); m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width);
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle);
ImGui::PushItemWidth(cursor_type_radio_pointer); ImGui::PushItemWidth(cursor_type_radio_pointer);
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
m_cursor_type = TriangleSelector::CursorType::POINTER; m_cursor_type = TriangleSelector::CursorType::POINTER;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width); m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width);
m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE); m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size")); m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel"));
m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled); m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width); m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width);
m_imgui->disabled_end(); m_imgui->disabled_end();
} else { } else {
assert(m_tool_type == ToolType::SMART_FILL); assert(m_tool_type == ToolType::SMART_FILL);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["smart_fill_angle"] + ":"); m_imgui->text(m_desc["smart_fill_angle"] + ":");
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel")))
for (auto &triangle_selector : m_triangle_selectors) { for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data(); triangle_selector->request_update_render_data();
} }
} }
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) { if (m_c->object_clipper()->get_position() == 0.f) {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));
} }
else { else {
if (m_imgui->button(m_desc.at("reset_direction"))) { if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){ wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false); m_c->object_clipper()->set_position(-1., false);
}); });
} }
} }
auto clp_dist = float(m_c->object_clipper()->get_position()); auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true); m_c->object_clipper()->set_position(clp_dist, true);
ImGui::Separator(); ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) { if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
ModelObject *mo = m_c->selection_info()->model_object(); ModelObject *mo = m_c->selection_info()->model_object();
int idx = -1; int idx = -1;
for (ModelVolume *mv : mo->volumes) for (ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
++idx; ++idx;
m_triangle_selectors[idx]->reset(); m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data(); m_triangle_selectors[idx]->request_update_render_data();
} }
update_model_object(); update_model_object();
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
m_imgui->end(); m_imgui->end();
} }
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
{ {
float threshold = (float(M_PI)/180.f)*threshold_deg; float threshold = (float(M_PI)/180.f)*threshold_deg;
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
int mesh_id = -1; int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) { for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part()) if (! mv->is_model_part())
continue; continue;
++mesh_id; ++mesh_id;
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true); #if ENABLE_WORLD_COORDINATE
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized(); const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized(); #else
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
float dot_limit = limit.dot(down); #endif // ENABLE_WORLD_COORDINATE
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
// Now calculate dot product of vert_direction and facets' normals. Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
int idx = 0;
const indexed_triangle_set &its = mv->mesh().its; float dot_limit = limit.dot(down);
for (const stl_triangle_vertex_indices &face : its.indices) {
if (its_face_normal(its, face).dot(down) > dot_limit) { // Now calculate dot product of vert_direction and facets' normals.
m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); int idx = 0;
m_triangle_selectors.back()->request_update_render_data(); const indexed_triangle_set &its = mv->mesh().its;
} for (const stl_triangle_vertex_indices &face : its.indices) {
++ idx; if (its_face_normal(its, face).dot(down) > dot_limit) {
} m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER);
} m_triangle_selectors.back()->request_update_render_data();
}
Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle") ++ idx;
: _L("Add supports by angle")); }
update_model_object(); }
m_parent.set_as_dirty();
} Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
: _L("Add supports by angle"));
update_model_object();
m_parent.set_as_dirty();
void GLGizmoFdmSupports::update_model_object() const }
{
bool updated = false;
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1; void GLGizmoFdmSupports::update_model_object() const
for (ModelVolume* mv : mo->volumes) { {
if (! mv->is_model_part()) bool updated = false;
continue; ModelObject* mo = m_c->selection_info()->model_object();
++idx; int idx = -1;
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get()); for (ModelVolume* mv : mo->volumes) {
} if (! mv->is_model_part())
continue;
if (updated) { ++idx;
const ModelObjectPtrs& mos = wxGetApp().model().objects; updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); }
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); if (updated) {
} const ModelObjectPtrs& mos = wxGetApp().model().objects;
} wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
void GLGizmoFdmSupports::update_from_model_object() }
{
wxBusyCursor wait;
const ModelObject* mo = m_c->selection_info()->model_object(); void GLGizmoFdmSupports::update_from_model_object()
m_triangle_selectors.clear(); {
wxBusyCursor wait;
int volume_id = -1;
for (const ModelVolume* mv : mo->volumes) { const ModelObject* mo = m_c->selection_info()->model_object();
if (! mv->is_model_part()) m_triangle_selectors.clear();
continue;
int volume_id = -1;
++volume_id; for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
// This mesh does not account for the possible Z up SLA offset. continue;
const TriangleMesh* mesh = &mv->mesh();
++volume_id;
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
// Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). // This mesh does not account for the possible Z up SLA offset.
m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false); const TriangleMesh* mesh = &mv->mesh();
m_triangle_selectors.back()->request_update_render_data();
} m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
} // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize().
m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false);
m_triangle_selectors.back()->request_update_render_data();
}
PainterGizmoType GLGizmoFdmSupports::get_painter_type() const }
{
return PainterGizmoType::FDM_SUPPORTS;
}
PainterGizmoType GLGizmoFdmSupports::get_painter_type() const
wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const {
{ return PainterGizmoType::FDM_SUPPORTS;
wxString action_name; }
if (shift_down)
action_name = _L("Remove selection"); wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
else { {
if (button_down == Button::Left) wxString action_name;
action_name = _L("Add supports"); if (shift_down)
else action_name = _L("Remove selection");
action_name = _L("Block supports"); else {
} if (button_down == Button::Left)
return action_name; action_name = _L("Add supports");
} else
action_name = _L("Block supports");
} // namespace Slic3r::GUI }
return action_name;
}
} // namespace Slic3r::GUI

View File

@ -116,17 +116,17 @@ void GLGizmoFlatten::on_render()
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
@ -170,17 +170,17 @@ void GLGizmoFlatten::on_render_for_picking()
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
@ -226,7 +226,11 @@ void GLGizmoFlatten::update_planes()
} }
ch = ch.convex_hull_3d(); ch = ch.convex_hull_3d();
m_planes.clear(); m_planes.clear();
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = mo->instances.front()->get_matrix_no_offset();
#else
const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true); const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Following constants are used for discarding too small polygons. // Following constants are used for discarding too small polygons.
const float minimal_area = 5.f; // in square mm (world coordinates) const float minimal_area = 5.f; // in square mm (world coordinates)

View File

@ -94,7 +94,7 @@ void GLGizmoHollow::on_render_for_picking()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
//#if ENABLE_RENDER_PICKING_PASS //#if ENABLE_RENDER_PICKING_PASS
// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); // m_z_shift = selection.get_first_volume()->get_sla_shift_z();
//#endif //#endif
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
@ -117,12 +117,16 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); }); ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* vol = selection.get_first_volume();
Geometry::Transformation trafo = vol->get_instance_transformation() * vol->get_volume_transformation(); Geometry::Transformation trafo = vol->get_instance_transformation() * vol->get_volume_transformation();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_scaling_factor_matrix().inverse();
#else
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * trafo.get_matrix(); #endif // ENABLE_WORLD_COORDINATE
const Transform3d instance_matrix = Geometry::translation_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * trafo.get_matrix();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d& view_matrix = camera.get_view_matrix(); const Transform3d& view_matrix = camera.get_view_matrix();
@ -235,7 +239,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation(); Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));

View File

@ -2,6 +2,9 @@
#include "GLGizmoMove.hpp" #include "GLGizmoMove.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#if ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
@ -21,18 +24,29 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
std::string GLGizmoMove3D::get_tooltip() const std::string GLGizmoMove3D::get_tooltip() const
{ {
#if ENABLE_WORLD_COORDINATE
if (m_hover_id == 0)
return "X: " + format(m_displacement.x(), 2);
else if (m_hover_id == 1)
return "Y: " + format(m_displacement.y(), 2);
else if (m_hover_id == 2)
return "Z: " + format(m_displacement.z(), 2);
else
return "";
#else
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
bool show_position = selection.is_single_full_instance(); const bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center(); const Vec3d& position = selection.get_bounding_box().center();
if (m_hover_id == 0 || m_grabbers[0].dragging) if (m_hover_id == 0 || m_grabbers[0].dragging)
return "X: " + format(show_position ? position(0) : m_displacement(0), 2); return "X: " + format(show_position ? position.x() : m_displacement.x(), 2);
else if (m_hover_id == 1 || m_grabbers[1].dragging) else if (m_hover_id == 1 || m_grabbers[1].dragging)
return "Y: " + format(show_position ? position(1) : m_displacement(1), 2); return "Y: " + format(show_position ? position.y() : m_displacement.y(), 2);
else if (m_hover_id == 2 || m_grabbers[2].dragging) else if (m_hover_id == 2 || m_grabbers[2].dragging)
return "Z: " + format(show_position ? position(2) : m_displacement(2), 2); return "Z: " + format(show_position ? position.z() : m_displacement.z(), 2);
else else
return ""; return "";
#endif // ENABLE_WORLD_COORDINATE
} }
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) { bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
@ -40,9 +54,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
} }
void GLGizmoMove3D::data_changed() { void GLGizmoMove3D::data_changed() {
const Selection &selection = m_parent.get_selection(); m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
bool is_wipe_tower = selection.is_wipe_tower();
m_grabbers[2].enabled = !is_wipe_tower;
} }
bool GLGizmoMove3D::on_init() bool GLGizmoMove3D::on_init()
@ -79,11 +91,29 @@ void GLGizmoMove3D::on_start_dragging()
assert(m_hover_id != -1); assert(m_hover_id != -1);
m_displacement = Vec3d::Zero(); m_displacement = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World)
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
}
else {
const GLVolume& v = *selection.get_first_volume();
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
}
m_starting_box_center = m_center;
m_starting_box_bottom_center = m_center;
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center; m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center(); m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center(); m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center(2) = box.min(2); m_starting_box_bottom_center.z() = box.min.z();
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_stop_dragging() void GLGizmoMove3D::on_stop_dragging()
@ -102,7 +132,19 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
m_displacement.z() = calc_projection(data); m_displacement.z() = calc_projection(data);
Selection &selection = m_parent.get_selection(); Selection &selection = m_parent.get_selection();
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
switch (wxGetApp().obj_manipul()->get_coordinates_type())
{
case ECoordinatesType::Instance: { trafo_type.set_instance(); break; }
case ECoordinatesType::Local: { trafo_type.set_local(); break; }
default: { break; }
}
selection.translate(m_displacement, trafo_type);
#else
selection.translate(m_displacement); selection.translate(m_displacement);
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_render() void GLGizmoMove3D::on_render()
@ -112,11 +154,39 @@ void GLGizmoMove3D::on_render()
m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0)); m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0));
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
const Selection& selection = m_parent.get_selection();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPushMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
calc_selection_box_and_center();
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
transform_to_local(m_parent.get_selection());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
const Vec3d zero = Vec3d::Zero();
const Vec3d half_box_size = 0.5 * m_bounding_box.size();
// x axis
m_grabbers[0].center = { half_box_size.x() + Offset, 0.0, 0.0 };
m_grabbers[0].color = AXES_COLOR[0];
// y axis
m_grabbers[1].center = { 0.0, half_box_size.y() + Offset, 0.0 };
m_grabbers[1].color = AXES_COLOR[1];
// z axis
m_grabbers[2].center = { 0.0, 0.0, half_box_size.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2];
#else
const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
const Vec3d& center = box.center(); const Vec3d& center = box.center();
@ -131,6 +201,7 @@ void GLGizmoMove3D::on_render()
// z axis // z axis
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset }; m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2]; m_grabbers[2].color = AXES_COLOR[2];
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
if (!OpenGLManager::get_gl_info().is_core_profile()) if (!OpenGLManager::get_gl_info().is_core_profile())
@ -138,10 +209,19 @@ void GLGizmoMove3D::on_render()
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
auto render_grabber_connection = [this, &zero](unsigned int id) {
#else
auto render_grabber_connection = [this, &center](unsigned int id) { auto render_grabber_connection = [this, &center](unsigned int id) {
#endif // ENABLE_WORLD_COORDINATE
if (m_grabbers[id].enabled) { if (m_grabbers[id].enabled) {
#if ENABLE_WORLD_COORDINATE
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(m_grabbers[id].center)) {
m_grabber_connections[id].old_center = m_grabbers[id].center;
#else
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) { if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
m_grabber_connections[id].old_center = center; m_grabber_connections[id].old_center = center;
#endif // ENABLE_WORLD_COORDINATE
m_grabber_connections[id].model.reset(); m_grabber_connections[id].model.reset();
GLModel::Geometry init_data; GLModel::Geometry init_data;
@ -151,7 +231,11 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2); init_data.reserve_indices(2);
// vertices // vertices
#if ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)zero.cast<float>());
#else
init_data.add_vertex((Vec3f)center.cast<float>()); init_data.add_vertex((Vec3f)center.cast<float>());
#endif // ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>()); init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
// indices // indices
@ -175,7 +259,11 @@ void GLGizmoMove3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -193,7 +281,11 @@ void GLGizmoMove3D::on_render()
if (m_grabbers[i].enabled) { if (m_grabbers[i].enabled) {
glsafe(::glColor4fv(AXES_COLOR[i].data())); glsafe(::glColor4fv(AXES_COLOR[i].data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[i].center.data()); ::glVertex3dv(m_grabbers[i].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
} }
@ -206,6 +298,19 @@ void GLGizmoMove3D::on_render()
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
// draw grabbers // draw grabbers
#if ENABLE_WORLD_COORDINATE
render_grabbers(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled)
#if ENABLE_LEGACY_OPENGL_REMOVAL
render_grabber_extension((Axis)i, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)i, m_bounding_box, false);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
}
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
render_grabbers(box); render_grabbers(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) { for (unsigned int i = 0; i < 3; ++i) {
@ -213,6 +318,7 @@ void GLGizmoMove3D::on_render()
render_grabber_extension((Axis)i, box, false); render_grabber_extension((Axis)i, box, false);
} }
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
} }
else { else {
// draw axis // draw axis
@ -226,7 +332,11 @@ void GLGizmoMove3D::on_render()
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -243,7 +353,11 @@ void GLGizmoMove3D::on_render()
#else #else
glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data())); glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[m_hover_id].center.data()); ::glVertex3dv(m_grabbers[m_hover_id].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
@ -253,20 +367,65 @@ void GLGizmoMove3D::on_render()
shader->start_using(); shader->start_using();
shader->set_uniform("emission_factor", 0.1f); shader->set_uniform("emission_factor", 0.1f);
// draw grabber // draw grabber
const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); #if ENABLE_WORLD_COORDINATE
const Vec3d box_size = m_bounding_box.size();
#else
const Vec3d box_size = box.size();
#endif // ENABLE_WORLD_COORDINATE
const float mean_size = (float)((box_size.x() + box_size.y() + box_size.z()) / 3.0);
m_grabbers[m_hover_id].render(true, mean_size); m_grabbers[m_hover_id].render(true, mean_size);
shader->stop_using(); shader->stop_using();
} }
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
render_grabber_extension((Axis)m_hover_id, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)m_hover_id, m_bounding_box, false);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#else
render_grabber_extension((Axis)m_hover_id, box, false); render_grabber_extension((Axis)m_hover_id, box, false);
#endif // ENABLE_WORLD_COORDINATE
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
} }
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_render_for_picking() void GLGizmoMove3D::on_render_for_picking()
{ {
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
render_grabbers_for_picking(m_bounding_box);
#if ENABLE_LEGACY_OPENGL_REMOVAL
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, base_matrix, m_bounding_box, true);
render_grabber_extension(Y, base_matrix, m_bounding_box, true);
render_grabber_extension(Z, base_matrix, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, m_bounding_box, true);
render_grabber_extension(Y, m_bounding_box, true);
render_grabber_extension(Z, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
glsafe(::glPopMatrix());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
render_grabbers_for_picking(box); render_grabbers_for_picking(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
@ -274,23 +433,24 @@ void GLGizmoMove3D::on_render_for_picking()
render_grabber_extension(Y, box, true); render_grabber_extension(Y, box, true);
render_grabber_extension(Z, box, true); render_grabber_extension(Z, box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
} }
double GLGizmoMove3D::calc_projection(const UpdateData& data) const double GLGizmoMove3D::calc_projection(const UpdateData& data) const
{ {
double projection = 0.0; double projection = 0.0;
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
double len_starting_vec = starting_vec.norm(); const 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(); const Vec3d mouse_dir = data.mouse_ray.unit_vector();
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
// in our case plane normal and ray direction are the same (orthogonal view) // in our case plane normal and ray direction are the same (orthogonal view)
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
// vector from the starting position to the found intersection // vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_starting_drag_position; const Vec3d inters_vec = inters - m_starting_drag_position;
// finds projection of the vector along the staring direction // finds projection of the vector along the staring direction
projection = inters_vec.dot(starting_vec.normalized()); projection = inters_vec.dot(starting_vec.normalized());
@ -303,9 +463,14 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
} }
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE && ENABLE_LEGACY_OPENGL_REMOVAL
void GLGizmoMove3D::render_grabber_extension(Axis axis, const Transform3d& base_matrix, const BoundingBoxf3& box, bool picking)
#else
void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking)
#endif // ENABLE_WORLD_COORDINATE && ENABLE_LEGACY_OPENGL_REMOVAL
{ {
const float mean_size = float((box.size().x() + box.size().y() + box.size().z()) / 3.0); const Vec3d box_size = box.size();
const float mean_size = float((box_size.x() + box_size.y() + box_size.z()) / 3.0);
const double size = m_dragging ? double(m_grabbers[axis].get_dragging_half_size(mean_size)) : double(m_grabbers[axis].get_half_size(mean_size)); const double size = m_dragging ? double(m_grabbers[axis].get_dragging_half_size(mean_size)) : double(m_grabbers[axis].get_half_size(mean_size));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -361,5 +526,62 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
} }
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoMove3D::transform_to_local(const Selection& selection) const
{
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
void GLGizmoMove3D::calc_selection_box_and_center()
{
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World) {
m_bounding_box = selection.get_bounding_box();
m_center = m_bounding_box.center();
}
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
m_center = v.world_matrix() * m_bounding_box.center();
}
else {
m_bounding_box.reset();
const Selection::IndicesList& ids = selection.get_volume_idxs();
for (unsigned int id : ids) {
const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
}
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
}
}
#endif // ENABLE_WORLD_COORDINATE
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -7,11 +7,19 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_WORLD_COORDINATE
class Selection;
#endif // ENABLE_WORLD_COORDINATE
class GLGizmoMove3D : public GLGizmoBase class GLGizmoMove3D : public GLGizmoBase
{ {
static const double Offset; static const double Offset;
Vec3d m_displacement{ Vec3d::Zero() }; Vec3d m_displacement{ Vec3d::Zero() };
#if ENABLE_WORLD_COORDINATE
Vec3d m_center{ Vec3d::Zero() };
BoundingBoxf3 m_bounding_box;
#endif // ENABLE_WORLD_COORDINATE
double m_snap_step{ 1.0 }; double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() }; Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() }; Vec3d m_starting_box_center{ Vec3d::Zero() };
@ -49,7 +57,6 @@ public:
/// Detect reduction of move for wipetover on selection change /// Detect reduction of move for wipetover on selection change
/// </summary> /// </summary>
void data_changed() override; void data_changed() override;
protected: protected:
bool on_init() override; bool on_init() override;
std::string on_get_name() const override; std::string on_get_name() const override;
@ -62,11 +69,25 @@ protected:
private: private:
double calc_projection(const UpdateData& data) const; double calc_projection(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const;
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
void calc_selection_box_and_center();
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE && ENABLE_LEGACY_OPENGL_REMOVAL
void render_grabber_extension(Axis axis, const Transform3d& base_matrix, const BoundingBoxf3& box, bool picking);
#else
void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking); void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking);
#endif // ENABLE_WORLD_COORDINATE && ENABLE_LEGACY_OPENGL_REMOVAL
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
}; };
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -324,7 +324,11 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
return; return;
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_scaling_factor_matrix().inverse();
#else
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse(); const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed();
#if !ENABLE_LEGACY_OPENGL_REMOVAL #if !ENABLE_LEGACY_OPENGL_REMOVAL
@ -539,7 +543,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object(); const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
#if ENABLE_WORLD_COORDINATE
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix_no_offset() * mo->volumes[m_rr.mesh_id]->get_matrix_no_offset();
#else
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true); const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix(); const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle, m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true); m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
@ -578,7 +586,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const ModelObject *mo = m_c->selection_info()->model_object(); const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix(); const Transform3d instance_trafo = mi->get_transformation().get_matrix();
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
#else
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true); const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes. // Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices; std::vector<Transform3d> trafo_matrices;
@ -586,7 +598,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes) for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix()); trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
#if ENABLE_WORLD_COORDINATE
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix_no_offset());
#else
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true)); trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
#endif // ENABLE_WORLD_COORDINATE
} }
std::vector<std::vector<ProjectedMousePosition>> projected_mouse_positions_by_mesh = get_projected_mouse_positions(mouse_position, 1., trafo_matrices); std::vector<std::vector<ProjectedMousePosition>> projected_mouse_positions_by_mesh = get_projected_mouse_positions(mouse_position, 1., trafo_matrices);
@ -668,7 +684,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const ModelObject *mo = m_c->selection_info()->model_object(); const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix(); const Transform3d instance_trafo = mi->get_transformation().get_matrix();
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
#else
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true); const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes. // Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices; std::vector<Transform3d> trafo_matrices;
@ -676,7 +696,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes) for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix()); trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
#if ENABLE_WORLD_COORDINATE
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate* mv->get_matrix_no_offset());
#else
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true)); trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
#endif // ENABLE_WORLD_COORDINATE
} }
// Now "click" into all the prepared points and spill paint around them. // Now "click" into all the prepared points and spill paint around them.

View File

@ -2,15 +2,18 @@
#include "GLGizmoRotate.hpp" #include "GLGizmoRotate.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp"
#if ENABLE_WORLD_COORDINATE
#include <GL/glew.h> #include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" #include <GL/glew.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -99,6 +102,9 @@ bool GLGizmoRotate::on_init()
void GLGizmoRotate::on_start_dragging() void GLGizmoRotate::on_start_dragging()
{ {
#if ENABLE_WORLD_COORDINATE
init_data_from_selection(m_parent.get_selection());
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
@ -106,6 +112,7 @@ void GLGizmoRotate::on_start_dragging()
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius; m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoRotate::on_dragging(const UpdateData &data) void GLGizmoRotate::on_dragging(const UpdateData &data)
@ -151,15 +158,21 @@ void GLGizmoRotate::on_render()
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
#if !ENABLE_WORLD_COORDINATE
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
#endif // !ENABLE_WORLD_COORDINATE
if (m_hover_id != 0 && !m_grabbers.front().dragging) { if (m_hover_id != 0 && !m_grabbers.front().dragging) {
#if ENABLE_WORLD_COORDINATE
init_data_from_selection(selection);
#else
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_in_radius = m_radius / 3.0f;
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius; m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth);
#endif // ENABLE_WORLD_COORDINATE
} }
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
@ -234,10 +247,17 @@ void GLGizmoRotate::on_render()
render_angle(); render_angle();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
render_grabber(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(m_bounding_box, false);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
render_grabber(box); render_grabber(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(box, false); render_grabber_extension(box, false);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_LEGACY_OPENGL_REMOVAL #if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
@ -257,17 +277,73 @@ void GLGizmoRotate::on_render_for_picking()
transform_to_local(selection); transform_to_local(selection);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
render_grabbers_for_picking(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
render_grabbers_for_picking(box); render_grabbers_for_picking(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(box, true); render_grabber_extension(box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_LEGACY_OPENGL_REMOVAL #if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL #endif // !ENABLE_LEGACY_OPENGL_REMOVAL
} }
#if ENABLE_WORLD_COORDINATE
void GLGizmoRotate::init_data_from_selection(const Selection& selection)
{
ECoordinatesType coordinates_type;
if (selection.is_wipe_tower())
coordinates_type = ECoordinatesType::Local;
else
coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World) {
m_bounding_box = selection.get_bounding_box();
m_center = m_bounding_box.center();
}
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
m_center = v.world_matrix() * m_bounding_box.center();
}
else {
m_bounding_box.reset();
const Selection::IndicesList& ids = selection.get_volume_idxs();
for (unsigned int id : ids) {
const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
}
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
}
m_radius = Offset + m_bounding_box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f;
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
if (coordinates_type == ECoordinatesType::World)
m_orient_matrix = Transform3d::Identity();
else if (coordinates_type == ECoordinatesType::Local && (selection.is_wipe_tower() || selection.is_single_volume_or_modifier())) {
const GLVolume& v = *selection.get_first_volume();
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix();
}
else {
const GLVolume& v = *selection.get_first_volume();
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix();
}
}
#endif // ENABLE_WORLD_COORDINATE
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
@ -328,10 +404,10 @@ void GLGizmoRotate::render_circle() const
#else #else
::glBegin(GL_LINE_LOOP); ::glBegin(GL_LINE_LOOP);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) { for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
float angle = (float)i * ScaleStepRad; const float angle = float(i) * ScaleStepRad;
float x = ::cos(angle) * m_radius; const float x = ::cos(angle) * m_radius;
float y = ::sin(angle) * m_radius; const float y = ::sin(angle) * m_radius;
float z = 0.0f; const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
} }
glsafe(::glEnd()); glsafe(::glEnd());
@ -530,10 +606,10 @@ void GLGizmoRotate::render_angle() const
#else #else
::glBegin(GL_LINE_STRIP); ::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i <= AngleResolution; ++i) { for (unsigned int i = 0; i <= AngleResolution; ++i) {
float angle = (float)i * step_angle; const float angle = float(i) * step_angle;
float x = ::cos(angle) * ex_radius; const float x = ::cos(angle) * ex_radius;
float y = ::sin(angle) * ex_radius; const float y = ::sin(angle) * ex_radius;
float z = 0.0f; const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
} }
glsafe(::glEnd()); glsafe(::glEnd());
@ -670,12 +746,20 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
{ {
case X: case X:
{ {
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.5 * PI, 0.0)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)); #if ENABLE_WORLD_COORDINATE
ret = Geometry::rotation_transform(0.5 * PI * Vec3d::UnitY()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ());
#else
ret = Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ());
#endif // ENABLE_WORLD_COORDINATE
break; break;
} }
case Y: case Y:
{ {
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, -0.5 * PI, 0.0)); #if ENABLE_WORLD_COORDINATE
ret = Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitY());
#else
ret = Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitY());
#endif // ENABLE_WORLD_COORDINATE
break; break;
} }
default: default:
@ -686,20 +770,28 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
} }
} }
#if ENABLE_WORLD_COORDINATE
return Geometry::translation_transform(m_center) * m_orient_matrix * ret;
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
ret = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true) * ret; ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret;
return Geometry::assemble_transform(m_center) * ret; return Geometry::assemble_transform(m_center) * ret;
#endif // ENABLE_WORLD_COORDINATE
} }
#else #else
void GLGizmoRotate::transform_to_local(const Selection& selection) const void GLGizmoRotate::transform_to_local(const Selection& selection) const
{ {
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
#if ENABLE_WORLD_COORDINATE
glsafe(::glMultMatrixd(m_orient_matrix.data()));
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) {
const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); const Transform3d orient_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
#endif // ENABLE_WORLD_COORDINATE
switch (m_axis) switch (m_axis)
{ {
@ -753,8 +845,12 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
} }
} }
#if ENABLE_WORLD_COORDINATE
m = m * m_orient_matrix.inverse();
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse(); m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
m.translate(-m_center); m.translate(-m_center);
@ -775,31 +871,51 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
{ {
if (mouse_event.Dragging() && m_dragging) { if (mouse_event.Dragging() && m_dragging) {
// Apply new temporary rotations // Apply new temporary rotations
TransformationType transformation_type( #if ENABLE_WORLD_COORDINATE
TransformationType::World_Relative_Joint); TransformationType transformation_type;
if (mouse_event.AltDown()) transformation_type.set_independent(); if (m_parent.get_selection().is_wipe_tower())
transformation_type = TransformationType::Instance_Relative_Joint;
else {
switch (wxGetApp().obj_manipul()->get_coordinates_type())
{
default:
case ECoordinatesType::World: { transformation_type = TransformationType::World_Relative_Joint; break; }
case ECoordinatesType::Instance: { transformation_type = TransformationType::Instance_Relative_Joint; break; }
case ECoordinatesType::Local: { transformation_type = TransformationType::Local_Relative_Joint; break; }
}
}
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
#endif // ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown())
transformation_type.set_independent();
m_parent.get_selection().rotate(get_rotation(), transformation_type); m_parent.get_selection().rotate(get_rotation(), transformation_type);
} }
return use_grabbers(mouse_event); return use_grabbers(mouse_event);
} }
void GLGizmoRotate3D::data_changed() { void GLGizmoRotate3D::data_changed() {
const Selection &selection = m_parent.get_selection(); if (m_parent.get_selection().is_wipe_tower()) {
bool is_wipe_tower = selection.is_wipe_tower(); #if !ENABLE_WORLD_COORDINATE
if (is_wipe_tower) { const DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config; const float wipe_tower_rotation_angle =
float wipe_tower_rotation_angle = dynamic_cast<const ConfigOptionFloat*>(
dynamic_cast<const ConfigOptionFloat *>( config.option("wipe_tower_rotation_angle"))->value;
config.option("wipe_tower_rotation_angle"))
->value;
set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle)); set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
#endif // !ENABLE_WORLD_COORDINATE
m_gizmos[0].disable_grabber(); m_gizmos[0].disable_grabber();
m_gizmos[1].disable_grabber(); m_gizmos[1].disable_grabber();
} else { }
else {
#if !ENABLE_WORLD_COORDINATE
set_rotation(Vec3d::Zero()); set_rotation(Vec3d::Zero());
#endif // !ENABLE_WORLD_COORDINATE
m_gizmos[0].enable_grabber(); m_gizmos[0].enable_grabber();
m_gizmos[1].enable_grabber(); m_gizmos[1].enable_grabber();
} }
#if ENABLE_WORLD_COORDINATE
set_rotation(Vec3d::Zero());
#endif // ENABLE_WORLD_COORDINATE
} }
bool GLGizmoRotate3D::on_init() bool GLGizmoRotate3D::on_init()

View File

@ -34,6 +34,10 @@ private:
float m_snap_coarse_out_radius{ 0.0f }; float m_snap_coarse_out_radius{ 0.0f };
float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_in_radius{ 0.0f };
float m_snap_fine_out_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f };
#if ENABLE_WORLD_COORDINATE
BoundingBoxf3 m_bounding_box;
Transform3d m_orient_matrix{ Transform3d::Identity() };
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
GLModel m_cone; GLModel m_cone;
@ -119,6 +123,10 @@ private:
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const;
#if ENABLE_WORLD_COORDINATE
void init_data_from_selection(const Selection& selection);
#endif // ENABLE_WORLD_COORDINATE
}; };
class GLGizmoRotate3D : public GLGizmoBase class GLGizmoRotate3D : public GLGizmoBase
@ -129,7 +137,7 @@ public:
GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation.x()); m_gizmos[Y].set_angle(rotation.y()); m_gizmos[Z].set_angle(rotation.z()); }
std::string get_tooltip() const override { std::string get_tooltip() const override {
std::string tooltip = m_gizmos[X].get_tooltip(); std::string tooltip = m_gizmos[X].get_tooltip();

View File

@ -2,19 +2,22 @@
#include "GLGizmoScale.hpp" #include "GLGizmoScale.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#if ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#include <GL/glew.h> #include <GL/glew.h>
#include <wx/utils.h> #include <wx/utils.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
const float GLGizmoScale3D::Offset = 5.0f; const double GLGizmoScale3D::Offset = 5.0;
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
@ -38,16 +41,17 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
std::string GLGizmoScale3D::get_tooltip() const std::string GLGizmoScale3D::get_tooltip() const
{ {
#if ENABLE_WORLD_COORDINATE
const Vec3d scale = 100.0 * m_scale;
#else
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance(); Vec3d scale = 100.0 * Vec3d::Ones();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume(); if (selection.is_single_full_instance())
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
Vec3f scale = 100.0f * Vec3f::Ones(); else if (selection.is_single_modifier() || selection.is_single_volume())
if (single_instance) scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>(); #endif // ENABLE_WORLD_COORDINATE
else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
return "X: " + format(scale.x(), 4) + "%"; return "X: " + format(scale.x(), 4) + "%";
@ -72,12 +76,28 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
if (m_dragging) { if (m_dragging) {
// Apply new temporary scale factors // Apply new temporary scale factors
TransformationType transformation_type(TransformationType::Local_Absolute_Joint); #if ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown()) transformation_type.set_independent(); 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();
Selection &selection = m_parent.get_selection(); transformation_type.set_relative();
selection.scale(get_scale(), transformation_type); #else
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
#endif // ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown())
transformation_type.set_independent();
#if ENABLE_WORLD_COORDINATE
m_parent.get_selection().scale_and_translate(m_scale, m_offset, transformation_type);
#else
Selection& selection = m_parent.get_selection();
selection.scale(m_scale, transformation_type);
if (mouse_event.CmdDown()) selection.translate(m_offset, true); if (mouse_event.CmdDown()) selection.translate(m_offset, true);
#endif // ENABLE_WORLD_COORDINATE
} }
} }
return use_grabbers(mouse_event); return use_grabbers(mouse_event);
@ -85,26 +105,29 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
void GLGizmoScale3D::data_changed() void GLGizmoScale3D::data_changed()
{ {
const Selection &selection = m_parent.get_selection(); #if ENABLE_WORLD_COORDINATE
bool enable_scale_xyz = selection.is_single_full_instance() || set_scale(Vec3d::Ones());
selection.is_single_volume() || #else
selection.is_single_modifier(); const Selection& selection = m_parent.get_selection();
bool enable_scale_xyz = selection.is_single_full_instance() ||
selection.is_single_volume() ||
selection.is_single_modifier();
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable_scale_xyz; m_grabbers[i].enabled = enable_scale_xyz;
if (enable_scale_xyz) { if (enable_scale_xyz) {
// all volumes in the selection belongs to the same instance, any of // all volumes in the selection belongs to the same instance, any of
// them contains the needed data, so we take the first // them contains the needed data, so we take the first
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance())
set_scale(volume->get_instance_scaling_factor()); set_scale(volume->get_instance_scaling_factor());
} else if (selection.is_single_volume() || else if (selection.is_single_volume() || selection.is_single_modifier())
selection.is_single_modifier()) {
set_scale(volume->get_volume_scaling_factor()); set_scale(volume->get_volume_scaling_factor());
}
} else {
set_scale(Vec3d::Ones());
} }
else
set_scale(Vec3d::Ones());
#endif // ENABLE_WORLD_COORDINATE
} }
bool GLGizmoScale3D::on_init() bool GLGizmoScale3D::on_init()
@ -113,15 +136,17 @@ bool GLGizmoScale3D::on_init()
m_grabbers.push_back(Grabber()); m_grabbers.push_back(Grabber());
} }
#if !ENABLE_WORLD_COORDINATE
double half_pi = 0.5 * (double)PI; double half_pi = 0.5 * (double)PI;
// x axis // x axis
m_grabbers[0].angles(1) = half_pi; m_grabbers[0].angles.y() = half_pi;
m_grabbers[1].angles(1) = half_pi; m_grabbers[1].angles.y() = half_pi;
// y axis // y axis
m_grabbers[2].angles(0) = half_pi; m_grabbers[2].angles.x() = half_pi;
m_grabbers[3].angles(0) = half_pi; m_grabbers[3].angles.x() = half_pi;
#endif // !ENABLE_WORLD_COORDINATE
m_shortcut_key = WXK_CONTROL_S; m_shortcut_key = WXK_CONTROL_S;
@ -142,9 +167,15 @@ bool GLGizmoScale3D::on_is_activable() const
void GLGizmoScale3D::on_start_dragging() void GLGizmoScale3D::on_start_dragging()
{ {
assert(m_hover_id != -1); assert(m_hover_id != -1);
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL); m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box(); #if ENABLE_WORLD_COORDINATE
m_starting.drag_position = m_grabbers_transform * m_grabbers[m_hover_id].center;
m_starting.box = m_bounding_box;
m_starting.center = m_center;
m_starting.instance_center = m_instance_center;
#else
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box();
const Vec3d& center = m_starting.box.center(); const Vec3d& center = m_starting.box.center();
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
@ -153,6 +184,7 @@ void GLGizmoScale3D::on_start_dragging()
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z()); m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z()); m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z()); m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoScale3D::on_stop_dragging() { void GLGizmoScale3D::on_stop_dragging() {
@ -175,78 +207,156 @@ void GLGizmoScale3D::on_render()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
m_box.reset(); m_bounding_box.reset();
#if ENABLE_WORLD_COORDINATE
m_grabbers_transform = Transform3d::Identity();
m_center = Vec3d::Zero();
m_instance_center = Vec3d::Zero();
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
#else
m_transform = Transform3d::Identity(); m_transform = Transform3d::Identity();
// Transforms grabbers' offsets to world refefence system // Transforms grabbers' offsets to world refefence system
Transform3d offsets_transform = Transform3d::Identity(); Transform3d offsets_transform = Transform3d::Identity();
m_offsets_transform = Transform3d::Identity(); m_offsets_transform = Transform3d::Identity();
Vec3d angles = Vec3d::Zero(); Vec3d angles = Vec3d::Zero();
if (single_instance) { if (selection.is_single_full_instance()) {
#endif // ENABLE_WORLD_COORDINATE
// calculate bounding box in instance local reference system // calculate bounding box in instance local reference system
const Selection::IndicesList& idxs = selection.get_volume_idxs(); const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) { for (unsigned int idx : idxs) {
const GLVolume* vol = selection.get_volume(idx); const GLVolume& v = *selection.get_volume(idx);
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix())); m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
} }
#if ENABLE_WORLD_COORDINATE
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix());
#endif // ENABLE_WORLD_COORDINATE
// gets transform from first selected volume // gets transform from first selected volume
const GLVolume* v = selection.get_volume(*idxs.begin()); const GLVolume& v = *selection.get_first_volume();
m_transform = v->get_instance_transformation().get_matrix(); #if ENABLE_WORLD_COORDINATE
const Transform3d inst_trafo = v.get_instance_transformation().get_matrix_no_scaling_factor();
m_grabbers_transform = inst_trafo * Geometry::translation_transform(m_bounding_box.center());
m_center = inst_trafo * m_bounding_box.center();
m_instance_center = v.get_instance_offset();
}
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) {
#else
m_transform = v.get_instance_transformation().get_matrix();
// gets angles from first selected volume // gets angles from first selected volume
angles = v->get_instance_rotation(); angles = v.get_instance_rotation();
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
m_offsets_transform = offsets_transform; m_offsets_transform = offsets_transform;
} }
else if (single_volume) { else if (selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); #endif // ENABLE_WORLD_COORDINATE
m_box = v->bounding_box(); const GLVolume& v = *selection.get_first_volume();
m_transform = v->world_matrix(); #if ENABLE_WORLD_COORDINATE
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_matrix_no_offset()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix());
trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center();
m_instance_center = m_center;
}
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix());
trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center();
m_instance_center = m_center;
}
else {
m_bounding_box = selection.get_bounding_box();
m_grabbers_transform = Geometry::assemble_transform(m_bounding_box.center());
m_center = m_bounding_box.center();
m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center;
}
#else
m_bounding_box = v.bounding_box();
m_transform = v.world_matrix();
angles = Geometry::extract_euler_angles(m_transform); angles = Geometry::extract_euler_angles(m_transform);
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror()); m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror());
} }
else else
m_box = selection.get_bounding_box(); m_bounding_box = selection.get_bounding_box();
const Vec3d& center = m_box.center(); const Vec3d& center = m_bounding_box.center();
const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0);
const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset);
const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL)); const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
// x axis // x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), center.z()) - offset_x; const Vec3d box_half_size = 0.5 * m_bounding_box.size();
bool use_constrain = wxGetKeyState(WXK_CONTROL) && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
#else
// x axis
m_grabbers[0].center = m_transform * Vec3d(m_bounding_box.min.x(), center.y(), center.z()) - offset_x;
m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0]; m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), center.z()) + offset_x; m_grabbers[1].center = m_transform * Vec3d(m_bounding_box.max.x(), center.y(), center.z()) + offset_x;
m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0]; m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis // y axis
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), center.z()) - offset_y; m_grabbers[2].center = m_transform * Vec3d(center.x(), m_bounding_box.min.y(), center.z()) - offset_y;
m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1]; m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), center.z()) + offset_y; m_grabbers[3].center = m_transform * Vec3d(center.x(), m_bounding_box.max.y(), center.z()) + offset_y;
m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1]; m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis // z axis
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()) - offset_z; m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.min.z()) - offset_z;
m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2]; m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()) + offset_z; m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.max.z()) + offset_z;
m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2]; m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform // uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), center.z()) - offset_x - offset_y; m_grabbers[6].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.min.y(), center.z()) - offset_x - offset_y;
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), center.z()) + offset_x - offset_y; m_grabbers[7].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.min.y(), center.z()) + offset_x - offset_y;
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), center.z()) + offset_x + offset_y; m_grabbers[8].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.max.y(), center.z()) + offset_x + offset_y;
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), center.z()) - offset_x + offset_y; m_grabbers[9].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y;
for (int i = 6; i < 10; ++i) { for (int i = 6; i < 10; ++i) {
m_grabbers[i].color = m_highlight_color; m_grabbers[i].color = m_highlight_color;
} }
@ -255,15 +365,29 @@ void GLGizmoScale3D::on_render()
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
m_grabbers[i].angles = angles; m_grabbers[i].angles = angles;
} }
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
if (!OpenGLManager::get_gl_info().is_core_profile()) if (!OpenGLManager::get_gl_info().is_core_profile())
#endif // ENABLE_GL_CORE_PROFILE #endif // ENABLE_GL_CORE_PROFILE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
const BoundingBoxf3& selection_box = selection.get_bounding_box(); #if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d base_matrix = local_transform(selection);
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(selection);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
#else
const BoundingBoxf3& selection_box = selection.get_bounding_box();
const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0); const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0);
#endif // ENABLE_WORLD_COORDINATE
if (m_hover_id == -1) { if (m_hover_id == -1) {
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -276,7 +400,11 @@ void GLGizmoScale3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -331,7 +459,11 @@ void GLGizmoScale3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -347,7 +479,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[0].color.data())); glsafe(::glColor4fv(AXES_COLOR[0].data()));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers // draw grabbers
@ -372,7 +504,11 @@ void GLGizmoScale3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -388,7 +524,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[2].color.data())); glsafe(::glColor4fv(AXES_COLOR[1].data()));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers // draw grabbers
@ -413,7 +549,11 @@ void GLGizmoScale3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -429,7 +569,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[4].color.data())); glsafe(::glColor4fv(AXES_COLOR[2].data()));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers // draw grabbers
@ -454,7 +594,11 @@ void GLGizmoScale3D::on_render()
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#if ENABLE_GL_CORE_PROFILE #if ENABLE_GL_CORE_PROFILE
const std::array<int, 4>& viewport = camera.get_viewport(); const std::array<int, 4>& viewport = camera.get_viewport();
@ -491,12 +635,34 @@ void GLGizmoScale3D::on_render()
shader->stop_using(); shader->stop_using();
} }
} }
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoScale3D::on_render_for_picking() void GLGizmoScale3D::on_render_for_picking()
{ {
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
render_grabbers_for_picking(m_bounding_box);
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#else
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -552,13 +718,67 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int
} }
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{ {
double ratio = calc_ratio(data); double ratio = calc_ratio(data);
if (ratio > 0.0) {
Vec3d curr_scale = m_scale;
Vec3d starting_scale = m_starting.scale;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
curr_scale(axis) = starting_scale(axis) * ratio;
m_scale = curr_scale;
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
double local_offset = 0.5 * (ratio - 1.0) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis)
local_offset *= -1.0;
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from world coordinates to instance coordinates
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
local_offset += (ratio - 1.0) * center_offset(axis);
switch (axis)
{
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
case Y: { m_offset = local_offset * Vec3d::UnitY(); break; }
case Z: { m_offset = local_offset * Vec3d::UnitZ(); break; }
default: { m_offset = Vec3d::Zero(); break; }
}
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from instance coordinates to world coordinates
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
}
}
#else
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
const double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0) {
m_scale(axis) = m_starting.scale(axis) * ratio; m_scale(axis) = m_starting.scale(axis) * ratio;
if (m_starting.ctrl_down) { if (m_starting.ctrl_down) {
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis); double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis) if (m_hover_id == 2 * axis)
local_offset *= -1.0; local_offset *= -1.0;
@ -577,36 +797,86 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
} }
} }
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
{
const double ratio = calc_ratio(data);
if (ratio > 0.0) {
m_scale = m_starting.scale * ratio;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
m_offset = 0.5 * (ratio - 1.0) * m_starting.box.size();
if (m_hover_id == 6 || m_hover_id == 9)
m_offset.x() *= -1.0;
if (m_hover_id == 6 || m_hover_id == 7)
m_offset.y() *= -1.0;
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from world coordinates to instance coordinates
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
m_offset += (ratio - 1.0) * center_offset;
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from instance coordinates to world coordinates
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
}
}
#else
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{ {
double ratio = calc_ratio(data); const double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0) {
m_scale = m_starting.scale * ratio; m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
} }
} }
#endif // ENABLE_WORLD_COORDINATE
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{ {
double ratio = 0.0; double ratio = 0.0;
Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.box.center(); #if ENABLE_WORLD_COORDINATE
const Vec3d starting_vec = m_starting.drag_position - m_starting.center;
#else
const Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.box.center();
const Vec3d starting_vec = m_starting.drag_position - pivot;
#endif // ENABLE_WORLD_COORDINATE
const double len_starting_vec = starting_vec.norm();
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(); const Vec3d mouse_dir = data.mouse_ray.unit_vector();
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
// in our case plane normal and ray direction are the same (orthogonal view) // in our case plane normal and ray direction are the same (orthogonal view)
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; const Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
// vector from the starting position to the found intersection // vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_starting.drag_position; const Vec3d inters_vec = inters - m_starting.drag_position;
// finds projection of the vector along the staring direction // finds projection of the vector along the staring direction
double proj = inters_vec.dot(starting_vec.normalized()); const double proj = inters_vec.dot(starting_vec.normalized());
ratio = (len_starting_vec + proj) / len_starting_vec; ratio = (len_starting_vec + proj) / len_starting_vec;
} }
@ -617,5 +887,34 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio; return ratio;
} }
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
Transform3d GLGizmoScale3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoScale3D::transform_to_local(const Selection& selection) const
{
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
Transform3d orient_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * selection.get_first_volume()->get_volume_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_WORLD_COORDINATE
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -3,31 +3,46 @@
#include "GLGizmoBase.hpp" #include "GLGizmoBase.hpp"
#if !ENABLE_WORLD_COORDINATE
#include "libslic3r/BoundingBox.hpp" #include "libslic3r/BoundingBox.hpp"
#endif // !ENABLE_WORLD_COORDINATE
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_WORLD_COORDINATE
class Selection;
#endif // ENABLE_WORLD_COORDINATE
class GLGizmoScale3D : public GLGizmoBase class GLGizmoScale3D : public GLGizmoBase
{ {
static const float Offset; static const double Offset;
struct StartingData struct StartingData
{ {
Vec3d scale; bool ctrl_down{ false };
Vec3d drag_position; Vec3d scale{ Vec3d::Ones() };
Vec3d drag_position{ Vec3d::Zero() };
#if ENABLE_WORLD_COORDINATE
Vec3d center{ Vec3d::Zero() };
Vec3d instance_center{ Vec3d::Zero() };
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 box; BoundingBoxf3 box;
Vec3d pivots[6]; #if !ENABLE_WORLD_COORDINATE
bool ctrl_down; std::array<Vec3d, 6> pivots{ Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
#endif // !ENABLE_WORLD_COORDINATE
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
}; };
mutable BoundingBoxf3 m_box; BoundingBoxf3 m_bounding_box;
mutable Transform3d m_transform; #if ENABLE_WORLD_COORDINATE
Transform3d m_grabbers_transform;
Vec3d m_center{ Vec3d::Zero() };
Vec3d m_instance_center{ Vec3d::Zero() };
#else
Transform3d m_transform;
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes) // Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
mutable Transform3d m_offsets_transform; Transform3d m_offsets_transform;
#endif // ENABLE_WORLD_COORDINATE
Vec3d m_scale{ Vec3d::Ones() }; Vec3d m_scale{ Vec3d::Ones() };
Vec3d m_offset{ Vec3d::Zero() }; Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step{ 0.05 }; double m_snap_step{ 0.05 };
@ -54,7 +69,11 @@ public:
void set_snap_step(double step) { m_snap_step = step; } void set_snap_step(double step) { m_snap_step = step; }
const Vec3d& get_scale() const { return m_scale; } const Vec3d& get_scale() const { return m_scale; }
#if ENABLE_WORLD_COORDINATE
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; m_offset = Vec3d::Zero(); }
#else
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#endif // ENABLE_WORLD_COORDINATE
std::string get_tooltip() const override; std::string get_tooltip() const override;
@ -87,6 +106,13 @@ private:
void do_scale_uniform(const UpdateData& data); void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const; double calc_ratio(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const;
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#endif // ENABLE_WORLD_COORDINATE
}; };

View File

@ -146,9 +146,13 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
}); });
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* vol = selection.get_first_volume();
Geometry::Transformation transformation(vol->get_instance_transformation().get_matrix() * vol->get_volume_transformation().get_matrix()); Geometry::Transformation transformation(vol->get_instance_transformation().get_matrix() * vol->get_volume_transformation().get_matrix());
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
#else
const Transform3d& instance_scaling_matrix_inverse = transformation.get_matrix(true, true, false, true).inverse(); const Transform3d& instance_scaling_matrix_inverse = transformation.get_matrix(true, true, false, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * transformation.get_matrix(); const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * transformation.get_matrix();
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
@ -360,7 +364,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation(); Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));

View File

@ -119,7 +119,7 @@ void SelectionInfo::on_update()
const Selection& selection = get_pool()->get_canvas()->get_selection(); const Selection& selection = get_pool()->get_canvas()->get_selection();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
m_model_object = selection.get_model()->objects[selection.get_object_idx()]; m_model_object = selection.get_model()->objects[selection.get_object_idx()];
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); m_z_shift = selection.get_first_volume()->get_sla_shift_z();
} }
else else
m_model_object = nullptr; m_model_object = nullptr;

View File

@ -408,7 +408,8 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
// at this moment is enebled to process mouse move under gizmo // at this moment is enebled to process mouse move under gizmo
// tools bar e.g. Do not interupt dragging. // tools bar e.g. Do not interupt dragging.
return false; return false;
} else if (mc.exist_tooltip) { }
else if (mc.exist_tooltip) {
// first move out of gizmo tool bar - unselect tooltip // first move out of gizmo tool bar - unselect tooltip
mc.exist_tooltip = false; mc.exist_tooltip = false;
update_hover_state(Undefined); update_hover_state(Undefined);
@ -423,10 +424,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
mc.left = true; mc.left = true;
open_gizmo(gizmo); open_gizmo(gizmo);
return true; return true;
} else if (mouse_event.RightDown()) { }
else if (mouse_event.RightDown()) {
mc.right = true; mc.right = true;
return true; return true;
} else if (mouse_event.MiddleDown()) { }
else if (mouse_event.MiddleDown()) {
mc.middle = true; mc.middle = true;
return true; return true;
} }
@ -441,14 +444,17 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
update_hover_state(Undefined); update_hover_state(Undefined);
} }
// draging start on toolbar so no propagation into scene // draging start on toolbar so no propagation into scene
return true; return true;
} else if (mc.left && mouse_event.LeftUp()) { }
else if (mc.left && mouse_event.LeftUp()) {
mc.left = false; mc.left = false;
return true; return true;
} else if (mc.right && mouse_event.RightUp()) { }
else if (mc.right && mouse_event.RightUp()) {
mc.right = false; mc.right = false;
return true; return true;
} else if (mc.middle && mouse_event.MiddleUp()) { }
else if (mc.middle && mouse_event.MiddleUp()) {
mc.middle = false; mc.middle = false;
return true; return true;
} }

View File

@ -205,7 +205,7 @@ public:
bool handle_shortcut(int key); bool handle_shortcut(int key);
bool is_dragging() const; bool is_dragging() const;
ClippingPlane get_clipping_plane() const; ClippingPlane get_clipping_plane() const;
bool wants_reslice_supports_on_undo() const; bool wants_reslice_supports_on_undo() const;

View File

@ -38,22 +38,18 @@ class PlaterWorker: public Worker {
void update_status(int st, const std::string &msg = "") override void update_status(int st, const std::string &msg = "") override
{ {
wxWakeUpIdle();
ctl.update_status(st, msg); ctl.update_status(st, msg);
wxWakeUpIdle();
// If the worker is not using additional threads, the UI
// is refreshed with this call. If the worker is running
// in it's own thread, the yield should not have any
// visible effects.
wxYieldIfNeeded();
} }
bool was_canceled() const override { return ctl.was_canceled(); } bool was_canceled() const override { return ctl.was_canceled(); }
std::future<void> call_on_main_thread(std::function<void()> fn) override std::future<void> call_on_main_thread(std::function<void()> fn) override
{ {
auto ftr = ctl.call_on_main_thread(std::move(fn));
wxWakeUpIdle(); wxWakeUpIdle();
return ctl.call_on_main_thread(std::move(fn));
return ftr;
} }
} wctl{c}; } wctl{c};

View File

@ -62,7 +62,15 @@ protected:
std::future<void> call_on_main_thread(std::function<void()> fn) override std::future<void> call_on_main_thread(std::function<void()> fn) override
{ {
return std::async(std::launch::deferred, [fn]{ fn(); }); std::future<void> ftr = std::async(std::launch::deferred, [fn]{ fn(); });
// So, it seems that the destructor of std::future will not call the
// packaged function. The future needs to be accessed at least ones
// or waited upon. Calling wait() instead of get() will keep the
// returned future's state valid.
ftr.wait();
return ftr;
} }
public: public:

View File

@ -108,7 +108,11 @@ void MeshClipper::render_cut()
void MeshClipper::recalculate_triangles() void MeshClipper::recalculate_triangles()
{ {
#if ENABLE_WORLD_COORDINATE
const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast<float>();
#else
const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>(); const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>();
#endif // ENABLE_WORLD_COORDINATE
// Calculate clipping plane normal in mesh coordinates. // Calculate clipping plane normal in mesh coordinates.
const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>(); const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>();
const Vec3d up = up_noscale.cast<double>().cwiseProduct(m_trafo.get_scaling_factor()); const Vec3d up = up_noscale.cast<double>().cwiseProduct(m_trafo.get_scaling_factor());
@ -299,7 +303,11 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
{ {
std::vector<unsigned> out; std::vector<unsigned> out;
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_matrix_no_translation_no_scaling = trafo.get_rotation_matrix();
#else
const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true); const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
#endif // ENABLE_WORLD_COORDINATE
Vec3d direction_to_camera = -camera.get_dir_forward(); Vec3d direction_to_camera = -camera.get_dir_forward();
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval(); Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval();
direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor()); direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());

View File

@ -57,6 +57,9 @@
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp" #include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "GUI_Factories.hpp" #include "GUI_Factories.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
@ -1514,6 +1517,11 @@ void Sidebar::update_mode()
wxWindowUpdateLocker noUpdates(this); wxWindowUpdateLocker noUpdates(this);
#if ENABLE_WORLD_COORDINATE
if (m_mode == comSimple)
p->object_manipulation->set_coordinates_type(ECoordinatesType::World);
#endif // ENABLE_WORLD_COORDINATE
p->object_list->get_sizer()->Show(m_mode > comSimple); p->object_list->get_sizer()->Show(m_mode > comSimple);
p->object_list->unselect_objects(); p->object_list->unselect_objects();
@ -2077,6 +2085,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this);
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this); view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this);
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); });
#if ENABLE_WORLD_COORDINATE
view3D_canvas->Bind(EVT_GLCANVAS_RESET_SKEW, [this](SimpleEvent&) { update(); });
#endif // ENABLE_WORLD_COORDINATE
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); }); view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); });
view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool>& evt) { this->sidebar->enable_buttons(evt.data); }); view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool>& evt) { this->sidebar->enable_buttons(evt.data); });
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this); view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this);
@ -2922,7 +2933,7 @@ int Plater::priv::get_selected_volume_idx() const
if ((0 > idx) || (idx > 1000)) if ((0 > idx) || (idx > 1000))
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
return-1; return-1;
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_first_volume();
if (model.objects[idx]->volumes.size() > 1) if (model.objects[idx]->volumes.size() > 1)
return v->volume_idx(); return v->volume_idx();
return -1; return -1;
@ -3484,7 +3495,11 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
new_volume->set_type(old_volume->type()); new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation()); new_volume->set_transformation(old_volume->get_transformation());
#if ENABLE_WORLD_COORDINATE
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_WORLD_COORDINATE
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters); assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches) if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units(); new_volume->convert_from_imperial_units();
@ -3521,7 +3536,7 @@ void Plater::priv::replace_with_stl()
if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1) if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
return; return;
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_first_volume();
int object_idx = v->object_idx(); int object_idx = v->object_idx();
int volume_idx = v->volume_idx(); int volume_idx = v->volume_idx();
@ -3839,10 +3854,16 @@ void Plater::priv::reload_from_disk()
new_volume->config.apply(old_volume->config); new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type()); new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); new_volume->set_material_id(old_volume->material_id());
#if ENABLE_WORLD_COORDINATE
new_volume->set_transformation(Geometry::translation_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix_no_offset() * old_volume->source.transform.get_matrix_no_offset());
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) * new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix(true) * old_volume->get_transformation().get_matrix(true) *
old_volume->source.transform.get_matrix(true)); old_volume->source.transform.get_matrix(true));
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_WORLD_COORDINATE
new_volume->source.object_idx = old_volume->source.object_idx; new_volume->source.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_idx; new_volume->source.volume_idx = old_volume->source.volume_idx;
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters); assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
@ -4448,8 +4469,12 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
const bool is_some_full_instances = selection.is_single_full_instance() || const bool is_some_full_instances = selection.is_single_full_instance() ||
selection.is_single_full_object() || selection.is_single_full_object() ||
selection.is_multiple_full_instance(); selection.is_multiple_full_instance();
#if ENABLE_WORLD_COORDINATE
const bool is_part = selection.is_single_volume_or_modifier();
#else
const bool is_part = selection.is_single_volume() || selection.is_single_modifier(); const bool is_part = selection.is_single_volume() || selection.is_single_modifier();
menu = is_some_full_instances ? menus.object_menu() : #endif // ENABLE_WORLD_COORDINATE
menu = is_some_full_instances ? menus.object_menu() :
is_part ? menus.part_menu() : menus.multi_selection_menu(); is_part ? menus.part_menu() : menus.multi_selection_menu();
} }
} }
@ -6030,7 +6055,7 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
if (selection.get_mode() == Selection::Instance) if (selection.get_mode() == Selection::Instance)
mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx()); mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
else { else {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
mesh = model_object->volumes[volume->volume_idx()]->mesh(); mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix(), true); mesh.transform(volume->get_volume_transformation().get_matrix(), true);
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,12 @@
#define slic3r_GUI_Selection_hpp_ #define slic3r_GUI_Selection_hpp_
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#include "CoordAxes.hpp"
#else
#include "GLModel.hpp" #include "GLModel.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include <set> #include <set>
#include <optional> #include <optional>
@ -24,6 +29,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
namespace GUI { namespace GUI {
#if !ENABLE_WORLD_COORDINATE
class TransformationType class TransformationType
{ {
public: public:
@ -76,6 +82,7 @@ private:
Enum m_value; Enum m_value;
}; };
#endif // !ENABLE_WORLD_COORDINATE
class Selection class Selection
{ {
@ -110,16 +117,19 @@ private:
private: private:
struct TransformCache struct TransformCache
{ {
Vec3d position; Vec3d position{ Vec3d::Zero() };
Vec3d rotation; Vec3d rotation{ Vec3d::Zero() };
Vec3d scaling_factor; Vec3d scaling_factor{ Vec3d::Ones() };
Vec3d mirror; Vec3d mirror{ Vec3d::Ones() };
Transform3d rotation_matrix; Transform3d rotation_matrix{ Transform3d::Identity() };
Transform3d scale_matrix; Transform3d scale_matrix{ Transform3d::Identity() };
Transform3d mirror_matrix; Transform3d mirror_matrix{ Transform3d::Identity() };
Transform3d full_matrix; Transform3d full_matrix{ Transform3d::Identity() };
#if ENABLE_WORLD_COORDINATE
Geometry::Transformation transform;
#endif // ENABLE_WORLD_COORDINATE
TransformCache(); TransformCache() = default;
explicit TransformCache(const Geometry::Transformation& transform); explicit TransformCache(const Geometry::Transformation& transform);
}; };
@ -131,13 +141,18 @@ private:
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform); VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; } const Vec3d& get_volume_position() const { return m_volume.position; }
#if !ENABLE_WORLD_COORDINATE
const Vec3d& get_volume_rotation() const { return m_volume.rotation; } const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; } const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
const Vec3d& get_volume_mirror() const { return m_volume.mirror; } const Vec3d& get_volume_mirror() const { return m_volume.mirror; }
#endif // !ENABLE_WORLD_COORDINATE
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; } const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; } const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; } const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; }
const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; } const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; }
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& get_volume_transform() const { return m_volume.transform; }
#endif // ENABLE_WORLD_COORDINATE
const Vec3d& get_instance_position() const { return m_instance.position; } const Vec3d& get_instance_position() const { return m_instance.position; }
const Vec3d& get_instance_rotation() const { return m_instance.rotation; } const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
@ -147,6 +162,9 @@ private:
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; } const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; } const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; } const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; }
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& get_instance_transform() const { return m_instance.transform; }
#endif // ENABLE_WORLD_COORDINATE
}; };
public: public:
@ -207,15 +225,32 @@ private:
Cache m_cache; Cache m_cache;
Clipboard m_clipboard; Clipboard m_clipboard;
std::optional<BoundingBoxf3> m_bounding_box; std::optional<BoundingBoxf3> m_bounding_box;
// Bounding box of a selection, with no instance scaling applied. This bounding box // Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// is useful for absolute scaling of tilted objects in world coordinate space. // This bounding box is useful for absolute scaling of tilted objects in world coordinate space.
// Modifiers are NOT taken in account
std::optional<BoundingBoxf3> m_unscaled_instance_bounding_box; std::optional<BoundingBoxf3> m_unscaled_instance_bounding_box;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are NOT taken in account
std::optional<BoundingBoxf3> m_scaled_instance_bounding_box; std::optional<BoundingBoxf3> m_scaled_instance_bounding_box;
#if ENABLE_WORLD_COORDINATE
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_unscaled_instance_bounding_box;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_scaled_instance_bounding_box;
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_unscaled_instance_local_bounding_box;
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_RENDER_SELECTION_CENTER #if ENABLE_RENDER_SELECTION_CENTER
GLModel m_vbo_sphere; GLModel m_vbo_sphere;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_WORLD_COORDINATE
CoordAxes m_axes;
#endif // ENABLE_WORLD_COORDINATE
GLModel m_arrow; GLModel m_arrow;
GLModel m_curved_arrow; GLModel m_curved_arrow;
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -290,6 +325,9 @@ public:
bool is_from_single_object() const; bool is_from_single_object() const;
bool is_sla_compliant() const; bool is_sla_compliant() const;
bool is_instance_mode() const { return m_mode == Instance; } bool is_instance_mode() const { return m_mode == Instance; }
#if ENABLE_WORLD_COORDINATE
bool is_single_volume_or_modifier() const { return is_single_volume() || is_single_modifier(); }
#endif // ENABLE_WORLD_COORDINATE
bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); } bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); }
// returns true if the selection contains all the given indices // returns true if the selection contains all the given indices
@ -299,7 +337,18 @@ public:
// returns true if the selection contains all and only the given indices // returns true if the selection contains all and only the given indices
bool matches(const std::vector<unsigned int>& volume_idxs) const; bool matches(const std::vector<unsigned int>& volume_idxs) const;
#if ENABLE_WORLD_COORDINATE
enum class EUniformScaleRequiredReason : unsigned char
{
NotRequired,
InstanceNotAxisAligned_World,
VolumeNotAxisAligned_World,
VolumeNotAxisAligned_Instance,
MultipleSelection,
};
#else
bool requires_uniform_scale() const; bool requires_uniform_scale() const;
#endif // ENABLE_WORLD_COORDINATE
// Returns the the object id if the selection is from a single object, otherwise is -1 // Returns the the object id if the selection is from a single object, otherwise is -1
int get_object_idx() const; int get_object_idx() const;
@ -311,28 +360,60 @@ public:
const IndicesList& get_volume_idxs() const { return m_list; } const IndicesList& get_volume_idxs() const { return m_list; }
const GLVolume* get_volume(unsigned int volume_idx) const; const GLVolume* get_volume(unsigned int volume_idx) const;
const GLVolume* get_first_volume() const { return get_volume(*m_list.begin()); }
const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; } const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; }
unsigned int volumes_count() const { return (unsigned int)m_list.size(); } unsigned int volumes_count() const { return (unsigned int)m_list.size(); }
const BoundingBoxf3& get_bounding_box() const; const BoundingBoxf3& get_bounding_box() const;
// Bounding box of a selection, with no instance scaling applied. This bounding box // Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// is useful for absolute scaling of tilted objects in world coordinate space. // This bounding box is useful for absolute scaling of tilted objects in world coordinate space.
// Modifiers are NOT taken in account
const BoundingBoxf3& get_unscaled_instance_bounding_box() const; const BoundingBoxf3& get_unscaled_instance_bounding_box() const;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are NOT taken in account
const BoundingBoxf3& get_scaled_instance_bounding_box() const; const BoundingBoxf3& get_scaled_instance_bounding_box() const;
#if ENABLE_WORLD_COORDINATE
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// Modifiers are taken in account
const BoundingBoxf3& get_full_unscaled_instance_bounding_box() const;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are taken in account
const BoundingBoxf3& get_full_scaled_instance_bounding_box() const;
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
// Modifiers are taken in account
const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const;
#endif // ENABLE_WORLD_COORDINATE
void setup_cache(); void setup_cache();
#if ENABLE_WORLD_COORDINATE
void translate(const Vec3d& displacement, TransformationType transformation_type);
#else
void translate(const Vec3d& displacement, bool local = false); void translate(const Vec3d& displacement, bool local = false);
#endif // ENABLE_WORLD_COORDINATE
void rotate(const Vec3d& rotation, TransformationType transformation_type); void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal); void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type); void scale(const Vec3d& scale, TransformationType transformation_type);
void scale_to_fit_print_volume(const BuildVolume& volume); void scale_to_fit_print_volume(const BuildVolume& volume);
void mirror(Axis axis); void mirror(Axis axis);
#if ENABLE_WORLD_COORDINATE
void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type);
void reset_skew();
#else
void translate(unsigned int object_idx, const Vec3d& displacement); void translate(unsigned int object_idx, const Vec3d& displacement);
#endif // ENABLE_WORLD_COORDINATE
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement); void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
#if ENABLE_WORLD_COORDINATE
// returns:
// -1 if the user refused to proceed with baking when asked
// 0 if the baking was performed
// 1 if no baking was needed
int bake_transform_if_needed() const;
#endif // ENABLE_WORLD_COORDINATE
void erase(); void erase();
void render(float scale_factor = 1.0); void render(float scale_factor = 1.0);
@ -368,10 +449,25 @@ private:
void do_remove_volume(unsigned int volume_idx); void do_remove_volume(unsigned int volume_idx);
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
void do_remove_object(unsigned int object_idx); void do_remove_object(unsigned int object_idx);
#if ENABLE_WORLD_COORDINATE
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_local_bounding_box.reset();;
}
#else
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
#endif // ENABLE_WORLD_COORDINATE
void render_synchronized_volumes(); void render_synchronized_volumes();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
#else
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color); void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color);
#endif // ENABLE_WORLD_COORDINATE
void render_selected_volumes() const;
void render_bounding_box(const BoundingBoxf3& box, float* color) const;
void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix); void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
void render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix); void render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
void render_sidebar_scale_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix); void render_sidebar_scale_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
@ -386,11 +482,15 @@ private:
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
public: public:
enum SyncRotationType { enum class SyncRotationType {
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
SYNC_ROTATION_NONE = 0, NONE = 0,
// Synchronize after rotation by an axis not parallel with Z. // Synchronize after rotation by an axis not parallel with Z.
SYNC_ROTATION_GENERAL = 1, GENERAL = 1,
#if ENABLE_WORLD_COORDINATE
// Fully synchronize rotation.
FULL = 2,
#endif // ENABLE_WORLD_COORDINATE
}; };
void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
void synchronize_unselected_volumes(); void synchronize_unselected_volumes();
@ -402,6 +502,11 @@ private:
void paste_volumes_from_clipboard(); void paste_volumes_from_clipboard();
void paste_objects_from_clipboard(); void paste_objects_from_clipboard();
#if ENABLE_WORLD_COORDINATE
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
const Transform3d& transform);
#endif // ENABLE_WORLD_COORDINATE
}; };
} // namespace GUI } // namespace GUI

View File

@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event)
if (m_disabled) if (m_disabled)
return; return;
#if ENABLE_WORLD_COORDINATE
SetLock(!m_is_pushed);
#else
m_is_pushed = !m_is_pushed; m_is_pushed = !m_is_pushed;
update_button_bitmaps(); update_button_bitmaps();
#endif // ENABLE_WORLD_COORDINATE
event.Skip(); event.Skip();
} }

View File

@ -7,12 +7,42 @@
using namespace Slic3r; using namespace Slic3r;
struct PointGridTracer { TEST_CASE("Testing basic invariants of AStar", "[AStar]") {
struct DummyTracer {
using Node = int;
int goal = 0;
float distance(int a, int b) const { return a - b; }
float goal_heuristic(int n) const { return n == goal ? -1.f : 0.f; }
size_t unique_id(int n) const { return n; }
void foreach_reachable(int, std::function<bool(int)>) const {}
};
std::vector<int> out;
SECTION("Output is empty when source is also the destination") {
bool found = astar::search_route(DummyTracer{}, 0, std::back_inserter(out));
REQUIRE(out.empty());
REQUIRE(found);
}
SECTION("Return false when there is no route to destination") {
bool found = astar::search_route(DummyTracer{}, 1, std::back_inserter(out));
REQUIRE(!found);
REQUIRE(out.empty());
}
}
struct PointGridTracer3D {
using Node = size_t; using Node = size_t;
const PointGrid<float> &grid; const PointGrid<float> &grid;
size_t final; size_t final;
PointGridTracer(const PointGrid<float> &g, size_t goal) : PointGridTracer3D(const PointGrid<float> &g, size_t goal) :
grid{g}, final{goal} {} grid{g}, final{goal} {}
template<class Fn> template<class Fn>
@ -49,14 +79,328 @@ struct PointGridTracer {
size_t unique_id(size_t n) const { return n; } size_t unique_id(size_t n) const { return n; }
}; };
template<class Node, class Cmp = std::less<Node>>
bool has_duplicates(const std::vector<Node> &res, Cmp cmp = {})
{
auto cpy = res;
std::sort(cpy.begin(), cpy.end(), cmp);
auto it = std::unique(cpy.begin(), cpy.end());
return it != cpy.end();
}
TEST_CASE("astar algorithm test over 3D point grid", "[AStar]") { TEST_CASE("astar algorithm test over 3D point grid", "[AStar]") {
auto vol = BoundingBox3Base<Vec3f>{{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}}; auto vol = BoundingBox3Base<Vec3f>{{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}};
auto pgrid = point_grid(ex_seq, vol, {0.1f, 0.1f, 0.1f}); auto pgrid = point_grid(ex_seq, vol, {0.1f, 0.1f, 0.1f});
PointGridTracer pgt{pgrid, pgrid.point_count() - 1}; size_t target = pgrid.point_count() - 1;
PointGridTracer3D pgt{pgrid, target};
std::vector<size_t> out; std::vector<size_t> out;
bool found = astar::search_route(pgt, size_t(0), std::back_inserter(out)); bool found = astar::search_route(pgt, 0, std::back_inserter(out));
REQUIRE(found); REQUIRE(found);
REQUIRE(!out.empty());
REQUIRE(out.front() == target);
#ifndef NDEBUG
std::cout << "Route taken: ";
for (auto it = out.rbegin(); it != out.rend(); ++it) {
std::cout << "(" << pgrid.get_coord(*it).transpose() << ") ";
}
std::cout << std::endl;
#endif
REQUIRE(!has_duplicates(out)); // No duplicates in output
}
enum CellValue {ON, OFF};
struct CellGridTracer2D_AllDirs {
using Node = Vec2i;
static constexpr auto Cols = size_t(5);
static constexpr auto Rows = size_t(8);
static constexpr size_t GridSize = Cols * Rows;
const std::array<std::array<CellValue, Cols>, Rows> &grid;
Vec2i goal;
CellGridTracer2D_AllDirs(const std::array<std::array<CellValue, Cols>, Rows> &g,
const Vec2i &goal_)
: grid{g}, goal{goal_}
{}
template<class Fn>
void foreach_reachable(const Vec2i &src, Fn &&fn) const
{
auto is_inside = [](const Vec2i& v) { return v.x() >= 0 && v.x() < Cols && v.y() >= 0 && v.y() < Rows; };
if (Vec2i crd = src + Vec2i{0, 1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{1, 0}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{1, 1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{0, -1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{-1, 0}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{-1, -1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{1, -1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{-1, 1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
}
float distance(const Vec2i & a, const Vec2i & b) const { return (a - b).squaredNorm(); }
float goal_heuristic(const Vec2i & n) const { return n == goal ? -1.f : (n - goal).squaredNorm(); }
size_t unique_id(const Vec2i & n) const { return n.y() * Cols + n.x(); }
};
struct CellGridTracer2D_Axis {
using Node = Vec2i;
static constexpr auto Cols = size_t(5);
static constexpr auto Rows = size_t(8);
static constexpr size_t GridSize = Cols * Rows;
const std::array<std::array<CellValue, Cols>, Rows> &grid;
Vec2i goal;
CellGridTracer2D_Axis(
const std::array<std::array<CellValue, Cols>, Rows> &g,
const Vec2i &goal_)
: grid{g}, goal{goal_}
{}
template<class Fn>
void foreach_reachable(const Vec2i &src, Fn &&fn) const
{
auto is_inside = [](const Vec2i& v) { return v.x() >= 0 && v.x() < Cols && v.y() >= 0 && v.y() < Rows; };
if (Vec2i crd = src + Vec2i{0, 1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{0, -1}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{1, 0}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
if (Vec2i crd = src + Vec2i{-1, 0}; is_inside(crd) && grid[crd.y()] [crd.x()] == ON) fn(crd);
}
float distance(const Vec2i & a, const Vec2i & b) const { return (a - b).squaredNorm(); }
float goal_heuristic(const Vec2i &n) const
{
int manhattan_dst = std::abs(n.x() - goal.x()) +
std::abs(n.y() - goal.y());
return n == goal ? -1.f : manhattan_dst;
}
size_t unique_id(const Vec2i & n) const { return n.y() * Cols + n.x(); }
};
using TestClasses = std::tuple< CellGridTracer2D_AllDirs, CellGridTracer2D_Axis >;
TEMPLATE_LIST_TEST_CASE("Astar should avoid simple barrier", "[AStar]", TestClasses) {
std::array<std::array<CellValue, 5>, 8> grid = {{
{ON , ON , ON , ON , ON},
{ON , ON , ON , ON , ON},
{ON , ON , ON , ON , ON},
{ON , ON , ON , ON , ON},
{ON , ON , ON , ON , ON},
{ON , OFF, OFF, OFF, ON},
{ON , ON , ON , ON , ON},
{ON , ON , ON , ON , ON}
}};
Vec2i dst = {2, 0};
TestType cgt{grid, dst};
std::vector<Vec2i> out;
bool found = astar::search_route(cgt, {2, 7}, std::back_inserter(out));
REQUIRE(found);
REQUIRE(!out.empty());
REQUIRE(out.front() == dst);
REQUIRE(!has_duplicates(out, [](const Vec2i &a, const Vec2i &b) {
return a.x() == b.x() ? a.y() < b.y() : a.x() < b.x();
}));
#ifndef NDEBUG
std::cout << "Route taken: ";
for (auto it = out.rbegin(); it != out.rend(); ++it) {
std::cout << "(" << it->transpose() << ") ";
}
std::cout << std::endl;
#endif
}
TEMPLATE_LIST_TEST_CASE("Astar should manage to avoid arbitrary barriers", "[AStar]", TestClasses) {
std::array<std::array<CellValue, 5>, 8> grid = {{
{ON , ON , ON , ON , ON},
{ON , ON , ON , OFF, ON},
{OFF, OFF, ON , OFF, ON},
{ON , ON , ON , OFF, ON},
{ON , OFF, ON , OFF, ON},
{ON , OFF, ON , ON , ON},
{ON , OFF, ON , OFF, ON},
{ON , ON , ON , ON , ON}
}};
Vec2i dst = {0, 0};
TestType cgt{grid, dst};
std::vector<Vec2i> out;
bool found = astar::search_route(cgt, {0, 7}, std::back_inserter(out));
REQUIRE(found);
REQUIRE(!out.empty());
REQUIRE(out.front() == dst);
REQUIRE(!has_duplicates(out, [](const Vec2i &a, const Vec2i &b) {
return a.x() == b.x() ? a.y() < b.y() : a.x() < b.x();
}));
#ifndef NDEBUG
std::cout << "Route taken: ";
for (auto it = out.rbegin(); it != out.rend(); ++it) {
std::cout << "(" << it->transpose() << ") ";
}
std::cout << std::endl;
#endif
}
TEMPLATE_LIST_TEST_CASE("Astar should find the way out of a labyrinth", "[AStar]", TestClasses) {
std::array<std::array<CellValue, 5>, 8> grid = {{
{ON , ON , ON , ON , ON },
{ON , OFF, OFF, OFF, OFF},
{ON , ON , ON , ON , ON },
{OFF, OFF, OFF, OFF, ON },
{ON , ON , ON , ON , ON },
{ON , OFF, OFF, OFF, OFF},
{ON , ON , ON , ON , ON },
{OFF, OFF, OFF, OFF, ON }
}};
Vec2i dst = {4, 0};
TestType cgt{grid, dst};
std::vector<Vec2i> out;
bool found = astar::search_route(cgt, {4, 7}, std::back_inserter(out));
REQUIRE(found);
REQUIRE(!out.empty());
REQUIRE(out.front() == dst);
REQUIRE(!has_duplicates(out, [](const Vec2i &a, const Vec2i &b) {
return a.x() == b.x() ? a.y() < b.y() : a.x() < b.x();
}));
#ifndef NDEBUG
std::cout << "Route taken: ";
for (auto it = out.rbegin(); it != out.rend(); ++it) {
std::cout << "(" << it->transpose() << ") ";
}
std::cout << std::endl;
#endif
}
TEST_CASE("Zero heuristic function should result in dijsktra's algo", "[AStar]")
{
struct GraphTracer {
using Node = size_t;
using QNode = astar::QNode<GraphTracer>;
struct Edge
{
size_t to_id = size_t(-1);
float cost = 0.f;
bool operator <(const Edge &e) const { return to_id < e.to_id; }
};
struct ENode: public QNode {
std::vector<Edge> edges;
ENode(size_t node_id, std::initializer_list<Edge> edgelist)
: QNode{node_id}, edges(edgelist)
{}
ENode &operator=(const QNode &q)
{
assert(node == q.node);
g = q.g;
h = q.h;
parent = q.parent;
queue_id = q.queue_id;
return *this;
}
};
// Example graph from
// https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/?ref=lbp
std::vector<ENode> nodes = {
{0, {{1, 4.f}, {7, 8.f}}},
{1, {{0, 4.f}, {2, 8.f}, {7, 11.f}}},
{2, {{1, 8.f}, {3, 7.f}, {5, 4.f}, {8, 2.f}}},
{3, {{2, 7.f}, {4, 9.f}, {5, 14.f}}},
{4, {{3, 9.f}, {5, 10.f}}},
{5, {{2, 4.f}, {3, 14.f}, {4, 10.f}, {6, 2.f}}},
{6, {{5, 2.f}, {7, 1.f}, {8, 6.f}}},
{7, {{0, 8.f}, {1, 11.f}, {6, 1.f}, {8, 7.f}}},
{8, {{2, 2.f}, {6, 6.f}, {7, 7.f}}}
};
float distance(size_t a, size_t b) const {
float ret = std::numeric_limits<float>::infinity();
if (a < nodes.size()) {
auto it = std::lower_bound(nodes[a].edges.begin(),
nodes[a].edges.end(),
Edge{b, 0.f});
if (it != nodes[a].edges.end()) {
ret = it->cost;
}
}
return ret;
}
float goal_heuristic(size_t) const { return 0.f; }
size_t unique_id(size_t n) const { return n; }
void foreach_reachable(size_t n, std::function<bool(int)> fn) const
{
if (n < nodes.size()) {
for (const Edge &e : nodes[n].edges)
fn(e.to_id);
}
}
} graph;
std::vector<size_t> out;
// 'graph.nodes' is able to be a node cache (it simulates an associative container)
bool found = astar::search_route(graph, size_t(0), std::back_inserter(out), graph.nodes);
// But should not crash or loop infinitely.
REQUIRE(!found);
// Without a destination, there is no output. But the algorithm should halt.
REQUIRE(out.empty());
// Source node should have it's parent unset
REQUIRE(graph.nodes[0].parent == astar::Unassigned);
// All other nodes should have their parents set
for (size_t i = 1; i < graph.nodes.size(); ++i)
REQUIRE(graph.nodes[i].parent != astar::Unassigned);
std::array<float, 9> ref_distances = {0.f, 4.f, 12.f, 19.f, 21.f,
11.f, 9.f, 8.f, 14.f};
// Try to trace each node back to the source node. Each of them should
// arrive to the source within less hops than the full number of nodes.
for (size_t i = 0, k = 0; i < graph.nodes.size(); ++i, k = 0) {
GraphTracer::QNode *q = &graph.nodes[i];
REQUIRE(q->g == Approx(ref_distances[i]));
while (k++ < graph.nodes.size() && q->parent != astar::Unassigned)
q = &graph.nodes[q->parent];
REQUIRE(q->parent == astar::Unassigned);
}
} }

View File

@ -4,7 +4,8 @@ add_executable(${_TEST_NAME}_tests
slic3r_jobs_tests.cpp slic3r_jobs_tests.cpp
) )
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r_gui libslic3r) # mold linker for successful linking needs also to link TBB library and link it before libslic3r.
target_link_libraries(${_TEST_NAME}_tests test_common TBB::tbb libslic3r_gui libslic3r)
if (MSVC) if (MSVC)
target_link_libraries(${_TEST_NAME}_tests Setupapi.lib) target_link_libraries(${_TEST_NAME}_tests Setupapi.lib)
endif () endif ()