|
Nikita Kitaev |
dc5e35 |
/* === S Y N F I G ========================================================= */
|
|
Nikita Kitaev |
dc5e35 |
/*! \file matrix.cpp
|
|
Nikita Kitaev |
dc5e35 |
** \brief Template File
|
|
Nikita Kitaev |
dc5e35 |
**
|
|
Nikita Kitaev |
dc5e35 |
** $Id$
|
|
Nikita Kitaev |
dc5e35 |
**
|
|
Nikita Kitaev |
dc5e35 |
** \legal
|
|
Nikita Kitaev |
dc5e35 |
** Copyright (c) 2008 Carlos Lรณpez
|
|
Nikita Kitaev |
dc5e35 |
** Copyright (c) 2008 Chris Moore
|
|
Nikita Kitaev |
dc5e35 |
**
|
|
Nikita Kitaev |
dc5e35 |
** This package is free software; you can redistribute it and/or
|
|
Nikita Kitaev |
dc5e35 |
** modify it under the terms of the GNU General Public License as
|
|
Nikita Kitaev |
dc5e35 |
** published by the Free Software Foundation; either version 2 of
|
|
Nikita Kitaev |
dc5e35 |
** the License, or (at your option) any later version.
|
|
Nikita Kitaev |
dc5e35 |
**
|
|
Nikita Kitaev |
dc5e35 |
** This package is distributed in the hope that it will be useful,
|
|
Nikita Kitaev |
dc5e35 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Nikita Kitaev |
dc5e35 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Nikita Kitaev |
dc5e35 |
** General Public License for more details.
|
|
Nikita Kitaev |
dc5e35 |
** \endlegal
|
|
Nikita Kitaev |
dc5e35 |
*/
|
|
Nikita Kitaev |
dc5e35 |
/* ========================================================================= */
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
/* === H E A D E R S ======================================================= */
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
#ifdef USING_PCH
|
|
Nikita Kitaev |
dc5e35 |
# include "pch.h"
|
|
Nikita Kitaev |
dc5e35 |
#else
|
|
Nikita Kitaev |
dc5e35 |
#ifdef HAVE_CONFIG_H
|
|
Nikita Kitaev |
dc5e35 |
# include <config.h></config.h>
|
|
Nikita Kitaev |
dc5e35 |
#endif
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
#include "matrix.h"
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
#endif
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
/* === U S I N G =========================================================== */
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
using namespace std;
|
|
Nikita Kitaev |
dc5e35 |
using namespace etl;
|
|
Nikita Kitaev |
dc5e35 |
using namespace synfig;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
/* === M A C R O S ========================================================= */
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
/* === G L O B A L S ======================================================= */
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
/* === M E T H O D S ======================================================= */
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
ab6e41 |
// Matrix2
|
|
|
ab6e41 |
|
|
|
ab6e41 |
Matrix2 &
|
|
|
ab6e41 |
Matrix2::set_scale(const value_type &sx, const value_type &sy)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
ab6e41 |
m00=sx; m01=0.0;
|
|
|
ab6e41 |
m10=0.0; m11=sy;
|
|
|
ab6e41 |
return *this;
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
|
|
|
ab6e41 |
Matrix2 &
|
|
|
ab6e41 |
Matrix2::set_rotate(const Angle &a)
|
|
|
ab6e41 |
{
|
|
|
ab6e41 |
value_type c(Angle::cos(a).get());
|
|
|
ab6e41 |
value_type s(Angle::sin(a).get());
|
|
|
bf609b |
m00= c; m01=s;
|
|
|
bf609b |
m10=-s; m11=c;
|
|
|
ab6e41 |
return *this;
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
|
|
|
ab6e41 |
void
|
|
|
ab6e41 |
Matrix2::get_transformed(value_type &out_x, value_type &out_y, const value_type x, const value_type y)const
|
|
|
ab6e41 |
{ out_x = x*m00+y*m10; out_y = x*m01+y*m11; }
|
|
|
ab6e41 |
|
|
|
ab6e41 |
Matrix2
|
|
|
3a4aaf |
Matrix2::operator*(const Matrix2 &rhs) const
|
|
|
ab6e41 |
{
|
|
|
3a4aaf |
return Matrix2( *this * rhs.row_x(),
|
|
|
3a4aaf |
*this * rhs.row_y() );
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
813bad |
bool
|
|
|
ab6e41 |
Matrix2::operator==(const Matrix2 &rhs) const
|
|
|
813bad |
{
|
|
|
d9ebd0 |
return approximate_equal(m00, rhs.m00)
|
|
|
d9ebd0 |
&& approximate_equal(m01, rhs.m01)
|
|
|
d9ebd0 |
&& approximate_equal(m10, rhs.m10)
|
|
|
d9ebd0 |
&& approximate_equal(m11, rhs.m11);
|
|
|
813bad |
}
|
|
|
813bad |
|
|
|
3a4aaf |
Matrix2&
|
|
|
ab6e41 |
Matrix2::operator*=(const value_type &rhs)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
ab6e41 |
m00*=rhs;
|
|
|
ab6e41 |
m01*=rhs;
|
|
|
ab6e41 |
|
|
|
ab6e41 |
m10*=rhs;
|
|
|
ab6e41 |
m11*=rhs;
|
|
|
ab6e41 |
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
3a4aaf |
Matrix2&
|
|
|
ab6e41 |
Matrix2::operator+=(const Matrix2 &rhs)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
ab6e41 |
m00+=rhs.m00;
|
|
|
ab6e41 |
m01+=rhs.m01;
|
|
|
ab6e41 |
|
|
|
ab6e41 |
m10+=rhs.m10;
|
|
|
ab6e41 |
m11+=rhs.m11;
|
|
|
ab6e41 |
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
34a685 |
Matrix2::value_type
|
|
|
34a685 |
Matrix2::det() const
|
|
|
34a685 |
{ return m00*m11 - m01*m10; }
|
|
|
34a685 |
|
|
|
ab6e41 |
bool
|
|
|
34a685 |
Matrix2::is_invertible() const
|
|
|
34a685 |
{ return approximate_not_zero(det()); }
|
|
|
ab6e41 |
|
|
|
ab6e41 |
Matrix2&
|
|
|
ab6e41 |
Matrix2::invert()
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
34a685 |
value_type d = det();
|
|
|
34a685 |
if (approximate_not_zero(d)) {
|
|
|
34a685 |
value_type k = 1/d;
|
|
|
ab6e41 |
std::swap(m00, m11);
|
|
|
ab6e41 |
std::swap(m01, m10);
|
|
|
ab6e41 |
m00 *= k; m01 *= -k;
|
|
|
ab6e41 |
m11 *= k; m10 *= -k;
|
|
|
34a685 |
} else
|
|
|
34a685 |
if (m00*m00 + m01*m01 > m10*m10 + m11*m11) {
|
|
|
ab6e41 |
m10 = m01; m01 = 0; m11 = 0;
|
|
|
34a685 |
} else {
|
|
|
ab6e41 |
m01 = m10; m00 = 0; m10 = 0;
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
ab6e41 |
String
|
|
|
ab6e41 |
Matrix2::get_string(int spaces, String before, String after)const
|
|
|
ab6e41 |
{
|
|
|
ab6e41 |
return etl::strprintf("%*s [%7.2f %7.2f] %s\n%*s [%7.2f %7.2f]\n",
|
|
|
ab6e41 |
spaces, before.c_str(), m00, m01, after.c_str(),
|
|
|
ab6e41 |
spaces, "", m10, m11);
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
|
|
|
ab6e41 |
// Matrix3
|
|
|
ab6e41 |
|
|
|
3a4aaf |
Matrix3&
|
|
|
ab6e41 |
Matrix3::set_scale(const value_type &sx, const value_type &sy)
|
|
|
ab6e41 |
{
|
|
|
ab6e41 |
m00=sx; m01=0.0; m02=0.0;
|
|
|
ab6e41 |
m10=0.0; m11=sy; m12=0.0;
|
|
|
ab6e41 |
m20=0.0; m21=0.0; m22=1.0;
|
|
|
ab6e41 |
return *this;
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
|
|
|
3a4aaf |
Matrix3&
|
|
|
ab6e41 |
Matrix3::set_rotate(const Angle &a)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
Nikita Kitaev |
dc5e35 |
value_type c(Angle::cos(a).get());
|
|
Nikita Kitaev |
dc5e35 |
value_type s(Angle::sin(a).get());
|
|
|
bf609b |
m00= c; m01=s; m02=0.0;
|
|
|
bf609b |
m10=-s; m11=c; m12=0.0;
|
|
|
bf609b |
m20= 0.0; m21=0.0; m22=1.0;
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
3a4aaf |
Matrix3&
|
|
|
ab6e41 |
Matrix3::set_translate(value_type x, value_type y)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
Nikita Kitaev |
dc5e35 |
m00=1.0; m01=0.0; m02=0.0;
|
|
Nikita Kitaev |
dc5e35 |
m10=0.0; m11=1.0; m12=0.0;
|
|
Nikita Kitaev |
dc5e35 |
m20=x ; m21=y ; m22=1.0;
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
8005ee |
void
|
|
|
3a4aaf |
Matrix3::get_transformed(
|
|
|
3a4aaf |
value_type &out_x, value_type &out_y, value_type &out_z,
|
|
|
3a4aaf |
const value_type x, const value_type y, const value_type z )const
|
|
|
8005ee |
{
|
|
|
3a4aaf |
out_x = x*m00 + y*m10 + z*m20;
|
|
|
3a4aaf |
out_y = x*m01 + y*m11 + z*m21;
|
|
|
48c23f |
out_z = x*m02 + y*m12 + z*m22;
|
|
|
8005ee |
}
|
|
|
8005ee |
|
|
|
ab6e41 |
bool
|
|
|
ab6e41 |
Matrix3::operator==(const Matrix3 &rhs) const
|
|
|
ab6e41 |
{
|
|
|
d9ebd0 |
return approximate_equal(m00, rhs.m00)
|
|
|
d9ebd0 |
&& approximate_equal(m01, rhs.m01)
|
|
|
d9ebd0 |
&& approximate_equal(m02, rhs.m02)
|
|
|
d9ebd0 |
&& approximate_equal(m10, rhs.m10)
|
|
|
d9ebd0 |
&& approximate_equal(m11, rhs.m11)
|
|
|
d9ebd0 |
&& approximate_equal(m12, rhs.m12)
|
|
|
d9ebd0 |
&& approximate_equal(m20, rhs.m20)
|
|
|
d9ebd0 |
&& approximate_equal(m21, rhs.m21)
|
|
|
d9ebd0 |
&& approximate_equal(m22, rhs.m22);
|
|
|
ab6e41 |
}
|
|
|
ab6e41 |
|
|
|
ab6e41 |
Matrix3
|
|
|
3a4aaf |
Matrix3::operator*(const Matrix3 &rhs) const
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
3a4aaf |
return Matrix3( *this * rhs.row_x(),
|
|
|
3a4aaf |
*this * rhs.row_y(),
|
|
|
3a4aaf |
*this * rhs.row_z() );
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
3a4aaf |
Matrix3&
|
|
|
ab6e41 |
Matrix3::operator*=(const value_type &rhs)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
Nikita Kitaev |
dc5e35 |
m00*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m01*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m02*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
m10*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m11*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m12*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
m20*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m21*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
m22*=rhs;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
3a4aaf |
Matrix3&
|
|
|
ab6e41 |
Matrix3::operator+=(const Matrix3 &rhs)
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
Nikita Kitaev |
dc5e35 |
m00+=rhs.m00;
|
|
Nikita Kitaev |
dc5e35 |
m01+=rhs.m01;
|
|
Nikita Kitaev |
dc5e35 |
m02+=rhs.m02;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
m10+=rhs.m10;
|
|
Nikita Kitaev |
dc5e35 |
m11+=rhs.m11;
|
|
Nikita Kitaev |
dc5e35 |
m12+=rhs.m12;
|
|
Nikita Kitaev |
dc5e35 |
|
|
Nikita Kitaev |
dc5e35 |
m20+=rhs.m20;
|
|
Nikita Kitaev |
dc5e35 |
m21+=rhs.m21;
|
|
Nikita Kitaev |
dc5e35 |
m22+=rhs.m22;
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
ab6e41 |
return *this;
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
23f768 |
Matrix3::value_type
|
|
|
23f768 |
Matrix3::det()const
|
|
|
23f768 |
{
|
|
|
23f768 |
return m00*(m11*m22 - m12*m21)
|
|
|
23f768 |
- m01*(m10*m22 - m12*m20)
|
|
|
23f768 |
+ m02*(m10*m21 - m11*m20);
|
|
|
23f768 |
}
|
|
|
23f768 |
|
|
|
23f768 |
|
|
Nikita Kitaev |
dc5e35 |
bool
|
|
|
ab6e41 |
Matrix3::is_invertible()const
|
|
|
23f768 |
{ return approximate_not_equal(det(), 0.0); }
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
23f768 |
Matrix3
|
|
|
23f768 |
Matrix3::get_inverted()const
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
|
23f768 |
value_type d = det();
|
|
|
24d709 |
if (approximate_equal(d, value_type(0))) {
|
|
|
24d709 |
// result of transformation is not 3d
|
|
|
24d709 |
// all points always transforms into one plane (2d), or line (1d), or dot (0d)
|
|
|
24d709 |
|
|
luz.paz |
99f3ef |
// we cannot do the real back transform, but we will try
|
|
|
24d709 |
// to make valid matrix for X-axis only or for Y-axis only
|
|
|
24d709 |
|
|
|
24d709 |
// try to make back transform for X-axis
|
|
|
24d709 |
if ( approximate_equal(row_x()[2], value_type(0))
|
|
|
24d709 |
&& row_y().is_equal_to(Vector3::zero())
|
|
|
24d709 |
&& approximate_equal(row_z()[2], value_type(1)) )
|
|
|
24d709 |
{
|
|
|
24d709 |
d = axis_x().mag_squared();
|
|
|
24d709 |
if (d > real_precision<value_type>()) {</value_type>
|
|
|
24d709 |
d = 1.0/d;
|
|
|
24d709 |
return Matrix3(
|
|
|
24d709 |
d*m00, 0.0, 0.0,
|
|
|
24d709 |
d*m01, 0.0, 0.0,
|
|
|
24d709 |
-d*(m20*m00 + m21*m01), 0.0, 1.0 );
|
|
|
24d709 |
}
|
|
|
24d709 |
}
|
|
|
24d709 |
|
|
|
24d709 |
// try to make back transform for Y-axis
|
|
|
24d709 |
if ( row_x().is_equal_to(Vector3::zero())
|
|
|
24d709 |
&& approximate_equal(row_y()[2], value_type(0))
|
|
|
24d709 |
&& approximate_equal(row_z()[2], value_type(1)) )
|
|
|
24d709 |
{
|
|
|
24d709 |
d = axis_y().mag_squared();
|
|
|
24d709 |
if (d > real_precision<value_type>()) {</value_type>
|
|
|
24d709 |
d = 1.0/d;
|
|
|
24d709 |
return Matrix3(
|
|
|
24d709 |
0.0, d*m10, 0.0,
|
|
|
24d709 |
0.0, d*m11, 0.0,
|
|
|
24d709 |
0.0, -d*(m20*m10 + m21*m11), 1.0 );
|
|
|
24d709 |
}
|
|
|
24d709 |
}
|
|
|
24d709 |
|
|
|
24d709 |
// give up
|
|
|
23f768 |
return Matrix3( 0.0, 0.0, 0.0,
|
|
|
23f768 |
0.0, 0.0, 0.0,
|
|
|
23f768 |
0.0, 0.0, 0.0 );
|
|
|
24d709 |
}
|
|
|
24d709 |
|
|
|
24d709 |
// proper inversion
|
|
|
23f768 |
value_type p = 1.0/d;
|
|
|
23f768 |
value_type m = -p;
|
|
|
23f768 |
return Matrix3(
|
|
|
23f768 |
p*(m11*m22 - m12*m21), // row0
|
|
|
23f768 |
m*(m01*m22 - m02*m21),
|
|
|
23f768 |
p*(m01*m12 - m02*m11),
|
|
|
23f768 |
m*(m10*m22 - m12*m20), // row1
|
|
|
23f768 |
p*(m00*m22 - m02*m20),
|
|
|
23f768 |
m*(m00*m12 - m02*m10),
|
|
|
23f768 |
p*(m10*m21 - m11*m20), // row2
|
|
|
23f768 |
m*(m00*m21 - m01*m20),
|
|
|
23f768 |
p*(m00*m11 - m01*m10) );
|
|
Nikita Kitaev |
dc5e35 |
}
|
|
Nikita Kitaev |
dc5e35 |
|
|
|
34a685 |
Matrix3&
|
|
|
fc7a04 |
Matrix3::normalize_by_det()
|
|
|
34a685 |
{
|
|
|
fc7a04 |
Real d = det();
|
|
|
fc7a04 |
if (approximate_not_zero(d)) *this *= 1/cbrt(fabs(d));
|
|
|
34a685 |
return *this;
|
|
|
34a685 |
}
|
|
|
34a685 |
|
|
|
34a685 |
|
|
Nikita Kitaev |
dc5e35 |
String
|
|
|
ab6e41 |
Matrix3::get_string(int spaces, String before, String after)const
|
|
Nikita Kitaev |
dc5e35 |
{
|
|
Nikita Kitaev |
dc5e35 |
return etl::strprintf("%*s [%7.2f %7.2f %7.2f] %s\n%*s [%7.2f %7.2f %7.2f]\n%*s [%7.2f %7.2f %7.2f]\n",
|
|
Nikita Kitaev |
dc5e35 |
spaces, before.c_str(), m00, m01, m02, after.c_str(),
|
|
Nikita Kitaev |
dc5e35 |
spaces, "", m10, m11, m12,
|
|
Nikita Kitaev |
dc5e35 |
spaces, "", m20, m21, m22);
|
|
Nikita Kitaev |
dc5e35 |
}
|