|
@@ -10,6 +10,7 @@
|
|
|
// Needs to be included before others
|
|
|
#include <Eigen/StdVector>
|
|
|
#include "RotateWidget.h"
|
|
|
+#include "TranslateWidget.h"
|
|
|
#include <Eigen/Core>
|
|
|
#include <Eigen/Geometry>
|
|
|
#include <vector>
|
|
@@ -48,6 +49,12 @@ namespace igl
|
|
|
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
|
|
@@ -61,6 +68,7 @@ namespace igl
|
|
|
// 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
|
|
@@ -69,13 +77,24 @@ namespace igl
|
|
|
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_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
|
|
@@ -83,8 +102,10 @@ namespace igl
|
|
|
// 〃 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);
|
|
@@ -124,13 +145,19 @@ namespace igl
|
|
|
// 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
|
|
|
};
|
|
@@ -202,9 +229,13 @@ inline igl::opengl2::MouseController::MouseController():
|
|
|
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_root_enabled(true),
|
|
|
+ m_widget_mode(WIDGET_MODE_ROTATE)
|
|
|
{
|
|
|
}
|
|
|
|
|
@@ -219,7 +250,12 @@ 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.down(x,m_height-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;
|
|
@@ -238,46 +274,74 @@ inline bool igl::opengl2::MouseController::drag(const int x, const int y)
|
|
|
return m_is_selecting;
|
|
|
}else
|
|
|
{
|
|
|
- if(!m_widget.drag(x,m_height-y))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- assert(any_selection());
|
|
|
- assert(m_selection.size() == (int)m_rotations.size());
|
|
|
- for(int e = 0;e<m_selection.size();e++)
|
|
|
+ switch(m_widget_mode)
|
|
|
{
|
|
|
- if(m_selection(e))
|
|
|
+ default: // fall through
|
|
|
+ case WIDGET_MODE_ROTATE:
|
|
|
{
|
|
|
- // 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;
|
|
|
+ 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;
|
|
@@ -288,6 +352,7 @@ 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;
|
|
|
}
|
|
|
|
|
@@ -295,7 +360,16 @@ inline void igl::opengl2::MouseController::draw() const
|
|
|
{
|
|
|
if(any_selection())
|
|
|
{
|
|
|
- m_widget.draw();
|
|
|
+ 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)
|
|
|
{
|
|
@@ -342,6 +416,7 @@ inline void igl::opengl2::MouseController::set_selection_from_last_drag(
|
|
|
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
|
|
@@ -350,7 +425,7 @@ inline void igl::opengl2::MouseController::set_selection_from_last_drag(
|
|
|
// vQ[e] = vQ[p(e)] * m_rotation[e]
|
|
|
vector<Quaterniond,aligned_allocator<Quaterniond> > vQ;
|
|
|
vector<Vector3d> vT;
|
|
|
- forward_kinematics(C,BE,P,m_rotations,vQ,vT);
|
|
|
+ forward_kinematics(C,BE,P,m_rotations,m_translations,vQ,vT);
|
|
|
// Loop over deformed bones
|
|
|
for(int e = 0;e<BE.rows();e++)
|
|
|
{
|
|
@@ -380,8 +455,19 @@ inline void igl::opengl2::MouseController::set_selection(
|
|
|
using namespace std;
|
|
|
vector<Quaterniond,aligned_allocator<Quaterniond> > & vQ =
|
|
|
m_fk_rotations_at_selection;
|
|
|
- vector<Vector3d> vT;
|
|
|
- forward_kinematics(C,BE,P,m_rotations,vQ,vT);
|
|
|
+ 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;
|
|
@@ -439,7 +525,8 @@ inline void igl::opengl2::MouseController::set_selection(
|
|
|
if(any_of(m_selection))
|
|
|
{
|
|
|
// Taking average
|
|
|
- m_widget.pos.setConstant(0);
|
|
|
+ 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);
|
|
@@ -456,29 +543,37 @@ inline void igl::opengl2::MouseController::set_selection(
|
|
|
Affine3d a = Affine3d::Identity();
|
|
|
a.translate(vT[e]);
|
|
|
a.rotate(vQ[e]);
|
|
|
- m_widget.pos += a*s;
|
|
|
+ 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
|
|
|
- m_widget.pos.array() /= (double)num_selection;
|
|
|
+ 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,0,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;
|
|
|
}
|
|
|
}
|
|
@@ -490,9 +585,23 @@ inline void igl::opengl2::MouseController::set_size(const int n)
|
|
|
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;
|
|
@@ -514,6 +623,27 @@ inline void igl::opengl2::MouseController::reset_selected_rotations()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+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())
|
|
@@ -525,6 +655,17 @@ inline bool igl::opengl2::MouseController::set_rotations(const RotationList & 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);
|
|
@@ -535,4 +676,18 @@ inline bool igl::opengl2::MouseController::any_selection() const
|
|
|
return igl::any_of(m_selection);
|
|
|
}
|
|
|
|
|
|
+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
|