2018-11-26 14:19:42 +00:00
// Include GLGizmo.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
# include "GLGizmo.hpp"
2018-06-13 13:44:04 +00:00
# include <GL/glew.h>
2018-11-26 13:41:58 +00:00
# include <Eigen/Dense>
2018-06-13 07:12:16 +00:00
2018-11-26 13:41:58 +00:00
# include "libslic3r/libslic3r.h"
# include "libslic3r/Geometry.hpp"
# include "libslic3r/Utils.hpp"
# include "libslic3r/SLA/SLASupportTree.hpp"
2018-12-21 11:35:20 +00:00
# include "libslic3r/SLAPrint.hpp"
2018-11-06 17:01:18 +00:00
2018-10-18 13:13:38 +00:00
# include <cstdio>
2018-08-20 11:02:54 +00:00
# include <numeric>
2018-10-18 13:13:38 +00:00
# include <algorithm>
# include <wx/sizer.h>
# include <wx/panel.h>
# include <wx/button.h>
# include <wx/checkbox.h>
# include <wx/stattext.h>
# include <wx/debug.h>
2018-12-07 13:10:16 +00:00
# include "Tab.hpp"
2018-10-18 13:13:38 +00:00
# include "GUI.hpp"
# include "GUI_Utils.hpp"
# include "GUI_App.hpp"
2018-11-26 13:41:58 +00:00
# include "I18N.hpp"
# include "PresetBundle.hpp"
2018-10-18 13:13:38 +00:00
2018-11-22 09:14:31 +00:00
# include <wx/defs.h>
2018-10-18 13:13:38 +00:00
// TODO: Display tooltips quicker on Linux
2018-06-13 07:12:16 +00:00
2018-08-20 08:23:17 +00:00
static const float DEFAULT_BASE_COLOR [ 3 ] = { 0.625f , 0.625f , 0.625f } ;
static const float DEFAULT_DRAG_COLOR [ 3 ] = { 1.0f , 1.0f , 1.0f } ;
static const float DEFAULT_HIGHLIGHT_COLOR [ 3 ] = { 1.0f , 0.38f , 0.0f } ;
2018-09-07 11:40:26 +00:00
static const float AXES_COLOR [ 3 ] [ 3 ] = { { 1.0f , 0.0f , 0.0f } , { 0.0f , 1.0f , 0.0f } , { 0.0f , 0.0f , 1.0f } } ;
2018-08-21 06:50:35 +00:00
2018-06-13 07:12:16 +00:00
namespace Slic3r {
namespace GUI {
2018-09-11 12:48:17 +00:00
const float GLGizmoBase : : Grabber : : SizeFactor = 0.025f ;
const float GLGizmoBase : : Grabber : : MinHalfSize = 1.5f ;
2018-08-20 08:23:17 +00:00
const float GLGizmoBase : : Grabber : : DraggingScaleFactor = 1.25f ;
2018-06-15 12:10:28 +00:00
GLGizmoBase : : Grabber : : Grabber ( )
2018-08-28 11:23:28 +00:00
: center ( Vec3d : : Zero ( ) )
, angles ( Vec3d : : Zero ( ) )
2018-08-20 08:23:17 +00:00
, dragging ( false )
2018-09-11 10:40:42 +00:00
, enabled ( true )
2018-06-15 12:10:28 +00:00
{
color [ 0 ] = 1.0f ;
color [ 1 ] = 1.0f ;
color [ 2 ] = 1.0f ;
}
2018-10-12 14:18:37 +00:00
void GLGizmoBase : : Grabber : : render ( bool hover , float size ) const
2018-06-15 12:10:28 +00:00
{
2018-08-20 08:23:17 +00:00
float render_color [ 3 ] ;
if ( hover )
{
render_color [ 0 ] = 1.0f - color [ 0 ] ;
render_color [ 1 ] = 1.0f - color [ 1 ] ;
render_color [ 2 ] = 1.0f - color [ 2 ] ;
}
else
: : memcpy ( ( void * ) render_color , ( const void * ) color , 3 * sizeof ( float ) ) ;
2018-06-15 12:10:28 +00:00
2018-10-12 14:18:37 +00:00
render ( size , render_color , true ) ;
2018-08-20 08:23:17 +00:00
}
2018-11-15 09:16:51 +00:00
float GLGizmoBase : : Grabber : : get_half_size ( float size ) const
{
return std : : max ( size * SizeFactor , MinHalfSize ) ;
}
float GLGizmoBase : : Grabber : : get_dragging_half_size ( float size ) const
{
return std : : max ( size * SizeFactor * DraggingScaleFactor , MinHalfSize ) ;
}
2018-10-12 14:18:37 +00:00
void GLGizmoBase : : Grabber : : render ( float size , const float * render_color , bool use_lighting ) const
2018-08-20 08:23:17 +00:00
{
2018-11-15 09:16:51 +00:00
float half_size = dragging ? get_dragging_half_size ( size ) : get_half_size ( size ) ;
2018-09-11 12:48:17 +00:00
2018-08-21 12:27:36 +00:00
if ( use_lighting )
: : glEnable ( GL_LIGHTING ) ;
2018-08-20 08:23:17 +00:00
2018-10-11 08:52:50 +00:00
: : glColor3fv ( render_color ) ;
2018-06-15 12:10:28 +00:00
2018-06-15 14:16:55 +00:00
: : glPushMatrix ( ) ;
2018-10-11 08:52:50 +00:00
: : glTranslated ( center ( 0 ) , center ( 1 ) , center ( 2 ) ) ;
2018-08-20 08:23:17 +00:00
2018-10-15 09:30:50 +00:00
: : glRotated ( Geometry : : rad2deg ( angles ( 2 ) ) , 0.0 , 0.0 , 1.0 ) ;
: : glRotated ( Geometry : : rad2deg ( angles ( 1 ) ) , 0.0 , 1.0 , 0.0 ) ;
: : glRotated ( Geometry : : rad2deg ( angles ( 0 ) ) , 1.0 , 0.0 , 0.0 ) ;
2018-06-15 14:16:55 +00:00
2018-08-21 12:27:36 +00:00
// face min x
: : glPushMatrix ( ) ;
: : glTranslatef ( - ( GLfloat ) half_size , 0.0f , 0.0f ) ;
: : glRotatef ( - 90.0f , 0.0f , 1.0f , 0.0f ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
// face max x
: : glPushMatrix ( ) ;
: : glTranslatef ( ( GLfloat ) half_size , 0.0f , 0.0f ) ;
: : glRotatef ( 90.0f , 0.0f , 1.0f , 0.0f ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
// face min y
: : glPushMatrix ( ) ;
: : glTranslatef ( 0.0f , - ( GLfloat ) half_size , 0.0f ) ;
: : glRotatef ( 90.0f , 1.0f , 0.0f , 0.0f ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
// face max y
: : glPushMatrix ( ) ;
: : glTranslatef ( 0.0f , ( GLfloat ) half_size , 0.0f ) ;
: : glRotatef ( - 90.0f , 1.0f , 0.0f , 0.0f ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
// face min z
: : glPushMatrix ( ) ;
: : glTranslatef ( 0.0f , 0.0f , - ( GLfloat ) half_size ) ;
: : glRotatef ( 180.0f , 1.0f , 0.0f , 0.0f ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
// face max z
: : glPushMatrix ( ) ;
: : glTranslatef ( 0.0f , 0.0f , ( GLfloat ) half_size ) ;
render_face ( half_size ) ;
: : glPopMatrix ( ) ;
2018-06-15 12:10:28 +00:00
2018-06-15 14:16:55 +00:00
: : glPopMatrix ( ) ;
2018-08-21 12:27:36 +00:00
if ( use_lighting )
: : glDisable ( GL_LIGHTING ) ;
}
void GLGizmoBase : : Grabber : : render_face ( float half_size ) const
{
: : glBegin ( GL_TRIANGLES ) ;
: : glNormal3f ( 0.0f , 0.0f , 1.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , ( GLfloat ) half_size , 0.0f ) ;
: : glVertex3f ( - ( GLfloat ) half_size , - ( GLfloat ) half_size , 0.0f ) ;
: : glEnd ( ) ;
2018-06-15 12:10:28 +00:00
}
2018-06-14 08:00:59 +00:00
2018-08-24 12:11:41 +00:00
GLGizmoBase : : GLGizmoBase ( GLCanvas3D & parent )
: m_parent ( parent )
, m_group_id ( - 1 )
2018-08-20 08:23:17 +00:00
, m_state ( Off )
2018-11-22 09:14:31 +00:00
, m_shortcut_key ( 0 )
2018-06-14 13:32:26 +00:00
, m_hover_id ( - 1 )
2018-09-10 08:01:49 +00:00
, m_dragging ( false )
2018-11-27 11:00:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
, m_imgui ( wxGetApp ( ) . imgui ( ) )
2018-11-27 11:00:44 +00:00
# endif // ENABLE_IMGUI
2018-06-13 07:12:16 +00:00
{
2018-08-20 08:23:17 +00:00
: : memcpy ( ( void * ) m_base_color , ( const void * ) DEFAULT_BASE_COLOR , 3 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_drag_color , ( const void * ) DEFAULT_DRAG_COLOR , 3 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_highlight_color , ( const void * ) DEFAULT_HIGHLIGHT_COLOR , 3 * sizeof ( float ) ) ;
2018-06-13 07:12:16 +00:00
}
2018-08-20 08:23:17 +00:00
void GLGizmoBase : : set_hover_id ( int id )
2018-06-15 12:10:28 +00:00
{
2018-08-27 12:00:53 +00:00
if ( m_grabbers . empty ( ) | | ( id < ( int ) m_grabbers . size ( ) ) )
2018-08-20 08:23:17 +00:00
{
m_hover_id = id ;
on_set_hover_id ( ) ;
}
2018-06-15 12:10:28 +00:00
}
2018-08-20 08:23:17 +00:00
void GLGizmoBase : : set_highlight_color ( const float * color )
2018-06-14 13:32:26 +00:00
{
2018-08-20 08:23:17 +00:00
if ( color ! = nullptr )
: : memcpy ( ( void * ) m_highlight_color , ( const void * ) color , 3 * sizeof ( float ) ) ;
2018-06-15 12:10:28 +00:00
}
2018-09-11 10:40:42 +00:00
void GLGizmoBase : : enable_grabber ( unsigned int id )
{
if ( ( 0 < = id ) & & ( id < ( unsigned int ) m_grabbers . size ( ) ) )
m_grabbers [ id ] . enabled = true ;
on_enable_grabber ( id ) ;
}
void GLGizmoBase : : disable_grabber ( unsigned int id )
{
if ( ( 0 < = id ) & & ( id < ( unsigned int ) m_grabbers . size ( ) ) )
m_grabbers [ id ] . enabled = false ;
on_disable_grabber ( id ) ;
}
2018-10-15 09:30:50 +00:00
void GLGizmoBase : : start_dragging ( const GLCanvas3D : : Selection & selection )
2018-06-15 12:10:28 +00:00
{
2018-09-10 08:01:49 +00:00
m_dragging = true ;
2018-08-20 08:23:17 +00:00
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
m_grabbers [ i ] . dragging = ( m_hover_id = = i ) ;
}
2018-10-15 09:30:50 +00:00
on_start_dragging ( selection ) ;
2018-06-15 12:10:28 +00:00
}
2018-07-12 09:26:13 +00:00
void GLGizmoBase : : stop_dragging ( )
{
2018-09-10 08:01:49 +00:00
m_dragging = false ;
2018-08-24 13:49:57 +00:00
2018-08-20 08:23:17 +00:00
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
m_grabbers [ i ] . dragging = false ;
}
2018-07-12 09:26:13 +00:00
on_stop_dragging ( ) ;
}
2019-01-10 12:13:11 +00:00
void GLGizmoBase : : update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-06-15 12:10:28 +00:00
{
if ( m_hover_id ! = - 1 )
2019-01-10 12:13:11 +00:00
on_update ( data , selection ) ;
2018-06-14 13:32:26 +00:00
}
2018-08-20 08:23:17 +00:00
float GLGizmoBase : : picking_color_component ( unsigned int id ) const
2018-07-12 09:26:13 +00:00
{
2018-08-20 08:23:17 +00:00
int color = 254 - ( int ) id ;
if ( m_group_id > - 1 )
color - = m_group_id ;
2018-07-12 09:26:13 +00:00
2018-08-20 08:23:17 +00:00
return ( float ) color / 255.0f ;
2018-07-12 09:26:13 +00:00
}
2018-09-11 12:48:17 +00:00
void GLGizmoBase : : render_grabbers ( const BoundingBoxf3 & box ) const
2018-07-12 09:26:13 +00:00
{
2018-10-12 14:18:37 +00:00
float size = ( float ) box . max_size ( ) ;
2018-08-20 08:23:17 +00:00
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
2018-09-11 10:40:42 +00:00
if ( m_grabbers [ i ] . enabled )
2018-10-12 14:18:37 +00:00
m_grabbers [ i ] . render ( ( m_hover_id = = i ) , size ) ;
2018-08-20 08:23:17 +00:00
}
2018-06-18 13:07:17 +00:00
}
2018-11-28 15:09:04 +00:00
void GLGizmoBase : : render_grabbers ( float size ) const
{
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
if ( m_grabbers [ i ] . enabled )
m_grabbers [ i ] . render ( ( m_hover_id = = i ) , size ) ;
}
}
2018-09-11 12:48:17 +00:00
void GLGizmoBase : : render_grabbers_for_picking ( const BoundingBoxf3 & box ) const
2018-06-14 08:00:59 +00:00
{
2018-10-12 14:18:37 +00:00
float size = ( float ) box . max_size ( ) ;
2018-09-07 10:20:56 +00:00
for ( unsigned int i = 0 ; i < ( unsigned int ) m_grabbers . size ( ) ; + + i )
2018-06-14 13:32:26 +00:00
{
2018-09-11 10:40:42 +00:00
if ( m_grabbers [ i ] . enabled )
{
m_grabbers [ i ] . color [ 0 ] = 1.0f ;
m_grabbers [ i ] . color [ 1 ] = 1.0f ;
m_grabbers [ i ] . color [ 2 ] = picking_color_component ( i ) ;
2018-10-12 14:18:37 +00:00
m_grabbers [ i ] . render_for_picking ( size ) ;
2018-09-11 10:40:42 +00:00
}
2018-06-14 13:32:26 +00:00
}
2018-06-14 08:00:59 +00:00
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
void GLGizmoBase : : create_external_gizmo_widgets ( wxWindow * parent ) { }
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
2018-08-24 12:11:41 +00:00
void GLGizmoBase : : set_tooltip ( const std : : string & tooltip ) const
{
m_parent . set_tooltip ( tooltip ) ;
}
std : : string GLGizmoBase : : format ( float value , unsigned int decimals ) const
{
2018-11-19 10:07:39 +00:00
return Slic3r : : string_printf ( " %.*f " , decimals , value ) ;
2018-08-24 12:11:41 +00:00
}
2018-06-14 08:00:59 +00:00
const float GLGizmoRotate : : Offset = 5.0f ;
const unsigned int GLGizmoRotate : : CircleResolution = 64 ;
2018-06-15 14:16:55 +00:00
const unsigned int GLGizmoRotate : : AngleResolution = 64 ;
2018-08-20 08:23:17 +00:00
const unsigned int GLGizmoRotate : : ScaleStepsCount = 72 ;
2018-06-14 08:00:59 +00:00
const float GLGizmoRotate : : ScaleStepRad = 2.0f * ( float ) PI / GLGizmoRotate : : ScaleStepsCount ;
2018-08-20 08:23:17 +00:00
const unsigned int GLGizmoRotate : : ScaleLongEvery = 2 ;
2018-09-21 11:44:38 +00:00
const float GLGizmoRotate : : ScaleLongTooth = 0.1f ; // in percent of radius
2018-06-14 08:00:59 +00:00
const unsigned int GLGizmoRotate : : SnapRegionsCount = 8 ;
2018-09-21 11:44:38 +00:00
const float GLGizmoRotate : : GrabberOffset = 0.15f ; // in percent of radius
2018-06-14 08:00:59 +00:00
2018-08-24 12:11:41 +00:00
GLGizmoRotate : : GLGizmoRotate ( GLCanvas3D & parent , GLGizmoRotate : : Axis axis )
: GLGizmoBase ( parent )
2018-08-20 08:23:17 +00:00
, m_axis ( axis )
2018-08-28 11:23:28 +00:00
, m_angle ( 0.0 )
2018-12-03 08:37:46 +00:00
, m_quadric ( nullptr )
2018-08-23 13:37:38 +00:00
, m_center ( 0.0 , 0.0 , 0.0 )
2018-06-15 14:16:55 +00:00
, m_radius ( 0.0f )
2018-09-21 11:44:38 +00:00
, m_snap_coarse_in_radius ( 0.0f )
, m_snap_coarse_out_radius ( 0.0f )
, m_snap_fine_in_radius ( 0.0f )
, m_snap_fine_out_radius ( 0.0f )
2018-06-13 07:12:16 +00:00
{
2018-12-03 08:37:46 +00:00
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
}
GLGizmoRotate : : GLGizmoRotate ( const GLGizmoRotate & other )
: GLGizmoBase ( other . m_parent )
, m_axis ( other . m_axis )
, m_angle ( other . m_angle )
, m_quadric ( nullptr )
, m_center ( other . m_center )
, m_radius ( other . m_radius )
, m_snap_coarse_in_radius ( other . m_snap_coarse_in_radius )
, m_snap_coarse_out_radius ( other . m_snap_coarse_out_radius )
, m_snap_fine_in_radius ( other . m_snap_fine_in_radius )
, m_snap_fine_out_radius ( other . m_snap_fine_out_radius )
{
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
}
GLGizmoRotate : : ~ GLGizmoRotate ( )
{
if ( m_quadric ! = nullptr )
: : gluDeleteQuadric ( m_quadric ) ;
2018-06-13 07:12:16 +00:00
}
2018-08-28 11:23:28 +00:00
void GLGizmoRotate : : set_angle ( double angle )
2018-06-19 07:46:26 +00:00
{
2018-08-28 11:23:28 +00:00
if ( std : : abs ( angle - 2.0 * ( double ) PI ) < EPSILON )
angle = 0.0 ;
2018-06-19 07:46:26 +00:00
2018-08-20 08:23:17 +00:00
m_angle = angle ;
2018-06-19 07:46:26 +00:00
}
2018-06-13 07:12:16 +00:00
bool GLGizmoRotate : : on_init ( )
{
2018-06-15 12:10:28 +00:00
m_grabbers . push_back ( Grabber ( ) ) ;
2018-06-13 07:12:16 +00:00
return true ;
}
2018-10-15 09:30:50 +00:00
void GLGizmoRotate : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
2018-09-10 08:01:49 +00:00
{
2018-10-15 09:30:50 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
2018-09-10 08:01:49 +00:00
m_center = box . center ( ) ;
m_radius = Offset + box . radius ( ) ;
2018-09-21 11:44:38 +00:00
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 ;
2018-09-10 08:01:49 +00:00
}
2019-01-10 12:13:11 +00:00
void GLGizmoRotate : : on_update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-11-14 11:57:12 +00:00
{
2019-01-10 12:13:11 +00:00
Vec2d mouse_pos = to_2d ( mouse_position_in_local_plane ( data . mouse_ray , selection ) ) ;
2018-08-20 08:23:17 +00:00
2018-08-23 13:37:38 +00:00
Vec2d orig_dir = Vec2d : : UnitX ( ) ;
Vec2d new_dir = mouse_pos . normalized ( ) ;
2018-08-20 08:23:17 +00:00
2018-08-23 13:37:38 +00:00
double theta = : : acos ( clamp ( - 1.0 , 1.0 , new_dir . dot ( orig_dir ) ) ) ;
Removed Point::scale(),translate(),coincides_with(),distance_to(),
distance_to_squared(),perp_distance_to(),negative(),vector_to(),
translate(), distance_to() etc,
replaced with the Eigen equivalents.
2018-08-17 12:14:24 +00:00
if ( cross2 ( orig_dir , new_dir ) < 0.0 )
2018-08-24 08:20:00 +00:00
theta = 2.0 * ( double ) PI - theta ;
2018-06-15 14:16:55 +00:00
2018-08-23 13:37:38 +00:00
double len = mouse_pos . norm ( ) ;
2018-08-24 10:16:11 +00:00
2018-09-21 11:44:38 +00:00
// snap to coarse snap region
if ( ( m_snap_coarse_in_radius < = len ) & & ( len < = m_snap_coarse_out_radius ) )
2018-06-15 14:16:55 +00:00
{
2018-08-24 08:20:00 +00:00
double step = 2.0 * ( double ) PI / ( double ) SnapRegionsCount ;
theta = step * ( double ) std : : round ( theta / step ) ;
2018-06-15 14:16:55 +00:00
}
2018-08-24 10:16:11 +00:00
else
{
2018-09-21 11:44:38 +00:00
// snap to fine snap region (scale)
if ( ( m_snap_fine_in_radius < = len ) & & ( len < = m_snap_fine_out_radius ) )
2018-08-24 10:16:11 +00:00
{
double step = 2.0 * ( double ) PI / ( double ) ScaleStepsCount ;
theta = step * ( double ) std : : round ( theta / step ) ;
}
}
2018-06-15 14:16:55 +00:00
2018-08-24 08:20:00 +00:00
if ( theta = = 2.0 * ( double ) PI )
2018-06-15 14:16:55 +00:00
theta = 0.0 ;
2018-06-19 07:46:26 +00:00
2018-08-28 11:23:28 +00:00
m_angle = theta ;
2018-06-15 12:10:28 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoRotate : : on_render ( const GLCanvas3D : : Selection & selection ) const
2018-06-13 13:44:04 +00:00
{
2018-09-11 10:40:42 +00:00
if ( ! m_grabbers [ 0 ] . enabled )
return ;
2018-10-15 09:30:50 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
2018-10-24 12:12:33 +00:00
std : : string axis ;
switch ( m_axis )
{
2018-12-03 09:17:42 +00:00
case X : { axis = " X " ; break ; }
case Y : { axis = " Y " ; break ; }
case Z : { axis = " Z " ; break ; }
2018-10-24 12:12:33 +00:00
}
2018-10-15 09:30:50 +00:00
2018-12-03 09:17:42 +00:00
if ( ! m_dragging & & ( m_hover_id = = 0 ) )
set_tooltip ( axis ) ;
else if ( m_dragging )
set_tooltip ( axis + " : " + format ( ( float ) Geometry : : rad2deg ( m_angle ) , 4 ) + " \u00B0 " ) ;
2018-09-10 08:01:49 +00:00
else
2018-07-12 09:26:13 +00:00
{
2018-08-15 10:50:06 +00:00
m_center = box . center ( ) ;
2018-08-20 08:23:17 +00:00
m_radius = Offset + box . radius ( ) ;
2018-09-21 11:44:38 +00:00
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 ) ;
2018-07-12 09:26:13 +00:00
}
2018-06-14 08:00:59 +00:00
2018-09-10 08:01:49 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-08-20 08:23:17 +00:00
: : glPushMatrix ( ) ;
2019-01-10 12:13:11 +00:00
transform_to_local ( selection ) ;
2018-08-20 08:23:17 +00:00
2018-08-21 07:03:38 +00:00
: : glLineWidth ( ( m_hover_id ! = - 1 ) ? 2.0f : 1.5f ) ;
: : glColor3fv ( ( m_hover_id ! = - 1 ) ? m_drag_color : m_highlight_color ) ;
2018-06-15 14:16:55 +00:00
2018-08-20 08:23:17 +00:00
render_circle ( ) ;
2018-08-28 10:50:26 +00:00
2018-08-20 08:23:17 +00:00
if ( m_hover_id ! = - 1 )
{
render_scale ( ) ;
render_snap_radii ( ) ;
render_reference_radius ( ) ;
}
: : glColor3fv ( m_highlight_color ) ;
2018-08-28 10:50:26 +00:00
2018-08-20 08:23:17 +00:00
if ( m_hover_id ! = - 1 )
render_angle ( ) ;
2018-09-11 12:48:17 +00:00
render_grabber ( box ) ;
2018-11-29 14:10:11 +00:00
render_grabber_extension ( box , false ) ;
2018-08-20 08:23:17 +00:00
: : glPopMatrix ( ) ;
2018-06-14 08:00:59 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoRotate : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
2018-06-14 13:32:26 +00:00
{
: : glDisable ( GL_DEPTH_TEST ) ;
2018-08-20 08:23:17 +00:00
: : glPushMatrix ( ) ;
2019-01-10 12:13:11 +00:00
transform_to_local ( selection ) ;
2018-11-29 14:10:11 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
render_grabbers_for_picking ( box ) ;
render_grabber_extension ( box , true ) ;
2018-08-20 08:23:17 +00:00
: : glPopMatrix ( ) ;
2018-06-14 13:32:26 +00:00
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate : : render_circle ( ) const
2018-06-14 08:00:59 +00:00
{
: : glBegin ( GL_LINE_LOOP ) ;
for ( unsigned int i = 0 ; i < ScaleStepsCount ; + + i )
{
float angle = ( float ) i * ScaleStepRad ;
2018-08-20 08:23:17 +00:00
float x = : : cos ( angle ) * m_radius ;
float y = : : sin ( angle ) * m_radius ;
float z = 0.0f ;
: : glVertex3f ( ( GLfloat ) x , ( GLfloat ) y , ( GLfloat ) z ) ;
2018-06-14 08:00:59 +00:00
}
: : glEnd ( ) ;
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate : : render_scale ( ) const
2018-06-14 08:00:59 +00:00
{
2018-09-21 11:44:38 +00:00
float out_radius_long = m_snap_fine_out_radius ;
float out_radius_short = m_radius * ( 1.0f + 0.5f * ScaleLongTooth ) ;
2018-06-14 08:00:59 +00:00
: : glBegin ( GL_LINES ) ;
for ( unsigned int i = 0 ; i < ScaleStepsCount ; + + i )
{
float angle = ( float ) i * ScaleStepRad ;
float cosa = : : cos ( angle ) ;
float sina = : : sin ( angle ) ;
2018-08-20 08:23:17 +00:00
float in_x = cosa * m_radius ;
float in_y = sina * m_radius ;
float in_z = 0.0f ;
float out_x = ( i % ScaleLongEvery = = 0 ) ? cosa * out_radius_long : cosa * out_radius_short ;
float out_y = ( i % ScaleLongEvery = = 0 ) ? sina * out_radius_long : sina * out_radius_short ;
float out_z = 0.0f ;
: : glVertex3f ( ( GLfloat ) in_x , ( GLfloat ) in_y , ( GLfloat ) in_z ) ;
: : glVertex3f ( ( GLfloat ) out_x , ( GLfloat ) out_y , ( GLfloat ) out_z ) ;
2018-06-14 08:00:59 +00:00
}
: : glEnd ( ) ;
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate : : render_snap_radii ( ) const
2018-06-14 08:00:59 +00:00
{
2018-06-15 14:16:55 +00:00
float step = 2.0f * ( float ) PI / ( float ) SnapRegionsCount ;
2018-06-14 08:00:59 +00:00
2018-06-15 14:16:55 +00:00
float in_radius = m_radius / 3.0f ;
2018-06-14 08:00:59 +00:00
float out_radius = 2.0f * in_radius ;
: : glBegin ( GL_LINES ) ;
for ( unsigned int i = 0 ; i < SnapRegionsCount ; + + i )
{
2018-06-15 14:16:55 +00:00
float angle = ( float ) i * step ;
2018-06-14 08:00:59 +00:00
float cosa = : : cos ( angle ) ;
float sina = : : sin ( angle ) ;
2018-08-20 08:23:17 +00:00
float in_x = cosa * in_radius ;
float in_y = sina * in_radius ;
float in_z = 0.0f ;
float out_x = cosa * out_radius ;
float out_y = sina * out_radius ;
float out_z = 0.0f ;
: : glVertex3f ( ( GLfloat ) in_x , ( GLfloat ) in_y , ( GLfloat ) in_z ) ;
: : glVertex3f ( ( GLfloat ) out_x , ( GLfloat ) out_y , ( GLfloat ) out_z ) ;
2018-06-14 08:00:59 +00:00
}
: : glEnd ( ) ;
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate : : render_reference_radius ( ) const
2018-06-14 08:00:59 +00:00
{
: : glBegin ( GL_LINES ) ;
2018-08-20 08:23:17 +00:00
: : glVertex3f ( 0.0f , 0.0f , 0.0f ) ;
2018-09-21 11:44:38 +00:00
: : glVertex3f ( ( GLfloat ) ( m_radius * ( 1.0f + GrabberOffset ) ) , 0.0f , 0.0f ) ;
2018-06-14 08:00:59 +00:00
: : glEnd ( ) ;
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate : : render_angle ( ) const
2018-06-14 08:00:59 +00:00
{
2018-08-28 11:23:28 +00:00
float step_angle = ( float ) m_angle / AngleResolution ;
2018-09-21 11:44:38 +00:00
float ex_radius = m_radius * ( 1.0f + GrabberOffset ) ;
2018-06-14 08:00:59 +00:00
2018-06-15 14:16:55 +00:00
: : glBegin ( GL_LINE_STRIP ) ;
for ( unsigned int i = 0 ; i < = AngleResolution ; + + i )
{
float angle = ( float ) i * step_angle ;
2018-08-20 08:23:17 +00:00
float x = : : cos ( angle ) * ex_radius ;
float y = : : sin ( angle ) * ex_radius ;
float z = 0.0f ;
: : glVertex3f ( ( GLfloat ) x , ( GLfloat ) y , ( GLfloat ) z ) ;
2018-06-15 14:16:55 +00:00
}
: : glEnd ( ) ;
}
2018-09-11 12:48:17 +00:00
void GLGizmoRotate : : render_grabber ( const BoundingBoxf3 & box ) const
2018-06-15 14:16:55 +00:00
{
2018-11-21 08:28:27 +00:00
double grabber_radius = ( double ) m_radius * ( 1.0 + ( double ) GrabberOffset ) ;
2018-08-23 13:37:38 +00:00
m_grabbers [ 0 ] . center = Vec3d ( : : cos ( m_angle ) * grabber_radius , : : sin ( m_angle ) * grabber_radius , 0.0 ) ;
2018-08-28 11:23:28 +00:00
m_grabbers [ 0 ] . angles ( 2 ) = m_angle ;
2018-08-20 08:23:17 +00:00
2018-08-21 07:03:38 +00:00
: : glColor3fv ( ( m_hover_id ! = - 1 ) ? m_drag_color : m_highlight_color ) ;
2018-06-15 14:16:55 +00:00
2018-06-14 08:00:59 +00:00
: : glBegin ( GL_LINES ) ;
2018-08-20 08:23:17 +00:00
: : glVertex3f ( 0.0f , 0.0f , 0.0f ) ;
2018-10-11 08:52:50 +00:00
: : glVertex3dv ( m_grabbers [ 0 ] . center . data ( ) ) ;
2018-06-14 08:00:59 +00:00
: : glEnd ( ) ;
2018-08-20 08:23:17 +00:00
: : memcpy ( ( void * ) m_grabbers [ 0 ] . color , ( const void * ) m_highlight_color , 3 * sizeof ( float ) ) ;
2018-09-11 12:48:17 +00:00
render_grabbers ( box ) ;
2018-06-13 13:44:04 +00:00
}
2018-11-29 14:10:11 +00:00
void GLGizmoRotate : : render_grabber_extension ( const BoundingBoxf3 & box , bool picking ) const
{
2018-12-03 08:37:46 +00:00
if ( m_quadric = = nullptr )
return ;
2018-12-03 07:51:18 +00:00
double size = m_dragging ? ( double ) m_grabbers [ 0 ] . get_dragging_half_size ( ( float ) box . max_size ( ) ) : ( double ) m_grabbers [ 0 ] . get_half_size ( ( float ) box . max_size ( ) ) ;
2018-11-29 14:10:11 +00:00
float color [ 3 ] ;
: : memcpy ( ( void * ) color , ( const void * ) m_grabbers [ 0 ] . color , 3 * sizeof ( float ) ) ;
if ( ! picking & & ( m_hover_id ! = - 1 ) )
{
color [ 0 ] = 1.0f - color [ 0 ] ;
color [ 1 ] = 1.0f - color [ 1 ] ;
color [ 2 ] = 1.0f - color [ 2 ] ;
}
if ( ! picking )
: : glEnable ( GL_LIGHTING ) ;
: : glColor3fv ( color ) ;
: : glPushMatrix ( ) ;
: : glTranslated ( m_grabbers [ 0 ] . center ( 0 ) , m_grabbers [ 0 ] . center ( 1 ) , m_grabbers [ 0 ] . center ( 2 ) ) ;
: : glRotated ( Geometry : : rad2deg ( m_angle ) , 0.0 , 0.0 , 1.0 ) ;
: : glRotated ( 90.0 , 1.0 , 0.0 , 0.0 ) ;
: : glTranslated ( 0.0 , 0.0 , 2.0 * size ) ;
2018-12-03 08:37:46 +00:00
: : gluQuadricOrientation ( m_quadric , GLU_OUTSIDE ) ;
: : gluCylinder ( m_quadric , 0.75 * size , 0.0 , 3.0 * size , 36 , 1 ) ;
: : gluQuadricOrientation ( m_quadric , GLU_INSIDE ) ;
: : gluDisk ( m_quadric , 0.0 , 0.75 * size , 36 , 1 ) ;
2018-11-29 14:10:11 +00:00
: : glPopMatrix ( ) ;
: : glPushMatrix ( ) ;
: : glTranslated ( m_grabbers [ 0 ] . center ( 0 ) , m_grabbers [ 0 ] . center ( 1 ) , m_grabbers [ 0 ] . center ( 2 ) ) ;
: : glRotated ( Geometry : : rad2deg ( m_angle ) , 0.0 , 0.0 , 1.0 ) ;
: : glRotated ( - 90.0 , 1.0 , 0.0 , 0.0 ) ;
: : glTranslated ( 0.0 , 0.0 , 2.0 * size ) ;
2018-12-03 08:37:46 +00:00
: : gluQuadricOrientation ( m_quadric , GLU_OUTSIDE ) ;
: : gluCylinder ( m_quadric , 0.75 * size , 0.0 , 3.0 * size , 36 , 1 ) ;
: : gluQuadricOrientation ( m_quadric , GLU_INSIDE ) ;
: : gluDisk ( m_quadric , 0.0 , 0.75 * size , 36 , 1 ) ;
2018-11-29 14:10:11 +00:00
: : glPopMatrix ( ) ;
if ( ! picking )
: : glDisable ( GL_LIGHTING ) ;
}
2019-01-10 12:13:11 +00:00
void GLGizmoRotate : : transform_to_local ( const GLCanvas3D : : Selection & selection ) const
2018-08-20 08:23:17 +00:00
{
2018-10-11 08:52:50 +00:00
: : glTranslated ( m_center ( 0 ) , m_center ( 1 ) , m_center ( 2 ) ) ;
2018-08-20 08:23:17 +00:00
2019-01-10 12:13:11 +00:00
if ( selection . is_single_volume ( ) | | selection . is_single_modifier ( ) )
{
Transform3d orient_matrix = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_instance_transformation ( ) . get_matrix ( true , false , true , true ) ;
: : glMultMatrixd ( orient_matrix . data ( ) ) ;
}
2018-08-20 08:23:17 +00:00
switch ( m_axis )
{
case X :
{
: : glRotatef ( 90.0f , 0.0f , 1.0f , 0.0f ) ;
2018-12-07 09:01:30 +00:00
: : glRotatef ( - 90.0f , 0.0f , 0.0f , 1.0f ) ;
2018-08-20 08:23:17 +00:00
break ;
}
case Y :
{
2018-12-07 09:01:30 +00:00
: : glRotatef ( - 90.0f , 0.0f , 0.0f , 1.0f ) ;
: : glRotatef ( - 90.0f , 0.0f , 1.0f , 0.0f ) ;
2018-08-20 08:23:17 +00:00
break ;
}
default :
case Z :
{
// no rotation
break ;
}
}
}
2019-01-10 12:13:11 +00:00
Vec3d GLGizmoRotate : : mouse_position_in_local_plane ( const Linef3 & mouse_ray , const GLCanvas3D : : Selection & selection ) const
2018-08-20 08:23:17 +00:00
{
2018-08-23 13:37:38 +00:00
double half_pi = 0.5 * ( double ) PI ;
2018-08-21 06:50:35 +00:00
2018-08-23 13:37:38 +00:00
Transform3d m = Transform3d : : Identity ( ) ;
2018-08-20 08:23:17 +00:00
switch ( m_axis )
{
case X :
{
2018-12-07 09:01:30 +00:00
m . rotate ( Eigen : : AngleAxisd ( half_pi , Vec3d : : UnitZ ( ) ) ) ;
2018-08-23 13:37:38 +00:00
m . rotate ( Eigen : : AngleAxisd ( - half_pi , Vec3d : : UnitY ( ) ) ) ;
2018-08-20 08:23:17 +00:00
break ;
}
case Y :
{
2018-12-07 09:01:30 +00:00
m . rotate ( Eigen : : AngleAxisd ( half_pi , Vec3d : : UnitY ( ) ) ) ;
m . rotate ( Eigen : : AngleAxisd ( half_pi , Vec3d : : UnitZ ( ) ) ) ;
2018-08-20 08:23:17 +00:00
break ;
}
default :
case Z :
{
// no rotation applied
break ;
}
}
2019-01-10 12:13:11 +00:00
if ( selection . is_single_volume ( ) | | selection . is_single_modifier ( ) )
m = m * selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_instance_transformation ( ) . get_matrix ( true , false , true , true ) . inverse ( ) ;
2018-08-23 13:37:38 +00:00
m . translate ( - m_center ) ;
2018-08-20 08:23:17 +00:00
2018-08-28 11:23:28 +00:00
return transform ( mouse_ray , m ) . intersect_plane ( 0.0 ) ;
2018-08-20 08:23:17 +00:00
}
2018-08-24 12:11:41 +00:00
GLGizmoRotate3D : : GLGizmoRotate3D ( GLCanvas3D & parent )
: GLGizmoBase ( parent )
2018-08-20 08:23:17 +00:00
{
2018-09-10 08:01:49 +00:00
m_gizmos . emplace_back ( parent , GLGizmoRotate : : X ) ;
m_gizmos . emplace_back ( parent , GLGizmoRotate : : Y ) ;
m_gizmos . emplace_back ( parent , GLGizmoRotate : : Z ) ;
for ( unsigned int i = 0 ; i < 3 ; + + i )
{
m_gizmos [ i ] . set_group_id ( i ) ;
}
2018-08-20 08:23:17 +00:00
}
bool GLGizmoRotate3D : : on_init ( )
{
2018-09-10 08:01:49 +00:00
for ( GLGizmoRotate & g : m_gizmos )
{
if ( ! g . init ( ) )
return false ;
}
2018-08-20 08:23:17 +00:00
2018-09-10 08:01:49 +00:00
for ( unsigned int i = 0 ; i < 3 ; + + i )
{
m_gizmos [ i ] . set_highlight_color ( AXES_COLOR [ i ] ) ;
}
2018-08-20 08:23:17 +00:00
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Off ] . load_from_file ( path + " rotate_off.png " , false ) )
2018-08-20 08:23:17 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Hover ] . load_from_file ( path + " rotate_hover.png " , false ) )
2018-08-20 08:23:17 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ On ] . load_from_file ( path + " rotate_on.png " , false ) )
2018-08-20 08:23:17 +00:00
return false ;
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_R ;
2018-08-20 08:23:17 +00:00
return true ;
}
2018-10-25 07:35:08 +00:00
std : : string GLGizmoRotate3D : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " Rotate [R] " ) ;
2018-10-25 07:35:08 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoRotate3D : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
{
if ( ( 0 < = m_hover_id ) & & ( m_hover_id < 3 ) )
m_gizmos [ m_hover_id ] . start_dragging ( selection ) ;
}
2018-08-20 08:23:17 +00:00
void GLGizmoRotate3D : : on_stop_dragging ( )
{
2018-09-10 08:01:49 +00:00
if ( ( 0 < = m_hover_id ) & & ( m_hover_id < 3 ) )
m_gizmos [ m_hover_id ] . stop_dragging ( ) ;
2018-08-20 08:23:17 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoRotate3D : : on_render ( const GLCanvas3D : : Selection & selection ) const
{
2018-11-14 09:43:52 +00:00
: : glClear ( GL_DEPTH_BUFFER_BIT ) ;
2018-10-15 09:30:50 +00:00
if ( ( m_hover_id = = - 1 ) | | ( m_hover_id = = 0 ) )
m_gizmos [ X ] . render ( selection ) ;
if ( ( m_hover_id = = - 1 ) | | ( m_hover_id = = 1 ) )
m_gizmos [ Y ] . render ( selection ) ;
if ( ( m_hover_id = = - 1 ) | | ( m_hover_id = = 2 ) )
m_gizmos [ Z ] . render ( selection ) ;
}
2018-08-20 08:23:17 +00:00
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
void GLGizmoRotate3D : : on_render_input_window ( float x , float y , const GLCanvas3D : : Selection & selection )
2018-10-31 09:19:44 +00:00
{
2018-12-07 15:57:43 +00:00
# if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
Vec3d rotation ( Geometry : : rad2deg ( m_gizmos [ 0 ] . get_angle ( ) ) , Geometry : : rad2deg ( m_gizmos [ 1 ] . get_angle ( ) ) , Geometry : : rad2deg ( m_gizmos [ 2 ] . get_angle ( ) ) ) ;
2018-11-26 09:56:07 +00:00
wxString label = _ ( L ( " Rotation (deg) " ) ) ;
2018-10-31 09:19:44 +00:00
2018-11-26 09:56:07 +00:00
m_imgui - > set_next_window_pos ( x , y , ImGuiCond_Always ) ;
m_imgui - > set_next_window_bg_alpha ( 0.5f ) ;
m_imgui - > begin ( label , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
m_imgui - > input_vec3 ( " " , rotation , 100.0f , " %.2f " ) ;
m_imgui - > end ( ) ;
2018-12-07 15:57:43 +00:00
# endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
}
# endif // ENABLE_IMGUI
2018-08-21 06:50:35 +00:00
const float GLGizmoScale3D : : Offset = 5.0f ;
2018-08-24 12:11:41 +00:00
GLGizmoScale3D : : GLGizmoScale3D ( GLCanvas3D & parent )
: GLGizmoBase ( parent )
2018-08-28 11:23:28 +00:00
, m_scale ( Vec3d : : Ones ( ) )
2018-11-14 11:57:12 +00:00
, m_snap_step ( 0.05 )
2018-08-28 11:23:28 +00:00
, m_starting_scale ( Vec3d : : Ones ( ) )
2018-08-21 06:50:35 +00:00
{
}
bool GLGizmoScale3D : : on_init ( )
{
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Off ] . load_from_file ( path + " scale_off.png " , false ) )
2018-08-21 06:50:35 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Hover ] . load_from_file ( path + " scale_hover.png " , false ) )
2018-08-21 06:50:35 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ On ] . load_from_file ( path + " scale_on.png " , false ) )
2018-08-21 06:50:35 +00:00
return false ;
2018-08-21 12:27:36 +00:00
for ( int i = 0 ; i < 10 ; + + i )
2018-08-21 06:50:35 +00:00
{
m_grabbers . push_back ( Grabber ( ) ) ;
}
2018-08-28 11:23:28 +00:00
double half_pi = 0.5 * ( double ) PI ;
2018-08-21 06:50:35 +00:00
// x axis
2018-08-28 11:23:28 +00:00
m_grabbers [ 0 ] . angles ( 1 ) = half_pi ;
m_grabbers [ 1 ] . angles ( 1 ) = half_pi ;
2018-08-21 06:50:35 +00:00
// y axis
2018-08-28 11:23:28 +00:00
m_grabbers [ 2 ] . angles ( 0 ) = half_pi ;
m_grabbers [ 3 ] . angles ( 0 ) = half_pi ;
2018-08-21 06:50:35 +00:00
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_S ;
2018-08-21 06:50:35 +00:00
return true ;
}
2018-10-25 07:35:08 +00:00
std : : string GLGizmoScale3D : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " Scale [S] " ) ;
2018-10-25 07:35:08 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoScale3D : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
2018-08-21 06:50:35 +00:00
{
if ( m_hover_id ! = - 1 )
2018-08-22 09:22:07 +00:00
{
2018-08-21 06:50:35 +00:00
m_starting_drag_position = m_grabbers [ m_hover_id ] . center ;
2018-10-15 11:22:36 +00:00
m_starting_box = selection . get_bounding_box ( ) ;
2018-08-22 09:22:07 +00:00
}
2018-08-21 06:50:35 +00:00
}
2019-01-10 12:13:11 +00:00
void GLGizmoScale3D : : on_update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-08-21 06:50:35 +00:00
{
if ( ( m_hover_id = = 0 ) | | ( m_hover_id = = 1 ) )
2018-11-14 11:57:12 +00:00
do_scale_x ( data ) ;
2018-08-21 06:50:35 +00:00
else if ( ( m_hover_id = = 2 ) | | ( m_hover_id = = 3 ) )
2018-11-14 11:57:12 +00:00
do_scale_y ( data ) ;
2018-08-21 06:50:35 +00:00
else if ( ( m_hover_id = = 4 ) | | ( m_hover_id = = 5 ) )
2018-11-14 11:57:12 +00:00
do_scale_z ( data ) ;
2018-08-21 12:27:36 +00:00
else if ( m_hover_id > = 6 )
2018-11-14 11:57:12 +00:00
do_scale_uniform ( data ) ;
2018-08-21 06:50:35 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoScale3D : : on_render ( const GLCanvas3D : : Selection & selection ) const
2018-08-21 06:50:35 +00:00
{
2018-10-24 11:56:43 +00:00
bool single_instance = selection . is_single_full_instance ( ) ;
2018-11-12 08:54:04 +00:00
bool single_volume = selection . is_single_modifier ( ) | | selection . is_single_volume ( ) ;
bool single_selection = single_instance | | 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 > ( ) ;
2018-10-24 11:56:43 +00:00
2018-11-12 08:54:04 +00:00
if ( ( single_selection & & ( ( m_hover_id = = 0 ) | | ( m_hover_id = = 1 ) ) ) | | m_grabbers [ 0 ] . dragging | | m_grabbers [ 1 ] . dragging )
2018-10-24 11:56:43 +00:00
set_tooltip ( " X: " + format ( scale ( 0 ) , 4 ) + " % " ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 0 ] . dragging & & ! m_grabbers [ 1 ] . dragging & & ( ( m_hover_id = = 0 ) | | ( m_hover_id = = 1 ) ) )
set_tooltip ( " X " ) ;
2018-11-12 08:54:04 +00:00
else if ( ( single_selection & & ( ( m_hover_id = = 2 ) | | ( m_hover_id = = 3 ) ) ) | | m_grabbers [ 2 ] . dragging | | m_grabbers [ 3 ] . dragging )
2018-10-24 11:56:43 +00:00
set_tooltip ( " Y: " + format ( scale ( 1 ) , 4 ) + " % " ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 2 ] . dragging & & ! m_grabbers [ 3 ] . dragging & & ( ( m_hover_id = = 2 ) | | ( m_hover_id = = 3 ) ) )
set_tooltip ( " Y " ) ;
2018-11-12 08:54:04 +00:00
else if ( ( single_selection & & ( ( m_hover_id = = 4 ) | | ( m_hover_id = = 5 ) ) ) | | m_grabbers [ 4 ] . dragging | | m_grabbers [ 5 ] . dragging )
2018-10-24 11:56:43 +00:00
set_tooltip ( " Z: " + format ( scale ( 2 ) , 4 ) + " % " ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 4 ] . dragging & & ! m_grabbers [ 5 ] . dragging & & ( ( m_hover_id = = 4 ) | | ( m_hover_id = = 5 ) ) )
set_tooltip ( " Z " ) ;
2018-11-12 08:54:04 +00:00
else if ( ( single_selection & & ( ( m_hover_id = = 6 ) | | ( m_hover_id = = 7 ) | | ( m_hover_id = = 8 ) | | ( m_hover_id = = 9 ) ) )
2018-10-24 11:56:43 +00:00
| | m_grabbers [ 6 ] . dragging | | m_grabbers [ 7 ] . dragging | | m_grabbers [ 8 ] . dragging | | m_grabbers [ 9 ] . dragging )
{
std : : string tooltip = " X: " + format ( scale ( 0 ) , 4 ) + " % \n " ;
tooltip + = " Y: " + format ( scale ( 1 ) , 4 ) + " % \n " ;
tooltip + = " Z: " + format ( scale ( 2 ) , 4 ) + " % " ;
set_tooltip ( tooltip ) ;
}
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 6 ] . dragging & & ! m_grabbers [ 7 ] . dragging & & ! m_grabbers [ 8 ] . dragging & & ! m_grabbers [ 9 ] . dragging & &
( ( m_hover_id = = 6 ) | | ( m_hover_id = = 7 ) | | ( m_hover_id = = 8 ) | | ( m_hover_id = = 9 ) ) )
set_tooltip ( " X/Y/Z " ) ;
2018-08-24 12:11:41 +00:00
2018-11-14 09:43:52 +00:00
: : glClear ( GL_DEPTH_BUFFER_BIT ) ;
2018-08-21 12:27:36 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-08-21 06:50:35 +00:00
2018-10-15 09:30:50 +00:00
BoundingBoxf3 box ;
Transform3d transform = Transform3d : : Identity ( ) ;
Vec3d angles = Vec3d : : Zero ( ) ;
2018-10-19 09:24:27 +00:00
Transform3d offsets_transform = Transform3d : : Identity ( ) ;
2018-10-15 09:30:50 +00:00
2018-11-28 15:09:04 +00:00
Vec3d grabber_size = Vec3d : : Zero ( ) ;
2018-10-24 11:56:43 +00:00
if ( single_instance )
2018-10-15 09:30:50 +00:00
{
// calculate bounding box in instance local reference system
const GLCanvas3D : : Selection : : IndicesList & idxs = selection . get_volume_idxs ( ) ;
for ( unsigned int idx : idxs )
{
2018-11-20 14:39:36 +00:00
const GLVolume * vol = selection . get_volume ( idx ) ;
box . merge ( vol - > bounding_box . transformed ( vol - > get_volume_transformation ( ) . get_matrix ( ) ) ) ;
2018-10-15 09:30:50 +00:00
}
// gets transform from first selected volume
2018-10-19 09:24:27 +00:00
const GLVolume * v = selection . get_volume ( * idxs . begin ( ) ) ;
2018-11-20 14:39:36 +00:00
transform = v - > get_instance_transformation ( ) . get_matrix ( ) ;
2018-10-19 09:24:27 +00:00
// gets angles from first selected volume
2018-11-02 11:11:28 +00:00
angles = v - > get_instance_rotation ( ) ;
2018-11-12 08:54:04 +00:00
// consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , angles , Vec3d : : Ones ( ) , v - > get_instance_mirror ( ) ) ;
2018-11-28 15:09:04 +00:00
grabber_size = v - > get_instance_transformation ( ) . get_matrix ( true , true , false , true ) * box . size ( ) ;
2018-11-12 08:54:04 +00:00
}
else if ( single_volume )
{
const GLVolume * v = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
box = v - > bounding_box ;
transform = v - > world_matrix ( ) ;
angles = Geometry : : extract_euler_angles ( transform ) ;
// consider rotation+mirror only components of the transform for offsets
2018-11-02 11:11:28 +00:00
offsets_transform = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , angles , Vec3d : : Ones ( ) , v - > get_instance_mirror ( ) ) ;
2018-11-28 15:09:04 +00:00
grabber_size = v - > get_volume_transformation ( ) . get_matrix ( true , true , false , true ) * box . size ( ) ;
2018-10-15 09:30:50 +00:00
}
else
2018-11-28 15:09:04 +00:00
{
2018-10-15 09:30:50 +00:00
box = selection . get_bounding_box ( ) ;
2018-11-28 15:09:04 +00:00
grabber_size = box . size ( ) ;
}
2018-10-15 09:30:50 +00:00
2018-10-15 11:22:36 +00:00
m_box = box ;
2018-08-23 13:37:38 +00:00
const Vec3d & center = m_box . center ( ) ;
2018-10-19 09:24:27 +00:00
Vec3d offset_x = offsets_transform * Vec3d ( ( double ) Offset , 0.0 , 0.0 ) ;
Vec3d offset_y = offsets_transform * Vec3d ( 0.0 , ( double ) Offset , 0.0 ) ;
Vec3d offset_z = offsets_transform * Vec3d ( 0.0 , 0.0 , ( double ) Offset ) ;
2018-08-21 06:50:35 +00:00
// x axis
2018-10-15 11:22:36 +00:00
m_grabbers [ 0 ] . center = transform * Vec3d ( m_box . min ( 0 ) , center ( 1 ) , center ( 2 ) ) - offset_x ;
m_grabbers [ 1 ] . center = transform * Vec3d ( m_box . max ( 0 ) , center ( 1 ) , center ( 2 ) ) + offset_x ;
2018-09-07 11:40:26 +00:00
: : memcpy ( ( void * ) m_grabbers [ 0 ] . color , ( const void * ) & AXES_COLOR [ 0 ] , 3 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_grabbers [ 1 ] . color , ( const void * ) & AXES_COLOR [ 0 ] , 3 * sizeof ( float ) ) ;
2018-08-21 12:27:36 +00:00
// y axis
2018-10-15 11:22:36 +00:00
m_grabbers [ 2 ] . center = transform * Vec3d ( center ( 0 ) , m_box . min ( 1 ) , center ( 2 ) ) - offset_y ;
m_grabbers [ 3 ] . center = transform * Vec3d ( center ( 0 ) , m_box . max ( 1 ) , center ( 2 ) ) + offset_y ;
2018-09-07 11:40:26 +00:00
: : memcpy ( ( void * ) m_grabbers [ 2 ] . color , ( const void * ) & AXES_COLOR [ 1 ] , 3 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_grabbers [ 3 ] . color , ( const void * ) & AXES_COLOR [ 1 ] , 3 * sizeof ( float ) ) ;
2018-08-21 12:27:36 +00:00
// z axis
2018-10-15 11:22:36 +00:00
m_grabbers [ 4 ] . center = transform * Vec3d ( center ( 0 ) , center ( 1 ) , m_box . min ( 2 ) ) - offset_z ;
m_grabbers [ 5 ] . center = transform * Vec3d ( center ( 0 ) , center ( 1 ) , m_box . max ( 2 ) ) + offset_z ;
2018-09-07 11:40:26 +00:00
: : memcpy ( ( void * ) m_grabbers [ 4 ] . color , ( const void * ) & AXES_COLOR [ 2 ] , 3 * sizeof ( float ) ) ;
: : memcpy ( ( void * ) m_grabbers [ 5 ] . color , ( const void * ) & AXES_COLOR [ 2 ] , 3 * sizeof ( float ) ) ;
2018-08-21 06:50:35 +00:00
2018-08-21 12:27:36 +00:00
// uniform
2018-10-15 11:22:36 +00:00
m_grabbers [ 6 ] . center = transform * Vec3d ( m_box . min ( 0 ) , m_box . min ( 1 ) , center ( 2 ) ) - offset_x - offset_y ;
m_grabbers [ 7 ] . center = transform * Vec3d ( m_box . max ( 0 ) , m_box . min ( 1 ) , center ( 2 ) ) + offset_x - offset_y ;
m_grabbers [ 8 ] . center = transform * Vec3d ( m_box . max ( 0 ) , m_box . max ( 1 ) , center ( 2 ) ) + offset_x + offset_y ;
m_grabbers [ 9 ] . center = transform * Vec3d ( m_box . min ( 0 ) , m_box . max ( 1 ) , center ( 2 ) ) - offset_x + offset_y ;
2018-08-21 12:27:36 +00:00
for ( int i = 6 ; i < 10 ; + + i )
{
: : memcpy ( ( void * ) m_grabbers [ i ] . color , ( const void * ) m_highlight_color , 3 * sizeof ( float ) ) ;
}
2018-10-15 09:30:50 +00:00
// sets grabbers orientation
for ( int i = 0 ; i < 10 ; + + i )
{
m_grabbers [ i ] . angles = angles ;
}
2018-08-21 12:27:36 +00:00
: : glLineWidth ( ( m_hover_id ! = - 1 ) ? 2.0f : 1.5f ) ;
2018-08-21 06:50:35 +00:00
2018-11-28 15:09:04 +00:00
float grabber_max_size = ( float ) std : : max ( grabber_size ( 0 ) , std : : max ( grabber_size ( 1 ) , grabber_size ( 2 ) ) ) ;
2018-10-12 14:18:37 +00:00
2018-08-21 06:50:35 +00:00
if ( m_hover_id = = - 1 )
{
2018-09-07 11:40:26 +00:00
// draw connections
2018-09-11 10:40:42 +00:00
if ( m_grabbers [ 0 ] . enabled & & m_grabbers [ 1 ] . enabled )
{
: : glColor3fv ( m_grabbers [ 0 ] . color ) ;
render_grabbers_connection ( 0 , 1 ) ;
}
if ( m_grabbers [ 2 ] . enabled & & m_grabbers [ 3 ] . enabled )
{
: : glColor3fv ( m_grabbers [ 2 ] . color ) ;
render_grabbers_connection ( 2 , 3 ) ;
}
if ( m_grabbers [ 4 ] . enabled & & m_grabbers [ 5 ] . enabled )
{
: : glColor3fv ( m_grabbers [ 4 ] . color ) ;
render_grabbers_connection ( 4 , 5 ) ;
}
2018-10-12 12:23:34 +00:00
: : glColor3fv ( m_base_color ) ;
render_grabbers_connection ( 6 , 7 ) ;
render_grabbers_connection ( 7 , 8 ) ;
render_grabbers_connection ( 8 , 9 ) ;
render_grabbers_connection ( 9 , 6 ) ;
2018-08-21 06:50:35 +00:00
// draw grabbers
2018-11-28 15:09:04 +00:00
render_grabbers ( grabber_max_size ) ;
2018-08-21 06:50:35 +00:00
}
else if ( ( m_hover_id = = 0 ) | | ( m_hover_id = = 1 ) )
{
2018-08-21 12:27:36 +00:00
// draw connection
2018-08-29 11:36:03 +00:00
: : glColor3fv ( m_grabbers [ 0 ] . color ) ;
2018-08-21 12:27:36 +00:00
render_grabbers_connection ( 0 , 1 ) ;
// draw grabbers
2018-11-28 15:09:04 +00:00
m_grabbers [ 0 ] . render ( true , grabber_max_size ) ;
m_grabbers [ 1 ] . render ( true , grabber_max_size ) ;
2018-08-21 06:50:35 +00:00
}
else if ( ( m_hover_id = = 2 ) | | ( m_hover_id = = 3 ) )
{
2018-08-21 12:27:36 +00:00
// draw connection
2018-08-29 11:36:03 +00:00
: : glColor3fv ( m_grabbers [ 2 ] . color ) ;
2018-08-21 12:27:36 +00:00
render_grabbers_connection ( 2 , 3 ) ;
// draw grabbers
2018-11-28 15:09:04 +00:00
m_grabbers [ 2 ] . render ( true , grabber_max_size ) ;
m_grabbers [ 3 ] . render ( true , grabber_max_size ) ;
2018-08-21 06:50:35 +00:00
}
else if ( ( m_hover_id = = 4 ) | | ( m_hover_id = = 5 ) )
{
2018-08-21 12:27:36 +00:00
// draw connection
2018-08-29 11:36:03 +00:00
: : glColor3fv ( m_grabbers [ 4 ] . color ) ;
2018-08-21 12:27:36 +00:00
render_grabbers_connection ( 4 , 5 ) ;
// draw grabbers
2018-11-28 15:09:04 +00:00
m_grabbers [ 4 ] . render ( true , grabber_max_size ) ;
m_grabbers [ 5 ] . render ( true , grabber_max_size ) ;
2018-08-21 06:50:35 +00:00
}
2018-08-21 12:27:36 +00:00
else if ( m_hover_id > = 6 )
2018-08-21 06:50:35 +00:00
{
2018-10-12 12:23:34 +00:00
// draw connection
2018-08-21 06:50:35 +00:00
: : glColor3fv ( m_drag_color ) ;
2018-10-12 12:23:34 +00:00
render_grabbers_connection ( 6 , 7 ) ;
render_grabbers_connection ( 7 , 8 ) ;
render_grabbers_connection ( 8 , 9 ) ;
render_grabbers_connection ( 9 , 6 ) ;
2018-08-21 12:27:36 +00:00
// draw grabbers
for ( int i = 6 ; i < 10 ; + + i )
{
2018-11-28 15:09:04 +00:00
m_grabbers [ i ] . render ( true , grabber_max_size ) ;
2018-08-21 12:27:36 +00:00
}
2018-08-21 06:50:35 +00:00
}
}
2018-10-15 09:30:50 +00:00
void GLGizmoScale3D : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
2018-08-21 06:50:35 +00:00
{
2018-08-24 09:17:53 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
2018-08-21 06:50:35 +00:00
2018-10-15 09:30:50 +00:00
render_grabbers_for_picking ( selection . get_bounding_box ( ) ) ;
2018-08-21 06:50:35 +00:00
}
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
void GLGizmoScale3D : : on_render_input_window ( float x , float y , const GLCanvas3D : : Selection & selection )
2018-10-31 09:19:44 +00:00
{
2018-12-07 15:57:43 +00:00
# if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
bool single_instance = selection . is_single_full_instance ( ) ;
2018-11-26 09:56:07 +00:00
wxString label = _ ( L ( " Scale (%) " ) ) ;
2018-10-31 09:19:44 +00:00
2018-11-26 09:56:07 +00:00
m_imgui - > set_next_window_pos ( x , y , ImGuiCond_Always ) ;
m_imgui - > set_next_window_bg_alpha ( 0.5f ) ;
m_imgui - > begin ( label , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
2018-12-07 13:10:16 +00:00
m_imgui - > input_vec3 ( " " , m_scale * 100.f , 100.0f , " %.2f " ) ;
2018-11-26 09:56:07 +00:00
m_imgui - > end ( ) ;
2018-12-07 15:57:43 +00:00
# endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
}
# endif // ENABLE_IMGUI
2018-08-21 12:27:36 +00:00
void GLGizmoScale3D : : render_grabbers_connection ( unsigned int id_1 , unsigned int id_2 ) const
2018-08-21 06:50:35 +00:00
{
2018-08-21 12:27:36 +00:00
unsigned int grabbers_count = ( unsigned int ) m_grabbers . size ( ) ;
if ( ( id_1 < grabbers_count ) & & ( id_2 < grabbers_count ) )
{
: : glBegin ( GL_LINES ) ;
2018-10-11 08:52:50 +00:00
: : glVertex3dv ( m_grabbers [ id_1 ] . center . data ( ) ) ;
: : glVertex3dv ( m_grabbers [ id_2 ] . center . data ( ) ) ;
2018-08-21 12:27:36 +00:00
: : glEnd ( ) ;
}
2018-08-21 06:50:35 +00:00
}
2018-11-14 11:57:12 +00:00
void GLGizmoScale3D : : do_scale_x ( const UpdateData & data )
2018-08-21 06:50:35 +00:00
{
2018-11-14 11:57:12 +00:00
double ratio = calc_ratio ( data ) ;
2018-08-22 09:22:07 +00:00
if ( ratio > 0.0 )
2018-08-28 11:23:28 +00:00
m_scale ( 0 ) = m_starting_scale ( 0 ) * ratio ;
2018-08-21 06:50:35 +00:00
}
2018-11-14 11:57:12 +00:00
void GLGizmoScale3D : : do_scale_y ( const UpdateData & data )
2018-08-21 06:50:35 +00:00
{
2018-11-14 11:57:12 +00:00
double ratio = calc_ratio ( data ) ;
2018-08-22 09:22:07 +00:00
if ( ratio > 0.0 )
2018-09-24 13:54:09 +00:00
m_scale ( 1 ) = m_starting_scale ( 1 ) * ratio ;
2018-08-21 06:50:35 +00:00
}
2018-11-14 11:57:12 +00:00
void GLGizmoScale3D : : do_scale_z ( const UpdateData & data )
2018-08-21 06:50:35 +00:00
{
2018-11-14 11:57:12 +00:00
double ratio = calc_ratio ( data ) ;
2018-08-22 09:22:07 +00:00
if ( ratio > 0.0 )
2018-09-24 13:54:09 +00:00
m_scale ( 2 ) = m_starting_scale ( 2 ) * ratio ;
2018-08-22 09:22:07 +00:00
}
2018-08-21 06:50:35 +00:00
2018-11-14 11:57:12 +00:00
void GLGizmoScale3D : : do_scale_uniform ( const UpdateData & data )
2018-08-22 09:22:07 +00:00
{
2018-11-14 11:57:12 +00:00
double ratio = calc_ratio ( data ) ;
2018-08-22 09:22:07 +00:00
if ( ratio > 0.0 )
2018-08-28 11:23:28 +00:00
m_scale = m_starting_scale * ratio ;
2018-08-21 06:50:35 +00:00
}
2018-11-14 11:57:12 +00:00
double GLGizmoScale3D : : calc_ratio ( const UpdateData & data ) const
2018-10-15 13:21:37 +00:00
{
double ratio = 0.0 ;
// vector from the center to the starting position
Vec3d starting_vec = m_starting_drag_position - m_starting_box . center ( ) ;
double len_starting_vec = starting_vec . norm ( ) ;
if ( len_starting_vec ! = 0.0 )
{
2018-11-14 11:57:12 +00:00
Vec3d mouse_dir = data . mouse_ray . unit_vector ( ) ;
2018-10-15 13:21:37 +00:00
// 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
2018-11-14 11:57:12 +00:00
Vec3d inters = data . mouse_ray . a + ( m_starting_drag_position - data . mouse_ray . a ) . dot ( mouse_dir ) / mouse_dir . squaredNorm ( ) * mouse_dir ;
2018-10-15 13:21:37 +00:00
// vector from the starting position to the found intersection
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 ( ) ) ;
2018-11-14 11:57:12 +00:00
ratio = ( len_starting_vec + proj ) / len_starting_vec ;
2018-10-15 13:21:37 +00:00
}
2018-11-14 11:57:12 +00:00
if ( data . shift_down )
ratio = m_snap_step * ( double ) std : : round ( ratio / m_snap_step ) ;
2018-10-15 13:21:37 +00:00
return ratio ;
}
2018-08-21 06:50:35 +00:00
2018-09-11 07:00:28 +00:00
const double GLGizmoMove3D : : Offset = 10.0 ;
GLGizmoMove3D : : GLGizmoMove3D ( GLCanvas3D & parent )
: GLGizmoBase ( parent )
2018-10-08 12:02:12 +00:00
, m_displacement ( Vec3d : : Zero ( ) )
2018-11-14 12:29:57 +00:00
, m_snap_step ( 1.0 )
2018-09-11 07:00:28 +00:00
, m_starting_drag_position ( Vec3d : : Zero ( ) )
, m_starting_box_center ( Vec3d : : Zero ( ) )
2018-09-14 12:37:13 +00:00
, m_starting_box_bottom_center ( Vec3d : : Zero ( ) )
2018-12-03 08:37:46 +00:00
, m_quadric ( nullptr )
2018-09-11 07:00:28 +00:00
{
2018-12-03 08:37:46 +00:00
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
}
GLGizmoMove3D : : ~ GLGizmoMove3D ( )
{
if ( m_quadric ! = nullptr )
: : gluDeleteQuadric ( m_quadric ) ;
2018-09-11 07:00:28 +00:00
}
bool GLGizmoMove3D : : on_init ( )
{
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Off ] . load_from_file ( path + " move_off.png " , false ) )
2018-09-11 07:00:28 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Hover ] . load_from_file ( path + " move_hover.png " , false ) )
2018-09-11 07:00:28 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ On ] . load_from_file ( path + " move_on.png " , false ) )
2018-09-11 07:00:28 +00:00
return false ;
for ( int i = 0 ; i < 3 ; + + i )
{
m_grabbers . push_back ( Grabber ( ) ) ;
}
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_M ;
2018-09-11 07:00:28 +00:00
return true ;
}
2018-10-25 07:35:08 +00:00
std : : string GLGizmoMove3D : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " Move [M] " ) ;
2018-10-25 07:35:08 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoMove3D : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
2018-09-11 07:00:28 +00:00
{
if ( m_hover_id ! = - 1 )
{
2018-10-08 12:02:12 +00:00
m_displacement = Vec3d : : Zero ( ) ;
2018-10-15 09:30:50 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
2018-09-11 07:00:28 +00:00
m_starting_drag_position = m_grabbers [ m_hover_id ] . center ;
m_starting_box_center = box . center ( ) ;
2018-09-14 12:37:13 +00:00
m_starting_box_bottom_center = box . center ( ) ;
m_starting_box_bottom_center ( 2 ) = box . min ( 2 ) ;
2018-09-11 07:00:28 +00:00
}
}
2018-10-24 11:28:35 +00:00
void GLGizmoMove3D : : on_stop_dragging ( )
{
m_displacement = Vec3d : : Zero ( ) ;
}
2019-01-10 12:13:11 +00:00
void GLGizmoMove3D : : on_update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-09-11 07:00:28 +00:00
{
2018-10-08 12:02:12 +00:00
if ( m_hover_id = = 0 )
2018-11-14 11:57:12 +00:00
m_displacement ( 0 ) = calc_projection ( data ) ;
2018-10-08 12:02:12 +00:00
else if ( m_hover_id = = 1 )
2018-11-14 11:57:12 +00:00
m_displacement ( 1 ) = calc_projection ( data ) ;
2018-10-08 12:02:12 +00:00
else if ( m_hover_id = = 2 )
2018-11-14 11:57:12 +00:00
m_displacement ( 2 ) = calc_projection ( data ) ;
2018-09-11 07:00:28 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoMove3D : : on_render ( const GLCanvas3D : : Selection & selection ) const
2018-09-11 07:00:28 +00:00
{
2018-10-24 11:28:35 +00:00
bool show_position = selection . is_single_full_instance ( ) ;
const Vec3d & position = selection . get_bounding_box ( ) . center ( ) ;
if ( ( show_position & & ( m_hover_id = = 0 ) ) | | m_grabbers [ 0 ] . dragging )
set_tooltip ( " X: " + format ( show_position ? position ( 0 ) : m_displacement ( 0 ) , 2 ) ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 0 ] . dragging & & ( m_hover_id = = 0 ) )
set_tooltip ( " X " ) ;
2018-10-24 11:28:35 +00:00
else if ( ( show_position & & ( m_hover_id = = 1 ) ) | | m_grabbers [ 1 ] . dragging )
set_tooltip ( " Y: " + format ( show_position ? position ( 1 ) : m_displacement ( 1 ) , 2 ) ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 1 ] . dragging & & ( m_hover_id = = 1 ) )
set_tooltip ( " Y " ) ;
2018-10-24 11:28:35 +00:00
else if ( ( show_position & & ( m_hover_id = = 2 ) ) | | m_grabbers [ 2 ] . dragging )
set_tooltip ( " Z: " + format ( show_position ? position ( 2 ) : m_displacement ( 2 ) , 2 ) ) ;
2018-12-03 09:17:42 +00:00
else if ( ! m_grabbers [ 2 ] . dragging & & ( m_hover_id = = 2 ) )
set_tooltip ( " Z " ) ;
2018-09-11 07:00:28 +00:00
2018-11-14 09:43:52 +00:00
: : glClear ( GL_DEPTH_BUFFER_BIT ) ;
2018-09-11 07:00:28 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-10-15 09:30:50 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
2018-09-11 07:00:28 +00:00
const Vec3d & center = box . center ( ) ;
// x axis
m_grabbers [ 0 ] . center = Vec3d ( box . max ( 0 ) + Offset , center ( 1 ) , center ( 2 ) ) ;
: : memcpy ( ( void * ) m_grabbers [ 0 ] . color , ( const void * ) & AXES_COLOR [ 0 ] , 3 * sizeof ( float ) ) ;
// y axis
m_grabbers [ 1 ] . center = Vec3d ( center ( 0 ) , box . max ( 1 ) + Offset , center ( 2 ) ) ;
: : memcpy ( ( void * ) m_grabbers [ 1 ] . color , ( const void * ) & AXES_COLOR [ 1 ] , 3 * sizeof ( float ) ) ;
// z axis
m_grabbers [ 2 ] . center = Vec3d ( center ( 0 ) , center ( 1 ) , box . max ( 2 ) + Offset ) ;
: : memcpy ( ( void * ) m_grabbers [ 2 ] . color , ( const void * ) & AXES_COLOR [ 2 ] , 3 * sizeof ( float ) ) ;
: : glLineWidth ( ( m_hover_id ! = - 1 ) ? 2.0f : 1.5f ) ;
if ( m_hover_id = = - 1 )
{
// draw axes
for ( unsigned int i = 0 ; i < 3 ; + + i )
{
2018-09-11 10:40:42 +00:00
if ( m_grabbers [ i ] . enabled )
{
: : glColor3fv ( AXES_COLOR [ i ] ) ;
: : glBegin ( GL_LINES ) ;
2018-10-11 08:52:50 +00:00
: : glVertex3dv ( center . data ( ) ) ;
: : glVertex3dv ( m_grabbers [ i ] . center . data ( ) ) ;
2018-09-11 10:40:42 +00:00
: : glEnd ( ) ;
}
2018-09-11 07:00:28 +00:00
}
// draw grabbers
2018-09-11 12:48:17 +00:00
render_grabbers ( box ) ;
2018-12-12 12:04:06 +00:00
for ( unsigned int i = 0 ; i < 3 ; + + i )
{
if ( m_grabbers [ i ] . enabled )
render_grabber_extension ( ( Axis ) i , box , false ) ;
}
2018-09-11 07:00:28 +00:00
}
else
{
// draw axis
: : glColor3fv ( AXES_COLOR [ m_hover_id ] ) ;
: : glBegin ( GL_LINES ) ;
2018-10-11 08:52:50 +00:00
: : glVertex3dv ( center . data ( ) ) ;
: : glVertex3dv ( m_grabbers [ m_hover_id ] . center . data ( ) ) ;
2018-09-11 07:00:28 +00:00
: : glEnd ( ) ;
// draw grabber
2018-10-12 14:18:37 +00:00
m_grabbers [ m_hover_id ] . render ( true , box . max_size ( ) ) ;
2018-12-03 07:51:18 +00:00
render_grabber_extension ( ( Axis ) m_hover_id , box , false ) ;
2018-09-11 07:00:28 +00:00
}
}
2018-10-15 09:30:50 +00:00
void GLGizmoMove3D : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
{
: : glDisable ( GL_DEPTH_TEST ) ;
2018-12-03 07:51:18 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
render_grabbers_for_picking ( box ) ;
render_grabber_extension ( X , box , true ) ;
render_grabber_extension ( Y , box , true ) ;
render_grabber_extension ( Z , box , true ) ;
2018-10-15 09:30:50 +00:00
}
2018-09-11 07:00:28 +00:00
2018-10-31 09:19:44 +00:00
# if ENABLE_IMGUI
2018-11-26 09:56:07 +00:00
void GLGizmoMove3D : : on_render_input_window ( float x , float y , const GLCanvas3D : : Selection & selection )
2018-10-31 09:19:44 +00:00
{
2018-12-07 15:57:43 +00:00
# if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
bool show_position = selection . is_single_full_instance ( ) ;
const Vec3d & position = selection . get_bounding_box ( ) . center ( ) ;
Vec3d displacement = show_position ? position : m_displacement ;
2018-11-26 09:56:07 +00:00
wxString label = show_position ? _ ( L ( " Position (mm) " ) ) : _ ( L ( " Displacement (mm) " ) ) ;
2018-10-31 09:19:44 +00:00
2018-11-26 09:56:07 +00:00
m_imgui - > set_next_window_pos ( x , y , ImGuiCond_Always ) ;
m_imgui - > set_next_window_bg_alpha ( 0.5f ) ;
m_imgui - > begin ( label , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
m_imgui - > input_vec3 ( " " , displacement , 100.0f , " %.2f " ) ;
2018-10-31 09:19:44 +00:00
2018-11-26 09:56:07 +00:00
m_imgui - > end ( ) ;
2018-12-07 15:57:43 +00:00
# endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
2018-10-31 09:19:44 +00:00
}
# endif // ENABLE_IMGUI
2018-11-14 11:57:12 +00:00
double GLGizmoMove3D : : calc_projection ( const UpdateData & data ) const
2018-10-15 13:21:37 +00:00
{
double projection = 0.0 ;
2018-09-11 07:00:28 +00:00
2018-10-15 13:21:37 +00:00
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center ;
double len_starting_vec = starting_vec . norm ( ) ;
if ( len_starting_vec ! = 0.0 )
{
2018-11-14 11:57:12 +00:00
Vec3d mouse_dir = data . mouse_ray . unit_vector ( ) ;
2018-10-15 13:21:37 +00:00
// 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
2018-11-14 11:57:12 +00:00
Vec3d inters = data . mouse_ray . a + ( m_starting_drag_position - data . mouse_ray . a ) . dot ( mouse_dir ) / mouse_dir . squaredNorm ( ) * mouse_dir ;
2018-10-15 13:21:37 +00:00
// vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_starting_drag_position ;
// finds projection of the vector along the staring direction
projection = inters_vec . dot ( starting_vec . normalized ( ) ) ;
}
2018-11-14 12:29:57 +00:00
if ( data . shift_down )
projection = m_snap_step * ( double ) std : : round ( projection / m_snap_step ) ;
2018-10-15 13:21:37 +00:00
return projection ;
}
2018-08-27 12:00:53 +00:00
2018-12-03 07:51:18 +00:00
void GLGizmoMove3D : : render_grabber_extension ( Axis axis , const BoundingBoxf3 & box , bool picking ) const
{
2018-12-03 08:37:46 +00:00
if ( m_quadric = = nullptr )
return ;
2018-12-03 07:51:18 +00:00
double size = m_dragging ? ( double ) m_grabbers [ axis ] . get_dragging_half_size ( ( float ) box . max_size ( ) ) : ( double ) m_grabbers [ axis ] . get_half_size ( ( float ) box . max_size ( ) ) ;
float color [ 3 ] ;
: : memcpy ( ( void * ) color , ( const void * ) m_grabbers [ axis ] . color , 3 * sizeof ( float ) ) ;
if ( ! picking & & ( m_hover_id ! = - 1 ) )
{
color [ 0 ] = 1.0f - color [ 0 ] ;
color [ 1 ] = 1.0f - color [ 1 ] ;
color [ 2 ] = 1.0f - color [ 2 ] ;
}
if ( ! picking )
: : glEnable ( GL_LIGHTING ) ;
: : glColor3fv ( color ) ;
: : glPushMatrix ( ) ;
: : glTranslated ( m_grabbers [ axis ] . center ( 0 ) , m_grabbers [ axis ] . center ( 1 ) , m_grabbers [ axis ] . center ( 2 ) ) ;
if ( axis = = X )
: : glRotated ( 90.0 , 0.0 , 1.0 , 0.0 ) ;
else if ( axis = = Y )
: : glRotated ( - 90.0 , 1.0 , 0.0 , 0.0 ) ;
: : glTranslated ( 0.0 , 0.0 , 2.0 * size ) ;
2018-12-03 08:37:46 +00:00
: : gluQuadricOrientation ( m_quadric , GLU_OUTSIDE ) ;
: : gluCylinder ( m_quadric , 0.75 * size , 0.0 , 3.0 * size , 36 , 1 ) ;
: : gluQuadricOrientation ( m_quadric , GLU_INSIDE ) ;
: : gluDisk ( m_quadric , 0.0 , 0.75 * size , 36 , 1 ) ;
2018-12-03 07:51:18 +00:00
: : glPopMatrix ( ) ;
if ( ! picking )
: : glDisable ( GL_LIGHTING ) ;
}
2018-08-27 12:00:53 +00:00
GLGizmoFlatten : : GLGizmoFlatten ( GLCanvas3D & parent )
: GLGizmoBase ( parent )
2018-09-10 08:01:49 +00:00
, m_normal ( Vec3d : : Zero ( ) )
2018-09-10 09:58:24 +00:00
, m_starting_center ( Vec3d : : Zero ( ) )
2018-08-27 12:00:53 +00:00
{
}
2018-08-09 14:55:43 +00:00
bool GLGizmoFlatten : : on_init ( )
{
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Off ] . load_from_file ( path + " layflat_off.png " , false ) )
2018-08-09 14:55:43 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Hover ] . load_from_file ( path + " layflat_hover.png " , false ) )
2018-08-09 14:55:43 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ On ] . load_from_file ( path + " layflat_on.png " , false ) )
2018-08-09 14:55:43 +00:00
return false ;
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_F ;
2018-08-09 14:55:43 +00:00
return true ;
}
2018-10-25 07:35:08 +00:00
std : : string GLGizmoFlatten : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " Place on face [F] " ) ;
2018-10-25 07:35:08 +00:00
}
2018-11-28 11:06:17 +00:00
bool GLGizmoFlatten : : on_is_activable ( const GLCanvas3D : : Selection & selection ) const
{
2018-12-03 10:14:17 +00:00
return selection . is_single_full_instance ( ) ;
2018-11-28 11:06:17 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoFlatten : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
2018-08-09 14:55:43 +00:00
{
if ( m_hover_id ! = - 1 )
2018-09-10 08:01:49 +00:00
{
2019-01-26 17:51:34 +00:00
assert ( m_planes_valid ) ;
2018-08-09 14:55:43 +00:00
m_normal = m_planes [ m_hover_id ] . normal ;
2018-10-15 09:30:50 +00:00
m_starting_center = selection . get_bounding_box ( ) . center ( ) ;
2018-09-10 08:01:49 +00:00
}
2018-08-09 14:55:43 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoFlatten : : on_render ( const GLCanvas3D : : Selection & selection ) const
2018-08-09 14:55:43 +00:00
{
2018-11-26 12:02:40 +00:00
: : glClear ( GL_DEPTH_BUFFER_BIT ) ;
2018-12-03 10:14:17 +00:00
2018-08-17 13:40:47 +00:00
: : glEnable ( GL_DEPTH_TEST ) ;
2018-11-26 12:02:40 +00:00
: : glEnable ( GL_BLEND ) ;
2018-08-09 14:55:43 +00:00
2018-12-03 10:14:17 +00:00
if ( selection . is_single_full_instance ( ) )
{
const Transform3d & m = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_instance_transformation ( ) . get_matrix ( ) ;
: : glPushMatrix ( ) ;
: : glMultMatrixd ( m . data ( ) ) ;
2018-12-21 12:19:10 +00:00
: : glTranslatef ( 0.f , 0.f , selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_sla_shift_z ( ) ) ;
2019-01-26 17:51:34 +00:00
if ( this - > is_plane_update_necessary ( ) )
const_cast < GLGizmoFlatten * > ( this ) - > update_planes ( ) ;
2018-12-03 10:14:17 +00:00
for ( int i = 0 ; i < ( int ) m_planes . size ( ) ; + + i )
{
if ( i = = m_hover_id )
: : glColor4f ( 0.9f , 0.9f , 0.9f , 0.75f ) ;
else
: : glColor4f ( 0.9f , 0.9f , 0.9f , 0.5f ) ;
: : glBegin ( GL_POLYGON ) ;
for ( const Vec3d & vertex : m_planes [ i ] . vertices )
{
: : glVertex3dv ( vertex . data ( ) ) ;
2018-10-16 11:49:40 +00:00
}
2018-12-03 10:14:17 +00:00
: : glEnd ( ) ;
2018-10-16 11:49:40 +00:00
}
2018-12-03 10:14:17 +00:00
: : glPopMatrix ( ) ;
2018-08-09 14:55:43 +00:00
}
2018-09-04 12:42:14 +00:00
2018-10-19 11:26:42 +00:00
: : glEnable ( GL_CULL_FACE ) ;
2018-09-04 12:42:14 +00:00
: : glDisable ( GL_BLEND ) ;
2018-08-09 14:55:43 +00:00
}
2018-10-15 09:30:50 +00:00
void GLGizmoFlatten : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
2018-08-09 14:55:43 +00:00
{
2018-11-26 12:02:40 +00:00
: : glDisable ( GL_DEPTH_TEST ) ;
: : glDisable ( GL_BLEND ) ;
2018-12-03 10:14:17 +00:00
if ( selection . is_single_full_instance ( ) )
{
const Transform3d & m = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_instance_transformation ( ) . get_matrix ( ) ;
: : glPushMatrix ( ) ;
: : glMultMatrixd ( m . data ( ) ) ;
2018-12-21 12:19:10 +00:00
: : glTranslatef ( 0.f , 0.f , selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_sla_shift_z ( ) ) ;
2019-01-26 17:51:34 +00:00
if ( this - > is_plane_update_necessary ( ) )
const_cast < GLGizmoFlatten * > ( this ) - > update_planes ( ) ;
2018-12-03 10:14:17 +00:00
for ( int i = 0 ; i < ( int ) m_planes . size ( ) ; + + i )
{
: : glColor3f ( 1.0f , 1.0f , picking_color_component ( i ) ) ;
: : glBegin ( GL_POLYGON ) ;
for ( const Vec3d & vertex : m_planes [ i ] . vertices )
{
: : glVertex3dv ( vertex . data ( ) ) ;
2018-10-16 11:49:40 +00:00
}
2018-12-03 10:14:17 +00:00
: : glEnd ( ) ;
}
: : glPopMatrix ( ) ;
2018-08-09 14:55:43 +00:00
}
2018-10-19 11:26:42 +00:00
: : glEnable ( GL_CULL_FACE ) ;
2018-08-09 14:55:43 +00:00
}
2018-08-17 13:40:47 +00:00
void GLGizmoFlatten : : set_flattening_data ( const ModelObject * model_object )
2018-08-09 14:55:43 +00:00
{
2018-09-26 11:54:09 +00:00
m_starting_center = Vec3d : : Zero ( ) ;
2019-01-26 17:51:34 +00:00
if ( m_model_object ! = model_object ) {
m_planes . clear ( ) ;
m_planes_valid = false ;
}
2018-08-17 13:40:47 +00:00
m_model_object = model_object ;
}
void GLGizmoFlatten : : update_planes ( )
{
TriangleMesh ch ;
for ( const ModelVolume * vol : m_model_object - > volumes )
2018-11-02 11:11:28 +00:00
{
2018-11-26 12:02:40 +00:00
if ( vol - > type ( ) ! = ModelVolume : : Type : : MODEL_PART )
continue ;
2018-11-02 11:11:28 +00:00
TriangleMesh vol_ch = vol - > get_convex_hull ( ) ;
2018-11-02 12:47:47 +00:00
vol_ch . transform ( vol - > get_matrix ( ) ) ;
2018-11-02 11:11:28 +00:00
ch . merge ( vol_ch ) ;
}
2018-08-17 13:40:47 +00:00
ch = ch . convex_hull_3d ( ) ;
2019-01-04 15:18:25 +00:00
m_planes . clear ( ) ;
2019-01-21 11:53:30 +00:00
const Transform3d & inst_matrix = m_model_object - > instances . front ( ) - > get_matrix ( true ) ;
2019-01-04 14:34:07 +00:00
2019-01-04 16:47:08 +00:00
// Following constants are used for discarding too small polygons.
2019-01-07 11:05:16 +00:00
const float minimal_area = 5.f ; // in square mm (world coordinates)
2019-01-04 16:47:08 +00:00
const float minimal_side = 1.f ; // mm
// Now we'll go through all the facets and append Points of facets sharing the same normal.
// This part is still performed in mesh coordinate system.
2018-08-17 13:40:47 +00:00
const int num_of_facets = ch . stl . stats . number_of_facets ;
std : : vector < int > facet_queue ( num_of_facets , 0 ) ;
std : : vector < bool > facet_visited ( num_of_facets , false ) ;
int facet_queue_cnt = 0 ;
const stl_normal * normal_ptr = nullptr ;
while ( 1 ) {
// Find next unvisited triangle:
int facet_idx = 0 ;
for ( ; facet_idx < num_of_facets ; + + facet_idx )
if ( ! facet_visited [ facet_idx ] ) {
facet_queue [ facet_queue_cnt + + ] = facet_idx ;
facet_visited [ facet_idx ] = true ;
normal_ptr = & ch . stl . facet_start [ facet_idx ] . normal ;
m_planes . emplace_back ( ) ;
break ;
}
if ( facet_idx = = num_of_facets )
break ; // Everything was visited already
while ( facet_queue_cnt > 0 ) {
int facet_idx = facet_queue [ - - facet_queue_cnt ] ;
2018-08-27 12:00:53 +00:00
const stl_normal & this_normal = ch . stl . facet_start [ facet_idx ] . normal ;
2019-01-16 13:39:25 +00:00
if ( std : : abs ( this_normal ( 0 ) - ( * normal_ptr ) ( 0 ) ) < 0.001 & & std : : abs ( this_normal ( 1 ) - ( * normal_ptr ) ( 1 ) ) < 0.001 & & std : : abs ( this_normal ( 2 ) - ( * normal_ptr ) ( 2 ) ) < 0.001 ) {
2018-08-17 13:40:47 +00:00
stl_vertex * first_vertex = ch . stl . facet_start [ facet_idx ] . vertex ;
for ( int j = 0 ; j < 3 ; + + j )
2018-09-24 08:19:40 +00:00
m_planes . back ( ) . vertices . emplace_back ( ( double ) first_vertex [ j ] ( 0 ) , ( double ) first_vertex [ j ] ( 1 ) , ( double ) first_vertex [ j ] ( 2 ) ) ;
2018-08-17 13:40:47 +00:00
facet_visited [ facet_idx ] = true ;
for ( int j = 0 ; j < 3 ; + + j ) {
int neighbor_idx = ch . stl . neighbors_start [ facet_idx ] . neighbor [ j ] ;
if ( ! facet_visited [ neighbor_idx ] )
facet_queue [ facet_queue_cnt + + ] = neighbor_idx ;
}
}
}
2019-01-04 16:47:08 +00:00
m_planes . back ( ) . normal = normal_ptr - > cast < double > ( ) ;
// Now we'll transform all the points into world coordinates, so that the areas, angles and distances
// make real sense.
m_planes . back ( ) . vertices = transform ( m_planes . back ( ) . vertices , inst_matrix ) ;
2018-08-24 09:46:54 +00:00
2019-01-04 16:47:08 +00:00
// if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway):
2018-08-24 09:46:54 +00:00
if ( m_planes . back ( ) . vertices . size ( ) = = 3 & &
2019-01-04 16:47:08 +00:00
( ( m_planes . back ( ) . vertices [ 0 ] - m_planes . back ( ) . vertices [ 1 ] ) . norm ( ) < minimal_side
| | ( m_planes . back ( ) . vertices [ 0 ] - m_planes . back ( ) . vertices [ 2 ] ) . norm ( ) < minimal_side
| | ( m_planes . back ( ) . vertices [ 1 ] - m_planes . back ( ) . vertices [ 2 ] ) . norm ( ) < minimal_side ) )
2018-09-24 08:19:40 +00:00
m_planes . pop_back ( ) ;
2018-08-17 13:40:47 +00:00
}
2019-01-23 13:27:11 +00:00
// Let's prepare transformation of the normal vector from mesh to instance coordinates.
Geometry : : Transformation t ( inst_matrix ) ;
Vec3d scaling = t . get_scaling_factor ( ) ;
t . set_scaling_factor ( Vec3d ( 1. / scaling ( 0 ) , 1. / scaling ( 1 ) , 1. / scaling ( 2 ) ) ) ;
2018-08-17 13:40:47 +00:00
// Now we'll go through all the polygons, transform the points into xy plane to process them:
for ( unsigned int polygon_id = 0 ; polygon_id < m_planes . size ( ) ; + + polygon_id ) {
Pointf3s & polygon = m_planes [ polygon_id ] . vertices ;
2018-08-27 12:00:53 +00:00
const Vec3d & normal = m_planes [ polygon_id ] . normal ;
2018-08-17 13:40:47 +00:00
2019-01-23 13:27:11 +00:00
// transform the normal according to the instance matrix:
2019-01-04 16:47:08 +00:00
Vec3d normal_transformed = t . get_matrix ( ) * normal ;
2018-08-17 13:40:47 +00:00
// We are going to rotate about z and y to flatten the plane
2018-09-24 08:19:40 +00:00
Eigen : : Quaterniond q ;
2018-08-28 07:03:03 +00:00
Transform3d m = Transform3d : : Identity ( ) ;
2019-01-04 16:47:08 +00:00
m . matrix ( ) . block ( 0 , 0 , 3 , 3 ) = q . setFromTwoVectors ( normal_transformed , Vec3d : : UnitZ ( ) ) . toRotationMatrix ( ) ;
2018-08-28 07:03:03 +00:00
polygon = transform ( polygon , m ) ;
2019-01-04 16:47:08 +00:00
// Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since
// it works in fixed point representation, we will rescale the polygon to avoid overflows.
// And yes, it is a nasty thing to do. Whoever has time is free to refactor.
Vec3d bb_size = BoundingBoxf3 ( polygon ) . size ( ) ;
float sf = std : : min ( 1. / bb_size ( 0 ) , 1. / bb_size ( 1 ) ) ;
Transform3d tr = Geometry : : assemble_transform ( Vec3d : : Zero ( ) , Vec3d : : Zero ( ) , Vec3d ( sf , sf , 1.f ) ) ;
polygon = transform ( polygon , tr ) ;
polygon = Slic3r : : Geometry : : convex_hull ( polygon ) ;
polygon = transform ( polygon , tr . inverse ( ) ) ;
// Calculate area of the polygons and discard ones that are too small
2018-08-21 13:56:40 +00:00
float & area = m_planes [ polygon_id ] . area ;
area = 0.f ;
2018-08-17 13:40:47 +00:00
for ( unsigned int i = 0 ; i < polygon . size ( ) ; i + + ) // Shoelace formula
2018-08-27 12:00:53 +00:00
area + = polygon [ i ] ( 0 ) * polygon [ i + 1 < polygon . size ( ) ? i + 1 : 0 ] ( 1 ) - polygon [ i + 1 < polygon . size ( ) ? i + 1 : 0 ] ( 0 ) * polygon [ i ] ( 1 ) ;
2018-09-24 08:19:40 +00:00
area = 0.5f * std : : abs ( area ) ;
2018-08-17 13:40:47 +00:00
2018-09-24 08:19:40 +00:00
bool discard = false ;
2019-01-04 16:47:08 +00:00
if ( area < minimal_area )
discard = true ;
else {
// We also check the inner angles and discard polygons with angles smaller than the following threshold
const double angle_threshold = : : cos ( 10.0 * ( double ) PI / 180.0 ) ;
for ( unsigned int i = 0 ; i < polygon . size ( ) ; + + i ) {
const Vec3d & prec = polygon [ ( i = = 0 ) ? polygon . size ( ) - 1 : i - 1 ] ;
const Vec3d & curr = polygon [ i ] ;
const Vec3d & next = polygon [ ( i = = polygon . size ( ) - 1 ) ? 0 : i + 1 ] ;
if ( ( prec - curr ) . normalized ( ) . dot ( ( next - curr ) . normalized ( ) ) > angle_threshold ) {
discard = true ;
break ;
}
2018-09-24 08:19:40 +00:00
}
}
2019-01-04 16:47:08 +00:00
if ( discard ) {
2018-09-24 08:19:40 +00:00
m_planes . erase ( m_planes . begin ( ) + ( polygon_id - - ) ) ;
continue ;
}
2018-08-17 13:40:47 +00:00
// We will shrink the polygon a little bit so it does not touch the object edges:
2018-08-27 12:00:53 +00:00
Vec3d centroid = std : : accumulate ( polygon . begin ( ) , polygon . end ( ) , Vec3d ( 0.0 , 0.0 , 0.0 ) ) ;
centroid / = ( double ) polygon . size ( ) ;
2018-08-17 13:40:47 +00:00
for ( auto & vertex : polygon )
vertex = 0.9f * vertex + 0.1f * centroid ;
// Polygon is now simple and convex, we'll round the corners to make them look nicer.
// The algorithm takes a vertex, calculates middles of respective sides and moves the vertex
// towards their average (controlled by 'aggressivity'). This is repeated k times.
// In next iterations, the neighbours are not always taken at the middle (to increase the
// rounding effect at the corners, where we need it most).
const unsigned int k = 10 ; // number of iterations
const float aggressivity = 0.2f ; // agressivity
const unsigned int N = polygon . size ( ) ;
std : : vector < std : : pair < unsigned int , unsigned int > > neighbours ;
if ( k ! = 0 ) {
Pointf3s points_out ( 2 * k * N ) ; // vector long enough to store the future vertices
for ( unsigned int j = 0 ; j < N ; + + j ) {
points_out [ j * 2 * k ] = polygon [ j ] ;
neighbours . push_back ( std : : make_pair ( ( int ) ( j * 2 * k - k ) < 0 ? ( N - 1 ) * 2 * k + k : j * 2 * k - k , j * 2 * k + k ) ) ;
}
for ( unsigned int i = 0 ; i < k ; + + i ) {
// Calculate middle of each edge so that neighbours points to something useful:
for ( unsigned int j = 0 ; j < N ; + + j )
if ( i = = 0 )
points_out [ j * 2 * k + k ] = 0.5f * ( points_out [ j * 2 * k ] + points_out [ j = = N - 1 ? 0 : ( j + 1 ) * 2 * k ] ) ;
else {
float r = 0.2 + 0.3 / ( k - 1 ) * i ; // the neighbours are not always taken in the middle
points_out [ neighbours [ j ] . first ] = r * points_out [ j * 2 * k ] + ( 1 - r ) * points_out [ neighbours [ j ] . first - 1 ] ;
points_out [ neighbours [ j ] . second ] = r * points_out [ j * 2 * k ] + ( 1 - r ) * points_out [ neighbours [ j ] . second + 1 ] ;
}
// Now we have a triangle and valid neighbours, we can do an iteration:
for ( unsigned int j = 0 ; j < N ; + + j )
points_out [ 2 * k * j ] = ( 1 - aggressivity ) * points_out [ 2 * k * j ] +
aggressivity * 0.5f * ( points_out [ neighbours [ j ] . first ] + points_out [ neighbours [ j ] . second ] ) ;
for ( auto & n : neighbours ) {
+ + n . first ;
- - n . second ;
}
}
polygon = points_out ; // replace the coarse polygon with the smooth one that we just created
}
2018-08-28 07:03:03 +00:00
2019-01-04 16:47:08 +00:00
// Raise a bit above the object surface to avoid flickering:
for ( auto & b : polygon )
b ( 2 ) + = 0.1f ;
// Transform back to 3D (and also back to mesh coordinates)
polygon = transform ( polygon , inst_matrix . inverse ( ) * m . inverse ( ) ) ;
2018-08-09 14:55:43 +00:00
}
2018-08-17 13:40:47 +00:00
2018-09-06 07:16:32 +00:00
// We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations):
2018-08-21 13:56:40 +00:00
std : : sort ( m_planes . rbegin ( ) , m_planes . rend ( ) , [ ] ( const PlaneData & a , const PlaneData & b ) { return a . area < b . area ; } ) ;
2018-09-06 07:16:32 +00:00
m_planes . resize ( std : : min ( ( int ) m_planes . size ( ) , 254 ) ) ;
2018-08-21 13:56:40 +00:00
2018-08-17 13:40:47 +00:00
// Planes are finished - let's save what we calculated it from:
2018-11-28 10:37:17 +00:00
m_volumes_matrices . clear ( ) ;
2019-01-04 16:47:08 +00:00
m_volumes_types . clear ( ) ;
for ( const ModelVolume * vol : m_model_object - > volumes ) {
2018-11-28 10:37:17 +00:00
m_volumes_matrices . push_back ( vol - > get_matrix ( ) ) ;
2019-01-04 16:47:08 +00:00
m_volumes_types . push_back ( vol - > type ( ) ) ;
}
m_first_instance_scale = m_model_object - > instances . front ( ) - > get_scaling_factor ( ) ;
2019-01-21 11:53:30 +00:00
m_first_instance_mirror = m_model_object - > instances . front ( ) - > get_mirror ( ) ;
2019-01-26 17:51:34 +00:00
m_planes_valid = true ;
2018-08-17 13:40:47 +00:00
}
2019-01-04 16:47:08 +00:00
2018-08-17 13:40:47 +00:00
bool GLGizmoFlatten : : is_plane_update_necessary ( ) const
{
if ( m_state ! = On | | ! m_model_object | | m_model_object - > instances . empty ( ) )
return false ;
2019-01-26 17:51:34 +00:00
if ( ! m_planes_valid | | m_model_object - > volumes . size ( ) ! = m_volumes_matrices . size ( ) )
2018-09-20 13:00:40 +00:00
return true ;
2018-08-17 13:40:47 +00:00
2019-01-04 16:47:08 +00:00
// We want to recalculate when the scale changes - some planes could (dis)appear.
2019-01-21 11:53:30 +00:00
if ( ! m_model_object - > instances . front ( ) - > get_scaling_factor ( ) . isApprox ( m_first_instance_scale )
| | ! m_model_object - > instances . front ( ) - > get_mirror ( ) . isApprox ( m_first_instance_mirror ) )
2019-01-04 16:47:08 +00:00
return true ;
2018-11-28 10:37:17 +00:00
for ( unsigned int i = 0 ; i < m_model_object - > volumes . size ( ) ; + + i )
2019-01-04 16:47:08 +00:00
if ( ! m_model_object - > volumes [ i ] - > get_matrix ( ) . isApprox ( m_volumes_matrices [ i ] )
| | m_model_object - > volumes [ i ] - > type ( ) ! = m_volumes_types [ i ] )
2018-08-17 13:40:47 +00:00
return true ;
return false ;
2018-08-09 14:55:43 +00:00
}
2018-11-02 14:20:26 +00:00
Vec3d GLGizmoFlatten : : get_flattening_normal ( ) const
2018-09-20 13:00:40 +00:00
{
2018-11-02 14:20:26 +00:00
Vec3d out = m_normal ;
2018-08-27 12:00:53 +00:00
m_normal = Vec3d : : Zero ( ) ;
2018-10-26 13:45:52 +00:00
m_starting_center = Vec3d : : Zero ( ) ;
2018-11-02 14:20:26 +00:00
return out ;
2018-08-09 14:55:43 +00:00
}
2018-09-12 10:14:20 +00:00
GLGizmoSlaSupports : : GLGizmoSlaSupports ( GLCanvas3D & parent )
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
: GLGizmoBase ( parent ) , m_starting_center ( Vec3d : : Zero ( ) ) , m_quadric ( nullptr )
# else
2018-09-26 11:54:09 +00:00
: GLGizmoBase ( parent ) , m_starting_center ( Vec3d : : Zero ( ) )
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-12 10:14:20 +00:00
{
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
m_quadric = : : gluNewQuadric ( ) ;
if ( m_quadric ! = nullptr )
2018-12-07 09:36:43 +00:00
// using GLU_FILL does not work when the instance's transformation
// contains mirroring (normals are reverted)
2019-01-04 16:47:08 +00:00
: : gluQuadricDrawStyle ( m_quadric , GLU_FILL ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
}
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
GLGizmoSlaSupports : : ~ GLGizmoSlaSupports ( )
{
if ( m_quadric ! = nullptr )
: : gluDeleteQuadric ( m_quadric ) ;
2018-09-12 10:14:20 +00:00
}
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-12 10:14:20 +00:00
bool GLGizmoSlaSupports : : on_init ( )
{
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Off ] . load_from_file ( path + " sla_support_points_off.png " , false ) )
2018-09-12 10:14:20 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ Hover ] . load_from_file ( path + " sla_support_points_hover.png " , false ) )
2018-09-12 10:14:20 +00:00
return false ;
2018-11-14 12:49:41 +00:00
if ( ! m_textures [ On ] . load_from_file ( path + " sla_support_points_on.png " , false ) )
2018-09-12 10:14:20 +00:00
return false ;
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_L ;
2018-09-12 10:14:20 +00:00
return true ;
}
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLGizmoSlaSupports : : set_sla_support_data ( ModelObject * model_object , const GLCanvas3D : : Selection & selection )
{
m_starting_center = Vec3d : : Zero ( ) ;
m_old_model_object = m_model_object ;
m_model_object = model_object ;
2018-12-05 09:26:08 +00:00
if ( selection . is_empty ( ) )
m_old_instance_id = - 1 ;
2018-12-03 13:02:58 +00:00
if ( ( model_object ! = nullptr ) & & selection . is_from_single_instance ( ) )
{
if ( is_mesh_update_necessary ( ) )
update_mesh ( ) ;
2018-12-21 11:35:20 +00:00
// If there are no points, let's ask the backend if it calculated some.
if ( model_object - > sla_support_points . empty ( ) & & m_parent . sla_print ( ) - > is_step_done ( slaposSupportPoints ) ) {
for ( const SLAPrintObject * po : m_parent . sla_print ( ) - > objects ( ) ) {
if ( po - > model_object ( ) - > id ( ) = = model_object - > id ( ) ) {
const Eigen : : MatrixXd & points = po - > get_support_points ( ) ;
for ( unsigned int i = 0 ; i < points . rows ( ) ; + + i )
model_object - > sla_support_points . push_back ( Vec3f ( po - > trafo ( ) . inverse ( ) . cast < float > ( ) * Vec3f ( points ( i , 0 ) , points ( i , 1 ) , points ( i , 2 ) ) ) ) ;
break ;
}
}
}
2018-12-03 13:02:58 +00:00
}
}
# else
2018-09-26 11:54:09 +00:00
void GLGizmoSlaSupports : : set_model_object_ptr ( ModelObject * model_object )
{
2018-12-07 13:10:16 +00:00
if ( model_object ! = nullptr ) {
2018-11-02 11:11:28 +00:00
m_starting_center = Vec3d : : Zero ( ) ;
m_model_object = model_object ;
2018-11-26 09:49:25 +00:00
int selected_instance = m_parent . get_selection ( ) . get_instance_idx ( ) ;
assert ( selected_instance < ( int ) model_object - > instances . size ( ) ) ;
m_instance_matrix = model_object - > instances [ selected_instance ] - > get_matrix ( ) ;
2018-11-02 11:11:28 +00:00
if ( is_mesh_update_necessary ( ) )
update_mesh ( ) ;
}
2018-09-26 11:54:09 +00:00
}
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-26 11:54:09 +00:00
2018-10-26 13:45:52 +00:00
void GLGizmoSlaSupports : : on_render ( const GLCanvas3D : : Selection & selection ) const
2018-09-12 10:14:20 +00:00
{
: : glEnable ( GL_BLEND ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
2018-12-03 13:02:58 +00:00
# if !ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-26 11:54:09 +00:00
// the dragged_offset is a vector measuring where was the object moved
2018-11-26 09:49:25 +00:00
// with the gizmo being on. This is reset in set_model_object_ptr and
2018-09-26 11:54:09 +00:00
// does not work correctly when there are multiple copies.
2018-10-26 13:45:52 +00:00
if ( m_starting_center = = Vec3d : : Zero ( ) )
m_starting_center = selection . get_bounding_box ( ) . center ( ) ;
Vec3d dragged_offset = selection . get_bounding_box ( ) . center ( ) - m_starting_center ;
2018-12-03 13:02:58 +00:00
# endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-26 11:54:09 +00:00
2018-12-07 13:10:16 +00:00
2018-09-19 12:59:57 +00:00
for ( auto & g : m_grabbers ) {
g . color [ 0 ] = 1.f ;
g . color [ 1 ] = 0.f ;
g . color [ 2 ] = 0.f ;
2018-09-12 10:14:20 +00:00
}
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
render_grabbers ( selection , false ) ;
# else
2018-11-26 09:49:25 +00:00
//::glTranslatef((GLfloat)dragged_offset(0), (GLfloat)dragged_offset(1), (GLfloat)dragged_offset(2));
2018-11-26 19:39:18 +00:00
render_grabbers ( false ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-19 12:59:57 +00:00
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-09-26 12:37:25 +00:00
render_tooltip_texture ( ) ;
2018-11-26 14:54:12 +00:00
# endif // not ENABLE_IMGUI
2018-09-12 10:14:20 +00:00
: : glDisable ( GL_BLEND ) ;
}
2018-10-26 13:45:52 +00:00
void GLGizmoSlaSupports : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
2018-09-12 10:14:20 +00:00
{
: : glEnable ( GL_DEPTH_TEST ) ;
2018-09-19 12:59:57 +00:00
for ( unsigned int i = 0 ; i < m_grabbers . size ( ) ; + + i ) {
m_grabbers [ i ] . color [ 0 ] = 1.0f ;
m_grabbers [ i ] . color [ 1 ] = 1.0f ;
m_grabbers [ i ] . color [ 2 ] = picking_color_component ( i ) ;
}
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
render_grabbers ( selection , true ) ;
# else
2018-09-26 12:37:25 +00:00
render_grabbers ( true ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-19 12:59:57 +00:00
}
2018-09-12 10:14:20 +00:00
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
void GLGizmoSlaSupports : : render_grabbers ( const GLCanvas3D : : Selection & selection , bool picking ) const
{
if ( m_quadric = = nullptr )
return ;
if ( ! selection . is_from_single_instance ( ) )
return ;
const GLVolume * v = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
double z_shift = v - > get_sla_shift_z ( ) ;
: : glPushMatrix ( ) ;
: : glTranslated ( 0.0 , 0.0 , z_shift ) ;
const Transform3d & m = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) - > get_instance_transformation ( ) . get_matrix ( ) ;
: : glMultMatrixd ( m . data ( ) ) ;
if ( ! picking )
: : glEnable ( GL_LIGHTING ) ;
float render_color [ 3 ] ;
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
2018-12-07 13:10:16 +00:00
// first precalculate the grabber position in world coordinates, so that the grabber
// is not scaled with the object (as it would be if rendered with current gl matrix).
Eigen : : Matrix < GLfloat , 4 , 4 > glmatrix ;
glGetFloatv ( GL_MODELVIEW_MATRIX , glmatrix . data ( ) ) ;
Eigen : : Matrix < float , 4 , 1 > grabber_pos ;
for ( int j = 0 ; j < 3 ; + + j )
grabber_pos ( j ) = m_grabbers [ i ] . center ( j ) ;
grabber_pos [ 3 ] = 1.f ;
Eigen : : Matrix < float , 4 , 1 > grabber_world_position = glmatrix * grabber_pos ;
2018-12-03 13:02:58 +00:00
if ( ! picking & & ( m_hover_id = = i ) )
{
render_color [ 0 ] = 1.0f - m_grabbers [ i ] . color [ 0 ] ;
render_color [ 1 ] = 1.0f - m_grabbers [ i ] . color [ 1 ] ;
render_color [ 2 ] = 1.0f - m_grabbers [ i ] . color [ 2 ] ;
}
else
: : memcpy ( ( void * ) render_color , ( const void * ) m_grabbers [ i ] . color , 3 * sizeof ( float ) ) ;
: : glColor3fv ( render_color ) ;
: : glPushMatrix ( ) ;
2018-12-07 13:10:16 +00:00
: : glLoadIdentity ( ) ;
: : glTranslated ( grabber_world_position ( 0 ) , grabber_world_position ( 1 ) , grabber_world_position ( 2 ) + z_shift ) ;
2019-01-04 16:47:08 +00:00
const float diameter = 0.8f ;
: : gluSphere ( m_quadric , diameter / 2.f , 64 , 36 ) ;
2018-12-03 13:02:58 +00:00
: : glPopMatrix ( ) ;
}
if ( ! picking )
: : glDisable ( GL_LIGHTING ) ;
: : glPopMatrix ( ) ;
}
# else
2018-09-26 12:37:25 +00:00
void GLGizmoSlaSupports : : render_grabbers ( bool picking ) const
2018-09-19 12:59:57 +00:00
{
2018-11-26 18:22:16 +00:00
if ( m_parent . get_selection ( ) . is_empty ( ) )
return ;
float z_shift = m_parent . get_selection ( ) . get_volume ( 0 ) - > get_sla_shift_z ( ) ;
: : glTranslatef ( ( GLfloat ) 0 , ( GLfloat ) 0 , ( GLfloat ) z_shift ) ;
2018-11-26 19:39:18 +00:00
int selected_instance = m_parent . get_selection ( ) . get_instance_idx ( ) ;
assert ( selected_instance < ( int ) m_model_object - > instances . size ( ) ) ;
float render_color_inactive [ 3 ] = { 0.5f , 0.5f , 0.5f } ;
2018-11-26 09:49:25 +00:00
for ( const ModelInstance * inst : m_model_object - > instances ) {
2018-11-26 19:39:18 +00:00
bool active = inst = = m_model_object - > instances [ selected_instance ] ;
if ( picking & & ! active )
continue ;
2018-11-26 09:49:25 +00:00
for ( int i = 0 ; i < ( int ) m_grabbers . size ( ) ; + + i )
{
if ( ! m_grabbers [ i ] . enabled )
continue ;
float render_color [ 3 ] ;
2018-11-26 19:39:18 +00:00
if ( ! picking & & active & & m_hover_id = = i ) {
2018-11-26 09:49:25 +00:00
render_color [ 0 ] = 1.0f - m_grabbers [ i ] . color [ 0 ] ;
render_color [ 1 ] = 1.0f - m_grabbers [ i ] . color [ 1 ] ;
render_color [ 2 ] = 1.0f - m_grabbers [ i ] . color [ 2 ] ;
}
else
2018-11-26 19:39:18 +00:00
: : memcpy ( ( void * ) render_color , active ? ( const void * ) m_grabbers [ i ] . color : ( const void * ) render_color_inactive , 3 * sizeof ( float ) ) ;
2018-11-26 09:49:25 +00:00
if ( ! picking )
: : glEnable ( GL_LIGHTING ) ;
: : glColor3f ( ( GLfloat ) render_color [ 0 ] , ( GLfloat ) render_color [ 1 ] , ( GLfloat ) render_color [ 2 ] ) ;
: : glPushMatrix ( ) ;
Vec3d center = inst - > get_matrix ( ) * m_grabbers [ i ] . center ;
: : glTranslatef ( ( GLfloat ) center ( 0 ) , ( GLfloat ) center ( 1 ) , ( GLfloat ) center ( 2 ) ) ;
GLUquadricObj * quadric ;
quadric = : : gluNewQuadric ( ) ;
: : gluQuadricDrawStyle ( quadric , GLU_FILL ) ;
2019-01-04 16:47:08 +00:00
: : gluSphere ( quadric , 0.4 , 64 , 32 ) ;
2018-11-26 09:49:25 +00:00
: : gluDeleteQuadric ( quadric ) ;
: : glPopMatrix ( ) ;
if ( ! picking )
: : glDisable ( GL_LIGHTING ) ;
2018-09-12 10:14:20 +00:00
}
}
2018-11-26 18:22:16 +00:00
: : glTranslatef ( ( GLfloat ) 0 , ( GLfloat ) 0 , ( GLfloat ) - z_shift ) ;
2018-09-12 10:14:20 +00:00
}
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-12 10:14:20 +00:00
2018-09-24 11:39:44 +00:00
bool GLGizmoSlaSupports : : is_mesh_update_necessary ( ) const
{
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
return ( m_state = = On ) & & ( m_model_object ! = nullptr ) & & ( m_model_object ! = m_old_model_object ) & & ! m_model_object - > instances . empty ( ) ;
# else
return m_state = = On & & m_model_object & & ! m_model_object - > instances . empty ( ) & & ! m_instance_matrix . isApprox ( m_source_data . matrix ) ;
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-24 11:39:44 +00:00
2018-11-26 18:22:16 +00:00
//if (m_state != On || !m_model_object || m_model_object->instances.empty() || ! m_instance_matrix.isApprox(m_source_data.matrix))
// return false;
2018-09-24 11:39:44 +00:00
// following should detect direct mesh changes (can be removed after the mesh is made completely immutable):
2018-10-26 13:45:52 +00:00
/*const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex();
2018-09-24 11:39:44 +00:00
Vec3d first_point ( ( double ) first_vertex [ 0 ] , ( double ) first_vertex [ 1 ] , ( double ) first_vertex [ 2 ] ) ;
if ( first_point ! = m_source_data . mesh_first_point )
2018-10-26 13:45:52 +00:00
return true ; */
2018-09-24 11:39:44 +00:00
}
void GLGizmoSlaSupports : : update_mesh ( )
{
Eigen : : MatrixXf & V = m_V ;
Eigen : : MatrixXi & F = m_F ;
2018-11-26 18:22:16 +00:00
// Composite mesh of all instances in the world coordinate system.
// This mesh does not account for the possible Z up SLA offset.
2018-11-26 19:39:18 +00:00
TriangleMesh mesh = m_model_object - > raw_mesh ( ) ;
2018-11-08 13:55:25 +00:00
const stl_file & stl = mesh . stl ;
V . resize ( 3 * stl . stats . number_of_facets , 3 ) ;
2018-09-24 11:39:44 +00:00
F . resize ( stl . stats . number_of_facets , 3 ) ;
for ( unsigned int i = 0 ; i < stl . stats . number_of_facets ; + + i ) {
const stl_facet * facet = stl . facet_start + i ;
V ( 3 * i + 0 , 0 ) = facet - > vertex [ 0 ] ( 0 ) ; V ( 3 * i + 0 , 1 ) = facet - > vertex [ 0 ] ( 1 ) ; V ( 3 * i + 0 , 2 ) = facet - > vertex [ 0 ] ( 2 ) ;
V ( 3 * i + 1 , 0 ) = facet - > vertex [ 1 ] ( 0 ) ; V ( 3 * i + 1 , 1 ) = facet - > vertex [ 1 ] ( 1 ) ; V ( 3 * i + 1 , 2 ) = facet - > vertex [ 1 ] ( 2 ) ;
V ( 3 * i + 2 , 0 ) = facet - > vertex [ 2 ] ( 0 ) ; V ( 3 * i + 2 , 1 ) = facet - > vertex [ 2 ] ( 1 ) ; V ( 3 * i + 2 , 2 ) = facet - > vertex [ 2 ] ( 2 ) ;
F ( i , 0 ) = 3 * i + 0 ;
F ( i , 1 ) = 3 * i + 1 ;
F ( i , 2 ) = 3 * i + 2 ;
}
2018-11-26 09:49:25 +00:00
m_AABB = igl : : AABB < Eigen : : MatrixXf , 3 > ( ) ;
m_AABB . init ( m_V , m_F ) ;
2018-12-03 13:02:58 +00:00
# if !ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-26 09:49:25 +00:00
m_source_data . matrix = m_instance_matrix ;
2018-12-03 13:02:58 +00:00
# endif // !ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-26 09:49:25 +00:00
2018-09-24 11:39:44 +00:00
// we'll now reload Grabbers (selection might have changed):
m_grabbers . clear ( ) ;
2018-12-07 13:10:16 +00:00
2018-09-24 11:39:44 +00:00
for ( const Vec3f & point : m_model_object - > sla_support_points ) {
m_grabbers . push_back ( Grabber ( ) ) ;
m_grabbers . back ( ) . center = point . cast < double > ( ) ;
}
}
2018-09-19 12:59:57 +00:00
Vec3f GLGizmoSlaSupports : : unproject_on_mesh ( const Vec2d & mouse_pos )
{
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
if ( m_V . size ( ) = = 0 )
# else
2018-09-24 11:39:44 +00:00
if ( m_V . size ( ) = = 0 | | is_mesh_update_necessary ( ) )
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-24 11:39:44 +00:00
update_mesh ( ) ;
2018-09-12 10:14:20 +00:00
Eigen : : Matrix < GLint , 4 , 1 , Eigen : : DontAlign > viewport ;
: : glGetIntegerv ( GL_VIEWPORT , viewport . data ( ) ) ;
Eigen : : Matrix < GLdouble , 4 , 4 , Eigen : : DontAlign > modelview_matrix ;
: : glGetDoublev ( GL_MODELVIEW_MATRIX , modelview_matrix . data ( ) ) ;
Eigen : : Matrix < GLdouble , 4 , 4 , Eigen : : DontAlign > projection_matrix ;
: : glGetDoublev ( GL_PROJECTION_MATRIX , projection_matrix . data ( ) ) ;
2018-11-26 09:49:25 +00:00
Vec3d point1 ;
Vec3d point2 ;
: : gluUnProject ( mouse_pos ( 0 ) , viewport ( 3 ) - mouse_pos ( 1 ) , 0.f , modelview_matrix . data ( ) , projection_matrix . data ( ) , viewport . data ( ) , & point1 ( 0 ) , & point1 ( 1 ) , & point1 ( 2 ) ) ;
: : gluUnProject ( mouse_pos ( 0 ) , viewport ( 3 ) - mouse_pos ( 1 ) , 1.f , modelview_matrix . data ( ) , projection_matrix . data ( ) , viewport . data ( ) , & point2 ( 0 ) , & point2 ( 1 ) , & point2 ( 2 ) ) ;
igl : : Hit hit ;
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
const GLCanvas3D : : Selection & selection = m_parent . get_selection ( ) ;
const GLVolume * volume = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
double z_offset = volume - > get_sla_shift_z ( ) ;
# else
double z_offset = m_parent . get_selection ( ) . get_volume ( 0 ) - > get_sla_shift_z ( ) ;
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
point1 ( 2 ) - = z_offset ;
2018-11-26 18:22:16 +00:00
point2 ( 2 ) - = z_offset ;
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
Transform3d inv = volume - > get_instance_transformation ( ) . get_matrix ( ) . inverse ( ) ;
# else
2018-11-26 19:39:18 +00:00
Transform3d inv = m_instance_matrix . inverse ( ) ;
2018-12-03 13:02:58 +00:00
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-11-26 19:39:18 +00:00
point1 = inv * point1 ;
point2 = inv * point2 ;
2018-11-26 18:22:16 +00:00
2018-11-26 09:49:25 +00:00
if ( ! m_AABB . intersect_ray ( m_V , m_F , point1 . cast < float > ( ) , ( point2 - point1 ) . cast < float > ( ) , hit ) )
throw std : : invalid_argument ( " unproject_on_mesh(): No intersection found. " ) ;
int fid = hit . id ;
Vec3f bc ( 1 - hit . u - hit . v , hit . u , hit . v ) ;
2018-11-26 19:39:18 +00:00
return bc ( 0 ) * m_V . row ( m_F ( fid , 0 ) ) + bc ( 1 ) * m_V . row ( m_F ( fid , 1 ) ) + bc ( 2 ) * m_V . row ( m_F ( fid , 2 ) ) ;
2018-09-19 12:59:57 +00:00
}
void GLGizmoSlaSupports : : clicked_on_object ( const Vec2d & mouse_position )
{
2018-12-03 13:02:58 +00:00
# if ENABLE_SLA_SUPPORT_GIZMO_MOD
int instance_id = m_parent . get_selection ( ) . get_instance_idx ( ) ;
if ( m_old_instance_id ! = instance_id )
{
2018-12-05 09:26:08 +00:00
bool something_selected = ( m_old_instance_id ! = - 1 ) ;
2018-12-03 13:02:58 +00:00
m_old_instance_id = instance_id ;
2018-12-05 09:26:08 +00:00
if ( something_selected )
return ;
2018-12-03 13:02:58 +00:00
}
if ( instance_id = = - 1 )
return ;
# endif // ENABLE_SLA_SUPPORT_GIZMO_MOD
2018-09-19 12:59:57 +00:00
Vec3f new_pos ;
try {
new_pos = unproject_on_mesh ( mouse_position ) ; // this can throw - we don't want to create a new grabber in that case
}
2018-11-26 09:49:25 +00:00
catch ( . . . ) { return ; }
m_grabbers . push_back ( Grabber ( ) ) ;
m_grabbers . back ( ) . center = new_pos . cast < double > ( ) ;
m_model_object - > sla_support_points . push_back ( new_pos ) ;
// This should trigger the support generation
// wxGetApp().plater()->reslice();
m_parent . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2018-09-19 12:59:57 +00:00
}
void GLGizmoSlaSupports : : delete_current_grabber ( bool delete_all )
{
if ( delete_all ) {
m_grabbers . clear ( ) ;
2018-09-24 11:39:44 +00:00
m_model_object - > sla_support_points . clear ( ) ;
2018-11-12 16:35:57 +00:00
// This should trigger the support generation
2018-11-13 10:53:54 +00:00
// wxGetApp().plater()->reslice();
2018-09-19 12:59:57 +00:00
}
else
if ( m_hover_id ! = - 1 ) {
m_grabbers . erase ( m_grabbers . begin ( ) + m_hover_id ) ;
2018-09-24 11:39:44 +00:00
m_model_object - > sla_support_points . erase ( m_model_object - > sla_support_points . begin ( ) + m_hover_id ) ;
2018-09-19 12:59:57 +00:00
m_hover_id = - 1 ;
2018-11-12 16:35:57 +00:00
// This should trigger the support generation
2018-11-13 10:53:54 +00:00
// wxGetApp().plater()->reslice();
2018-09-19 12:59:57 +00:00
}
2018-11-26 09:49:25 +00:00
m_parent . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
2018-09-19 12:59:57 +00:00
}
2019-01-10 12:13:11 +00:00
void GLGizmoSlaSupports : : on_update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-09-19 12:59:57 +00:00
{
2018-11-14 11:57:12 +00:00
if ( m_hover_id ! = - 1 & & data . mouse_pos ) {
2018-09-19 12:59:57 +00:00
Vec3f new_pos ;
try {
2018-11-14 11:57:12 +00:00
new_pos = unproject_on_mesh ( Vec2d ( ( * data . mouse_pos ) ( 0 ) , ( * data . mouse_pos ) ( 1 ) ) ) ;
2018-09-19 12:59:57 +00:00
}
2018-11-26 09:49:25 +00:00
catch ( . . . ) { return ; }
m_grabbers [ m_hover_id ] . center = new_pos . cast < double > ( ) ;
m_model_object - > sla_support_points [ m_hover_id ] = new_pos ;
2018-11-26 18:22:16 +00:00
// Do not update immediately, wait until the mouse is released.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
2018-09-12 10:14:20 +00:00
}
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-09-19 12:59:57 +00:00
void GLGizmoSlaSupports : : render_tooltip_texture ( ) const {
if ( m_tooltip_texture . get_id ( ) = = 0 )
2018-11-26 09:49:25 +00:00
if ( ! m_tooltip_texture . load_from_file ( resources_dir ( ) + " /icons/sla_support_points_tooltip.png " , false ) )
2018-09-19 12:59:57 +00:00
return ;
if ( m_reset_texture . get_id ( ) = = 0 )
2018-11-26 09:49:25 +00:00
if ( ! m_reset_texture . load_from_file ( resources_dir ( ) + " /icons/sla_support_points_reset.png " , false ) )
2018-09-19 12:59:57 +00:00
return ;
float zoom = m_parent . get_camera_zoom ( ) ;
float inv_zoom = ( zoom ! = 0.0f ) ? 1.0f / zoom : 0.0f ;
float gap = 30.0f * inv_zoom ;
const Size & cnv_size = m_parent . get_canvas_size ( ) ;
float l = gap - cnv_size . get_width ( ) / 2.f * inv_zoom ;
float r = l + ( float ) m_tooltip_texture . get_width ( ) * inv_zoom ;
float b = gap - cnv_size . get_height ( ) / 2.f * inv_zoom ;
float t = b + ( float ) m_tooltip_texture . get_height ( ) * inv_zoom ;
Rect reset_rect = m_parent . get_gizmo_reset_rect ( m_parent , true ) ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glPushMatrix ( ) ;
: : glLoadIdentity ( ) ;
GLTexture : : render_texture ( m_tooltip_texture . get_id ( ) , l , r , b , t ) ;
GLTexture : : render_texture ( m_reset_texture . get_id ( ) , reset_rect . get_left ( ) , reset_rect . get_right ( ) , reset_rect . get_bottom ( ) , reset_rect . get_top ( ) ) ;
: : glPopMatrix ( ) ;
: : glEnable ( GL_DEPTH_TEST ) ;
}
2018-11-26 14:54:12 +00:00
# endif // not ENABLE_IMGUI
# if ENABLE_IMGUI
void GLGizmoSlaSupports : : on_render_input_window ( float x , float y , const GLCanvas3D : : Selection & selection )
{
2018-12-21 11:35:20 +00:00
bool first_run = true ; // This is a hack to redraw the button when all points are removed,
// so it is not delayed until the background process finishes.
RENDER_AGAIN :
2018-11-26 14:54:12 +00:00
m_imgui - > set_next_window_pos ( x , y , ImGuiCond_Always ) ;
m_imgui - > set_next_window_bg_alpha ( 0.5f ) ;
m_imgui - > begin ( on_get_name ( ) , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
ImGui : : PushItemWidth ( 100.0f ) ;
m_imgui - > text ( _ ( L ( " Left mouse click - add point " ) ) ) ;
m_imgui - > text ( _ ( L ( " Right mouse click - remove point " ) ) ) ;
m_imgui - > text ( " " ) ;
2018-12-07 13:10:16 +00:00
bool generate = m_imgui - > button ( _ ( L ( " Generate points automatically " ) ) ) ;
bool remove_all_clicked = m_imgui - > button ( _ ( L ( " Remove all points " ) ) + ( m_model_object = = nullptr ? " " : " ( " + std : : to_string ( m_model_object - > sla_support_points . size ( ) ) + " ) " ) ) ;
2018-11-26 14:54:12 +00:00
m_imgui - > end ( ) ;
2018-12-21 11:35:20 +00:00
if ( remove_all_clicked ) {
2018-11-26 14:54:12 +00:00
delete_current_grabber ( true ) ;
2018-12-21 11:35:20 +00:00
if ( first_run ) {
first_run = false ;
goto RENDER_AGAIN ;
2018-12-07 13:10:16 +00:00
}
}
if ( remove_all_clicked | | generate ) {
m_parent . reload_scene ( true ) ;
m_parent . post_event ( SimpleEvent ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS ) ) ;
}
2018-11-26 14:54:12 +00:00
}
# endif // ENABLE_IMGUI
2018-09-19 12:59:57 +00:00
2018-11-15 17:15:27 +00:00
bool GLGizmoSlaSupports : : on_is_activable ( const GLCanvas3D : : Selection & selection ) const
{
2018-11-26 09:49:25 +00:00
return ( wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) = = ptSLA )
& & selection . is_from_single_instance ( ) ;
2018-11-15 17:15:27 +00:00
}
2018-09-12 10:14:20 +00:00
2018-11-19 13:46:37 +00:00
bool GLGizmoSlaSupports : : on_is_selectable ( ) const
{
return ( wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) = = ptSLA ) ;
}
2018-10-26 13:45:52 +00:00
std : : string GLGizmoSlaSupports : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " SLA Support Points [L] " ) ;
2018-10-26 13:45:52 +00:00
}
2018-10-18 13:13:38 +00:00
// GLGizmoCut
class GLGizmoCutPanel : public wxPanel
{
public :
GLGizmoCutPanel ( wxWindow * parent ) ;
void display ( bool display ) ;
private :
bool m_active ;
wxCheckBox * m_cb_rotate ;
wxButton * m_btn_cut ;
wxButton * m_btn_cancel ;
} ;
GLGizmoCutPanel : : GLGizmoCutPanel ( wxWindow * parent )
: wxPanel ( parent )
, m_active ( false )
, m_cb_rotate ( new wxCheckBox ( this , wxID_ANY , _ ( L ( " Rotate lower part upwards " ) ) ) )
, m_btn_cut ( new wxButton ( this , wxID_OK , _ ( L ( " Perform cut " ) ) ) )
, m_btn_cancel ( new wxButton ( this , wxID_CANCEL , _ ( L ( " Cancel " ) ) ) )
{
enum { MARGIN = 5 } ;
2018-12-04 14:17:24 +00:00
auto * sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2018-10-18 13:13:38 +00:00
auto * label = new wxStaticText ( this , wxID_ANY , _ ( L ( " Cut object: " ) ) ) ;
sizer - > Add ( label , 0 , wxALL | wxALIGN_CENTER , MARGIN ) ;
sizer - > Add ( m_cb_rotate , 0 , wxALL | wxALIGN_CENTER , MARGIN ) ;
sizer - > AddStretchSpacer ( ) ;
sizer - > Add ( m_btn_cut , 0 , wxALL | wxALIGN_CENTER , MARGIN ) ;
sizer - > Add ( m_btn_cancel , 0 , wxALL | wxALIGN_CENTER , MARGIN ) ;
SetSizer ( sizer ) ;
}
void GLGizmoCutPanel : : display ( bool display )
{
Show ( display ) ;
GetParent ( ) - > Layout ( ) ;
}
const double GLGizmoCut : : Offset = 10.0 ;
const double GLGizmoCut : : Margin = 20.0 ;
const std : : array < float , 3 > GLGizmoCut : : GrabberColor = { 1.0 , 0.5 , 0.0 } ;
GLGizmoCut : : GLGizmoCut ( GLCanvas3D & parent )
: GLGizmoBase ( parent )
, m_cut_z ( 0.0 )
2018-11-29 11:21:42 +00:00
, m_max_z ( 0.0 )
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
, m_panel ( nullptr )
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
, m_keep_upper ( true )
, m_keep_lower ( true )
, m_rotate_lower ( false )
2018-10-18 13:13:38 +00:00
{ }
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
void GLGizmoCut : : create_external_gizmo_widgets ( wxWindow * parent )
{
wxASSERT ( m_panel = = nullptr ) ;
m_panel = new GLGizmoCutPanel ( parent ) ;
parent - > GetSizer ( ) - > Add ( m_panel , 0 , wxEXPAND ) ;
parent - > Layout ( ) ;
parent - > Fit ( ) ;
auto prev_heigh = parent - > GetMinSize ( ) . GetHeight ( ) ;
parent - > SetMinSize ( wxSize ( - 1 , std : : max ( prev_heigh , m_panel - > GetSize ( ) . GetHeight ( ) ) ) ) ;
m_panel - > Hide ( ) ;
m_panel - > Bind ( wxEVT_BUTTON , [ this ] ( wxCommandEvent & ) {
2018-11-26 09:56:07 +00:00
perform_cut ( m_parent . get_selection ( ) ) ;
2018-10-18 13:13:38 +00:00
} , wxID_OK ) ;
}
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
bool GLGizmoCut : : on_init ( )
{
// TODO: icon
std : : string path = resources_dir ( ) + " /icons/overlay/ " ;
if ( ! m_textures [ Off ] . load_from_file ( path + " cut_off.png " , false ) ) {
return false ;
}
if ( ! m_textures [ Hover ] . load_from_file ( path + " cut_hover.png " , false ) ) {
return false ;
}
if ( ! m_textures [ On ] . load_from_file ( path + " cut_on.png " , false ) ) {
return false ;
}
m_grabbers . emplace_back ( ) ;
2018-11-22 09:14:31 +00:00
m_shortcut_key = WXK_CONTROL_C ;
2018-10-18 13:13:38 +00:00
return true ;
}
std : : string GLGizmoCut : : on_get_name ( ) const
{
2019-01-16 10:51:30 +00:00
return L ( " Cut [C] " ) ;
2018-10-18 13:13:38 +00:00
}
void GLGizmoCut : : on_set_state ( )
{
// Reset m_cut_z on gizmo activation
if ( get_state ( ) = = On ) {
2018-11-26 11:08:10 +00:00
m_cut_z = m_parent . get_selection ( ) . get_bounding_box ( ) . size ( ) ( 2 ) / 2.0 ;
2018-10-18 13:13:38 +00:00
}
2018-11-27 11:18:43 +00:00
# if !ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
// Display or hide the extra panel
if ( m_panel ! = nullptr ) {
m_panel - > display ( get_state ( ) = = On ) ;
}
2018-11-26 09:56:07 +00:00
# endif // not ENABLE_IMGUI
2018-10-18 13:13:38 +00:00
}
bool GLGizmoCut : : on_is_activable ( const GLCanvas3D : : Selection & selection ) const
{
return selection . is_single_full_instance ( ) & & ! selection . is_wipe_tower ( ) ;
}
void GLGizmoCut : : on_start_dragging ( const GLCanvas3D : : Selection & selection )
{
if ( m_hover_id = = - 1 ) { return ; }
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
m_start_z = m_cut_z ;
2018-11-29 11:21:42 +00:00
update_max_z ( selection ) ;
2018-10-18 13:13:38 +00:00
m_drag_pos = m_grabbers [ m_hover_id ] . center ;
m_drag_center = box . center ( ) ;
2018-11-26 11:08:10 +00:00
m_drag_center ( 2 ) = m_cut_z ;
2018-10-18 13:13:38 +00:00
}
2019-01-10 12:13:11 +00:00
void GLGizmoCut : : on_update ( const UpdateData & data , const GLCanvas3D : : Selection & selection )
2018-10-18 13:13:38 +00:00
{
if ( m_hover_id ! = - 1 ) {
2018-11-29 11:21:42 +00:00
set_cut_z ( m_start_z + calc_projection ( data . mouse_ray ) ) ;
2018-10-18 13:13:38 +00:00
}
}
void GLGizmoCut : : on_render ( const GLCanvas3D : : Selection & selection ) const
{
if ( m_grabbers [ 0 ] . dragging ) {
set_tooltip ( " Z: " + format ( m_cut_z , 2 ) ) ;
}
2018-11-29 11:21:42 +00:00
update_max_z ( selection ) ;
2018-10-18 13:13:38 +00:00
const BoundingBoxf3 & box = selection . get_bounding_box ( ) ;
Vec3d plane_center = box . center ( ) ;
2018-11-26 11:08:10 +00:00
plane_center ( 2 ) = m_cut_z ;
2018-10-18 13:13:38 +00:00
const float min_x = box . min ( 0 ) - Margin ;
const float max_x = box . max ( 0 ) + Margin ;
const float min_y = box . min ( 1 ) - Margin ;
const float max_y = box . max ( 1 ) + Margin ;
: : glEnable ( GL_DEPTH_TEST ) ;
: : glDisable ( GL_CULL_FACE ) ;
: : glEnable ( GL_BLEND ) ;
: : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
// Draw the cutting plane
: : glBegin ( GL_QUADS ) ;
: : glColor4f ( 0.8f , 0.8f , 0.8f , 0.5f ) ;
: : glVertex3f ( min_x , min_y , plane_center ( 2 ) ) ;
: : glVertex3f ( max_x , min_y , plane_center ( 2 ) ) ;
: : glVertex3f ( max_x , max_y , plane_center ( 2 ) ) ;
: : glVertex3f ( min_x , max_y , plane_center ( 2 ) ) ;
: : glEnd ( ) ;
: : glEnable ( GL_CULL_FACE ) ;
: : glDisable ( GL_BLEND ) ;
// TODO: draw cut part contour?
// Draw the grabber and the connecting line
m_grabbers [ 0 ] . center = plane_center ;
m_grabbers [ 0 ] . center ( 2 ) = plane_center ( 2 ) + Offset ;
: : glDisable ( GL_DEPTH_TEST ) ;
: : glLineWidth ( m_hover_id ! = - 1 ? 2.0f : 1.5f ) ;
: : glColor3f ( 1.0 , 1.0 , 0.0 ) ;
: : glBegin ( GL_LINES ) ;
: : glVertex3dv ( plane_center . data ( ) ) ;
: : glVertex3dv ( m_grabbers [ 0 ] . center . data ( ) ) ;
: : glEnd ( ) ;
std : : copy ( std : : begin ( GrabberColor ) , std : : end ( GrabberColor ) , m_grabbers [ 0 ] . color ) ;
m_grabbers [ 0 ] . render ( m_hover_id = = 0 , box . max_size ( ) ) ;
}
void GLGizmoCut : : on_render_for_picking ( const GLCanvas3D : : Selection & selection ) const
{
: : glDisable ( GL_DEPTH_TEST ) ;
render_grabbers_for_picking ( selection . get_bounding_box ( ) ) ;
}
2018-11-26 09:56:07 +00:00
# if ENABLE_IMGUI
void GLGizmoCut : : on_render_input_window ( float x , float y , const GLCanvas3D : : Selection & selection )
2018-10-18 13:13:38 +00:00
{
2018-11-26 09:56:07 +00:00
m_imgui - > set_next_window_pos ( x , y , ImGuiCond_Always ) ;
m_imgui - > set_next_window_bg_alpha ( 0.5f ) ;
m_imgui - > begin ( _ ( L ( " Cut " ) ) , ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse ) ;
ImGui : : PushItemWidth ( 100.0f ) ;
bool _value_changed = ImGui : : InputDouble ( " Z " , & m_cut_z , 0.0f , 0.0f , " %.2f " ) ;
m_imgui - > checkbox ( _ ( L ( " Keep upper part " ) ) , m_keep_upper ) ;
m_imgui - > checkbox ( _ ( L ( " Keep lower part " ) ) , m_keep_lower ) ;
m_imgui - > checkbox ( _ ( L ( " Rotate lower part upwards " ) ) , m_rotate_lower ) ;
2018-10-18 13:13:38 +00:00
2019-01-18 14:02:07 +00:00
m_imgui - > disabled_begin ( ! m_keep_upper & & ! m_keep_lower ) ;
2018-11-26 09:56:07 +00:00
const bool cut_clicked = m_imgui - > button ( _ ( L ( " Perform cut " ) ) ) ;
2019-01-18 14:02:07 +00:00
m_imgui - > disabled_end ( ) ;
2018-11-26 09:56:07 +00:00
m_imgui - > end ( ) ;
2019-01-18 14:02:07 +00:00
if ( cut_clicked & & ( m_keep_upper | | m_keep_lower ) ) {
2018-11-26 09:56:07 +00:00
perform_cut ( selection ) ;
}
}
# endif // ENABLE_IMGUI
2018-11-29 11:21:42 +00:00
void GLGizmoCut : : update_max_z ( const GLCanvas3D : : Selection & selection ) const
{
m_max_z = selection . get_bounding_box ( ) . size ( ) ( 2 ) ;
set_cut_z ( m_cut_z ) ;
}
void GLGizmoCut : : set_cut_z ( double cut_z ) const
{
// Clamp the plane to the object's bounding box
m_cut_z = std : : max ( 0.0 , std : : min ( m_max_z , cut_z ) ) ;
}
2018-11-26 09:56:07 +00:00
void GLGizmoCut : : perform_cut ( const GLCanvas3D : : Selection & selection )
{
2018-10-18 13:13:38 +00:00
const auto instance_idx = selection . get_instance_idx ( ) ;
const auto object_idx = selection . get_object_idx ( ) ;
wxCHECK_RET ( instance_idx > = 0 & & object_idx > = 0 , " GLGizmoCut: Invalid object selection " ) ;
2018-11-26 09:56:07 +00:00
wxGetApp ( ) . plater ( ) - > cut ( object_idx , instance_idx , m_cut_z , m_keep_upper , m_keep_lower , m_rotate_lower ) ;
2018-10-18 13:13:38 +00:00
}
double GLGizmoCut : : calc_projection ( const Linef3 & mouse_ray ) const
{
double projection = 0.0 ;
const Vec3d starting_vec = m_drag_pos - m_drag_center ;
const double len_starting_vec = starting_vec . norm ( ) ;
if ( len_starting_vec ! = 0.0 )
{
Vec3d mouse_dir = 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 = mouse_ray . a + ( m_drag_pos - 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_drag_pos ;
// finds projection of the vector along the staring direction
projection = inters_vec . dot ( starting_vec . normalized ( ) ) ;
}
return projection ;
}
2018-06-13 07:12:16 +00:00
} // namespace GUI
} // namespace Slic3r