mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			691 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			691 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // This file is part of libigl, a simple c++ geometry processing library.
 | |
| // 
 | |
| // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
 | |
| // 
 | |
| // This Source Code Form is subject to the terms of the Mozilla Public License 
 | |
| // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 | |
| // obtain one at http://mozilla.org/MPL/2.0/.
 | |
| #ifndef IGL_OPENGL2_MOUSECONTROLLER_H
 | |
| #define IGL_OPENGL2_MOUSECONTROLLER_H
 | |
| // Needs to be included before others
 | |
| #include <Eigen/StdVector>
 | |
| #include "RotateWidget.h"
 | |
| #include "TranslateWidget.h"
 | |
| #include <Eigen/Core>
 | |
| #include <Eigen/Geometry>
 | |
| #include <vector>
 | |
| 
 | |
| // Class for control a skeletal FK rig with the mouse.
 | |
| namespace igl
 | |
| {
 | |
|   namespace opengl2
 | |
|   {
 | |
|     class MouseController
 | |
|     {
 | |
|       public:
 | |
|         typedef Eigen::VectorXi VectorXb;
 | |
|         // Propagate selection to descendants so that selected bones and their
 | |
|         // subtrees are all selected.
 | |
|         //
 | |
|         // Input:
 | |
|         //   S  #S list of whether selected
 | |
|         //   P  #S list of bone parents
 | |
|         // Output:
 | |
|         //   T  #S list of whether selected
 | |
|         static inline void propogate_to_descendants_if(
 | |
|           const VectorXb & S,
 | |
|           const Eigen::VectorXi & P,
 | |
|           VectorXb & T);
 | |
|         // Create a matrix of colors for the selection and their descendants.
 | |
|         //
 | |
|         // Inputs:
 | |
|         //   selection  #S list of whether a bone is selected
 | |
|         //   selected_color  color for selected bones
 | |
|         //   unselected_color  color for unselected bones
 | |
|         // Outputs:
 | |
|         //   C  #P by 4 list of colors
 | |
|         static inline void color_if(
 | |
|           const VectorXb & S,
 | |
|           const Eigen::Vector4f & selected_color,
 | |
|           const Eigen::Vector4f & unselected_color,
 | |
|           Eigen::MatrixXf & C);
 | |
|         enum WidgetMode
 | |
|         {
 | |
|           WIDGET_MODE_ROTATE = 0,
 | |
|           WIDGET_MODE_TRANSLATE = 1,
 | |
|           NUM_WIDGET_MODES = 2,
 | |
|         };
 | |
|       private:
 | |
|         // m_is_selecting  whether currently selecting 
 | |
|         // m_selection  #m_rotations list of whether a bone is selected
 | |
|         // m_down_x  x-coordinate of mouse location at down
 | |
|         // m_down_y  y-coordinate 〃
 | |
|         // m_drag_x  x-coordinate of mouse location at drag
 | |
|         // m_drag_y  y-coordinate 〃
 | |
|         // m_widget  rotation widget for selected bone
 | |
|         // m_width  width of containing window
 | |
|         // m_height  height 〃
 | |
|         // m_rotations  list of rotations for each bone
 | |
|         // m_rotations_at_selection  list of rotations for each bone at time of
 | |
|         //   selection
 | |
|         // m_translations   list of translations for each bone
 | |
|         // m_fk_rotations_at_selection  list of rotations for each bone at time of
 | |
|         //   selection
 | |
|         // m_root_enabled  Whether root is enabled
 | |
|         bool m_is_selecting;
 | |
|         VectorXb m_selection;
 | |
|         int m_down_x,m_down_y,m_drag_x,m_drag_y;
 | |
|         int m_width,m_height;
 | |
|         igl::opengl2::RotateWidget m_widget;
 | |
|         igl::opengl2::TranslateWidget m_trans_widget;
 | |
|         Eigen::Quaterniond m_widget_rot_at_selection;
 | |
|         //Eigen::Vector3d m_trans_widget_trans_at_selection;
 | |
|         typedef std::vector<
 | |
|           Eigen::Quaterniond,
 | |
|           Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
 | |
|         typedef std::vector< Eigen::Vector3d > TranslationList;
 | |
|         RotationList 
 | |
|           m_rotations,
 | |
|           m_rotations_at_selection,
 | |
|           m_fk_rotations_at_selection,
 | |
|           m_parent_rotations_at_selection;
 | |
|         TranslationList 
 | |
|           m_translations, 
 | |
|           m_translations_at_selection,
 | |
|           m_fk_translations_at_selection;
 | |
|         bool m_root_enabled;
 | |
|         WidgetMode m_widget_mode;
 | |
|       public:
 | |
|         MouseController();
 | |
|         // Returns const reference to m_selection
 | |
|         inline const VectorXb & selection() const{return m_selection;};
 | |
|         //                          〃 m_is_selecting
 | |
|         inline const bool & is_selecting() const{return m_is_selecting;}
 | |
|         inline bool is_widget_down() const{return m_widget.is_down();}
 | |
|         inline bool is_trans_widget_down() const{return m_trans_widget.is_down();}
 | |
|         //                          〃 m_rotations
 | |
|         inline const RotationList & rotations() const{return m_rotations;}
 | |
|         inline const TranslationList & translations() const{return m_translations;}
 | |
|         // Returns non-const reference to m_root_enabled
 | |
|         inline bool & root_enabled(){ return m_root_enabled;}
 | |
|         inline void reshape(const int w, const int h);
 | |
|         // Process down, drag, up mouse events
 | |
|         //
 | |
|         // Inputs:
 | |
|         //   x  x-coordinate of mouse click with respect to container
 | |
|         //   y  y-coordinate 〃 
 | |
|         // Returns true if accepted (action taken).
 | |
|         inline bool down(const int x, const int y);
 | |
|         inline bool drag(const int x, const int y);
 | |
|         inline bool up(const int x, const int y);
 | |
|         // Draw selection box and widget
 | |
|         inline void draw() const;
 | |
|         // Set `m_selection` based on the last drag selection and initialize
 | |
|         // widget.
 | |
|         //
 | |
|         // Inputs:
 | |
|         //   C  #C by dim list of joint positions at rest
 | |
|         //   BE  #BE by 2 list of bone indices at rest
 | |
|         //   P  #P list of bone parents
 | |
|         inline void set_selection_from_last_drag(
 | |
|           const Eigen::MatrixXd & C,
 | |
|           const Eigen::MatrixXi & BE,
 | |
|           const Eigen::VectorXi & P,
 | |
|           const Eigen::VectorXi & RP);
 | |
|         // Set from explicit selection
 | |
|         inline void set_selection(
 | |
|           const Eigen::VectorXi & S,
 | |
|           const Eigen::MatrixXd & C,
 | |
|           const Eigen::MatrixXi & BE,
 | |
|           const Eigen::VectorXi & P,
 | |
|           const Eigen::VectorXi & RP);
 | |
|         // Set size of skeleton
 | |
|         //
 | |
|         // Inputs:
 | |
|         //  n  number of bones
 | |
|         inline void set_size(const int n);
 | |
|         // Resets m_rotation elements to identity
 | |
|         inline void reset();
 | |
|         inline void reset_selected();
 | |
|         inline void reset_rotations();
 | |
|         inline void reset_selected_rotations();
 | |
|         inline void reset_translations();
 | |
|         inline void reset_selected_translations();
 | |
|         inline bool set_rotations(const RotationList & vQ);
 | |
|         inline bool set_translations(const TranslationList & vT);
 | |
|         // Sets all entries in m_selection to false
 | |
|         inline void clear_selection();
 | |
|         // Returns true iff some element in m_selection is true
 | |
|         inline bool any_selection() const;
 | |
|         inline void set_widget_mode(const WidgetMode & mode);
 | |
|       public:
 | |
|           EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 | |
|     };
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Implementation
 | |
| #include "../line_segment_in_rectangle.h"
 | |
| #include "draw_rectangular_marquee.h"
 | |
| #include "project.h"
 | |
| #include "../forward_kinematics.h"
 | |
| #include <iostream>
 | |
| #include <algorithm>
 | |
| #include <functional>
 | |
| 
 | |
| inline void igl::opengl2::MouseController::propogate_to_descendants_if(
 | |
|   const VectorXb & S,
 | |
|   const Eigen::VectorXi & P,
 | |
|   VectorXb & T)
 | |
| {
 | |
|   using namespace std;
 | |
|   const int n = S.rows();
 | |
|   assert(P.rows() == n);
 | |
|   // dynamic programming
 | |
|   T = S;
 | |
|   vector<bool> seen(n,false);
 | |
|   // Recursively look up chain and see if ancestor is selected
 | |
|   const function<bool(int)> look_up = [&](int e) -> bool
 | |
|   {
 | |
|     if(e==-1)
 | |
|     {
 | |
|       return false;
 | |
|     }
 | |
|     if(!seen[e])
 | |
|     {
 | |
|       seen[e] = true;
 | |
|       T(e) |= look_up(P(e));
 | |
|     }
 | |
|     return T(e);
 | |
|   };
 | |
|   for(int e = 0;e<n;e++)
 | |
|   {
 | |
|     if(!seen[e])
 | |
|     {
 | |
|       T(e) = look_up(e);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::color_if(
 | |
|   const VectorXb & S,
 | |
|   const Eigen::Vector4f & selected_color,
 | |
|   const Eigen::Vector4f & unselected_color,
 | |
|   Eigen::MatrixXf & C)
 | |
| {
 | |
|   C.resize(S.rows(),4);
 | |
|   for(int e=0;e<S.rows();e++)
 | |
|   {
 | |
|     C.row(e) = S(e)?selected_color:unselected_color;
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline igl::opengl2::MouseController::MouseController():
 | |
|   m_is_selecting(false),
 | |
|   m_selection(),
 | |
|   m_down_x(-1),m_down_y(-1),m_drag_x(-1),m_drag_y(-1),
 | |
|   m_width(-1),m_height(-1),
 | |
|   m_widget(),
 | |
|   m_widget_rot_at_selection(),
 | |
|   //m_trans_widget_trans_at_selection(),
 | |
|   m_trans_widget(),
 | |
|   m_rotations(),
 | |
|   m_translations(),
 | |
|   m_rotations_at_selection(),
 | |
|   m_root_enabled(true),
 | |
|   m_widget_mode(WIDGET_MODE_ROTATE)
 | |
| {
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reshape(const int w, const int h)
 | |
| {
 | |
|   m_width = w;
 | |
|   m_height = h;
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::down(const int x, const int y)
 | |
| {
 | |
|   using namespace std;
 | |
|   m_down_x = m_drag_x =x;
 | |
|   m_down_y = m_drag_y =y;
 | |
|   const bool widget_down = any_selection() && 
 | |
|     (
 | |
|      (m_widget_mode == WIDGET_MODE_ROTATE && m_widget.down(x,m_height-y)) ||
 | |
|      (m_widget_mode == WIDGET_MODE_TRANSLATE && 
 | |
|         m_trans_widget.down(x,m_height-y))
 | |
|     );
 | |
|   if(!widget_down)
 | |
|   {
 | |
|     m_is_selecting = true;
 | |
|   }
 | |
|   return m_is_selecting || widget_down;
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::drag(const int x, const int y)
 | |
| {
 | |
|   using namespace std;
 | |
|   using namespace Eigen;
 | |
|   m_drag_x = x;
 | |
|   m_drag_y = y;
 | |
|   if(m_is_selecting)
 | |
|   {
 | |
|     return m_is_selecting;
 | |
|   }else
 | |
|   {
 | |
|     switch(m_widget_mode)
 | |
|     {
 | |
|       default: // fall through
 | |
|       case WIDGET_MODE_ROTATE:
 | |
|       {
 | |
|         if(!m_widget.drag(x,m_height-y))
 | |
|         {
 | |
|           return false;
 | |
|         }
 | |
|         assert(any_selection());
 | |
|         assert(m_selection.size() == (int)m_rotations.size());
 | |
|         assert(m_selection.size() == (int)m_translations.size());
 | |
|         for(int e = 0;e<m_selection.size();e++)
 | |
|         {
 | |
|           if(m_selection(e))
 | |
|           {
 | |
|             // Let:
 | |
|             //     w.θr = w.θ ⋅ w.θ₀*  
 | |
|             // w.θr takes (absolute) frame of w.θ₀ to w.θ:
 | |
|             //     w.θ = w.θr ⋅ w.θ₀ 
 | |
|             // Define:
 | |
|             //     w.θ₀ = θfk ⋅ θx,
 | |
|             // the absolute rotation of the x axis to the deformed bone at
 | |
|             // selection. Likewise,
 | |
|             //     w.θ = θfk' ⋅ θx,
 | |
|             // the current absolute rotation of the x axis to the deformed bone.
 | |
|             // Define recursively:
 | |
|             //     θfk = θfk(p) ⋅ Θr,
 | |
|             // then because we're only changeing this relative rotation
 | |
|             //     θfk' = θfk(p) ⋅ Θr ⋅ θr* ⋅ θr'
 | |
|             //     θfk' = θfk ⋅ θr* ⋅ θr'
 | |
|             //     w.θ ⋅ θx* = θfk ⋅ θr* ⋅ θr'
 | |
|             //     θr ⋅ θfk* ⋅ w.θ ⋅ θx* = θr'
 | |
|             //     θr ⋅ θfk* ⋅ w.θr ⋅ w.θ₀ ⋅ θx* = θr'
 | |
|             //     θr ⋅ θfk* ⋅ w.θr ⋅ θfk ⋅θx ⋅ θx* = θr'
 | |
|             //     θr ⋅ θfk* ⋅ w.θr ⋅ θfk = θr'
 | |
|             // which I guess is the right multiply change after being changed to
 | |
|             // the bases of θfk, the rotation of the bone relative to its rest
 | |
|             // frame.
 | |
|             //
 | |
|             const Quaterniond & frame = m_fk_rotations_at_selection[e];
 | |
|             m_rotations[e] = 
 | |
|               m_rotations_at_selection[e] *
 | |
|               frame.conjugate() * 
 | |
|               (m_widget.rot*m_widget_rot_at_selection.conjugate()) *
 | |
|               frame;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       case WIDGET_MODE_TRANSLATE:
 | |
|       {
 | |
|         if(!m_trans_widget.drag(x,m_height-y))
 | |
|         {
 | |
|           return false;
 | |
|         }
 | |
|         assert(any_selection());
 | |
|         assert(m_selection.size() == (int)m_rotations.size());
 | |
|         assert(m_selection.size() == (int)m_translations.size());
 | |
|         for(int e = 0;e<m_selection.size();e++)
 | |
|         {
 | |
|           if(m_selection(e))
 | |
|           {
 | |
|             m_translations[e] = 
 | |
|               m_translations_at_selection[e] + 
 | |
|               m_parent_rotations_at_selection[e].conjugate()*
 | |
|                 m_trans_widget.m_trans;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::up(const int x, const int y)
 | |
| {
 | |
|   m_is_selecting = false;
 | |
|   m_widget.up(x,m_height-y);
 | |
|   m_trans_widget.up(x,m_height-y);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::draw() const
 | |
| {
 | |
|   if(any_selection())
 | |
|   {
 | |
|     switch(m_widget_mode)
 | |
|     {
 | |
|       default:
 | |
|       case WIDGET_MODE_ROTATE:
 | |
|         m_widget.draw();
 | |
|         break;
 | |
|       case WIDGET_MODE_TRANSLATE:
 | |
|         m_trans_widget.draw();
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
|   if(m_is_selecting)
 | |
|   {
 | |
|     // Remember settings
 | |
|     GLboolean dt;
 | |
|     glGetBooleanv(GL_DEPTH_TEST,&dt);
 | |
|     int old_vp[4];
 | |
|     glGetIntegerv(GL_VIEWPORT,old_vp);
 | |
| 
 | |
|     // True screen space
 | |
|     glViewport(0,0,m_width,m_height);
 | |
|     glMatrixMode(GL_PROJECTION);
 | |
|     glPushMatrix();
 | |
|     glLoadIdentity();
 | |
|     gluOrtho2D(0,m_width,0,m_height);
 | |
|     glMatrixMode(GL_MODELVIEW);
 | |
|     glPushMatrix();
 | |
|     glLoadIdentity();
 | |
| 
 | |
|     glDisable(GL_DEPTH_TEST);
 | |
|     draw_rectangular_marquee(
 | |
|       m_down_x,
 | |
|       m_height-m_down_y,
 | |
|       m_drag_x,
 | |
|       m_height-m_drag_y);
 | |
| 
 | |
|     // Restore settings
 | |
|     glMatrixMode(GL_PROJECTION);
 | |
|     glPopMatrix();
 | |
|     glMatrixMode(GL_MODELVIEW);
 | |
|     glPopMatrix();
 | |
|     glViewport(old_vp[0],old_vp[1],old_vp[2],old_vp[3]);
 | |
|     dt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
 | |
| 
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::set_selection_from_last_drag(
 | |
|   const Eigen::MatrixXd & C,
 | |
|   const Eigen::MatrixXi & BE,
 | |
|   const Eigen::VectorXi & P,
 | |
|   const Eigen::VectorXi & RP)
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   using namespace std;
 | |
|   m_rotations_at_selection = m_rotations;
 | |
|   m_translations_at_selection = m_translations;
 | |
|   assert(BE.rows() == P.rows());
 | |
|   m_selection = VectorXb::Zero(BE.rows());
 | |
|   // m_rotation[e]  is the relative rotation stored at bone e (as seen by the
 | |
|   //   joint traveling with its parent)
 | |
|   // vQ[e]  is the absolute rotation of a bone at rest to its current position:
 | |
|   //   vQ[e] = vQ[p(e)] * m_rotation[e]
 | |
|   vector<Quaterniond,aligned_allocator<Quaterniond> > vQ;
 | |
|   vector<Vector3d> vT;
 | |
|   forward_kinematics(C,BE,P,m_rotations,m_translations,vQ,vT);
 | |
|   // Loop over deformed bones
 | |
|   for(int e = 0;e<BE.rows();e++)
 | |
|   {
 | |
|     Affine3d a = Affine3d::Identity();
 | |
|     a.translate(vT[e]);
 | |
|     a.rotate(vQ[e]);
 | |
|     Vector3d s = a * (Vector3d)C.row(BE(e,0));
 | |
|     Vector3d d = a * (Vector3d)C.row(BE(e,1));
 | |
|     Vector3d projs = project(s);
 | |
|     Vector3d projd = project(d);
 | |
|     m_selection(e) = line_segment_in_rectangle(
 | |
|       projs.head(2),projd.head(2),
 | |
|       Vector2d(m_down_x,m_height-m_down_y),
 | |
|       Vector2d(m_drag_x,m_height-m_drag_y));
 | |
|   }
 | |
|   return set_selection(m_selection,C,BE,P,RP);
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::set_selection(
 | |
|     const Eigen::VectorXi & S,
 | |
|     const Eigen::MatrixXd & C,
 | |
|     const Eigen::MatrixXi & BE,
 | |
|     const Eigen::VectorXi & P,
 | |
|     const Eigen::VectorXi & RP)
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   using namespace std;
 | |
|   vector<Quaterniond,aligned_allocator<Quaterniond> > & vQ = 
 | |
|     m_fk_rotations_at_selection;
 | |
|   vector<Vector3d> & vT = m_fk_translations_at_selection;
 | |
|   forward_kinematics(C,BE,P,m_rotations,m_translations,vQ,vT);
 | |
|   m_parent_rotations_at_selection.resize(
 | |
|     m_rotations.size(),Quaterniond::Identity());
 | |
|   for(size_t r = 0;r<vQ.size();r++)
 | |
|   {
 | |
|     if(P(r)>=0)
 | |
|     {
 | |
|       m_parent_rotations_at_selection[r] = vQ[P(r)];
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   if(&m_selection != &S)
 | |
|   {
 | |
|     m_selection = S;
 | |
|   }
 | |
|   assert(m_selection.rows() == BE.rows());
 | |
|   assert(BE.rows() == P.rows());
 | |
|   assert(BE.rows() == RP.rows());
 | |
|   // Zero-out S up a path of ones from e
 | |
|   auto propagate = [&](const int e, const VectorXb & S, VectorXb & N)
 | |
|   {
 | |
|     if(S(e))
 | |
|     {
 | |
|       int f = e;
 | |
|       while(true)
 | |
|       {
 | |
|         int p = P(f);
 | |
|         if(p==-1||!S(p))
 | |
|         {
 | |
|           break;
 | |
|         }
 | |
|         N(f) = false;
 | |
|         f = p;
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   VectorXb prev_selection = m_selection;
 | |
|   // Combine upward, group rigid parts, repeat
 | |
|   while(true)
 | |
|   {
 | |
|     // Spread selection across rigid pieces
 | |
|     VectorXb SRP(VectorXb::Zero(RP.maxCoeff()+1));
 | |
|     for(int e = 0;e<BE.rows();e++)
 | |
|     {
 | |
|       SRP(RP(e)) |= m_selection(e);
 | |
|     }
 | |
|     for(int e = 0;e<BE.rows();e++)
 | |
|     {
 | |
|       m_selection(e) = SRP(RP(e));
 | |
|     }
 | |
|     // Clear selections below m_selection ancestors
 | |
|     VectorXb new_selection = m_selection;
 | |
|     for(int e = 0;e<P.rows();e++)
 | |
|     {
 | |
|       propagate(e,m_selection,new_selection);
 | |
|     }
 | |
|     m_selection = new_selection;
 | |
|     if(m_selection==prev_selection)
 | |
|     {
 | |
|       break;
 | |
|     }
 | |
|     prev_selection = m_selection;
 | |
|   }
 | |
| 
 | |
|   // Now selection should contain just bone roots of m_selection subtrees
 | |
|   if(m_selection.array().any())
 | |
|   {
 | |
|     // Taking average 
 | |
|     Vector3d avg_pos(0,0,0);
 | |
|     //m_trans_widget_trans_at_selection.setConstant(0);
 | |
|     m_widget_rot_at_selection.coeffs().setConstant(0);
 | |
|     m_widget.rot.coeffs().array().setConstant(0);
 | |
|     Quaterniond cur_rot(0,0,0,0);
 | |
|     int num_selection = 0;
 | |
|     // Compute average widget for selection
 | |
|     for(int e = 0;e<BE.rows();e++)
 | |
|     {
 | |
|       if(m_selection(e))
 | |
|       {
 | |
|         Vector3d s = C.row(BE(e,0));
 | |
|         Vector3d d = C.row(BE(e,1));
 | |
|         auto b = (d-s).transpose().eval();
 | |
|         {
 | |
|           Affine3d a = Affine3d::Identity();
 | |
|           a.translate(vT[e]);
 | |
|           a.rotate(vQ[e]);
 | |
|           avg_pos += a*s;
 | |
|         }
 | |
|         // Rotation of x axis to this bone
 | |
|         Quaterniond rot_at_bind;
 | |
|         rot_at_bind.setFromTwoVectors(Vector3d(1,0,0),b);
 | |
|         const Quaterniond abs_rot = vQ[e] * rot_at_bind;
 | |
|         m_widget_rot_at_selection.coeffs() += abs_rot.coeffs();
 | |
|         //m_trans_widget_trans_at_selection += vT[e];
 | |
|         num_selection++;
 | |
|       }
 | |
|     }
 | |
|     // Take average
 | |
|     avg_pos.array() /= (double)num_selection;
 | |
|     //m_trans_widget_trans_at_selection.array() /= (double)num_selection;
 | |
|     m_widget_rot_at_selection.coeffs().array() /= (double)num_selection;
 | |
|     m_widget_rot_at_selection.normalize();
 | |
|     m_widget.rot = m_widget_rot_at_selection;
 | |
|     m_widget.pos      = avg_pos;
 | |
|     m_trans_widget.m_pos = avg_pos;
 | |
|     //m_trans_widget.m_trans = m_trans_widget_trans_at_selection;
 | |
|     m_trans_widget.m_trans.setConstant(0);
 | |
|   }
 | |
|   m_widget.m_is_enabled = true;
 | |
|   m_trans_widget.m_is_enabled = true;
 | |
|   for(int s = 0;s<m_selection.rows();s++)
 | |
|   {
 | |
|     // a root is selected then disable.
 | |
|     if(!m_root_enabled && m_selection(s) && P(s) == -1)
 | |
|     {
 | |
|       m_widget.m_is_enabled = false;
 | |
|       m_trans_widget.m_is_enabled = false;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::set_size(const int n)
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   clear_selection();
 | |
|   m_rotations.clear();
 | |
|   m_rotations.resize(n,Quaterniond::Identity());
 | |
|   m_translations.clear();
 | |
|   m_translations.resize(n,Vector3d(0,0,0));
 | |
|   m_selection = VectorXb::Zero(n);
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset()
 | |
| {
 | |
|   reset_rotations();
 | |
|   reset_translations();
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset_selected()
 | |
| {
 | |
|   reset_selected_rotations();
 | |
|   reset_selected_translations();
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset_rotations()
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   using namespace std;
 | |
|   fill(m_rotations.begin(),m_rotations.end(),Quaterniond::Identity());
 | |
|   // cop out. just clear selection
 | |
|   clear_selection();
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset_selected_rotations()
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   for(int e = 0;e<m_selection.size();e++)
 | |
|   {
 | |
|     if(m_selection(e))
 | |
|     {
 | |
|       m_rotations[e] = Quaterniond::Identity();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset_translations()
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   using namespace std;
 | |
|   fill(m_translations.begin(),m_translations.end(),Vector3d(0,0,0));
 | |
|   // cop out. just clear selection
 | |
|   clear_selection();
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::reset_selected_translations()
 | |
| {
 | |
|   using namespace Eigen;
 | |
|   for(int e = 0;e<m_selection.size();e++)
 | |
|   {
 | |
|     if(m_selection(e))
 | |
|     {
 | |
|       m_translations[e] = Vector3d(0,0,0);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::set_rotations(const RotationList & vQ)
 | |
| {
 | |
|   if(vQ.size() != m_rotations.size())
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
|   assert(!any_selection());
 | |
|   m_rotations = vQ;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::set_translations(const TranslationList & vT)
 | |
| {
 | |
|   if(vT.size() != m_translations.size())
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
|   assert(!any_selection());
 | |
|   m_translations = vT;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::clear_selection()
 | |
| {
 | |
|   m_selection.setConstant(false);
 | |
| }
 | |
| 
 | |
| inline bool igl::opengl2::MouseController::any_selection() const
 | |
| {
 | |
|   return m_selection.array().any();
 | |
| }
 | |
| 
 | |
| inline void igl::opengl2::MouseController::set_widget_mode(const WidgetMode & mode)
 | |
| {
 | |
|   switch(m_widget_mode)
 | |
|   {
 | |
|     default:
 | |
|     case WIDGET_MODE_TRANSLATE:
 | |
|       m_widget.pos = m_trans_widget.m_pos+m_trans_widget.m_trans;
 | |
|       break;
 | |
|     case WIDGET_MODE_ROTATE:
 | |
|       break;
 | |
|   }
 | |
|   m_widget_mode = mode;
 | |
| }
 | |
| 
 | |
| #endif
 | 
