Fixed conflicts after merge with master
This commit is contained in:
commit
cd6155293b
@ -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
|
||||
0.1.4 Added Ender-3 Pro. Added M25 support for some printers.
|
||||
min_slic3r_version = 2.4.0-rc
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Creality
|
||||
# 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.
|
||||
config_version = 0.1.4
|
||||
config_version = 0.1.5
|
||||
# Where to get the updates from?
|
||||
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%
|
||||
@ -21,7 +21,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality Ender-3 BLTouch
|
||||
@ -30,7 +30,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality Ender-3 Pro
|
||||
@ -39,7 +39,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality Ender-3 V2
|
||||
@ -48,7 +48,7 @@ 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
|
||||
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]
|
||||
name = Creality Ender-3 S1
|
||||
@ -57,7 +57,16 @@ 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
|
||||
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]
|
||||
name = Creality Ender-3 Max
|
||||
@ -66,7 +75,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality Ender-4
|
||||
@ -75,7 +84,7 @@ 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
|
||||
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]
|
||||
name = Creality Ender-5
|
||||
@ -84,7 +93,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality Ender-5 Plus
|
||||
@ -93,7 +102,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender5plus_bed.stl
|
||||
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]
|
||||
name = Creality Ender-6
|
||||
@ -102,7 +111,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender6_bed.stl
|
||||
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]
|
||||
name = Creality Ender-7
|
||||
@ -111,7 +120,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender7_bed.stl
|
||||
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]
|
||||
name = Creality Ender-2
|
||||
@ -120,7 +129,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender2_bed.stl
|
||||
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]
|
||||
name = Creality Ender-2 Pro
|
||||
@ -129,7 +138,7 @@ technology = FFF
|
||||
family = ENDER
|
||||
bed_model = ender2pro_bed.stl
|
||||
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]
|
||||
name = Creality CR-5 Pro
|
||||
@ -138,7 +147,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr5pro_bed.stl
|
||||
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]
|
||||
name = Creality CR-5 Pro H
|
||||
@ -147,7 +156,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr5pro_bed.stl
|
||||
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]
|
||||
name = Creality CR-6 SE
|
||||
@ -156,7 +165,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr6se_bed.stl
|
||||
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]
|
||||
name = Creality CR-6 Max
|
||||
@ -165,7 +174,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10s4_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 SMART
|
||||
@ -174,7 +183,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 Mini
|
||||
@ -183,7 +192,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10mini_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 Max
|
||||
@ -192,7 +201,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10max_bed.stl
|
||||
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]
|
||||
name = Creality CR-10
|
||||
@ -201,7 +210,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 V2
|
||||
@ -210,7 +219,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 V3
|
||||
@ -219,7 +228,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 S
|
||||
@ -228,7 +237,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 S Pro
|
||||
@ -237,7 +246,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 S Pro V2
|
||||
@ -246,7 +255,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10v2_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 S4
|
||||
@ -255,7 +264,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10s4_bed.stl
|
||||
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]
|
||||
name = Creality CR-10 S5
|
||||
@ -264,7 +273,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr10s5_bed.stl
|
||||
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]
|
||||
name = Creality CR-20
|
||||
@ -273,7 +282,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality CR-20 Pro
|
||||
@ -282,7 +291,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = ender3_bed.stl
|
||||
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]
|
||||
name = Creality CR-200B
|
||||
@ -291,7 +300,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr200b_bed.stl
|
||||
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]
|
||||
name = Creality CR-8
|
||||
@ -300,7 +309,7 @@ technology = FFF
|
||||
family = CR
|
||||
bed_model = cr8_bed.stl
|
||||
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]
|
||||
#name = Creality CR-X
|
||||
@ -309,7 +318,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
|
||||
#family = CR-X
|
||||
#bed_model = cr10v2_bed.stl
|
||||
#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]
|
||||
#name = Creality CR-X Pro
|
||||
@ -318,7 +327,7 @@ default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @
|
||||
#family = CR-X
|
||||
#bed_model = cr10v2_bed.stl
|
||||
#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]
|
||||
name = Creality Sermoon-D1
|
||||
@ -327,7 +336,7 @@ technology = FFF
|
||||
family = SERMOON
|
||||
bed_model = sermoond1_bed.stl
|
||||
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
|
||||
# not make it into the user interface.
|
||||
@ -842,6 +851,17 @@ filament_cost = 27.44
|
||||
filament_density = 1.29
|
||||
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
|
||||
[printer:*common*]
|
||||
printer_technology = FFF
|
||||
@ -989,6 +1009,13 @@ max_print_height = 270
|
||||
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: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]
|
||||
inherits = *common*; *pauseprint*
|
||||
retract_length = 6
|
||||
|
BIN
resources/profiles/Creality/ENDER3S1PRO_thumbnail.png
Normal file
BIN
resources/profiles/Creality/ENDER3S1PRO_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
@ -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.2 Improved start gcode, changed filename format
|
||||
0.0.1 Initial version
|
||||
|
@ -3,7 +3,7 @@
|
||||
[vendor]
|
||||
# Vendor name will be shown by the Config Wizard.
|
||||
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/
|
||||
|
||||
###
|
||||
@ -24,9 +24,16 @@ technology = FFF
|
||||
family = Proton
|
||||
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*]
|
||||
@ -35,14 +42,15 @@ layer_height = 0.2
|
||||
first_layer_height = 0.2
|
||||
perimeters = 3
|
||||
spiral_vase = 0
|
||||
top_solid_layers = 4
|
||||
top_solid_layers = 5
|
||||
bottom_solid_layers = 3
|
||||
top_solid_min_thickness = 0.8
|
||||
top_solid_min_thickness = 1
|
||||
bottom_solid_min_thickness = 0.6
|
||||
extra_perimeters = 1
|
||||
ensure_vertical_shell_thickness = 1
|
||||
avoid_crossing_perimeters = 0
|
||||
thin_walls = 0
|
||||
thick_bridges = 0
|
||||
overhangs = 1
|
||||
seam_position = aligned
|
||||
external_perimeters_first = 0
|
||||
@ -76,7 +84,9 @@ support_material_auto = 1
|
||||
support_material_threshold = 0
|
||||
support_material_enforce_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_with_sheath = 0
|
||||
support_material_spacing = 5
|
||||
@ -92,8 +102,8 @@ perimeter_speed = 60
|
||||
small_perimeter_speed = 75%
|
||||
external_perimeter_speed = 50%
|
||||
infill_speed = 80
|
||||
solid_infill_speed = 100%
|
||||
top_solid_infill_speed = 30
|
||||
solid_infill_speed = 80%
|
||||
top_solid_infill_speed = 20
|
||||
support_material_speed = 80
|
||||
support_material_interface_speed = 100%
|
||||
bridge_speed = 60
|
||||
@ -126,7 +136,7 @@ infill_overlap = 25%
|
||||
bridge_flow_ratio = 1
|
||||
slice_closing_radius = 0.049
|
||||
resolution = 0
|
||||
xy_size_compensation = 0
|
||||
xy_size_compensation = -0.05
|
||||
elefant_foot_compensation = 0.3
|
||||
clip_multipart_objects = 0
|
||||
#output
|
||||
@ -138,47 +148,50 @@ gcode_label_objects = 0
|
||||
output_filename_format = {input_filename_base}_{filament_type[0]}.gcode
|
||||
|
||||
|
||||
[print:0.2mm Standard @PROTON_X]
|
||||
[print:*common 0.2mm Standard @INAT*]
|
||||
inherits = *common*
|
||||
|
||||
[print:0.2mm Strong @PROTON_X]
|
||||
[print:*common 0.2mm Strong @INAT*]
|
||||
inherits = *common*
|
||||
fill_density = 50%
|
||||
perimeters = 6
|
||||
|
||||
[print:0.2mm Advanced Material @PROTON_X]
|
||||
[print:*common 0.2mm Advanced Material @INAT*]
|
||||
inherits = *common*
|
||||
bottom_solid_layers = 5
|
||||
top_solid_layers = 6
|
||||
skirts = 0
|
||||
brim_width = 30
|
||||
brim_width = 20
|
||||
infill_speed = 60
|
||||
support_material_speed = 60
|
||||
travel_speed = 100
|
||||
first_layer_speed = 20
|
||||
elefant_foot_compensation = 0
|
||||
|
||||
[print:0.12mm Fine @PROTON_X]
|
||||
[print:*common 0.12mm Fine @INAT*]
|
||||
inherits = *common*
|
||||
layer_height = 0.12
|
||||
bottom_solid_layers = 7
|
||||
top_solid_layers = 7
|
||||
infill_every_layers = 2
|
||||
perimeter_speed = 50
|
||||
infill_speed = 50
|
||||
|
||||
[print:0.32mm Draft @PROTON_X]
|
||||
[print:*common 0.32mm Draft @INAT*]
|
||||
inherits = *common*
|
||||
layer_height = 0.32
|
||||
perimeter_speed = 80
|
||||
external_perimeter_speed = 75%
|
||||
infill_speed = 100
|
||||
top_solid_infill_speed = 60
|
||||
fill_density = 15%
|
||||
support_material_style = snug
|
||||
|
||||
###
|
||||
### PRINTER DEFINITIONS
|
||||
### COMMON PRINTER DEFINITIONS
|
||||
###
|
||||
|
||||
[printer:*common*]
|
||||
[printer:*proton_x_common*]
|
||||
printer_vendor = INAT s.r.o.
|
||||
default_filament_profile = "PLA @PROTON_X"
|
||||
#general
|
||||
@ -206,14 +219,14 @@ machine_max_feedrate_z = 10,10
|
||||
machine_max_feedrate_e = 100,100
|
||||
machine_max_acceleration_x = 500,500
|
||||
machine_max_acceleration_y = 500,500
|
||||
machine_max_acceleration_z = 100,100
|
||||
machine_max_acceleration_e = 2000,2000
|
||||
machine_max_acceleration_z = 200,200
|
||||
machine_max_acceleration_e = 8000,8000
|
||||
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_y = 8,8
|
||||
machine_max_jerk_z = 1,1
|
||||
machine_max_jerk_e = 2.5,2.5
|
||||
machine_max_jerk_z = 3,3
|
||||
machine_max_jerk_e = 10,10
|
||||
machine_min_extruding_rate = 5
|
||||
#extruder 1
|
||||
nozzle_diameter = 0.4
|
||||
@ -233,24 +246,65 @@ wipe = 1
|
||||
retract_before_wipe = 100%
|
||||
|
||||
|
||||
[printer:Proton X Rail]
|
||||
inherits = *common*
|
||||
printer_model = PROTON_X_RAIL
|
||||
printer_variant = 0.4
|
||||
default_print_profile = 0.2mm Standard @PROTON_X
|
||||
gcode_flavor = marlin
|
||||
machine_max_acceleration_y = 800,800
|
||||
|
||||
[printer:Proton X Rod]
|
||||
inherits = *common*
|
||||
printer_model = PROTON_X_ROD
|
||||
printer_variant = 0.4
|
||||
default_print_profile = 0.2mm Standard @PROTON_X
|
||||
[printer:*proton_xe750_common*]
|
||||
printer_vendor = INAT s.r.o.
|
||||
default_filament_profile = "PLA @PROTON_XE750"
|
||||
#general
|
||||
printer_technology = FFF
|
||||
bed_shape = 0x0,600x0,600x500,0x500
|
||||
max_print_height = 750
|
||||
z_offset = 0
|
||||
extruders_count = 2
|
||||
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*]
|
||||
@ -272,7 +326,7 @@ min_print_speed = 10
|
||||
filament_soluble = 0
|
||||
|
||||
|
||||
[filament:PLA @PROTON_X]
|
||||
[filament:*common PLA @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 210
|
||||
bed_temperature = 60
|
||||
@ -281,11 +335,12 @@ first_layer_bed_temperature = 60
|
||||
filament_type = PLA
|
||||
filament_cost = 20
|
||||
filament_density = 1.25
|
||||
fan_always_on = 1
|
||||
min_fan_speed = 50
|
||||
max_fan_speed = 100
|
||||
|
||||
|
||||
[filament:PETG @PROTON_X]
|
||||
[filament:*common PETG @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 240
|
||||
bed_temperature = 80
|
||||
@ -294,10 +349,11 @@ first_layer_bed_temperature = 80
|
||||
filament_type = PETG
|
||||
filament_cost = 25
|
||||
filament_density = 1.27
|
||||
min_fan_speed = 0
|
||||
fan_always_on = 1
|
||||
min_fan_speed = 25
|
||||
max_fan_speed = 50
|
||||
|
||||
[filament:ABS @PROTON_X]
|
||||
[filament:*common ABS @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 235
|
||||
bed_temperature = 100
|
||||
@ -309,7 +365,7 @@ filament_density = 1.01
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:ASA @PROTON_X]
|
||||
[filament:*common ASA @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 240
|
||||
bed_temperature = 110
|
||||
@ -320,7 +376,7 @@ filament_cost = 22
|
||||
filament_density = 1.07
|
||||
cooling = 0
|
||||
|
||||
[filament:TPE @PROTON_X]
|
||||
[filament:*common TPE @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 220
|
||||
bed_temperature = 40
|
||||
@ -334,7 +390,7 @@ max_fan_speed = 50
|
||||
filament_retract_length = 0.8
|
||||
filament_retract_speed = 25
|
||||
|
||||
[filament:HIPS @PROTON_X]
|
||||
[filament:*common HIPS @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 245
|
||||
bed_temperature = 100
|
||||
@ -347,7 +403,7 @@ min_fan_speed = 0
|
||||
max_fan_speed = 50
|
||||
filament_soluble = 1
|
||||
|
||||
[filament:Nylon @PROTON_X]
|
||||
[filament:*common Nylon @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 235
|
||||
bed_temperature = 130
|
||||
@ -359,19 +415,19 @@ filament_density = 1.01
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:PC @PROTON_X]
|
||||
[filament:*common PC @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 270
|
||||
bed_temperature = 130
|
||||
bed_temperature = 115
|
||||
first_layer_temperature = 270
|
||||
first_layer_bed_temperature = 130
|
||||
first_layer_bed_temperature = 115
|
||||
filament_type = PC
|
||||
filament_cost = 65
|
||||
filament_density = 1.19
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:CPE @PROTON_X]
|
||||
[filament:*common CPE @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 280
|
||||
bed_temperature = 90
|
||||
@ -383,7 +439,7 @@ filament_density = 1.27
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:PEEK @PROTON_X]
|
||||
[filament:*common PEEK @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 440
|
||||
bed_temperature = 150
|
||||
@ -395,7 +451,7 @@ filament_density = 1.3
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:PEI @PROTON_X]
|
||||
[filament:*common PEI @INAT*]
|
||||
inherits = *common*
|
||||
temperature = 400
|
||||
bed_temperature = 150
|
||||
@ -407,7 +463,7 @@ filament_density = 1.27
|
||||
cooling = 0
|
||||
bridge_fan_speed = 0
|
||||
|
||||
[filament:Polymaker PolyMide CoPA @PROTON_X]
|
||||
[filament:*common Polymaker PolyMide CoPA @INAT*]
|
||||
inherits = *common*
|
||||
filament_vendor = Polymaker
|
||||
temperature = 265
|
||||
@ -419,7 +475,7 @@ filament_cost = 93
|
||||
filament_density = 1.12
|
||||
cooling = 0
|
||||
|
||||
[filament:Polymaker PolyMide PA6-CF @PROTON_X]
|
||||
[filament:*common Polymaker PolyMide PA6-CF @INAT*]
|
||||
inherits = *common*
|
||||
filament_vendor = Polymaker
|
||||
temperature = 300
|
||||
@ -431,7 +487,7 @@ filament_cost = 95
|
||||
filament_density = 1.17
|
||||
cooling = 0
|
||||
|
||||
[filament:Polymaker PolyMide PA6-GF @PROTON_X]
|
||||
[filament:*common Polymaker PolyMide PA6-GF @INAT*]
|
||||
inherits = *common*
|
||||
filament_vendor = Polymaker
|
||||
temperature = 300
|
||||
@ -443,20 +499,21 @@ filament_cost = 95
|
||||
filament_density = 1.2
|
||||
cooling = 0
|
||||
|
||||
[filament:Devil Design PETG @PROTON_X]
|
||||
[filament:*common Devil Design PETG @INAT*]
|
||||
inherits = *common*
|
||||
filament_vendor = Devil Design
|
||||
temperature = 250
|
||||
temperature = 245
|
||||
bed_temperature = 80
|
||||
first_layer_temperature = 250
|
||||
first_layer_temperature = 245
|
||||
first_layer_bed_temperature = 80
|
||||
filament_type = PETG
|
||||
filament_cost = 22
|
||||
filament_density = 1.23
|
||||
min_fan_speed = 0
|
||||
fan_always_on = 1
|
||||
min_fan_speed = 25
|
||||
max_fan_speed = 50
|
||||
|
||||
[filament:Filament PM PETG FRJet @PROTON_X]
|
||||
[filament:*common Filament PM PETG FRJet @INAT*]
|
||||
inherits = *common*
|
||||
filament_vendor = Filament PM
|
||||
temperature = 250
|
||||
@ -467,3 +524,207 @@ filament_type = PETG
|
||||
filament_cost = 45.5
|
||||
filament_density = 1.27
|
||||
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*
|
||||
|
BIN
resources/profiles/INAT/PROTON_XE750_thumbnail.png
Normal file
BIN
resources/profiles/INAT/PROTON_XE750_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
@ -1,11 +1,12 @@
|
||||
#ifndef ASTAR_HPP
|
||||
#define ASTAR_HPP
|
||||
|
||||
#include <cmath> // std::isinf() is here
|
||||
#include <unordered_map>
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/MutablePriorityQueue.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Slic3r { namespace astar {
|
||||
|
||||
// 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.
|
||||
// This is referred to as the h value in AStar context.
|
||||
// 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)
|
||||
{
|
||||
return tracer.goal_heuristic(n);
|
||||
@ -50,131 +53,132 @@ template<class T> struct TracerTraits_
|
||||
template<class T>
|
||||
using TracerNodeT = typename TracerTraits_<remove_cvref_t<T>>::Node;
|
||||
|
||||
namespace detail {
|
||||
// Helper functions dispatching calls through the TracerTraits_ interface
|
||||
constexpr size_t Unassigned = size_t(-1);
|
||||
|
||||
template<class T> using TracerTraits = TracerTraits_<remove_cvref_t<T>>;
|
||||
|
||||
template<class T, class Fn>
|
||||
void foreach_reachable(const T &tracer, const TracerNodeT<T> &from, Fn &&fn)
|
||||
template<class Tracer>
|
||||
struct QNode // Queue node. Keeps track of scores g, and h
|
||||
{
|
||||
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 trace_distance(const T &tracer, const TracerNodeT<T> &a, const TracerNodeT<T> &b)
|
||||
{
|
||||
return TracerTraits<T>::distance(tracer, a, b);
|
||||
}
|
||||
float g, h;
|
||||
float f() const { return g + h; }
|
||||
|
||||
template<class T>
|
||||
float goal_heuristic(const T &tracer, const TracerNodeT<T> &n)
|
||||
{
|
||||
return TracerTraits<T>::goal_heuristic(tracer, n);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
size_t unique_id(const T &tracer, const TracerNodeT<T> &n)
|
||||
{
|
||||
return TracerTraits<T>::unique_id(tracer, n);
|
||||
}
|
||||
|
||||
} // namespace astar_detail
|
||||
QNode(TracerNodeT<Tracer> n = {},
|
||||
size_t p = Unassigned,
|
||||
float gval = std::numeric_limits<float>::infinity(),
|
||||
float hval = 0.f)
|
||||
: node{std::move(n)}, parent{p}, queue_id{Unassigned}, g{gval}, h{hval}
|
||||
{}
|
||||
};
|
||||
|
||||
// Run the AStar algorithm on a tracer implementation.
|
||||
// The 'tracer' argument encapsulates the domain (grid, point cloud, etc...)
|
||||
// The 'source' argument is the starting node.
|
||||
// The 'out' argument is the output iterator into which the output nodes are
|
||||
// written.
|
||||
// Note that no destination node is given. The tracer's goal_heuristic() method
|
||||
// should return a negative value if a node is a destination node.
|
||||
template<class Tracer, class It>
|
||||
bool search_route(const Tracer &tracer, const TracerNodeT<Tracer> &source, It out)
|
||||
// written. For performance reasons, the order is reverse, from the destination
|
||||
// to the source -- (destination included, source is not).
|
||||
// The 'cached_nodes' argument is an optional associative container to hold a
|
||||
// QNode entry for each visited node. Any compatible container can be used
|
||||
// (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>;
|
||||
enum class QueueType { Open, Closed, None };
|
||||
|
||||
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;
|
||||
struct LessPred { // Comparison functor needed by the priority queue
|
||||
NodeMap &m;
|
||||
bool operator ()(size_t node_a, size_t node_b) {
|
||||
auto ait = m.find(node_a);
|
||||
auto bit = m.find(node_b);
|
||||
assert (ait != m.end() && bit != m.end());
|
||||
|
||||
return ait->second.f() < bit->second.f();
|
||||
return m[node_a].f() < m[node_b].f();
|
||||
}
|
||||
};
|
||||
|
||||
auto qopen =
|
||||
make_mutable_priority_queue<size_t, false>([](size_t, size_t){},
|
||||
LessPred{cached_nodes});
|
||||
auto qopen = make_mutable_priority_queue<size_t, true>(
|
||||
[&cached_nodes](size_t el, size_t qidx) {
|
||||
cached_nodes[el].queue_id = qidx;
|
||||
},
|
||||
LessPred{cached_nodes});
|
||||
|
||||
auto qclosed =
|
||||
make_mutable_priority_queue<size_t, false>([](size_t, size_t){},
|
||||
LessPred{cached_nodes});
|
||||
QNode initial{source, /*parent = */ Unassigned, /*g = */0.f};
|
||||
size_t source_id = TracerTraits::unique_id(tracer, source);
|
||||
cached_nodes[source_id] = initial;
|
||||
qopen.push(source_id);
|
||||
|
||||
QNode initial{source, QueueType::Open};
|
||||
cached_nodes.insert({unique_id(tracer, source), initial});
|
||||
qopen.push(unique_id(tracer, source));
|
||||
size_t goal_id = TracerTraits::goal_heuristic(tracer, source) < 0.f ?
|
||||
source_id :
|
||||
Unassigned;
|
||||
|
||||
bool goal_reached = false;
|
||||
|
||||
while (!goal_reached && !qopen.empty()) {
|
||||
while (goal_id == Unassigned && !qopen.empty()) {
|
||||
size_t q_id = qopen.top();
|
||||
qopen.pop();
|
||||
QNode q = cached_nodes.at(q_id);
|
||||
QNode &q = cached_nodes[q_id];
|
||||
|
||||
foreach_reachable(tracer, q.node, [&](const Node &nd) {
|
||||
if (goal_reached) return goal_reached;
|
||||
// This should absolutely be initialized in the cache already
|
||||
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) {
|
||||
goal_reached = true;
|
||||
goal_id = succ_id;
|
||||
cached_nodes[succ_id] = qsucc_nd;
|
||||
} else {
|
||||
float dst = trace_distance(tracer, q.node, nd);
|
||||
QNode qnd{nd, QueueType::None, q.g + dst, h};
|
||||
size_t qnd_id = unique_id(tracer, nd);
|
||||
// If succ_id is not in cache, it gets created with g = infinity
|
||||
QNode &prev_nd = cached_nodes[succ_id];
|
||||
|
||||
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() ||
|
||||
(it->second.qtype != QueueType::None && qnd.f() < it->second.f())) {
|
||||
qnd.qtype = QueueType::Open;
|
||||
cached_nodes.insert_or_assign(qnd_id, qnd);
|
||||
qopen.push(qnd_id);
|
||||
// Save the old queue id, it would be lost after the next line
|
||||
size_t queue_id = prev_nd.queue_id;
|
||||
|
||||
// The cache needs to be updated either way
|
||||
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
|
||||
|
@ -230,8 +230,13 @@ static std::string appconfig_md5_hash_line(const std::string_view data)
|
||||
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.
|
||||
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 {
|
||||
std::stringstream ss;
|
||||
@ -240,7 +245,8 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs)
|
||||
};
|
||||
|
||||
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.
|
||||
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.
|
||||
// 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 }))
|
||||
return true;
|
||||
return {true, contains_null};
|
||||
}
|
||||
return false;
|
||||
return {false, contains_null};
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -269,14 +275,25 @@ std::string AppConfig::load(const std::string &path)
|
||||
ifs.open(path);
|
||||
#ifdef WIN32
|
||||
// Verify the checksum of the config file without taking just for debugging purpose.
|
||||
if (!verify_config_file_checksum(ifs))
|
||||
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.";
|
||||
const ConfigFileInfo config_file_info = check_config_file_and_verify_checksum(ifs);
|
||||
if (!config_file_info.correct_checksum)
|
||||
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);
|
||||
#endif
|
||||
pt::read_ini(ifs, tree);
|
||||
} catch (pt::ptree_error& ex) {
|
||||
try {
|
||||
pt::read_ini(ifs, tree);
|
||||
} catch (pt::ptree_error &ex) {
|
||||
throw Slic3r::CriticalException(ex.what());
|
||||
}
|
||||
} catch (Slic3r::CriticalException &ex) {
|
||||
#ifdef WIN32
|
||||
// The configuration file is corrupted, try replacing it with the backup configuration.
|
||||
ifs.close();
|
||||
@ -284,29 +301,29 @@ std::string AppConfig::load(const std::string &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.
|
||||
boost::nowide::ifstream backup_ifs(backup_path);
|
||||
if (!verify_config_file_checksum(backup_ifs)) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", path, backup_path);
|
||||
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(R"(Both "%1%" and "%2%" are corrupted. It isn't possible to restore configuration from the backup.)", path, backup_path);
|
||||
backup_ifs.close();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} 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();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} 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 {
|
||||
ifs.open(path);
|
||||
pt::read_ini(ifs, tree);
|
||||
recovered = true;
|
||||
} 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
|
||||
#endif // WIN32
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", path, ex.what());
|
||||
if (! recovered) {
|
||||
BOOST_LOG_TRIVIAL(info) << format(R"(Failed to parse configuration file "%1%": %2%)", path, ex.what());
|
||||
if (!recovered) {
|
||||
// Report the initial error of parsing PrusaSlicer.ini.
|
||||
// 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)
|
||||
|
@ -1,20 +1,25 @@
|
||||
#include "../Print.hpp"
|
||||
#include "../ShortestPath.hpp"
|
||||
|
||||
#include "FillLightning.hpp"
|
||||
#include "Lightning/Generator.hpp"
|
||||
#include "../Surface.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
namespace Slic3r::FillLightning {
|
||||
|
||||
Polylines Filler::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
void Filler::_fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon expolygon,
|
||||
Polylines &polylines_out)
|
||||
{
|
||||
const Layer &layer = generator->getTreesForLayer(this->layer_id);
|
||||
return layer.convertToLines(to_polygons(surface->expolygon), generator->infilll_extrusion_width());
|
||||
const Layer &layer = generator->getTreesForLayer(this->layer_id);
|
||||
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) {
|
||||
|
@ -24,8 +24,13 @@ public:
|
||||
Generator *generator { nullptr };
|
||||
protected:
|
||||
Fill* clone() const override { return new Filler(*this); }
|
||||
// Perform the fill.
|
||||
Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override;
|
||||
|
||||
void _fill_surface_single(const FillParams ¶ms,
|
||||
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.
|
||||
bool no_sort() const override { return false; }
|
||||
};
|
||||
|
@ -176,7 +176,7 @@ protected:
|
||||
const Point offset_loc = loc - m_grid_range.min;
|
||||
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(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;
|
||||
}
|
||||
};
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "../../ClipperUtils.hpp"
|
||||
#include "../../Layer.hpp"
|
||||
#include "../../Print.hpp"
|
||||
#include "../../Surface.hpp"
|
||||
|
||||
/* Possible future tasks/optimizations,etc.:
|
||||
* - 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)
|
||||
{
|
||||
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;
|
||||
//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 Surface& surface : layerm->fill_surfaces.surfaces)
|
||||
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.
|
||||
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)
|
||||
{
|
||||
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());
|
||||
|
||||
@ -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 Surface &surface : layerm->fill_surfaces.surfaces)
|
||||
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:
|
||||
@ -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)
|
||||
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.create(below_outlines, locator_cell_size);
|
||||
|
@ -433,15 +433,14 @@ static unsigned int moveInside(const Polygons& polygons, Point& from, int distan
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns 'added someting'.
|
||||
Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const
|
||||
Polylines Layer::convertToLines(const Polygons& limit_to_outline, const coord_t line_overlap) const
|
||||
{
|
||||
if (tree_roots.empty())
|
||||
return {};
|
||||
|
||||
Polylines result_lines;
|
||||
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);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
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);
|
||||
|
||||
|
@ -347,12 +347,12 @@ coord_t Node::prune(const coord_t& pruning_distance)
|
||||
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;
|
||||
result.emplace_back();
|
||||
convertToPolylines(0, result);
|
||||
removeJunctionOverlap(result, line_width);
|
||||
removeJunctionOverlap(result, line_overlap);
|
||||
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?
|
||||
size_t res_line_idx = 0;
|
||||
const coord_t reduction = line_overlap;
|
||||
size_t res_line_idx = 0;
|
||||
while (res_line_idx < result_lines.size()) {
|
||||
Polyline &polyline = result_lines[res_line_idx];
|
||||
if (polyline.size() <= 1) {
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
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)...);
|
||||
}
|
||||
@ -179,16 +179,16 @@ public:
|
||||
*/
|
||||
bool hasOffspring(const NodeSPtr& to_be_checked) const;
|
||||
|
||||
protected:
|
||||
Node() = delete; // Don't allow empty contruction
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* 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.
|
||||
* Connecting other nodes to this node indicates that a line segment should
|
||||
* 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.
|
||||
@ -239,7 +239,7 @@ public:
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
@ -260,7 +260,7 @@ protected:
|
||||
*/
|
||||
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;
|
||||
Point m_p;
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "SVG.hpp"
|
||||
|
||||
#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.
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
@ -1531,6 +1559,10 @@ void GCode::process_layers(
|
||||
[&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.
|
||||
output_stream.find_replace_supress();
|
||||
if (m_spiral_vase && m_find_replace)
|
||||
@ -1584,6 +1616,10 @@ void GCode::process_layers(
|
||||
[&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.
|
||||
output_stream.find_replace_supress();
|
||||
if (m_spiral_vase && m_find_replace)
|
||||
|
@ -313,9 +313,60 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
|
||||
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)
|
||||
{
|
||||
// reference: http://www.gregslabaugh.net/publications/euler.pdf
|
||||
// reference: http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
|
||||
Vec3d angles1 = Vec3d::Zero();
|
||||
Vec3d angles2 = Vec3d::Zero();
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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(Y, rotation.y());
|
||||
set_rotation(Z, rotation.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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)))
|
||||
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) {
|
||||
m_rotation(axis) = rotation;
|
||||
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)
|
||||
{
|
||||
#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(Y, scaling_factor.y());
|
||||
set_scaling_factor(Z, scaling_factor.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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)) {
|
||||
m_scaling_factor(axis) = std::abs(scaling_factor);
|
||||
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)
|
||||
{
|
||||
#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(Y, mirror.y());
|
||||
set_mirror(Z, mirror.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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)
|
||||
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) {
|
||||
m_mirror(axis) = mirror;
|
||||
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)
|
||||
{
|
||||
// offset
|
||||
@ -493,17 +685,62 @@ void Transformation::set_from_transform(const Transform3d& transform)
|
||||
// if (!m_matrix.isApprox(transform))
|
||||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::reset()
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_offset = Vec3d::Zero();
|
||||
m_rotation = Vec3d::Zero();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
m_mirror = Vec3d::Ones();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_matrix = Transform3d::Identity();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Transformation Transformation::operator * (const Transformation& other) const
|
||||
{
|
||||
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 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_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// 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.
|
||||
// Scale it to get the required size.
|
||||
@ -581,6 +819,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
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)
|
||||
{
|
||||
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();
|
||||
#ifndef NDEBUG
|
||||
if (std::abs(angle) > 1e-8) {
|
||||
|
@ -323,7 +323,8 @@ bool arrange(
|
||||
// 4) rotate Y
|
||||
// 5) rotate Z
|
||||
// 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:
|
||||
// 1) mirror
|
||||
@ -332,7 +333,43 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
|
||||
// 4) rotate Y
|
||||
// 5) rotate Z
|
||||
// 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
|
||||
// Warning -> The matrix should not contain any scale or shear !!!
|
||||
@ -344,6 +381,9 @@ Vec3d extract_euler_angles(const Transform3d& transform);
|
||||
|
||||
class Transformation
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d m_matrix{ Transform3d::Identity() };
|
||||
#else
|
||||
struct Flags
|
||||
{
|
||||
bool dont_translate{ true };
|
||||
@ -363,8 +403,26 @@ class Transformation
|
||||
mutable Transform3d m_matrix{ Transform3d::Identity() };
|
||||
mutable Flags m_flags;
|
||||
mutable bool m_dirty{ false };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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();
|
||||
explicit Transformation(const Transform3d& transform);
|
||||
|
||||
@ -376,47 +434,103 @@ public:
|
||||
|
||||
const Vec3d& get_rotation() const { return m_rotation; }
|
||||
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_rotation(const Vec3d& 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; }
|
||||
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(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; }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
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.; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_mirror(const Vec3d& mirror);
|
||||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool has_skew() const;
|
||||
#else
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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
|
||||
// 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.
|
||||
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
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);
|
||||
}
|
||||
friend class cereal::access;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
|
||||
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);
|
||||
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.
|
||||
|
@ -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);
|
||||
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
|
||||
|
||||
#endif // slic3r_LocalesUtils_hpp_
|
||||
|
@ -945,7 +945,11 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
if (this->instances.empty())
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
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 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);
|
||||
for (ModelVolume *v : this->volumes)
|
||||
{
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (ModelVolume *v : this->volumes) {
|
||||
if (v->is_model_part())
|
||||
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);
|
||||
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();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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());
|
||||
|
||||
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()))
|
||||
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
|
||||
return;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool left_handed = reference_trafo.is_left_handed();
|
||||
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.
|
||||
// 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);
|
||||
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) {
|
||||
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
|
||||
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;
|
||||
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
|
||||
// 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>
|
||||
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
// 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;
|
||||
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
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;
|
||||
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
if (!v->is_model_part())
|
||||
@ -1936,14 +1979,22 @@ void ModelVolume::convert_from_meters()
|
||||
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
|
||||
{
|
||||
// Rotate around mesh origin.
|
||||
TriangleMesh copy(mesh);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
copy.transform(get_transformation().get_rotation_matrix());
|
||||
#else
|
||||
copy.transform(get_matrix(true, false, true, true));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
BoundingBoxf3 bbox = copy.bounding_box();
|
||||
|
||||
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
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return bbox.transformed(dont_translate ? get_matrix_no_offset() : get_matrix());
|
||||
#else
|
||||
return bbox.transformed(get_matrix(dont_translate));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void ModelInstance::transform_polygon(Polygon* polygon) const
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 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:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,7 +50,7 @@
|
||||
// Enable showing time estimate for travel moves in legend
|
||||
#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// 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
|
||||
#define ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable removal of legacy OpenGL calls
|
||||
@ -67,6 +67,8 @@
|
||||
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable recalculating toolpaths when switching to/from volumetric rate visualization
|
||||
#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
|
||||
#define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1)
|
||||
// Enable modified rectangle selection
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "Thread.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "LocalesUtils.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -234,21 +235,8 @@ void name_tbb_thread_pool_threads_set_locale()
|
||||
std::ostringstream name;
|
||||
name << "slic3r_tbb_" << range.begin();
|
||||
set_current_thread_name(name.str().c_str());
|
||||
// Set locales of the worker thread to "C".
|
||||
#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
|
||||
// Set locales of the worker thread to "C".
|
||||
set_c_locales();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/GUI_App.hpp
|
||||
GUI/GUI_Utils.cpp
|
||||
GUI/GUI_Utils.hpp
|
||||
GUI/GUI_Geometry.cpp
|
||||
GUI/GUI_Geometry.hpp
|
||||
GUI/I18N.cpp
|
||||
GUI/I18N.hpp
|
||||
GUI/MainFrame.cpp
|
||||
@ -129,6 +131,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/2DBed.hpp
|
||||
GUI/3DBed.cpp
|
||||
GUI/3DBed.hpp
|
||||
GUI/CoordAxes.cpp
|
||||
GUI/CoordAxes.hpp
|
||||
GUI/Camera.cpp
|
||||
GUI/Camera.hpp
|
||||
GUI/wxExtensions.cpp
|
||||
|
@ -102,6 +102,7 @@ const float* GeometryBuffer::get_vertices_data() const
|
||||
}
|
||||
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
|
||||
const float Bed3D::Axes::DefaultStemLength = 25.0f;
|
||||
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
|
||||
@ -171,6 +172,7 @@ void Bed3D::Axes::render()
|
||||
|
||||
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)
|
||||
{
|
||||
@ -333,7 +335,11 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
|
||||
out.max.z() = 0.0;
|
||||
// extend to contain axes
|
||||
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()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.get_bounding_box();
|
||||
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()
|
||||
{
|
||||
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();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
@ -3,7 +3,11 @@
|
||||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
@ -44,6 +48,7 @@ public:
|
||||
|
||||
class Bed3D
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
@ -67,6 +72,7 @@ class Bed3D
|
||||
float get_total_length() const { return m_stem_length + DefaultTipLength; }
|
||||
void render();
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
public:
|
||||
enum class Type : unsigned char
|
||||
@ -107,7 +113,11 @@ private:
|
||||
#if !ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
unsigned int m_vbo_id{ 0 };
|
||||
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
CoordAxes m_axes;
|
||||
#else
|
||||
Axes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
|
@ -432,14 +432,23 @@ public:
|
||||
|
||||
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(); }
|
||||
#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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(); }
|
||||
@ -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(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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(); }
|
||||
@ -459,26 +472,43 @@ public:
|
||||
|
||||
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(); }
|
||||
#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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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(); }
|
||||
|
95
src/slic3r/GUI/CoordAxes.cpp
Normal file
95
src/slic3r/GUI/CoordAxes.cpp
Normal 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
|
64
src/slic3r/GUI/CoordAxes.hpp
Normal file
64
src/slic3r/GUI/CoordAxes.hpp
Normal 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_
|
@ -1075,6 +1075,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, 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_FORCE_UPDATE, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
@ -2888,7 +2891,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
||||
else
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
|
||||
update_sequential_clearance();
|
||||
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];
|
||||
if (model_object != nullptr) {
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
object_moved = true;
|
||||
model_object->invalidate_bounding_box();
|
||||
@ -3881,8 +3904,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
int object_idx = v->object_idx();
|
||||
if (object_idx == 1000) { // the wipe tower
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
Vec3d offset = v->get_volume_offset();
|
||||
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2))));
|
||||
const Vec3d offset = v->get_volume_offset();
|
||||
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z())));
|
||||
}
|
||||
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
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)
|
||||
continue;
|
||||
|
||||
int instance_idx = v->instance_idx();
|
||||
int volume_idx = v->volume_idx();
|
||||
const int instance_idx = v->instance_idx();
|
||||
const int volume_idx = v->volume_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];
|
||||
if (model_object != nullptr) {
|
||||
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_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
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_offset(v->get_volume_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
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();
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
int instance_idx = v->instance_idx();
|
||||
int volume_idx = v->volume_idx();
|
||||
const int instance_idx = v->instance_idx();
|
||||
const int volume_idx = v->volume_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];
|
||||
if (model_object != nullptr) {
|
||||
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_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
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->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor());
|
||||
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
@ -3982,10 +4022,10 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
||||
// Fixes sinking/flying instances
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
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
|
||||
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->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];
|
||||
if (model_object != nullptr) {
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
@ -4061,6 +4109,44 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
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()
|
||||
{
|
||||
set_as_dirty();
|
||||
|
@ -156,6 +156,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
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_WIPETOWER_ROTATED, Vec3dEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
|
||||
@ -732,7 +735,11 @@ public:
|
||||
|
||||
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; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void render();
|
||||
// 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_scale(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 reset_all_gizmos() { m_gizmos.reset_all_states(); }
|
||||
|
9
src/slic3r/GUI/GUI_Geometry.cpp
Normal file
9
src/slic3r/GUI/GUI_Geometry.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "GUI_Geometry.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
} // namespace GUI
|
81
src/slic3r/GUI/GUI_Geometry.hpp
Normal file
81
src/slic3r/GUI/GUI_Geometry.hpp
Normal 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_
|
@ -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);
|
||||
|
||||
// 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();
|
||||
#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();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Vec3d instance_offset = v->get_instance_offset();
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// 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.
|
||||
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);
|
||||
|
||||
// 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.
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Set the modifier position.
|
||||
auto offset = (type_name == "Slab") ?
|
||||
// Slab: Lift to print bed
|
||||
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.
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const wxString name = _L("Generic") + "-" + _(type_name);
|
||||
new_volume->name = into_u8(name);
|
||||
@ -2545,7 +2565,13 @@ void ObjectList::part_selection_changed()
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
|
||||
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
|
||||
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
|
||||
@ -3263,8 +3289,12 @@ void ObjectList::update_selections()
|
||||
return;
|
||||
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()) {
|
||||
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())
|
||||
return;
|
||||
}
|
||||
|
@ -52,10 +52,17 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
|
||||
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
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("Local coordinates"));
|
||||
temp->SetSelection(0);
|
||||
temp->SetValue(temp->GetString(0));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
|
||||
return temp;
|
||||
@ -81,8 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
|
||||
// Set rescaled 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("Local coordinates"));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
combo->SetValue(selection);
|
||||
#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_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" };
|
||||
|
||||
ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
OG_Settings(parent, true)
|
||||
{
|
||||
@ -157,8 +171,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
// Add world local combobox
|
||||
m_word_local_combo = create_word_local_combo(parent);
|
||||
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);
|
||||
}), m_word_local_combo->GetId());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}), m_word_local_combo->GetId());
|
||||
|
||||
// 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
|
||||
@ -264,8 +282,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
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()) {
|
||||
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));
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
@ -278,7 +300,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
return;
|
||||
|
||||
// Update mirroring at the GLVolumes.
|
||||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_mirror(L("Set Mirror"));
|
||||
@ -327,28 +349,60 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
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();
|
||||
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(*volume));
|
||||
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 {
|
||||
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"));
|
||||
change_position_value(0, diff.x());
|
||||
change_position_value(1, diff.y());
|
||||
change_position_value(2, diff.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
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 int idx = selection.get_object_idx();
|
||||
if (0 <= idx && idx < static_cast<int>(objects.size())) {
|
||||
const ModelObject* mo = wxGetApp().model().objects[idx];
|
||||
const double min_z = mo->bounding_box().min.z();
|
||||
if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
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);
|
||||
@ -365,21 +419,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||
volume->set_volume_rotation(Vec3d::Zero());
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier())
|
||||
#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()) {
|
||||
for (unsigned int idx : selection.get_volume_idxs()) {
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
|
||||
volume->set_instance_rotation(Vec3d::Zero());
|
||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// Update rotation at the GLVolumes.
|
||||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
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->SetToolTip(_L("Reset scale"));
|
||||
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"));
|
||||
change_scale_value(0, 100.);
|
||||
change_scale_value(1, 100.);
|
||||
change_scale_value(2, 100.);
|
||||
});
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
});
|
||||
editors_grid_sizer->Add(m_reset_scale_button);
|
||||
|
||||
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);
|
||||
|
||||
#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->SetFont(wxGetApp().normal_font());
|
||||
|
||||
@ -444,8 +536,27 @@ void ObjectManipulation::Show(const bool show)
|
||||
|
||||
if (show) {
|
||||
// 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;
|
||||
m_word_local_combo->Show(show_world_local_combo);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -489,8 +600,7 @@ void ObjectManipulation::update_ui_from_settings()
|
||||
}
|
||||
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";
|
||||
// update colors for edit-boxes
|
||||
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_scale_label_string = L("Scale factors");
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
m_world_coordinates = true;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
ObjectList* obj_list = wxGetApp().obj_list();
|
||||
if (selection.is_single_full_instance()) {
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
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.
|
||||
if (m_world_coordinates && ! m_uniform_scale &&
|
||||
if (m_world_coordinates && ! m_uniform_scale &&
|
||||
! 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.
|
||||
m_uniform_scale = 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) {
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_size = selection.get_scaled_instance_bounding_box().size();
|
||||
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
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 {
|
||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||
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.;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_move_label_string = L("Translate");
|
||||
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;
|
||||
@ -557,19 +683,52 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
m_new_position = box.center();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(100., 100., 100.);
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
m_new_size = box.size();
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_scale_label_string = L("Scale");
|
||||
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()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// 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_rotation = volume->get_volume_rotation() * (180. / M_PI);
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.;
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
#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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (selection.requires_uniform_scale()) {
|
||||
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->disable();
|
||||
}
|
||||
else {
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_lock_bnt->SetLock(m_uniform_scale);
|
||||
m_lock_bnt->SetToolTip(wxEmptyString);
|
||||
m_lock_bnt->enable();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
int new_selection = m_world_coordinates ? 0 : 1;
|
||||
if (m_word_local_combo->GetSelection() != new_selection)
|
||||
m_word_local_combo->SetSelection(new_selection);
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_new_enabled)
|
||||
m_og->enable();
|
||||
@ -677,29 +840,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||
bool show_rotation = false;
|
||||
bool show_scale = 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()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d rotation;
|
||||
Vec3d scale;
|
||||
double min_z = 0.;
|
||||
double min_z = 0.0;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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();
|
||||
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 {
|
||||
#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();
|
||||
scale = volume->get_volume_scaling_factor();
|
||||
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_scale = !scale.isApprox(Vec3d::Ones());
|
||||
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] {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// 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
|
||||
if (!this->IsShown())
|
||||
@ -707,6 +916,10 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||
m_reset_rotation_button->Show(show_rotation);
|
||||
m_reset_scale_button->Show(show_scale);
|
||||
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
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
@ -726,9 +939,17 @@ void ObjectManipulation::update_mirror_buttons_visibility()
|
||||
Selection& selection = canvas->get_selection();
|
||||
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_local_coordinates()) {
|
||||
#else
|
||||
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()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d mirror;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
m_new_position = Vec3d::Zero();
|
||||
@ -815,7 +1049,19 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
||||
auto canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
canvas->do_move(L("Set Position"));
|
||||
|
||||
m_cache.position = position;
|
||||
@ -834,6 +1080,18 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
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);
|
||||
if (selection.is_single_full_instance() || selection.requires_local_axes())
|
||||
transformation_type.set_independent();
|
||||
@ -842,6 +1100,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
||||
// transformation_type.set_absolute();
|
||||
transformation_type.set_local();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.setup_cache();
|
||||
selection.rotate(
|
||||
@ -887,8 +1146,12 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
|
||||
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()) {
|
||||
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_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
|
||||
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();
|
||||
}
|
||||
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() :
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_cache.size = size;
|
||||
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
|
||||
{
|
||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
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);
|
||||
if (selection.is_single_full_instance()) {
|
||||
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())
|
||||
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.setup_cache();
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
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)
|
||||
{
|
||||
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 (selection.is_single_full_instance() && m_world_coordinates && !new_value) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
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.
|
||||
// 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?
|
||||
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.
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
_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"
|
||||
@ -980,7 +1293,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
||||
_L("This operation is irreversible.\n"
|
||||
"Do you want to proceed?"),
|
||||
SLIC3R_APP_NAME,
|
||||
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
|
||||
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() != wxID_YES) {
|
||||
// Enforce uniform scaling.
|
||||
m_lock_bnt->SetLock(true);
|
||||
@ -994,9 +1307,29 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
||||
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()
|
||||
{
|
||||
const int em = wxGetApp().em_unit();
|
||||
@ -1014,6 +1347,9 @@ void ObjectManipulation::msw_rescale()
|
||||
m_mirror_bitmap_hidden.msw_rescale();
|
||||
m_reset_scale_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_lock_bnt->msw_rescale();
|
||||
|
||||
@ -1053,6 +1389,9 @@ void ObjectManipulation::sys_color_changed()
|
||||
m_mirror_bitmap_hidden.msw_rescale();
|
||||
m_reset_scale_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_lock_bnt->msw_rescale();
|
||||
|
||||
@ -1060,6 +1399,19 @@ void ObjectManipulation::sys_color_changed()
|
||||
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' };
|
||||
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
||||
const std::string& opt_key,
|
||||
@ -1101,8 +1453,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
||||
parent->set_focused_editor(nullptr);
|
||||
|
||||
#if ENABLE_OBJECT_MANIPULATOR_FOCUS
|
||||
// if the widgets exchanging focus are both manipulator fields, call kill_focus
|
||||
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr)
|
||||
// if the widgets loosing focus is a manipulator field, call kill_focus
|
||||
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
|
||||
#else
|
||||
if (!m_enter_pressed)
|
||||
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <float.h>
|
||||
|
||||
@ -57,6 +60,10 @@ public:
|
||||
void set_value(const wxString& new_value);
|
||||
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:
|
||||
double get_value();
|
||||
};
|
||||
@ -113,9 +120,12 @@ private:
|
||||
wxStaticText* m_empty_str = nullptr;
|
||||
|
||||
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
||||
ScalableButton* m_reset_scale_button = nullptr;
|
||||
ScalableButton* m_reset_rotation_button = nullptr;
|
||||
ScalableButton* m_drop_to_bed_button = nullptr;
|
||||
ScalableButton* m_reset_scale_button{ nullptr };
|
||||
ScalableButton* m_reset_rotation_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};
|
||||
|
||||
@ -144,22 +154,35 @@ private:
|
||||
Vec3d m_new_size;
|
||||
bool m_new_enabled {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?
|
||||
bool m_world_coordinates = true;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
LockButton* m_lock_bnt{ nullptr };
|
||||
choice_ctrl* m_word_local_combo { nullptr };
|
||||
|
||||
ScalableBitmap m_manifold_warning_bmp;
|
||||
wxStaticBitmap* m_fix_throught_netfab_bitmap;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Currently focused editor (nullptr if none)
|
||||
ManipulationEditor* m_focused_editor{ nullptr };
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
// Currently focused editor (nullptr if none)
|
||||
ManipulationEditor* m_focused_editor {nullptr};
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
wxFlexGridSizer* m_main_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
|
||||
wxBoxSizer* m_word_local_combo_sizer;
|
||||
std::vector<wxBoxSizer*> m_rescalable_sizers;
|
||||
@ -180,11 +203,19 @@ public:
|
||||
// Called from the App to update the UI 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; }
|
||||
#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?
|
||||
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; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void reset_cache() { m_cache.reset(); }
|
||||
#ifndef __APPLE__
|
||||
@ -200,11 +231,23 @@ public:
|
||||
void sys_color_changed();
|
||||
void on_change(const std::string& opt_key, int axis, double new_value);
|
||||
void set_focused_editor(ManipulationEditor* focused_editor) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_focused_editor = focused_editor;
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
m_focused_editor = focused_editor;
|
||||
#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:
|
||||
void reset_settings_value();
|
||||
void update_settings_value(const Selection& selection);
|
||||
@ -220,6 +263,11 @@ private:
|
||||
void change_scale_value(int axis, double value);
|
||||
void change_size_value(int axis, double value);
|
||||
void do_scale(int axis, const Vec3d &scale) const;
|
||||
#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
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -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();
|
||||
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.
|
||||
std::vector<std::string> colors;
|
||||
@ -983,10 +983,11 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
||||
if (gcode_preview_data_valid) {
|
||||
// Load the real G-code preview.
|
||||
m_canvas->load_gcode_preview(*m_gcode_result, colors);
|
||||
m_left_sizer->Show(m_bottom_toolbar_panel);
|
||||
m_left_sizer->Layout();
|
||||
Refresh();
|
||||
zs = m_canvas->get_gcode_layers_zs();
|
||||
if (!zs.empty())
|
||||
m_left_sizer->Show(m_bottom_toolbar_panel);
|
||||
m_loaded = true;
|
||||
}
|
||||
else if (wxGetApp().is_editor()) {
|
||||
|
@ -331,7 +331,11 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
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;
|
||||
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));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
return Slic3r::string_printf("%.*f", decimals, value);
|
||||
|
@ -89,151 +89,156 @@ protected:
|
||||
static GLModel s_cone;
|
||||
#else
|
||||
GLModel m_cube;
|
||||
#endif // ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
};
|
||||
|
||||
public:
|
||||
enum EState
|
||||
{
|
||||
Off,
|
||||
On,
|
||||
Num_States
|
||||
};
|
||||
|
||||
struct 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)
|
||||
{}
|
||||
};
|
||||
|
||||
protected:
|
||||
GLCanvas3D& m_parent;
|
||||
int m_group_id; // TODO: remove only for rotate
|
||||
EState m_state;
|
||||
int m_shortcut_key;
|
||||
std::string m_icon_filename;
|
||||
unsigned int m_sprite_id;
|
||||
int m_hover_id;
|
||||
bool m_dragging;
|
||||
mutable std::vector<Grabber> m_grabbers;
|
||||
ImGuiWrapper* m_imgui;
|
||||
bool m_first_input_window_render;
|
||||
CommonGizmosDataPool* m_c;
|
||||
public:
|
||||
GLGizmoBase(GLCanvas3D& parent,
|
||||
const std::string& icon_filename,
|
||||
unsigned int sprite_id);
|
||||
virtual ~GLGizmoBase() = default;
|
||||
|
||||
bool init() { return on_init(); }
|
||||
|
||||
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
|
||||
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
|
||||
|
||||
std::string get_name(bool include_shortcut = true) const;
|
||||
|
||||
EState get_state() const { return m_state; }
|
||||
void set_state(EState state) { m_state = state; on_set_state(); }
|
||||
|
||||
int get_shortcut_key() const { return m_shortcut_key; }
|
||||
|
||||
const std::string& get_icon_filename() const { return m_icon_filename; }
|
||||
|
||||
bool is_activable() const { return on_is_activable(); }
|
||||
bool is_selectable() const { return on_is_selectable(); }
|
||||
CommonGizmosDataID get_requirements() const { return on_get_requirements(); }
|
||||
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_leaving_text() const { assert(false); return ""; }
|
||||
virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); }
|
||||
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
||||
int get_hover_id() const { return m_hover_id; }
|
||||
void set_hover_id(int id);
|
||||
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
|
||||
// returns True when Gizmo changed its state
|
||||
bool update_items_state();
|
||||
|
||||
void render() { on_render(); }
|
||||
void render_for_picking() { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
/// <summary>
|
||||
/// Mouse tooltip text
|
||||
/// </summary>
|
||||
/// <returns>Text to be visible in mouse tooltip</returns>
|
||||
virtual std::string get_tooltip() const { return ""; }
|
||||
|
||||
/// <summary>
|
||||
/// Is called when data (Selection) is changed
|
||||
/// </summary>
|
||||
virtual void data_changed(){};
|
||||
|
||||
/// <summary>
|
||||
/// Implement when want to process mouse events in gizmo
|
||||
/// Click, Right click, move, drag, ...
|
||||
/// </summary>
|
||||
/// <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>
|
||||
virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; }
|
||||
protected:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
|
||||
virtual std::string on_get_name() const = 0;
|
||||
virtual void on_set_state() {}
|
||||
virtual void on_set_hover_id() {}
|
||||
virtual bool on_is_activable() const { return true; }
|
||||
virtual bool on_is_selectable() const { return true; }
|
||||
virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); }
|
||||
virtual void on_enable_grabber(unsigned int id) {}
|
||||
virtual void on_disable_grabber(unsigned int id) {}
|
||||
|
||||
// called inside use_grabbers
|
||||
virtual void on_start_dragging() {}
|
||||
virtual void on_stop_dragging() {}
|
||||
virtual void on_dragging(const UpdateData& data) {}
|
||||
|
||||
virtual void on_render() = 0;
|
||||
virtual void on_render_for_picking() = 0;
|
||||
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
|
||||
// No check is made for clashing with other picking color (i.e. GLVolumes)
|
||||
ColorRGBA picking_color_component(unsigned int id) const;
|
||||
|
||||
void render_grabbers(const BoundingBoxf3& box) const;
|
||||
void render_grabbers(float size) const;
|
||||
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
|
||||
|
||||
std::string format(float value, unsigned int decimals) const;
|
||||
|
||||
// Mark gizmo as dirty to Re-Render when idle()
|
||||
void set_dirty();
|
||||
|
||||
/// <summary>
|
||||
/// function which
|
||||
/// Set up m_dragging and call functions
|
||||
/// on_start_dragging / on_dragging / on_stop_dragging
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>same as on_mouse</returns>
|
||||
bool use_grabbers(const wxMouseEvent &mouse_event);
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
bool m_dirty;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLGizmoBase_hpp_
|
||||
#endif // ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
};
|
||||
|
||||
public:
|
||||
enum EState
|
||||
{
|
||||
Off,
|
||||
On,
|
||||
Num_States
|
||||
};
|
||||
|
||||
struct 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)
|
||||
{}
|
||||
};
|
||||
|
||||
protected:
|
||||
GLCanvas3D& m_parent;
|
||||
int m_group_id; // TODO: remove only for rotate
|
||||
EState m_state;
|
||||
int m_shortcut_key;
|
||||
std::string m_icon_filename;
|
||||
unsigned int m_sprite_id;
|
||||
int m_hover_id;
|
||||
bool m_dragging;
|
||||
mutable std::vector<Grabber> m_grabbers;
|
||||
ImGuiWrapper* m_imgui;
|
||||
bool m_first_input_window_render;
|
||||
CommonGizmosDataPool* m_c;
|
||||
public:
|
||||
GLGizmoBase(GLCanvas3D& parent,
|
||||
const std::string& icon_filename,
|
||||
unsigned int sprite_id);
|
||||
virtual ~GLGizmoBase() = default;
|
||||
|
||||
bool init() { return on_init(); }
|
||||
|
||||
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
|
||||
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
|
||||
|
||||
std::string get_name(bool include_shortcut = true) const;
|
||||
|
||||
EState get_state() const { return m_state; }
|
||||
void set_state(EState state) { m_state = state; on_set_state(); }
|
||||
|
||||
int get_shortcut_key() const { return m_shortcut_key; }
|
||||
|
||||
const std::string& get_icon_filename() const { return m_icon_filename; }
|
||||
|
||||
bool is_activable() const { return on_is_activable(); }
|
||||
bool is_selectable() const { return on_is_selectable(); }
|
||||
CommonGizmosDataID get_requirements() const { return on_get_requirements(); }
|
||||
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_leaving_text() const { assert(false); return ""; }
|
||||
virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); }
|
||||
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
||||
int get_hover_id() const { return m_hover_id; }
|
||||
void set_hover_id(int id);
|
||||
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
|
||||
// returns True when Gizmo changed its state
|
||||
bool update_items_state();
|
||||
|
||||
void render() { on_render(); }
|
||||
void render_for_picking() { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
/// <summary>
|
||||
/// Mouse tooltip text
|
||||
/// </summary>
|
||||
/// <returns>Text to be visible in mouse tooltip</returns>
|
||||
virtual std::string get_tooltip() const { return ""; }
|
||||
|
||||
/// <summary>
|
||||
/// Is called when data (Selection) is changed
|
||||
/// </summary>
|
||||
virtual void data_changed(){};
|
||||
|
||||
/// <summary>
|
||||
/// Implement when want to process mouse events in gizmo
|
||||
/// Click, Right click, move, drag, ...
|
||||
/// </summary>
|
||||
/// <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>
|
||||
virtual bool on_mouse(const wxMouseEvent &mouse_event) { return false; }
|
||||
protected:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
|
||||
virtual std::string on_get_name() const = 0;
|
||||
virtual void on_set_state() {}
|
||||
virtual void on_set_hover_id() {}
|
||||
virtual bool on_is_activable() const { return true; }
|
||||
virtual bool on_is_selectable() const { return true; }
|
||||
virtual CommonGizmosDataID on_get_requirements() const { return CommonGizmosDataID(0); }
|
||||
virtual void on_enable_grabber(unsigned int id) {}
|
||||
virtual void on_disable_grabber(unsigned int id) {}
|
||||
|
||||
// called inside use_grabbers
|
||||
virtual void on_start_dragging() {}
|
||||
virtual void on_stop_dragging() {}
|
||||
virtual void on_dragging(const UpdateData& data) {}
|
||||
|
||||
virtual void on_render() = 0;
|
||||
virtual void on_render_for_picking() = 0;
|
||||
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
|
||||
// No check is made for clashing with other picking color (i.e. GLVolumes)
|
||||
ColorRGBA picking_color_component(unsigned int id) const;
|
||||
|
||||
void render_grabbers(const BoundingBoxf3& box) const;
|
||||
void render_grabbers(float size) const;
|
||||
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
|
||||
|
||||
std::string format(float value, unsigned int decimals) const;
|
||||
|
||||
// Mark gizmo as dirty to Re-Render when idle()
|
||||
void set_dirty();
|
||||
|
||||
/// <summary>
|
||||
/// function which
|
||||
/// Set up m_dragging and call functions
|
||||
/// on_start_dragging / on_dragging / on_stop_dragging
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>same as on_mouse</returns>
|
||||
bool use_grabbers(const wxMouseEvent &mouse_event);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void do_stop_dragging(bool perform_mouse_cleanup);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
bool m_dirty;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLGizmoBase_hpp_
|
||||
|
@ -122,8 +122,8 @@ void GLGizmoCut::on_render()
|
||||
// Z changed when move with cut plane
|
||||
// X and Y changed when move with cutted object
|
||||
bool is_changed = std::abs(diff.x()) > EPSILON ||
|
||||
std::abs(diff.y()) > EPSILON ||
|
||||
std::abs(diff.z()) > EPSILON;
|
||||
std::abs(diff.y()) > EPSILON ||
|
||||
std::abs(diff.z()) > EPSILON;
|
||||
#endif // !ENABLE_GL_CORE_PROFILE
|
||||
m_old_center = plane_center;
|
||||
|
||||
@ -132,7 +132,7 @@ void GLGizmoCut::on_render()
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
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_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");
|
||||
|
||||
// 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();
|
||||
|
||||
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()
|
||||
{
|
||||
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 ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
|
||||
|
@ -1,437 +1,441 @@
|
||||
#include "GLGizmoFdmSupports.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
//#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_shutdown()
|
||||
{
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string GLGizmoFdmSupports::on_get_name() const
|
||||
{
|
||||
return _u8L("Paint-on supports");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GLGizmoFdmSupports::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_L;
|
||||
|
||||
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size"] = _L("Brush size") + ": ";
|
||||
m_desc["cursor_type"] = _L("Brush shape") + ": ";
|
||||
m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
|
||||
m_desc["enforce"] = _L("Enforce supports");
|
||||
m_desc["block_caption"] = _L("Right mouse button") + ": ";
|
||||
m_desc["block"] = _L("Block supports");
|
||||
m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": ";
|
||||
m_desc["remove"] = _L("Remove selection");
|
||||
m_desc["remove_all"] = _L("Remove all selection");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_desc["highlight_by_angle"] = _L("Highlight overhang by angle");
|
||||
m_desc["enforce_button"] = _L("Enforce");
|
||||
m_desc["cancel"] = _L("Cancel");
|
||||
|
||||
m_desc["tool_type"] = _L("Tool type") + ": ";
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
|
||||
m_desc["split_triangles"] = _L("Split triangles");
|
||||
m_desc["on_overhangs_only"] = _L("On overhangs only");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::render_painter_gizmo()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
render_triangles(selection);
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (! m_c->selection_info()->model_object())
|
||||
return;
|
||||
|
||||
const float approx_height = m_imgui->scaled(23.f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
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:
|
||||
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);
|
||||
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 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 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_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_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 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 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_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 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 total_text_max = 0.f;
|
||||
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);
|
||||
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);
|
||||
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 slider_icon_width = m_imgui->get_slider_icon_size().x;
|
||||
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, button_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, 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, 2.f * buttons_width + m_imgui->scaled(1.f));
|
||||
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text(text);
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
float position_before_text_y = ImGui::GetCursorPos().y;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
float position_after_text_y = ImGui::GetCursorPos().y;
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
|
||||
"Degree sign to use in the respective slider in FDM supports gizmo,"
|
||||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
|
||||
float slider_height = m_imgui->get_slider_float_height();
|
||||
// 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);
|
||||
ImGui::SetCursorPosY(slider_start_position_y);
|
||||
|
||||
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 "
|
||||
"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)) {
|
||||
m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg);
|
||||
if (! m_parent.is_using_slope()) {
|
||||
m_parent.use_slope(true);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
|
||||
m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f);
|
||||
ImGui::NewLine();
|
||||
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)) {
|
||||
select_facets_by_angle(m_highlight_by_angle_threshold_deg, false);
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
}
|
||||
ImGui::SameLine(window_width - buttons_width);
|
||||
if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) {
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
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;
|
||||
ImGui::SameLine(tool_type_offset);
|
||||
ImGui::PushItemWidth(tool_type_radio_brush);
|
||||
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH))
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(tool_type_radio_smart_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL))
|
||||
m_tool_type = ToolType::SMART_FILL;
|
||||
|
||||
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->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
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);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_tool_type == ToolType::BRUSH) {
|
||||
m_imgui->text(m_desc.at("cursor_type"));
|
||||
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;
|
||||
ImGui::SameLine(cursor_type_offset);
|
||||
ImGui::PushItemWidth(cursor_type_radio_sphere);
|
||||
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
|
||||
m_cursor_type = TriangleSelector::CursorType::SPHERE;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(cursor_type_radio_circle);
|
||||
|
||||
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
|
||||
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(cursor_type_radio_pointer);
|
||||
|
||||
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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);
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
ImGui::SameLine(sliders_left_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->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width);
|
||||
|
||||
m_imgui->disabled_end();
|
||||
} else {
|
||||
assert(m_tool_type == ToolType::SMART_FILL);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["smart_fill_angle"] + ":");
|
||||
|
||||
ImGui::SameLine(sliders_left_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")))
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this](){
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_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")))
|
||||
m_c->object_clipper()->set_position(clp_dist, true);
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
int idx = -1;
|
||||
for (ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
++idx;
|
||||
m_triangle_selectors[idx]->reset();
|
||||
m_triangle_selectors[idx]->request_update_render_data();
|
||||
}
|
||||
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
m_imgui->end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
||||
{
|
||||
float threshold = (float(M_PI)/180.f)*threshold_deg;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
||||
|
||||
int mesh_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
++mesh_id;
|
||||
|
||||
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
|
||||
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
|
||||
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
|
||||
|
||||
float dot_limit = limit.dot(down);
|
||||
|
||||
// Now calculate dot product of vert_direction and facets' normals.
|
||||
int idx = 0;
|
||||
const indexed_triangle_set &its = mv->mesh().its;
|
||||
for (const stl_triangle_vertex_indices &face : its.indices) {
|
||||
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();
|
||||
}
|
||||
++ idx;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
++idx;
|
||||
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
|
||||
}
|
||||
|
||||
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();
|
||||
m_triangle_selectors.clear();
|
||||
|
||||
int volume_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
++volume_id;
|
||||
|
||||
// This mesh does not account for the possible Z up SLA offset.
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
|
||||
{
|
||||
wxString action_name;
|
||||
if (shift_down)
|
||||
action_name = _L("Remove selection");
|
||||
else {
|
||||
if (button_down == Button::Left)
|
||||
action_name = _L("Add supports");
|
||||
else
|
||||
action_name = _L("Block supports");
|
||||
}
|
||||
return action_name;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
#include "GLGizmoFdmSupports.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
//#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_shutdown()
|
||||
{
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string GLGizmoFdmSupports::on_get_name() const
|
||||
{
|
||||
return _u8L("Paint-on supports");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GLGizmoFdmSupports::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_L;
|
||||
|
||||
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size"] = _L("Brush size") + ": ";
|
||||
m_desc["cursor_type"] = _L("Brush shape") + ": ";
|
||||
m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
|
||||
m_desc["enforce"] = _L("Enforce supports");
|
||||
m_desc["block_caption"] = _L("Right mouse button") + ": ";
|
||||
m_desc["block"] = _L("Block supports");
|
||||
m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": ";
|
||||
m_desc["remove"] = _L("Remove selection");
|
||||
m_desc["remove_all"] = _L("Remove all selection");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["pointer"] = _L("Triangles");
|
||||
m_desc["highlight_by_angle"] = _L("Highlight overhang by angle");
|
||||
m_desc["enforce_button"] = _L("Enforce");
|
||||
m_desc["cancel"] = _L("Cancel");
|
||||
|
||||
m_desc["tool_type"] = _L("Tool type") + ": ";
|
||||
m_desc["tool_brush"] = _L("Brush");
|
||||
m_desc["tool_smart_fill"] = _L("Smart fill");
|
||||
|
||||
m_desc["smart_fill_angle"] = _L("Smart fill angle");
|
||||
|
||||
m_desc["split_triangles"] = _L("Split triangles");
|
||||
m_desc["on_overhangs_only"] = _L("On overhangs only");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::render_painter_gizmo()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
render_triangles(selection);
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (! m_c->selection_info()->model_object())
|
||||
return;
|
||||
|
||||
const float approx_height = m_imgui->scaled(23.f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
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:
|
||||
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);
|
||||
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 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 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_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_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 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 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_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 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 total_text_max = 0.f;
|
||||
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);
|
||||
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);
|
||||
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 slider_icon_width = m_imgui->get_slider_icon_size().x;
|
||||
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, button_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, 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, 2.f * buttons_width + m_imgui->scaled(1.f));
|
||||
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text(text);
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
float position_before_text_y = ImGui::GetCursorPos().y;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
float position_after_text_y = ImGui::GetCursorPos().y;
|
||||
std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
|
||||
"Degree sign to use in the respective slider in FDM supports gizmo,"
|
||||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_left_width);
|
||||
|
||||
float slider_height = m_imgui->get_slider_float_height();
|
||||
// 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);
|
||||
ImGui::SetCursorPosY(slider_start_position_y);
|
||||
|
||||
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 "
|
||||
"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)) {
|
||||
m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg);
|
||||
if (! m_parent.is_using_slope()) {
|
||||
m_parent.use_slope(true);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
|
||||
m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f);
|
||||
ImGui::NewLine();
|
||||
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)) {
|
||||
select_facets_by_angle(m_highlight_by_angle_threshold_deg, false);
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
}
|
||||
ImGui::SameLine(window_width - buttons_width);
|
||||
if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) {
|
||||
m_highlight_by_angle_threshold_deg = 0.f;
|
||||
m_parent.use_slope(false);
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
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;
|
||||
ImGui::SameLine(tool_type_offset);
|
||||
ImGui::PushItemWidth(tool_type_radio_brush);
|
||||
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH))
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(tool_type_radio_smart_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL))
|
||||
m_tool_type = ToolType::SMART_FILL;
|
||||
|
||||
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->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
|
||||
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);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_tool_type == ToolType::BRUSH) {
|
||||
m_imgui->text(m_desc.at("cursor_type"));
|
||||
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;
|
||||
ImGui::SameLine(cursor_type_offset);
|
||||
ImGui::PushItemWidth(cursor_type_radio_sphere);
|
||||
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
|
||||
m_cursor_type = TriangleSelector::CursorType::SPHERE;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(cursor_type_radio_circle);
|
||||
|
||||
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
|
||||
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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::PushItemWidth(cursor_type_radio_pointer);
|
||||
|
||||
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
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);
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
ImGui::SameLine(sliders_left_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->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width);
|
||||
|
||||
m_imgui->disabled_end();
|
||||
} else {
|
||||
assert(m_tool_type == ToolType::SMART_FILL);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc["smart_fill_angle"] + ":");
|
||||
|
||||
ImGui::SameLine(sliders_left_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")))
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_c->object_clipper()->get_position() == 0.f) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(m_desc.at("clipping_of_view"));
|
||||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this](){
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
auto clp_dist = float(m_c->object_clipper()->get_position());
|
||||
ImGui::SameLine(sliders_left_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")))
|
||||
m_c->object_clipper()->set_position(clp_dist, true);
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
int idx = -1;
|
||||
for (ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
++idx;
|
||||
m_triangle_selectors[idx]->reset();
|
||||
m_triangle_selectors[idx]->request_update_render_data();
|
||||
}
|
||||
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
m_imgui->end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
||||
{
|
||||
float threshold = (float(M_PI)/180.f)*threshold_deg;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
||||
|
||||
int mesh_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
++mesh_id;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
|
||||
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
|
||||
|
||||
float dot_limit = limit.dot(down);
|
||||
|
||||
// Now calculate dot product of vert_direction and facets' normals.
|
||||
int idx = 0;
|
||||
const indexed_triangle_set &its = mv->mesh().its;
|
||||
for (const stl_triangle_vertex_indices &face : its.indices) {
|
||||
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();
|
||||
}
|
||||
++ idx;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
++idx;
|
||||
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
|
||||
}
|
||||
|
||||
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();
|
||||
m_triangle_selectors.clear();
|
||||
|
||||
int volume_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
++volume_id;
|
||||
|
||||
// This mesh does not account for the possible Z up SLA offset.
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
|
||||
{
|
||||
wxString action_name;
|
||||
if (shift_down)
|
||||
action_name = _L("Remove selection");
|
||||
else {
|
||||
if (button_down == Button::Left)
|
||||
action_name = _L("Add supports");
|
||||
else
|
||||
action_name = _L("Block supports");
|
||||
}
|
||||
return action_name;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
@ -116,17 +116,17 @@ void GLGizmoFlatten::on_render()
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
|
||||
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
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
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("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
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()));
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (this->is_plane_update_necessary())
|
||||
@ -170,17 +170,17 @@ void GLGizmoFlatten::on_render_for_picking()
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
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
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
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("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
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()));
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (this->is_plane_update_necessary())
|
||||
@ -226,7 +226,11 @@ void GLGizmoFlatten::update_planes()
|
||||
}
|
||||
ch = ch.convex_hull_3d();
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Following constants are used for discarding too small polygons.
|
||||
const float minimal_area = 5.f; // in square mm (world coordinates)
|
||||
|
@ -94,7 +94,7 @@ void GLGizmoHollow::on_render_for_picking()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
//#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
|
||||
|
||||
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(); });
|
||||
#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();
|
||||
|
||||
#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_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 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 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();
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include "GLGizmoMove.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.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
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
@ -21,18 +24,29 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
|
||||
|
||||
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();
|
||||
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();
|
||||
|
||||
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)
|
||||
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)
|
||||
return "Z: " + format(show_position ? position(2) : m_displacement(2), 2);
|
||||
return "Z: " + format(show_position ? position.z() : m_displacement.z(), 2);
|
||||
else
|
||||
return "";
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
||||
@ -40,9 +54,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::data_changed() {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
m_grabbers[2].enabled = !is_wipe_tower;
|
||||
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_init()
|
||||
@ -79,11 +91,29 @@ void GLGizmoMove3D::on_start_dragging()
|
||||
assert(m_hover_id != -1);
|
||||
|
||||
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();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
m_starting_box_bottom_center(2) = box.min(2);
|
||||
m_starting_box_bottom_center.z() = box.min.z();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_stop_dragging()
|
||||
@ -102,7 +132,19 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
|
||||
m_displacement.z() = calc_projection(data);
|
||||
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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));
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
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 Vec3d& center = box.center();
|
||||
|
||||
@ -131,6 +201,7 @@ void GLGizmoMove3D::on_render()
|
||||
// z axis
|
||||
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
|
||||
m_grabbers[2].color = AXES_COLOR[2];
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_GL_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));
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto render_grabber_connection = [this, &zero](unsigned int id) {
|
||||
#else
|
||||
auto render_grabber_connection = [this, ¢er](unsigned int id) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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)) {
|
||||
m_grabber_connections[id].old_center = center;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_grabber_connections[id].model.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
@ -151,7 +231,11 @@ void GLGizmoMove3D::on_render()
|
||||
init_data.reserve_indices(2);
|
||||
|
||||
// vertices
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
init_data.add_vertex((Vec3f)zero.cast<float>());
|
||||
#else
|
||||
init_data.add_vertex((Vec3f)center.cast<float>());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
|
||||
|
||||
// indices
|
||||
@ -175,7 +259,11 @@ void GLGizmoMove3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -193,7 +281,11 @@ void GLGizmoMove3D::on_render()
|
||||
if (m_grabbers[i].enabled) {
|
||||
glsafe(::glColor4fv(AXES_COLOR[i].data()));
|
||||
::glBegin(GL_LINES);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
::glVertex3dv(zero.data());
|
||||
#else
|
||||
::glVertex3dv(center.data());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
::glVertex3dv(m_grabbers[i].center.data());
|
||||
glsafe(::glEnd());
|
||||
}
|
||||
@ -206,6 +298,19 @@ void GLGizmoMove3D::on_render()
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
// 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);
|
||||
#if !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
@ -213,6 +318,7 @@ void GLGizmoMove3D::on_render()
|
||||
render_grabber_extension((Axis)i, box, false);
|
||||
}
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else {
|
||||
// draw axis
|
||||
@ -226,7 +332,11 @@ void GLGizmoMove3D::on_render()
|
||||
shader->start_using();
|
||||
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -243,7 +353,11 @@ void GLGizmoMove3D::on_render()
|
||||
#else
|
||||
glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data()));
|
||||
::glBegin(GL_LINES);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
::glVertex3dv(zero.data());
|
||||
#else
|
||||
::glVertex3dv(center.data());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
::glVertex3dv(m_grabbers[m_hover_id].center.data());
|
||||
glsafe(::glEnd());
|
||||
|
||||
@ -253,20 +367,65 @@ void GLGizmoMove3D::on_render()
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
// 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);
|
||||
shader->stop_using();
|
||||
}
|
||||
#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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#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()
|
||||
{
|
||||
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();
|
||||
render_grabbers_for_picking(box);
|
||||
#if !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
@ -274,23 +433,24 @@ void GLGizmoMove3D::on_render_for_picking()
|
||||
render_grabber_extension(Y, box, true);
|
||||
render_grabber_extension(Z, box, true);
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
||||
{
|
||||
double projection = 0.0;
|
||||
|
||||
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
|
||||
double len_starting_vec = starting_vec.norm();
|
||||
const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
|
||||
const double len_starting_vec = starting_vec.norm();
|
||||
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
|
||||
// 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)
|
||||
// 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
|
||||
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
|
||||
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_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)
|
||||
#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));
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
@ -361,5 +526,62 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
|
||||
}
|
||||
#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 Slic3r
|
||||
|
@ -7,11 +7,19 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoMove3D : public GLGizmoBase
|
||||
{
|
||||
static const double Offset;
|
||||
|
||||
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 };
|
||||
Vec3d m_starting_drag_position{ Vec3d::Zero() };
|
||||
Vec3d m_starting_box_center{ Vec3d::Zero() };
|
||||
@ -49,7 +57,6 @@ public:
|
||||
/// Detect reduction of move for wipetover on selection change
|
||||
/// </summary>
|
||||
void data_changed() override;
|
||||
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
@ -62,11 +69,25 @@ protected:
|
||||
|
||||
private:
|
||||
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_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);
|
||||
#endif // ENABLE_WORLD_COORDINATE && ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -324,7 +324,11 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
|
||||
return;
|
||||
#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();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed();
|
||||
|
||||
#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 ModelObject *mo = m_c->selection_info()->model_object();
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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_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 ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Precalculate transformations of individual meshes.
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
@ -586,7 +598,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
for (const ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
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 ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Precalculate transformations of individual meshes.
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
@ -676,7 +696,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
for (const ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
// Now "click" into all the prepared points and spill paint around them.
|
||||
|
@ -2,15 +2,18 @@
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -99,6 +102,9 @@ bool GLGizmoRotate::on_init()
|
||||
|
||||
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();
|
||||
m_center = box.center();
|
||||
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_fine_in_radius = m_radius;
|
||||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_dragging(const UpdateData &data)
|
||||
@ -151,15 +158,21 @@ void GLGizmoRotate::on_render()
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_hover_id != 0 && !m_grabbers.front().dragging) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
init_data_from_selection(selection);
|
||||
#else
|
||||
m_center = box.center();
|
||||
m_radius = Offset + 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_radius * (1.0f + ScaleLongTooth);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
|
||||
@ -234,10 +247,17 @@ void GLGizmoRotate::on_render()
|
||||
render_angle();
|
||||
#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);
|
||||
#if !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
render_grabber_extension(box, false);
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if !ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
glsafe(::glPopMatrix());
|
||||
@ -257,17 +277,73 @@ void GLGizmoRotate::on_render_for_picking()
|
||||
transform_to_local(selection);
|
||||
#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();
|
||||
render_grabbers_for_picking(box);
|
||||
#if !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
render_grabber_extension(box, true);
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if !ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
glsafe(::glPopMatrix());
|
||||
#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)
|
||||
{
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
@ -328,10 +404,10 @@ void GLGizmoRotate::render_circle() const
|
||||
#else
|
||||
::glBegin(GL_LINE_LOOP);
|
||||
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
|
||||
float angle = (float)i * ScaleStepRad;
|
||||
float x = ::cos(angle) * m_radius;
|
||||
float y = ::sin(angle) * m_radius;
|
||||
float z = 0.0f;
|
||||
const float angle = float(i) * ScaleStepRad;
|
||||
const float x = ::cos(angle) * m_radius;
|
||||
const float y = ::sin(angle) * m_radius;
|
||||
const float z = 0.0f;
|
||||
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
|
||||
}
|
||||
glsafe(::glEnd());
|
||||
@ -530,10 +606,10 @@ void GLGizmoRotate::render_angle() const
|
||||
#else
|
||||
::glBegin(GL_LINE_STRIP);
|
||||
for (unsigned int i = 0; i <= AngleResolution; ++i) {
|
||||
float angle = (float)i * step_angle;
|
||||
float x = ::cos(angle) * ex_radius;
|
||||
float y = ::sin(angle) * ex_radius;
|
||||
float z = 0.0f;
|
||||
const float angle = float(i) * step_angle;
|
||||
const float x = ::cos(angle) * ex_radius;
|
||||
const float y = ::sin(angle) * ex_radius;
|
||||
const float z = 0.0f;
|
||||
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
|
||||
}
|
||||
glsafe(::glEnd());
|
||||
@ -670,12 +746,20 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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())
|
||||
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;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
#else
|
||||
void GLGizmoRotate::transform_to_local(const Selection& selection) const
|
||||
{
|
||||
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()) {
|
||||
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()));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
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())
|
||||
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);
|
||||
|
||||
@ -775,31 +871,51 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging() && m_dragging) {
|
||||
// Apply new temporary rotations
|
||||
TransformationType transformation_type(
|
||||
TransformationType::World_Relative_Joint);
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
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);
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::data_changed() {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
if (is_wipe_tower) {
|
||||
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
float wipe_tower_rotation_angle =
|
||||
dynamic_cast<const ConfigOptionFloat *>(
|
||||
config.option("wipe_tower_rotation_angle"))
|
||||
->value;
|
||||
if (m_parent.get_selection().is_wipe_tower()) {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
const float wipe_tower_rotation_angle =
|
||||
dynamic_cast<const ConfigOptionFloat*>(
|
||||
config.option("wipe_tower_rotation_angle"))->value;
|
||||
set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_gizmos[0].disable_grabber();
|
||||
m_gizmos[1].disable_grabber();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
set_rotation(Vec3d::Zero());
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_gizmos[0].enable_grabber();
|
||||
m_gizmos[1].enable_grabber();
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
set_rotation(Vec3d::Zero());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoRotate3D::on_init()
|
||||
|
@ -34,6 +34,10 @@ private:
|
||||
float m_snap_coarse_out_radius{ 0.0f };
|
||||
float m_snap_fine_in_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
|
||||
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
|
||||
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
|
||||
@ -129,7 +137,7 @@ public:
|
||||
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()); }
|
||||
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 tooltip = m_gizmos[X].get_tooltip();
|
||||
|
@ -2,19 +2,22 @@
|
||||
#include "GLGizmoScale.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.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
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <wx/utils.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
namespace Slic3r {
|
||||
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)
|
||||
: 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
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d scale = 100.0 * m_scale;
|
||||
#else
|
||||
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();
|
||||
|
||||
Vec3f scale = 100.0f * Vec3f::Ones();
|
||||
if (single_instance)
|
||||
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>();
|
||||
else if (single_volume)
|
||||
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
|
||||
Vec3d scale = 100.0 * Vec3d::Ones();
|
||||
if (selection.is_single_full_instance())
|
||||
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume())
|
||||
scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
|
||||
return "X: " + format(scale.x(), 4) + "%";
|
||||
@ -72,12 +76,28 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
if (mouse_event.Dragging()) {
|
||||
if (m_dragging) {
|
||||
// Apply new temporary scale factors
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
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();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
transformation_type.set_relative();
|
||||
#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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
@ -85,26 +105,29 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
|
||||
void GLGizmoScale3D::data_changed()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||
selection.is_single_volume() ||
|
||||
selection.is_single_modifier();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
set_scale(Vec3d::Ones());
|
||||
#else
|
||||
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)
|
||||
m_grabbers[i].enabled = enable_scale_xyz;
|
||||
|
||||
if (enable_scale_xyz) {
|
||||
// all volumes in the selection belongs to the same instance, any of
|
||||
// them contains the needed data, so we take the first
|
||||
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
if (selection.is_single_full_instance()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
if (selection.is_single_full_instance())
|
||||
set_scale(volume->get_instance_scaling_factor());
|
||||
} else if (selection.is_single_volume() ||
|
||||
selection.is_single_modifier()) {
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
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()
|
||||
@ -113,15 +136,17 @@ bool GLGizmoScale3D::on_init()
|
||||
m_grabbers.push_back(Grabber());
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
double half_pi = 0.5 * (double)PI;
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].angles(1) = half_pi;
|
||||
m_grabbers[1].angles(1) = half_pi;
|
||||
m_grabbers[0].angles.y() = half_pi;
|
||||
m_grabbers[1].angles.y() = half_pi;
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].angles(0) = half_pi;
|
||||
m_grabbers[3].angles(0) = half_pi;
|
||||
m_grabbers[2].angles.x() = half_pi;
|
||||
m_grabbers[3].angles.x() = half_pi;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_shortcut_key = WXK_CONTROL_S;
|
||||
|
||||
@ -142,9 +167,15 @@ bool GLGizmoScale3D::on_is_activable() const
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
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();
|
||||
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[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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_stop_dragging() {
|
||||
@ -175,78 +207,156 @@ void GLGizmoScale3D::on_render()
|
||||
{
|
||||
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(::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();
|
||||
// Transforms grabbers' offsets to world refefence system
|
||||
Transform3d offsets_transform = Transform3d::Identity();
|
||||
m_offsets_transform = Transform3d::Identity();
|
||||
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
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
for (unsigned int idx : idxs) {
|
||||
const GLVolume* vol = selection.get_volume(idx);
|
||||
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
|
||||
const GLVolume& v = *selection.get_volume(idx);
|
||||
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
|
||||
const GLVolume* v = selection.get_volume(*idxs.begin());
|
||||
m_transform = v->get_instance_transformation().get_matrix();
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#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
|
||||
angles = v->get_instance_rotation();
|
||||
angles = v.get_instance_rotation();
|
||||
// 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;
|
||||
}
|
||||
else if (single_volume) {
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_box = v->bounding_box();
|
||||
m_transform = v->world_matrix();
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#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);
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
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());
|
||||
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());
|
||||
}
|
||||
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_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// 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[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];
|
||||
|
||||
// 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[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];
|
||||
|
||||
// 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[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];
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_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[8].center = m_transform * Vec3d(m_box.max.x(), m_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[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_bounding_box.max.x(), m_bounding_box.min.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_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y;
|
||||
|
||||
for (int i = 6; i < 10; ++i) {
|
||||
m_grabbers[i].color = m_highlight_color;
|
||||
}
|
||||
@ -255,15 +365,29 @@ void GLGizmoScale3D::on_render()
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
m_grabbers[i].angles = angles;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
if (!OpenGLManager::get_gl_info().is_core_profile())
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_hover_id == -1) {
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
@ -276,7 +400,11 @@ void GLGizmoScale3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -331,7 +459,11 @@ void GLGizmoScale3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -347,7 +479,7 @@ void GLGizmoScale3D::on_render()
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
#else
|
||||
// draw connection
|
||||
glsafe(::glColor4fv(m_grabbers[0].color.data()));
|
||||
glsafe(::glColor4fv(AXES_COLOR[0].data()));
|
||||
render_grabbers_connection(0, 1);
|
||||
|
||||
// draw grabbers
|
||||
@ -372,7 +504,11 @@ void GLGizmoScale3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -388,7 +524,7 @@ void GLGizmoScale3D::on_render()
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
#else
|
||||
// draw connection
|
||||
glsafe(::glColor4fv(m_grabbers[2].color.data()));
|
||||
glsafe(::glColor4fv(AXES_COLOR[1].data()));
|
||||
render_grabbers_connection(2, 3);
|
||||
|
||||
// draw grabbers
|
||||
@ -413,7 +549,11 @@ void GLGizmoScale3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -429,7 +569,7 @@ void GLGizmoScale3D::on_render()
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
#else
|
||||
// draw connection
|
||||
glsafe(::glColor4fv(m_grabbers[4].color.data()));
|
||||
glsafe(::glColor4fv(AXES_COLOR[2].data()));
|
||||
render_grabbers_connection(4, 5);
|
||||
|
||||
// draw grabbers
|
||||
@ -454,7 +594,11 @@ void GLGizmoScale3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -491,12 +635,34 @@ void GLGizmoScale3D::on_render()
|
||||
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()
|
||||
{
|
||||
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());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
{
|
||||
double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
Vec3d curr_scale = m_scale;
|
||||
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) {
|
||||
m_scale(axis) = m_starting.scale(axis) * ratio;
|
||||
|
||||
if (m_starting.ctrl_down) {
|
||||
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
|
||||
|
||||
if (m_hover_id == 2 * axis)
|
||||
local_offset *= -1.0;
|
||||
|
||||
@ -577,36 +797,86 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
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)
|
||||
{
|
||||
double ratio = calc_ratio(data);
|
||||
const double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
m_scale = m_starting.scale * ratio;
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||
{
|
||||
double ratio = 0.0;
|
||||
|
||||
Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.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) {
|
||||
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
|
||||
// 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)
|
||||
// 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
|
||||
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
|
||||
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;
|
||||
}
|
||||
@ -617,5 +887,34 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||
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 Slic3r
|
||||
|
@ -3,31 +3,46 @@
|
||||
|
||||
#include "GLGizmoBase.hpp"
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoScale3D : public GLGizmoBase
|
||||
{
|
||||
static const float Offset;
|
||||
static const double Offset;
|
||||
|
||||
struct StartingData
|
||||
{
|
||||
Vec3d scale;
|
||||
Vec3d drag_position;
|
||||
bool ctrl_down{ false };
|
||||
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;
|
||||
Vec3d pivots[6];
|
||||
bool ctrl_down;
|
||||
|
||||
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
std::array<Vec3d, 6> pivots{ Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
mutable BoundingBoxf3 m_box;
|
||||
mutable Transform3d m_transform;
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
#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)
|
||||
mutable Transform3d m_offsets_transform;
|
||||
Transform3d m_offsets_transform;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3d m_scale{ Vec3d::Ones() };
|
||||
Vec3d m_offset{ Vec3d::Zero() };
|
||||
double m_snap_step{ 0.05 };
|
||||
@ -54,7 +69,11 @@ public:
|
||||
void set_snap_step(double step) { m_snap_step = step; }
|
||||
|
||||
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; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
@ -87,6 +106,13 @@ private:
|
||||
void do_scale_uniform(const UpdateData& data);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
@ -146,9 +146,13 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
});
|
||||
#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());
|
||||
#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();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#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 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 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();
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
|
||||
|
||||
|
@ -119,7 +119,7 @@ void SelectionInfo::on_update()
|
||||
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
||||
if (selection.is_single_full_instance()) {
|
||||
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
|
||||
m_model_object = nullptr;
|
||||
|
@ -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
|
||||
// tools bar e.g. Do not interupt dragging.
|
||||
return false;
|
||||
} else if (mc.exist_tooltip) {
|
||||
}
|
||||
else if (mc.exist_tooltip) {
|
||||
// first move out of gizmo tool bar - unselect tooltip
|
||||
mc.exist_tooltip = false;
|
||||
update_hover_state(Undefined);
|
||||
@ -423,10 +424,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
|
||||
mc.left = true;
|
||||
open_gizmo(gizmo);
|
||||
return true;
|
||||
} else if (mouse_event.RightDown()) {
|
||||
}
|
||||
else if (mouse_event.RightDown()) {
|
||||
mc.right = true;
|
||||
return true;
|
||||
} else if (mouse_event.MiddleDown()) {
|
||||
}
|
||||
else if (mouse_event.MiddleDown()) {
|
||||
mc.middle = true;
|
||||
return true;
|
||||
}
|
||||
@ -441,14 +444,17 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
|
||||
update_hover_state(Undefined);
|
||||
}
|
||||
// draging start on toolbar so no propagation into scene
|
||||
return true;
|
||||
} else if (mc.left && mouse_event.LeftUp()) {
|
||||
return true;
|
||||
}
|
||||
else if (mc.left && mouse_event.LeftUp()) {
|
||||
mc.left = false;
|
||||
return true;
|
||||
} else if (mc.right && mouse_event.RightUp()) {
|
||||
}
|
||||
else if (mc.right && mouse_event.RightUp()) {
|
||||
mc.right = false;
|
||||
return true;
|
||||
} else if (mc.middle && mouse_event.MiddleUp()) {
|
||||
}
|
||||
else if (mc.middle && mouse_event.MiddleUp()) {
|
||||
mc.middle = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ public:
|
||||
bool handle_shortcut(int key);
|
||||
|
||||
bool is_dragging() const;
|
||||
|
||||
|
||||
ClippingPlane get_clipping_plane() const;
|
||||
bool wants_reslice_supports_on_undo() const;
|
||||
|
||||
|
@ -38,22 +38,18 @@ class PlaterWorker: public Worker {
|
||||
|
||||
void update_status(int st, const std::string &msg = "") override
|
||||
{
|
||||
wxWakeUpIdle();
|
||||
ctl.update_status(st, msg);
|
||||
|
||||
// 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();
|
||||
wxWakeUpIdle();
|
||||
}
|
||||
|
||||
bool was_canceled() const override { return ctl.was_canceled(); }
|
||||
|
||||
std::future<void> call_on_main_thread(std::function<void()> fn) override
|
||||
{
|
||||
auto ftr = ctl.call_on_main_thread(std::move(fn));
|
||||
wxWakeUpIdle();
|
||||
return ctl.call_on_main_thread(std::move(fn));
|
||||
|
||||
return ftr;
|
||||
}
|
||||
|
||||
} wctl{c};
|
||||
|
@ -62,7 +62,15 @@ protected:
|
||||
|
||||
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:
|
||||
|
@ -108,7 +108,11 @@ void MeshClipper::render_cut()
|
||||
|
||||
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>();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// 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 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;
|
||||
|
||||
#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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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();
|
||||
direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());
|
||||
|
@ -57,6 +57,9 @@
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
@ -1514,6 +1517,11 @@ void Sidebar::update_mode()
|
||||
|
||||
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->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_ROTATED, &priv::on_wipetower_rotated, this);
|
||||
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_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);
|
||||
@ -2922,7 +2933,7 @@ int Plater::priv::get_selected_volume_idx() const
|
||||
if ((0 > idx) || (idx > 1000))
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
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)
|
||||
return v->volume_idx();
|
||||
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_material_id(old_volume->material_id());
|
||||
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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
|
||||
if (old_volume->source.is_converted_from_inches)
|
||||
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)
|
||||
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 volume_idx = v->volume_idx();
|
||||
|
||||
@ -3839,10 +3854,16 @@ void Plater::priv::reload_from_disk()
|
||||
new_volume->config.apply(old_volume->config);
|
||||
new_volume->set_type(old_volume->type());
|
||||
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()) *
|
||||
old_volume->get_transformation().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));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
new_volume->source.object_idx = old_volume->source.object_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);
|
||||
@ -4448,8 +4469,12 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
|
||||
const bool is_some_full_instances = selection.is_single_full_instance() ||
|
||||
selection.is_single_full_object() ||
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -6030,7 +6055,7 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
|
||||
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());
|
||||
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.transform(volume->get_volume_transformation().get_matrix(), true);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,12 @@
|
||||
#define slic3r_GUI_Selection_hpp_
|
||||
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include <set>
|
||||
#include <optional>
|
||||
@ -24,6 +29,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
|
||||
|
||||
|
||||
namespace GUI {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class TransformationType
|
||||
{
|
||||
public:
|
||||
@ -76,6 +82,7 @@ private:
|
||||
|
||||
Enum m_value;
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
class Selection
|
||||
{
|
||||
@ -110,16 +117,19 @@ private:
|
||||
private:
|
||||
struct TransformCache
|
||||
{
|
||||
Vec3d position;
|
||||
Vec3d rotation;
|
||||
Vec3d scaling_factor;
|
||||
Vec3d mirror;
|
||||
Transform3d rotation_matrix;
|
||||
Transform3d scale_matrix;
|
||||
Transform3d mirror_matrix;
|
||||
Transform3d full_matrix;
|
||||
Vec3d position{ Vec3d::Zero() };
|
||||
Vec3d rotation{ Vec3d::Zero() };
|
||||
Vec3d scaling_factor{ Vec3d::Ones() };
|
||||
Vec3d mirror{ Vec3d::Ones() };
|
||||
Transform3d rotation_matrix{ Transform3d::Identity() };
|
||||
Transform3d scale_matrix{ Transform3d::Identity() };
|
||||
Transform3d mirror_matrix{ Transform3d::Identity() };
|
||||
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);
|
||||
};
|
||||
|
||||
@ -131,13 +141,18 @@ private:
|
||||
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
|
||||
|
||||
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_scaling_factor() const { return m_volume.scaling_factor; }
|
||||
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_scale_matrix() const { return m_volume.scale_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; }
|
||||
#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_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_mirror_matrix() const { return m_instance.mirror_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:
|
||||
@ -207,15 +225,32 @@ private:
|
||||
Cache m_cache;
|
||||
Clipboard m_clipboard;
|
||||
std::optional<BoundingBoxf3> m_bounding_box;
|
||||
// Bounding box of a selection, with no instance scaling applied. This bounding box
|
||||
// is useful for absolute scaling of tilted objects in world coordinate space.
|
||||
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
|
||||
// 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;
|
||||
// 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;
|
||||
#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
|
||||
GLModel m_vbo_sphere;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
CoordAxes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
GLModel m_arrow;
|
||||
GLModel m_curved_arrow;
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
@ -290,6 +325,9 @@ public:
|
||||
bool is_from_single_object() const;
|
||||
bool is_sla_compliant() const;
|
||||
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(); }
|
||||
// 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
|
||||
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;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Returns the the object id if the selection is from a single object, otherwise is -1
|
||||
int get_object_idx() const;
|
||||
@ -311,28 +360,60 @@ public:
|
||||
|
||||
const IndicesList& get_volume_idxs() const { return m_list; }
|
||||
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; }
|
||||
|
||||
unsigned int volumes_count() const { return (unsigned int)m_list.size(); }
|
||||
const BoundingBoxf3& get_bounding_box() const;
|
||||
// Bounding box of a selection, with no instance scaling applied. This bounding box
|
||||
// is useful for absolute scaling of tilted objects in world coordinate space.
|
||||
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
|
||||
// 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;
|
||||
// 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;
|
||||
#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();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void translate(const Vec3d& displacement, TransformationType transformation_type);
|
||||
#else
|
||||
void translate(const Vec3d& displacement, bool local = false);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||
void flattening_rotate(const Vec3d& normal);
|
||||
void scale(const Vec3d& scale, TransformationType transformation_type);
|
||||
void scale_to_fit_print_volume(const BuildVolume& volume);
|
||||
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);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
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 render(float scale_factor = 1.0);
|
||||
@ -368,10 +449,25 @@ private:
|
||||
void do_remove_volume(unsigned int volume_idx);
|
||||
void do_remove_instance(unsigned int object_idx, unsigned int instance_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(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void render_synchronized_volumes();
|
||||
#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);
|
||||
#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_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);
|
||||
@ -386,11 +482,15 @@ private:
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
public:
|
||||
enum SyncRotationType {
|
||||
enum class SyncRotationType {
|
||||
// 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.
|
||||
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_volumes();
|
||||
@ -402,6 +502,11 @@ private:
|
||||
|
||||
void paste_volumes_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
|
||||
|
@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event)
|
||||
if (m_disabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
SetLock(!m_is_pushed);
|
||||
#else
|
||||
m_is_pushed = !m_is_pushed;
|
||||
update_button_bitmaps();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
@ -7,12 +7,42 @@
|
||||
|
||||
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;
|
||||
const PointGrid<float> &grid;
|
||||
size_t final;
|
||||
|
||||
PointGridTracer(const PointGrid<float> &g, size_t goal) :
|
||||
PointGridTracer3D(const PointGrid<float> &g, size_t goal) :
|
||||
grid{g}, final{goal} {}
|
||||
|
||||
template<class Fn>
|
||||
@ -49,14 +79,328 @@ struct PointGridTracer {
|
||||
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]") {
|
||||
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});
|
||||
|
||||
PointGridTracer pgt{pgrid, pgrid.point_count() - 1};
|
||||
size_t target = pgrid.point_count() - 1;
|
||||
|
||||
PointGridTracer3D pgt{pgrid, target};
|
||||
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(!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);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ add_executable(${_TEST_NAME}_tests
|
||||
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)
|
||||
target_link_libraries(${_TEST_NAME}_tests Setupapi.lib)
|
||||
endif ()
|
||||
|
Loading…
Reference in New Issue
Block a user