refactor: update Puppet transform logic to support AffineTransform world matrices and improve selection highlighting
This commit is contained in:
@@ -57,21 +57,150 @@
|
||||
namespace uLib {
|
||||
|
||||
|
||||
|
||||
using Eigen::Isometry3f;
|
||||
using Eigen::Isometry3d;
|
||||
|
||||
using Eigen::Affine3f;
|
||||
using Eigen::Affine3d;
|
||||
|
||||
using Eigen::Projective3f;
|
||||
using Eigen::Projective3d;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////// AFFINE TRANSFORM WRAPPER //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
class AffineTransform : virtual public Object {
|
||||
public:
|
||||
uLibTypeMacro(AffineTransform, Object)
|
||||
protected:
|
||||
|
||||
Affine3f m_T;
|
||||
AffineTransform *m_Parent;
|
||||
|
||||
public:
|
||||
AffineTransform() :
|
||||
m_T(Matrix4f::Identity()),
|
||||
m_Parent(NULL)
|
||||
{}
|
||||
|
||||
AffineTransform(AffineTransform *parent) :
|
||||
m_T(Matrix4f::Identity()),
|
||||
m_Parent(parent)
|
||||
{}
|
||||
|
||||
AffineTransform(const AffineTransform ©) :
|
||||
m_T(copy.m_T),
|
||||
m_Parent(copy.m_Parent)
|
||||
{}
|
||||
|
||||
Affine3f& GetTransform() { return m_T; }
|
||||
|
||||
AffineTransform *GetParent() const { return this->m_Parent; }
|
||||
|
||||
void SetParent(AffineTransform *name) { this->m_Parent = name; }
|
||||
|
||||
void SetMatrix (const Matrix4f &mat) { m_T.matrix() = mat; }
|
||||
Matrix4f& GetMatrix () { return m_T.matrix(); }
|
||||
const Matrix4f& GetMatrix () const { return m_T.matrix(); }
|
||||
|
||||
Matrix4f GetWorldMatrix() const
|
||||
{
|
||||
if(!m_Parent) return m_T.matrix();
|
||||
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
|
||||
}
|
||||
|
||||
void SetWorldMatrix(const Matrix4f &mat)
|
||||
{
|
||||
if(!m_Parent) m_T.matrix() = mat;
|
||||
else m_T.matrix() = m_Parent->GetWorldMatrix().inverse() * mat;
|
||||
}
|
||||
|
||||
void SetPosition(const Vector3f &v) { this->m_T.translation() = v; }
|
||||
|
||||
Vector3f GetPosition() const { return this->m_T.translation(); }
|
||||
|
||||
void SetRotation(const Matrix3f &m) { this->m_T.linear() = m; }
|
||||
|
||||
Matrix3f GetRotation() const { return this->m_T.rotation(); }
|
||||
|
||||
void Translate(const Vector3f &v) { this->m_T.translate(v); }
|
||||
|
||||
void Scale(const Vector3f &v) { this->m_T.scale(v); }
|
||||
|
||||
Vector3f GetScale() const {
|
||||
return Vector3f(this->m_T.linear().col(0).norm(),
|
||||
this->m_T.linear().col(1).norm(),
|
||||
this->m_T.linear().col(2).norm());
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const Matrix3f &m) { this->m_T.rotate(m); }
|
||||
|
||||
void Rotate(const float angle, Vector3f axis)
|
||||
{
|
||||
axis.normalize(); // prehaps not necessary ( see eigens )
|
||||
Eigen::AngleAxisf ax(angle,axis);
|
||||
this->m_T.rotate(Eigen::Quaternion<float>(ax));
|
||||
}
|
||||
|
||||
void Rotate(const Vector3f euler_axis) {
|
||||
float angle = euler_axis.norm();
|
||||
Rotate(angle,euler_axis);
|
||||
}
|
||||
|
||||
void PreRotate(const Matrix3f &m) { this->m_T.prerotate(m); }
|
||||
|
||||
void QuaternionRotate(const Vector4f &q)
|
||||
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); }
|
||||
|
||||
void EulerYZYRotate(const Vector3f &e) {
|
||||
Matrix3f mat;
|
||||
mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY())
|
||||
* Eigen::AngleAxisf(e.y(), Vector3f::UnitZ())
|
||||
* Eigen::AngleAxisf(e.z(), Vector3f::UnitY());
|
||||
m_T.rotate(mat);
|
||||
}
|
||||
|
||||
void FlipAxes(int first, int second)
|
||||
{
|
||||
Matrix3f mat = Matrix3f::Identity();
|
||||
mat.col(first).swap(mat.col(second));
|
||||
m_T.rotate(mat);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////// TRS PARAMETERS /////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef Eigen::Affine3f AffineMatrix;
|
||||
|
||||
class TRS {
|
||||
class TRS : public AffineTransform {
|
||||
|
||||
public:
|
||||
uLibTypeMacro(TRS, AffineTransform)
|
||||
|
||||
Vector3f position = Vector3f::Zero();
|
||||
Vector3f rotation = Vector3f::Zero();
|
||||
Vector3f scaling = Vector3f::Ones();
|
||||
|
||||
TRS() = default;
|
||||
|
||||
TRS(const class AffineTransform& at);
|
||||
TRS(const class AffineTransform& at) {
|
||||
this->FromMatrix(at.GetMatrix());
|
||||
}
|
||||
|
||||
TRS(const Matrix4f& mat) {
|
||||
this->FromMatrix(mat);
|
||||
@@ -90,221 +219,60 @@ public:
|
||||
if (this->scaling(1) > 1e-6) rot.col(1) /= this->scaling(1);
|
||||
if (this->scaling(2) > 1e-6) rot.col(2) /= this->scaling(2);
|
||||
|
||||
// Decompose to Euler angles matching VTK (M = Rz * Ry * Rx)
|
||||
// Store internally as RADIANS (standard for uLib properties)
|
||||
Vector3f euler = rot.eulerAngles(2, 1, 0);
|
||||
this->rotation = Vector3f(euler(2), euler(1), euler(0));
|
||||
|
||||
this->SetMatrix(mat);
|
||||
}
|
||||
|
||||
void SetPosition(const Vector3f &v) {
|
||||
position = v;
|
||||
this->AffineTransform::SetPosition(v);
|
||||
}
|
||||
|
||||
void SetRotation(const Vector3f &v) {
|
||||
rotation = v;
|
||||
this->SyncMatrix();
|
||||
}
|
||||
|
||||
void SetOrientation(const Vector3f &v) { SetRotation(v); }
|
||||
|
||||
void SetScale(const Vector3f &v) {
|
||||
scaling = v;
|
||||
this->SyncMatrix();
|
||||
}
|
||||
|
||||
void SyncMatrix() {
|
||||
this->GetTransform() = GetAffineMatrix();
|
||||
}
|
||||
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & HRPU(position, "mm");
|
||||
ar & HRPU(rotation, "deg"); // Metadata informs UI to convert to/from degrees
|
||||
ar & HRPU(rotation, "rad");
|
||||
ar & HRP(scaling);
|
||||
}
|
||||
|
||||
AffineMatrix GetAffineMatrix() const {
|
||||
AffineMatrix t = AffineMatrix::Identity();
|
||||
t.translate(position);
|
||||
|
||||
// rotation is in Radians here
|
||||
t.rotate(Eigen::AngleAxisf(rotation.z(), Vector3f::UnitZ()));
|
||||
t.rotate(Eigen::AngleAxisf(rotation.y(), Vector3f::UnitY()));
|
||||
t.rotate(Eigen::AngleAxisf(rotation.x(), Vector3f::UnitX()));
|
||||
|
||||
t.scale(scaling);
|
||||
return t;
|
||||
AffineMatrix m = AffineMatrix::Identity();
|
||||
m.translate(position);
|
||||
m.rotate(Eigen::AngleAxisf(rotation.z(), Vector3f::UnitZ()));
|
||||
m.rotate(Eigen::AngleAxisf(rotation.y(), Vector3f::UnitY()));
|
||||
m.rotate(Eigen::AngleAxisf(rotation.x(), Vector3f::UnitX()));
|
||||
m.scale(scaling);
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix4f GetMatrix() const {
|
||||
return this->GetAffineMatrix().matrix();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///////// AFFINE TRANSFORM WRAPPER //////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AffineTransform : virtual public Object {
|
||||
public:
|
||||
uLibTypeMacro(AffineTransform, Object)
|
||||
|
||||
TRS Transform;
|
||||
|
||||
private:
|
||||
void NotifyProperties() {
|
||||
PropertyBase *p;
|
||||
if ((p = this->GetProperty("Transform.position"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.rotation"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.scaling"))) p->Updated();
|
||||
}
|
||||
|
||||
protected:
|
||||
Eigen::Affine3f m_T;
|
||||
AffineTransform *m_Parent;
|
||||
|
||||
public:
|
||||
AffineTransform() :
|
||||
m_T(Matrix4f::Identity()),
|
||||
m_Parent(NULL)
|
||||
{
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
virtual ~AffineTransform() {}
|
||||
|
||||
AffineTransform(AffineTransform *parent) :
|
||||
m_T(Matrix4f::Identity()),
|
||||
m_Parent(parent)
|
||||
{
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
AffineTransform(const AffineTransform ©) :
|
||||
m_T(copy.m_T),
|
||||
m_Parent(copy.m_Parent),
|
||||
Transform(copy.Transform)
|
||||
{
|
||||
ULIB_ACTIVATE_PROPERTIES(*this);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registration of properties in groups.
|
||||
*/
|
||||
template <class ArchiveT>
|
||||
void serialize(ArchiveT & ar, const unsigned int version) {
|
||||
ar & boost::serialization::make_nvp("Transform", Transform);
|
||||
}
|
||||
|
||||
Eigen::Affine3f& GetTransform() { return m_T; }
|
||||
|
||||
AffineTransform *GetParent() const { return this->m_Parent; }
|
||||
|
||||
void SetParent(AffineTransform *name) { this->m_Parent = name; }
|
||||
|
||||
void SetMatrix (Matrix4f mat) {
|
||||
m_T.matrix() = mat;
|
||||
this->UpdatePropertiesFromMatrix();
|
||||
}
|
||||
|
||||
Matrix4f GetMatrix() const { return m_T.matrix(); }
|
||||
|
||||
Matrix4f GetWorldMatrix() const
|
||||
{
|
||||
if(!m_Parent) return m_T.matrix();
|
||||
else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A //
|
||||
}
|
||||
|
||||
void SetPosition(const Vector3f v) {
|
||||
this->Transform.position = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetPosition() const { return this->Transform.position; }
|
||||
|
||||
void SetOrientation(const Vector3f v) {
|
||||
this->Transform.rotation = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetOrientation() const { return this->Transform.rotation; }
|
||||
|
||||
void SetScale(const Vector3f v) {
|
||||
this->Transform.scaling = v;
|
||||
this->Updated();
|
||||
this->NotifyProperties();
|
||||
}
|
||||
Vector3f GetScale() const { return this->Transform.scaling; }
|
||||
|
||||
void SetRotation(const Matrix3f m) {
|
||||
this->m_T.linear() = m;
|
||||
this->UpdatePropertiesFromMatrix();
|
||||
}
|
||||
|
||||
Matrix3f GetRotation() const { return this->m_T.rotation(); }
|
||||
|
||||
void Translate(const Vector3f v) {
|
||||
this->Transform.position += v;
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
void Scale(const Vector3f v) {
|
||||
this->Transform.scaling = this->Transform.scaling.cwiseProduct(v);
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const Matrix3f m) {
|
||||
this->m_T.rotate(m);
|
||||
this->UpdatePropertiesFromMatrix();
|
||||
}
|
||||
|
||||
void Rotate(const float angle, Vector3f axis)
|
||||
{
|
||||
axis.normalize();
|
||||
Eigen::AngleAxisf ax(angle,axis);
|
||||
this->m_T.rotate(Eigen::Quaternion<float>(ax));
|
||||
this->UpdatePropertiesFromMatrix();
|
||||
}
|
||||
|
||||
void Rotate(const Vector3f euler_axis) {
|
||||
float angle = euler_axis.norm();
|
||||
Rotate(angle,euler_axis);
|
||||
}
|
||||
|
||||
void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); this->UpdatePropertiesFromMatrix(); }
|
||||
|
||||
void QuaternionRotate(const Vector4f q)
|
||||
{ this->m_T.rotate(Eigen::Quaternion<float>(q)); this->UpdatePropertiesFromMatrix(); }
|
||||
|
||||
void EulerYZYRotate(const Vector3f e) {
|
||||
this->Transform.rotation = e;
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
void FlipAxes(int first, int second)
|
||||
{
|
||||
Matrix3f mat = Matrix3f::Identity();
|
||||
mat.col(first).swap(mat.col(second));
|
||||
m_T.rotate(mat);
|
||||
this->UpdatePropertiesFromMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decomposes the internal matrix m_T back into Position, Orientation, and Scale properties.
|
||||
*/
|
||||
void UpdatePropertiesFromMatrix() {
|
||||
this->Transform.FromMatrix(this->GetMatrix());
|
||||
|
||||
PropertyBase *p;
|
||||
if ((p = this->GetProperty("Transform.position"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.rotation"))) p->Updated();
|
||||
if ((p = this->GetProperty("Transform.scaling"))) p->Updated();
|
||||
}
|
||||
|
||||
signals:
|
||||
/** Signal emitted when properties change */
|
||||
virtual void Updated() override {
|
||||
this->Sync();
|
||||
ULIB_SIGNAL_EMIT(Object::Updated);
|
||||
}
|
||||
|
||||
private:
|
||||
void Sync() {
|
||||
m_T.matrix() = this->Transform.GetAffineMatrix().matrix();
|
||||
}
|
||||
};
|
||||
|
||||
inline TRS::TRS(const AffineTransform& at) {
|
||||
this->position = at.GetPosition();
|
||||
this->rotation = at.GetOrientation();
|
||||
this->scaling = at.GetScale();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
} // uLib
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user