agg: Pull in updated perspective transformation
The new version has many more features than the old one. This update is necessary for an upcoming update to Icon-O-Matic adding perspective transformers. This update is pulled from https://github.com/ghaerr/agg-2.6 at commit e7db22bd12700118257b4cb780539c421e01aa51 with our changes applied on top. Note that this repository isn't necessarily the chosen upstream that all future updates should be pulled from. See the discussion starting at [1] for more information. This also updates the affine transformation since the newer perspective transformation requires the newer version. [1] https://discuss.haiku-os.org/t/gsoc-2023-progress-on-perspective-transformation-haiku-project/13594/34 Change-Id: Ic578eec15fbb9131338b3c605c737ce1bfb252ca Reviewed-on: https://review.haiku-os.org/c/haiku/+/6808 Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
efbeada748
commit
a1c86e7ada
@@ -19,12 +19,12 @@
|
|||||||
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
||||||
#define AGG_TRANS_AFFINE_INCLUDED
|
#define AGG_TRANS_AFFINE_INCLUDED
|
||||||
|
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
#include "agg_basics.h"
|
#include "agg_basics.h"
|
||||||
|
|
||||||
namespace agg
|
namespace agg
|
||||||
{
|
{
|
||||||
const double affine_epsilon = 1e-14; // About of precision of doubles
|
const double affine_epsilon = 1e-14;
|
||||||
|
|
||||||
//============================================================trans_affine
|
//============================================================trans_affine
|
||||||
//
|
//
|
||||||
@@ -84,48 +84,58 @@ namespace agg
|
|||||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
|
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
|
||||||
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
|
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
class trans_affine
|
struct trans_affine
|
||||||
{
|
{
|
||||||
public:
|
double sx, shy, shx, sy, tx, ty;
|
||||||
|
|
||||||
//------------------------------------------ Construction
|
//------------------------------------------ Construction
|
||||||
// Construct an identity matrix - it does not transform anything
|
// Identity matrix
|
||||||
trans_affine() :
|
trans_affine() :
|
||||||
m0(1.0), m1(0.0), m2(0.0), m3(1.0), m4(0.0), m5(0.0)
|
sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Construct a custom matrix. Usually used in derived classes
|
// Custom matrix. Usually used in derived classes
|
||||||
trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) :
|
trans_affine(double v0, double v1, double v2,
|
||||||
m0(v0), m1(v1), m2(v2), m3(v3), m4(v4), m5(v5)
|
double v3, double v4, double v5) :
|
||||||
|
sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Construct a matrix to transform a parallelogram to another one.
|
// Custom matrix from m[6]
|
||||||
trans_affine(const double* rect, const double* parl)
|
explicit trans_affine(const double* m) :
|
||||||
{
|
sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5])
|
||||||
parl_to_parl(rect, parl);
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
// Construct a matrix to transform a rectangle to a parallelogram.
|
// Rectangle to a parallelogram.
|
||||||
trans_affine(double x1, double y1, double x2, double y2,
|
trans_affine(double x1, double y1, double x2, double y2,
|
||||||
const double* parl)
|
const double* parl)
|
||||||
{
|
{
|
||||||
rect_to_parl(x1, y1, x2, y2, parl);
|
rect_to_parl(x1, y1, x2, y2, parl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a matrix to transform a parallelogram to a rectangle.
|
// Parallelogram to a rectangle.
|
||||||
trans_affine(const double* parl,
|
trans_affine(const double* parl,
|
||||||
double x1, double y1, double x2, double y2)
|
double x1, double y1, double x2, double y2)
|
||||||
{
|
{
|
||||||
parl_to_rect(parl, x1, y1, x2, y2);
|
parl_to_rect(parl, x1, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Arbitrary parallelogram transformation.
|
||||||
|
trans_affine(const double* src, const double* dst)
|
||||||
|
{
|
||||||
|
parl_to_parl(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------- Parellelogram transformations
|
//---------------------------------- Parellelogram transformations
|
||||||
// Calculate a matrix to transform a parallelogram to another one.
|
// transform a parallelogram to another one. Src and dst are
|
||||||
// src and dst are pointers to arrays of three points
|
// pointers to arrays of three points (double[6], x1,y1,...) that
|
||||||
// (double[6], x,y,...) that identify three corners of the
|
// identify three corners of the parallelograms assuming implicit
|
||||||
// parallelograms assuming implicit fourth points.
|
// fourth point. The arguments are arrays of double[6] mapped
|
||||||
// There are also transformations rectangtle to parallelogram and
|
// to x1,y1, x2,y2, x3,y3 where the coordinates are:
|
||||||
// parellelogram to rectangle
|
// *-----------------*
|
||||||
|
// / (x3,y3)/
|
||||||
|
// / /
|
||||||
|
// /(x1,y1) (x2,y2)/
|
||||||
|
// *-----------------*
|
||||||
const trans_affine& parl_to_parl(const double* src,
|
const trans_affine& parl_to_parl(const double* src,
|
||||||
const double* dst);
|
const double* dst);
|
||||||
|
|
||||||
@@ -139,9 +149,15 @@ namespace agg
|
|||||||
|
|
||||||
|
|
||||||
//------------------------------------------ Operations
|
//------------------------------------------ Operations
|
||||||
// Reset - actually load an identity matrix
|
// Reset - load an identity matrix
|
||||||
const trans_affine& reset();
|
const trans_affine& reset();
|
||||||
|
|
||||||
|
// Direct transformations operations
|
||||||
|
const trans_affine& translate(double x, double y);
|
||||||
|
const trans_affine& rotate(double a);
|
||||||
|
const trans_affine& scale(double s);
|
||||||
|
const trans_affine& scale(double x, double y);
|
||||||
|
|
||||||
// Multiply matrix to another one
|
// Multiply matrix to another one
|
||||||
const trans_affine& multiply(const trans_affine& m);
|
const trans_affine& multiply(const trans_affine& m);
|
||||||
|
|
||||||
@@ -169,38 +185,38 @@ namespace agg
|
|||||||
// Store matrix to an array [6] of double
|
// Store matrix to an array [6] of double
|
||||||
void store_to(double* m) const
|
void store_to(double* m) const
|
||||||
{
|
{
|
||||||
*m++ = m0; *m++ = m1; *m++ = m2; *m++ = m3; *m++ = m4; *m++ = m5;
|
*m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load matrix from an array [6] of double
|
// Load matrix from an array [6] of double
|
||||||
const trans_affine& load_from(const double* m)
|
const trans_affine& load_from(const double* m)
|
||||||
{
|
{
|
||||||
m0 = *m++; m1 = *m++; m2 = *m++; m3 = *m++; m4 = *m++; m5 = *m++;
|
sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------- Operators
|
//------------------------------------------- Operators
|
||||||
|
|
||||||
// Multiply current matrix to another one
|
// Multiply the matrix by another one
|
||||||
const trans_affine& operator *= (const trans_affine& m)
|
const trans_affine& operator *= (const trans_affine& m)
|
||||||
{
|
{
|
||||||
return multiply(m);
|
return multiply(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply current matrix to inverse of another one
|
// Multiply the matrix by inverse of another one
|
||||||
const trans_affine& operator /= (const trans_affine& m)
|
const trans_affine& operator /= (const trans_affine& m)
|
||||||
{
|
{
|
||||||
return multiply_inv(m);
|
return multiply_inv(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply current matrix to another one and return
|
// Multiply the matrix by another one and return
|
||||||
// the result in a separete matrix.
|
// the result in a separete matrix.
|
||||||
trans_affine operator * (const trans_affine& m) const
|
trans_affine operator * (const trans_affine& m) const
|
||||||
{
|
{
|
||||||
return trans_affine(*this).multiply(m);
|
return trans_affine(*this).multiply(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply current matrix to inverse of another one
|
// Multiply the matrix by inverse of another one
|
||||||
// and return the result in a separete matrix.
|
// and return the result in a separete matrix.
|
||||||
trans_affine operator / (const trans_affine& m) const
|
trans_affine operator / (const trans_affine& m) const
|
||||||
{
|
{
|
||||||
@@ -227,22 +243,28 @@ namespace agg
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------- Transformations
|
//-------------------------------------------- Transformations
|
||||||
// Direct transformation x and y
|
// Direct transformation of x and y
|
||||||
void transform(double* x, double* y) const;
|
void transform(double* x, double* y) const;
|
||||||
|
|
||||||
// Direct transformation x and y, 2x2 matrix only, no translation
|
// Direct transformation of x and y, 2x2 matrix only, no translation
|
||||||
void transform_2x2(double* x, double* y) const;
|
void transform_2x2(double* x, double* y) const;
|
||||||
|
|
||||||
// Inverse transformation x and y. It works slower than the
|
// Inverse transformation of x and y. It works slower than the
|
||||||
// direct transformation, so if the performance is critical
|
// direct transformation. For massive operations it's better to
|
||||||
// it's better to invert() the matrix and then use transform()
|
// invert() the matrix and then use direct transformations.
|
||||||
void inverse_transform(double* x, double* y) const;
|
void inverse_transform(double* x, double* y) const;
|
||||||
|
|
||||||
//-------------------------------------------- Auxiliary
|
//-------------------------------------------- Auxiliary
|
||||||
// Calculate the determinant of matrix
|
// Calculate the determinant of matrix
|
||||||
double determinant() const
|
double determinant() const
|
||||||
{
|
{
|
||||||
return 1.0 / (m0 * m3 - m1 * m2);
|
return sx * sy - shy * shx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the reciprocal of the determinant
|
||||||
|
double determinant_reciprocal() const
|
||||||
|
{
|
||||||
|
return 1.0 / (sx * sy - shy * shx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the average scale (by X and Y).
|
// Get the average scale (by X and Y).
|
||||||
@@ -250,63 +272,107 @@ namespace agg
|
|||||||
// decomposinting curves into line segments.
|
// decomposinting curves into line segments.
|
||||||
double scale() const;
|
double scale() const;
|
||||||
|
|
||||||
|
// Check to see if the matrix is not degenerate
|
||||||
|
bool is_valid(double epsilon = affine_epsilon) const;
|
||||||
|
|
||||||
// Check to see if it's an identity matrix
|
// Check to see if it's an identity matrix
|
||||||
bool is_identity(double epsilon = affine_epsilon) const;
|
bool is_identity(double epsilon = affine_epsilon) const;
|
||||||
|
|
||||||
// Check to see if two matrices are equal
|
// Check to see if two matrices are equal
|
||||||
bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
|
bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
|
||||||
|
|
||||||
// Determine the major parameters. Use carefully considering degenerate matrices
|
// Determine the major parameters. Use with caution considering
|
||||||
|
// possible degenerate cases.
|
||||||
double rotation() const;
|
double rotation() const;
|
||||||
void translation(double* dx, double* dy) const;
|
void translation(double* dx, double* dy) const;
|
||||||
void scaling(double* sx, double* sy) const;
|
void scaling(double* x, double* y) const;
|
||||||
void scaling_abs(double* sx, double* sy) const
|
void scaling_abs(double* x, double* y) const;
|
||||||
{
|
|
||||||
*sx = sqrt(m0*m0 + m2*m2);
|
|
||||||
*sy = sqrt(m1*m1 + m3*m3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
double m0;
|
|
||||||
double m1;
|
|
||||||
double m2;
|
|
||||||
double m3;
|
|
||||||
double m4;
|
|
||||||
double m5;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
inline void trans_affine::transform(double* x, double* y) const
|
inline void trans_affine::transform(double* x, double* y) const
|
||||||
{
|
{
|
||||||
double tx = *x;
|
double tmp = *x;
|
||||||
*x = tx * m0 + *y * m2 + m4;
|
*x = tmp * sx + *y * shx + tx;
|
||||||
*y = tx * m1 + *y * m3 + m5;
|
*y = tmp * shy + *y * sy + ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
inline void trans_affine::transform_2x2(double* x, double* y) const
|
inline void trans_affine::transform_2x2(double* x, double* y) const
|
||||||
{
|
{
|
||||||
double tx = *x;
|
double tmp = *x;
|
||||||
*x = tx * m0 + *y * m2;
|
*x = tmp * sx + *y * shx;
|
||||||
*y = tx * m1 + *y * m3;
|
*y = tmp * shy + *y * sy;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
inline void trans_affine::inverse_transform(double* x, double* y) const
|
inline void trans_affine::inverse_transform(double* x, double* y) const
|
||||||
{
|
{
|
||||||
double d = determinant();
|
double d = determinant_reciprocal();
|
||||||
double a = (*x - m4) * d;
|
double a = (*x - tx) * d;
|
||||||
double b = (*y - m5) * d;
|
double b = (*y - ty) * d;
|
||||||
*x = a * m3 - b * m2;
|
*x = a * sy - b * shx;
|
||||||
*y = b * m0 - a * m1;
|
*y = b * sx - a * shy;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
inline double trans_affine::scale() const
|
inline double trans_affine::scale() const
|
||||||
{
|
{
|
||||||
double x = M_SQRT1_2 * m0 + M_SQRT1_2 * m2;
|
double x = M_SQRT1_2 * sx + M_SQRT1_2 * shx;
|
||||||
double y = M_SQRT1_2 * m1 + M_SQRT1_2 * m3;
|
double y = M_SQRT1_2 * shy + M_SQRT1_2 * sy;
|
||||||
return sqrt(x*x + y*y);
|
return std::sqrt(x*x + y*y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_affine& trans_affine::translate(double x, double y)
|
||||||
|
{
|
||||||
|
tx += x;
|
||||||
|
ty += y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_affine& trans_affine::rotate(double a)
|
||||||
|
{
|
||||||
|
double ca = std::cos(a);
|
||||||
|
double sa = std::sin(a);
|
||||||
|
double t0 = sx * ca - shy * sa;
|
||||||
|
double t2 = shx * ca - sy * sa;
|
||||||
|
double t4 = tx * ca - ty * sa;
|
||||||
|
shy = sx * sa + shy * ca;
|
||||||
|
sy = shx * sa + sy * ca;
|
||||||
|
ty = tx * sa + ty * ca;
|
||||||
|
sx = t0;
|
||||||
|
shx = t2;
|
||||||
|
tx = t4;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_affine& trans_affine::scale(double x, double y)
|
||||||
|
{
|
||||||
|
double mm0 = x; // Possible hint for the optimizer
|
||||||
|
double mm3 = y;
|
||||||
|
sx *= mm0;
|
||||||
|
shx *= mm0;
|
||||||
|
tx *= mm0;
|
||||||
|
shy *= mm3;
|
||||||
|
sy *= mm3;
|
||||||
|
ty *= mm3;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_affine& trans_affine::scale(double s)
|
||||||
|
{
|
||||||
|
double m = s; // Possible hint for the optimizer
|
||||||
|
sx *= m;
|
||||||
|
shx *= m;
|
||||||
|
tx *= m;
|
||||||
|
shy *= m;
|
||||||
|
sy *= m;
|
||||||
|
ty *= m;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
@@ -321,8 +387,7 @@ namespace agg
|
|||||||
{
|
{
|
||||||
trans_affine t = m;
|
trans_affine t = m;
|
||||||
t.invert();
|
t.invert();
|
||||||
multiply(t);
|
return multiply(t);
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
@@ -333,6 +398,16 @@ namespace agg
|
|||||||
return *this = t.multiply(*this);
|
return *this = t.multiply(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_affine::scaling_abs(double* x, double* y) const
|
||||||
|
{
|
||||||
|
// Used to calculate scaling coefficients in image resampling.
|
||||||
|
// When there is considerable shear this method gives us much
|
||||||
|
// better estimation than just sx, sy.
|
||||||
|
*x = std::sqrt(sx * sx + shx * shx);
|
||||||
|
*y = std::sqrt(shy * shy + sy * sy);
|
||||||
|
}
|
||||||
|
|
||||||
//====================================================trans_affine_rotation
|
//====================================================trans_affine_rotation
|
||||||
// Rotation matrix. sin() and cos() are calculated twice for the same angle.
|
// Rotation matrix. sin() and cos() are calculated twice for the same angle.
|
||||||
// There's no harm because the performance of sin()/cos() is very good on all
|
// There's no harm because the performance of sin()/cos() is very good on all
|
||||||
@@ -342,17 +417,17 @@ namespace agg
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
trans_affine_rotation(double a) :
|
trans_affine_rotation(double a) :
|
||||||
trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
|
trans_affine(std::cos(a), std::sin(a), -std::sin(a), std::cos(a), 0.0, 0.0)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
//====================================================trans_affine_scaling
|
//====================================================trans_affine_scaling
|
||||||
// Scaling matrix. sx, sy - scale coefficients by X and Y respectively
|
// Scaling matrix. x, y - scale coefficients by X and Y respectively
|
||||||
class trans_affine_scaling : public trans_affine
|
class trans_affine_scaling : public trans_affine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
trans_affine_scaling(double sx, double sy) :
|
trans_affine_scaling(double x, double y) :
|
||||||
trans_affine(sx, 0.0, 0.0, sy, 0.0, 0.0)
|
trans_affine(x, 0.0, 0.0, y, 0.0, 0.0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
trans_affine_scaling(double s) :
|
trans_affine_scaling(double s) :
|
||||||
@@ -365,8 +440,8 @@ namespace agg
|
|||||||
class trans_affine_translation : public trans_affine
|
class trans_affine_translation : public trans_affine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
trans_affine_translation(double tx, double ty) :
|
trans_affine_translation(double x, double y) :
|
||||||
trans_affine(1.0, 0.0, 0.0, 1.0, tx, ty)
|
trans_affine(1.0, 0.0, 0.0, 1.0, x, y)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -375,8 +450,8 @@ namespace agg
|
|||||||
class trans_affine_skewing : public trans_affine
|
class trans_affine_skewing : public trans_affine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
trans_affine_skewing(double sx, double sy) :
|
trans_affine_skewing(double x, double y) :
|
||||||
trans_affine(1.0, tan(sy), tan(sx), 1.0, 0.0, 0.0)
|
trans_affine(1.0, std::tan(y), std::tan(x), 1.0, 0.0, 0.0)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -394,14 +469,48 @@ namespace agg
|
|||||||
double dy = y2 - y1;
|
double dy = y2 - y1;
|
||||||
if(dist > 0.0)
|
if(dist > 0.0)
|
||||||
{
|
{
|
||||||
multiply(trans_affine_scaling(sqrt(dx * dx + dy * dy) / dist));
|
multiply(trans_affine_scaling(std::sqrt(dx * dx + dy * dy) / dist));
|
||||||
}
|
}
|
||||||
multiply(trans_affine_rotation(atan2(dy, dx)));
|
multiply(trans_affine_rotation(std::atan2(dy, dx)));
|
||||||
multiply(trans_affine_translation(x1, y1));
|
multiply(trans_affine_translation(x1, y1));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//============================================trans_affine_reflection_unit
|
||||||
|
// Reflection matrix. Reflect coordinates across the line through
|
||||||
|
// the origin containing the unit vector (ux, uy).
|
||||||
|
// Contributed by John Horigan
|
||||||
|
class trans_affine_reflection_unit : public trans_affine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
trans_affine_reflection_unit(double ux, double uy) :
|
||||||
|
trans_affine(2.0 * ux * ux - 1.0,
|
||||||
|
2.0 * ux * uy,
|
||||||
|
2.0 * ux * uy,
|
||||||
|
2.0 * uy * uy - 1.0,
|
||||||
|
0.0, 0.0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//=================================================trans_affine_reflection
|
||||||
|
// Reflection matrix. Reflect coordinates across the line through
|
||||||
|
// the origin at the angle a or containing the non-unit vector (x, y).
|
||||||
|
// Contributed by John Horigan
|
||||||
|
class trans_affine_reflection : public trans_affine_reflection_unit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
trans_affine_reflection(double a) :
|
||||||
|
trans_affine_reflection_unit(std::cos(a), std::sin(a))
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
trans_affine_reflection(double x, double y) :
|
||||||
|
trans_affine_reflection_unit(x / std::sqrt(x * x + y * y), y / std::sqrt(x * x + y * y))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,125 +19,213 @@
|
|||||||
#ifndef AGG_TRANS_PERSPECTIVE_INCLUDED
|
#ifndef AGG_TRANS_PERSPECTIVE_INCLUDED
|
||||||
#define AGG_TRANS_PERSPECTIVE_INCLUDED
|
#define AGG_TRANS_PERSPECTIVE_INCLUDED
|
||||||
|
|
||||||
#include "agg_basics.h"
|
#include <cmath>
|
||||||
#include "agg_simul_eq.h"
|
#include "agg_trans_affine.h"
|
||||||
|
|
||||||
namespace agg
|
namespace agg
|
||||||
{
|
{
|
||||||
//=======================================================trans_perspective
|
//=======================================================trans_perspective
|
||||||
class trans_perspective
|
struct trans_perspective
|
||||||
{
|
{
|
||||||
public:
|
double sx, shy, w0, shx, sy, w1, tx, ty, w2;
|
||||||
//--------------------------------------------------------------------
|
|
||||||
trans_perspective() : m_valid(false) {}
|
|
||||||
|
|
||||||
|
//------------------------------------------------------- Construction
|
||||||
|
// Identity matrix
|
||||||
|
trans_perspective() :
|
||||||
|
sx (1), shy(0), w0(0),
|
||||||
|
shx(0), sy (1), w1(0),
|
||||||
|
tx (0), ty (0), w2(1) {}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
// Custom matrix
|
||||||
// Arbitrary quadrangle transformations
|
trans_perspective(double v0, double v1, double v2,
|
||||||
trans_perspective(const double* src, const double* dst)
|
double v3, double v4, double v5,
|
||||||
{
|
double v6, double v7, double v8) :
|
||||||
quad_to_quad(src, dst);
|
sx (v0), shy(v1), w0(v2),
|
||||||
}
|
shx(v3), sy (v4), w1(v5),
|
||||||
|
tx (v6), ty (v7), w2(v8) {}
|
||||||
|
|
||||||
|
// Custom matrix from m[9]
|
||||||
|
explicit trans_perspective(const double* m) :
|
||||||
|
sx (m[0]), shy(m[1]), w0(m[2]),
|
||||||
|
shx(m[3]), sy (m[4]), w1(m[5]),
|
||||||
|
tx (m[6]), ty (m[7]), w2(m[8]) {}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
// From affine
|
||||||
// Direct transformations
|
explicit trans_perspective(const trans_affine& a) :
|
||||||
|
sx (a.sx ), shy(a.shy), w0(0),
|
||||||
|
shx(a.shx), sy (a.sy ), w1(0),
|
||||||
|
tx (a.tx ), ty (a.ty ), w2(1) {}
|
||||||
|
|
||||||
|
// Rectangle to quadrilateral
|
||||||
trans_perspective(double x1, double y1, double x2, double y2,
|
trans_perspective(double x1, double y1, double x2, double y2,
|
||||||
const double* quad)
|
const double* quad);
|
||||||
{
|
|
||||||
rect_to_quad(x1, y1, x2, y2, quad);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Quadrilateral to rectangle
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Reverse transformations
|
|
||||||
trans_perspective(const double* quad,
|
trans_perspective(const double* quad,
|
||||||
double x1, double y1, double x2, double y2)
|
double x1, double y1, double x2, double y2);
|
||||||
|
|
||||||
|
// Arbitrary quadrilateral transformations
|
||||||
|
trans_perspective(const double* src, const double* dst);
|
||||||
|
|
||||||
|
//-------------------------------------- Quadrilateral transformations
|
||||||
|
// The arguments are double[8] that are mapped to quadrilaterals:
|
||||||
|
// x1,y1, x2,y2, x3,y3, x4,y4
|
||||||
|
bool quad_to_quad(const double* qs, const double* qd);
|
||||||
|
|
||||||
|
bool rect_to_quad(double x1, double y1,
|
||||||
|
double x2, double y2,
|
||||||
|
const double* q);
|
||||||
|
|
||||||
|
bool quad_to_rect(const double* q,
|
||||||
|
double x1, double y1,
|
||||||
|
double x2, double y2);
|
||||||
|
|
||||||
|
// Map square (0,0,1,1) to the quadrilateral and vice versa
|
||||||
|
bool square_to_quad(const double* q);
|
||||||
|
bool quad_to_square(const double* q);
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------- Operations
|
||||||
|
// Reset - load an identity matrix
|
||||||
|
const trans_perspective& reset();
|
||||||
|
|
||||||
|
// Invert matrix. Returns false in degenerate case
|
||||||
|
bool invert();
|
||||||
|
|
||||||
|
// Direct transformations operations
|
||||||
|
const trans_perspective& translate(double x, double y);
|
||||||
|
const trans_perspective& rotate(double a);
|
||||||
|
const trans_perspective& scale(double s);
|
||||||
|
const trans_perspective& scale(double x, double y);
|
||||||
|
|
||||||
|
// Multiply the matrix by another one
|
||||||
|
const trans_perspective& multiply(const trans_perspective& m);
|
||||||
|
|
||||||
|
// Multiply "m" by "this" and assign the result to "this"
|
||||||
|
const trans_perspective& premultiply(const trans_perspective& m);
|
||||||
|
|
||||||
|
// Multiply matrix to inverse of another one
|
||||||
|
const trans_perspective& multiply_inv(const trans_perspective& m);
|
||||||
|
|
||||||
|
// Multiply inverse of "m" by "this" and assign the result to "this"
|
||||||
|
const trans_perspective& premultiply_inv(const trans_perspective& m);
|
||||||
|
|
||||||
|
// Multiply the matrix by another one
|
||||||
|
const trans_perspective& multiply(const trans_affine& m);
|
||||||
|
|
||||||
|
// Multiply "m" by "this" and assign the result to "this"
|
||||||
|
const trans_perspective& premultiply(const trans_affine& m);
|
||||||
|
|
||||||
|
// Multiply the matrix by inverse of another one
|
||||||
|
const trans_perspective& multiply_inv(const trans_affine& m);
|
||||||
|
|
||||||
|
// Multiply inverse of "m" by "this" and assign the result to "this"
|
||||||
|
const trans_perspective& premultiply_inv(const trans_affine& m);
|
||||||
|
|
||||||
|
//--------------------------------------------------------- Load/Store
|
||||||
|
void store_to(double* m) const;
|
||||||
|
const trans_perspective& load_from(const double* m);
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Operators
|
||||||
|
// Multiply the matrix by another one
|
||||||
|
const trans_perspective& operator *= (const trans_perspective& m)
|
||||||
{
|
{
|
||||||
quad_to_rect(quad, x1, y1, x2, y2);
|
return multiply(m);
|
||||||
|
}
|
||||||
|
const trans_perspective& operator *= (const trans_affine& m)
|
||||||
|
{
|
||||||
|
return multiply(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiply the matrix by inverse of another one
|
||||||
//--------------------------------------------------------------------
|
const trans_perspective& operator /= (const trans_perspective& m)
|
||||||
// Set the transformations using two arbitrary quadrangles.
|
|
||||||
void quad_to_quad(const double* src, const double* dst)
|
|
||||||
{
|
{
|
||||||
|
return multiply_inv(m);
|
||||||
double left[8][8];
|
}
|
||||||
double right[8][1];
|
const trans_perspective& operator /= (const trans_affine& m)
|
||||||
|
{
|
||||||
unsigned i;
|
return multiply_inv(m);
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
unsigned ix = i * 2;
|
|
||||||
unsigned iy = ix + 1;
|
|
||||||
|
|
||||||
left[ix][0] = 1.0;
|
|
||||||
left[ix][1] = src[ix];
|
|
||||||
left[ix][2] = src[iy];
|
|
||||||
left[ix][3] = 0.0;
|
|
||||||
left[ix][4] = 0.0;
|
|
||||||
left[ix][5] = 0.0;
|
|
||||||
left[ix][6] = -src[ix] * dst[ix];
|
|
||||||
left[ix][7] = -src[iy] * dst[ix];
|
|
||||||
right[ix][0] = dst[ix];
|
|
||||||
|
|
||||||
left[iy][0] = 0.0;
|
|
||||||
left[iy][1] = 0.0;
|
|
||||||
left[iy][2] = 0.0;
|
|
||||||
left[iy][3] = 1.0;
|
|
||||||
left[iy][4] = src[ix];
|
|
||||||
left[iy][5] = src[iy];
|
|
||||||
left[iy][6] = -src[ix] * dst[iy];
|
|
||||||
left[iy][7] = -src[iy] * dst[iy];
|
|
||||||
right[iy][0] = dst[iy];
|
|
||||||
}
|
|
||||||
m_valid = simul_eq<8, 1>::solve(left, right, m_mtx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiply the matrix by another one and return
|
||||||
//--------------------------------------------------------------------
|
// the result in a separete matrix.
|
||||||
// Set the direct transformations, i.e., rectangle -> quadrangle
|
trans_perspective operator * (const trans_perspective& m) const
|
||||||
void rect_to_quad(double x1, double y1, double x2, double y2,
|
|
||||||
const double* quad)
|
|
||||||
{
|
{
|
||||||
double src[8];
|
return trans_perspective(*this).multiply(m);
|
||||||
src[0] = src[6] = x1;
|
}
|
||||||
src[2] = src[4] = x2;
|
trans_perspective operator * (const trans_affine& m) const
|
||||||
src[1] = src[3] = y1;
|
{
|
||||||
src[5] = src[7] = y2;
|
return trans_perspective(*this).multiply(m);
|
||||||
quad_to_quad(src, quad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiply the matrix by inverse of another one
|
||||||
//--------------------------------------------------------------------
|
// and return the result in a separete matrix.
|
||||||
// Set the reverse transformations, i.e., quadrangle -> rectangle
|
trans_perspective operator / (const trans_perspective& m) const
|
||||||
void quad_to_rect(const double* quad,
|
|
||||||
double x1, double y1, double x2, double y2)
|
|
||||||
{
|
{
|
||||||
double dst[8];
|
return trans_perspective(*this).multiply_inv(m);
|
||||||
dst[0] = dst[6] = x1;
|
}
|
||||||
dst[2] = dst[4] = x2;
|
trans_perspective operator / (const trans_affine& m) const
|
||||||
dst[1] = dst[3] = y1;
|
{
|
||||||
dst[5] = dst[7] = y2;
|
return trans_perspective(*this).multiply_inv(m);
|
||||||
quad_to_quad(quad, dst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
// Calculate and return the inverse matrix
|
||||||
// Check if the equations were solved successfully
|
trans_perspective operator ~ () const
|
||||||
bool is_valid() const { return m_valid; }
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Transform a point (x, y)
|
|
||||||
void transform(double* x, double* y) const
|
|
||||||
{
|
{
|
||||||
double tx = *x;
|
trans_perspective ret = *this;
|
||||||
double ty = *y;
|
ret.invert();
|
||||||
double d = 1.0 / (m_mtx[6][0] * tx + m_mtx[7][0] * ty + 1.0);
|
return ret;
|
||||||
*x = (m_mtx[0][0] + m_mtx[1][0] * tx + m_mtx[2][0] * ty) * d;
|
|
||||||
*y = (m_mtx[3][0] + m_mtx[4][0] * tx + m_mtx[5][0] * ty) * d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal operator with default epsilon
|
||||||
|
bool operator == (const trans_perspective& m) const
|
||||||
|
{
|
||||||
|
return is_equal(m, affine_epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not Equal operator with default epsilon
|
||||||
|
bool operator != (const trans_perspective& m) const
|
||||||
|
{
|
||||||
|
return !is_equal(m, affine_epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------- Transformations
|
||||||
|
// Direct transformation of x and y
|
||||||
|
void transform(double* x, double* y) const;
|
||||||
|
|
||||||
|
// Direct transformation of x and y, affine part only
|
||||||
|
void transform_affine(double* x, double* y) const;
|
||||||
|
|
||||||
|
// Direct transformation of x and y, 2x2 matrix only, no translation
|
||||||
|
void transform_2x2(double* x, double* y) const;
|
||||||
|
|
||||||
|
// Inverse transformation of x and y. It works slow because
|
||||||
|
// it explicitly inverts the matrix on every call. For massive
|
||||||
|
// operations it's better to invert() the matrix and then use
|
||||||
|
// direct transformations.
|
||||||
|
void inverse_transform(double* x, double* y) const;
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------- Auxiliary
|
||||||
|
const trans_perspective& from_affine(const trans_affine& a);
|
||||||
|
double determinant() const;
|
||||||
|
double determinant_reciprocal() const;
|
||||||
|
|
||||||
|
bool is_valid(double epsilon = affine_epsilon) const;
|
||||||
|
bool is_identity(double epsilon = affine_epsilon) const;
|
||||||
|
bool is_equal(const trans_perspective& m,
|
||||||
|
double epsilon = affine_epsilon) const;
|
||||||
|
|
||||||
|
// Determine the major affine parameters. Use with caution
|
||||||
|
// considering possible degenerate cases.
|
||||||
|
double scale() const;
|
||||||
|
double rotation() const;
|
||||||
|
void translation(double* dx, double* dy) const;
|
||||||
|
void scaling(double* x, double* y) const;
|
||||||
|
void scaling_abs(double* x, double* y) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
class iterator_x
|
class iterator_x
|
||||||
{
|
{
|
||||||
@@ -153,17 +241,16 @@ namespace agg
|
|||||||
double y;
|
double y;
|
||||||
|
|
||||||
iterator_x() {}
|
iterator_x() {}
|
||||||
iterator_x(double tx, double ty, double step, const double m[8][1]) :
|
iterator_x(double px, double py, double step, const trans_perspective& m) :
|
||||||
den(m[6][0] * tx + m[7][0] * ty + 1.0),
|
den(px * m.w0 + py * m.w1 + m.w2),
|
||||||
den_step(m[6][0] * step),
|
den_step(m.w0 * step),
|
||||||
nom_x(m[0][0] + m[1][0] * tx + m[2][0] * ty),
|
nom_x(px * m.sx + py * m.shx + m.tx),
|
||||||
nom_x_step(m[1][0] * step),
|
nom_x_step(step * m.sx),
|
||||||
nom_y(m[3][0] + m[4][0] * tx + m[5][0] * ty),
|
nom_y(px * m.shy + py * m.sy + m.ty),
|
||||||
nom_y_step(m[4][0] * step),
|
nom_y_step(step * m.shy),
|
||||||
x(nom_x / den),
|
x(nom_x / den),
|
||||||
y(nom_y / den)
|
y(nom_y / den)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void operator ++ ()
|
void operator ++ ()
|
||||||
{
|
{
|
||||||
@@ -179,14 +266,467 @@ namespace agg
|
|||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
iterator_x begin(double x, double y, double step) const
|
iterator_x begin(double x, double y, double step) const
|
||||||
{
|
{
|
||||||
return iterator_x(x, y, step, m_mtx);
|
return iterator_x(x, y, step, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
double m_mtx[8][1];
|
|
||||||
bool m_valid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::square_to_quad(const double* q)
|
||||||
|
{
|
||||||
|
double dx = q[0] - q[2] + q[4] - q[6];
|
||||||
|
double dy = q[1] - q[3] + q[5] - q[7];
|
||||||
|
if(dx == 0.0 && dy == 0.0)
|
||||||
|
{
|
||||||
|
// Affine case (parallelogram)
|
||||||
|
//---------------
|
||||||
|
sx = q[2] - q[0];
|
||||||
|
shy = q[3] - q[1];
|
||||||
|
w0 = 0.0;
|
||||||
|
shx = q[4] - q[2];
|
||||||
|
sy = q[5] - q[3];
|
||||||
|
w1 = 0.0;
|
||||||
|
tx = q[0];
|
||||||
|
ty = q[1];
|
||||||
|
w2 = 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double dx1 = q[2] - q[4];
|
||||||
|
double dy1 = q[3] - q[5];
|
||||||
|
double dx2 = q[6] - q[4];
|
||||||
|
double dy2 = q[7] - q[5];
|
||||||
|
double den = dx1 * dy2 - dx2 * dy1;
|
||||||
|
if(den == 0.0)
|
||||||
|
{
|
||||||
|
// Singular case
|
||||||
|
//---------------
|
||||||
|
sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// General case
|
||||||
|
//---------------
|
||||||
|
double u = (dx * dy2 - dy * dx2) / den;
|
||||||
|
double v = (dy * dx1 - dx * dy1) / den;
|
||||||
|
sx = q[2] - q[0] + u * q[2];
|
||||||
|
shy = q[3] - q[1] + u * q[3];
|
||||||
|
w0 = u;
|
||||||
|
shx = q[6] - q[0] + v * q[6];
|
||||||
|
sy = q[7] - q[1] + v * q[7];
|
||||||
|
w1 = v;
|
||||||
|
tx = q[0];
|
||||||
|
ty = q[1];
|
||||||
|
w2 = 1.0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::invert()
|
||||||
|
{
|
||||||
|
double d0 = sy * w2 - w1 * ty;
|
||||||
|
double d1 = w0 * ty - shy * w2;
|
||||||
|
double d2 = shy * w1 - w0 * sy;
|
||||||
|
double d = sx * d0 + shx * d1 + tx * d2;
|
||||||
|
if(d == 0.0)
|
||||||
|
{
|
||||||
|
sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
d = 1.0 / d;
|
||||||
|
trans_perspective a = *this;
|
||||||
|
sx = d * d0;
|
||||||
|
shy = d * d1;
|
||||||
|
w0 = d * d2;
|
||||||
|
shx = d * (a.w1 *a.tx - a.shx*a.w2);
|
||||||
|
sy = d * (a.sx *a.w2 - a.w0 *a.tx);
|
||||||
|
w1 = d * (a.w0 *a.shx - a.sx *a.w1);
|
||||||
|
tx = d * (a.shx*a.ty - a.sy *a.tx);
|
||||||
|
ty = d * (a.shy*a.tx - a.sx *a.ty);
|
||||||
|
w2 = d * (a.sx *a.sy - a.shy*a.shx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::quad_to_square(const double* q)
|
||||||
|
{
|
||||||
|
if(!square_to_quad(q)) return false;
|
||||||
|
invert();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::quad_to_quad(const double* qs,
|
||||||
|
const double* qd)
|
||||||
|
{
|
||||||
|
trans_perspective p;
|
||||||
|
if(! quad_to_square(qs)) return false;
|
||||||
|
if(!p.square_to_quad(qd)) return false;
|
||||||
|
multiply(p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::rect_to_quad(double x1, double y1,
|
||||||
|
double x2, double y2,
|
||||||
|
const double* q)
|
||||||
|
{
|
||||||
|
double r[8];
|
||||||
|
r[0] = r[6] = x1;
|
||||||
|
r[2] = r[4] = x2;
|
||||||
|
r[1] = r[3] = y1;
|
||||||
|
r[5] = r[7] = y2;
|
||||||
|
return quad_to_quad(r, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::quad_to_rect(const double* q,
|
||||||
|
double x1, double y1,
|
||||||
|
double x2, double y2)
|
||||||
|
{
|
||||||
|
double r[8];
|
||||||
|
r[0] = r[6] = x1;
|
||||||
|
r[2] = r[4] = x2;
|
||||||
|
r[1] = r[3] = y1;
|
||||||
|
r[5] = r[7] = y2;
|
||||||
|
return quad_to_quad(q, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline trans_perspective::trans_perspective(double x1, double y1,
|
||||||
|
double x2, double y2,
|
||||||
|
const double* quad)
|
||||||
|
{
|
||||||
|
rect_to_quad(x1, y1, x2, y2, quad);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline trans_perspective::trans_perspective(const double* quad,
|
||||||
|
double x1, double y1,
|
||||||
|
double x2, double y2)
|
||||||
|
{
|
||||||
|
quad_to_rect(quad, x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline trans_perspective::trans_perspective(const double* src,
|
||||||
|
const double* dst)
|
||||||
|
{
|
||||||
|
quad_to_quad(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective& trans_perspective::reset()
|
||||||
|
{
|
||||||
|
sx = 1; shy = 0; w0 = 0;
|
||||||
|
shx = 0; sy = 1; w1 = 0;
|
||||||
|
tx = 0; ty = 0; w2 = 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::multiply(const trans_perspective& a)
|
||||||
|
{
|
||||||
|
trans_perspective b = *this;
|
||||||
|
sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0;
|
||||||
|
shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1;
|
||||||
|
tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2;
|
||||||
|
shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0;
|
||||||
|
sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1;
|
||||||
|
ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2;
|
||||||
|
w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0;
|
||||||
|
w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1;
|
||||||
|
w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::multiply(const trans_affine& a)
|
||||||
|
{
|
||||||
|
trans_perspective b = *this;
|
||||||
|
sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0;
|
||||||
|
shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1;
|
||||||
|
tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2;
|
||||||
|
shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0;
|
||||||
|
sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1;
|
||||||
|
ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::premultiply(const trans_perspective& b)
|
||||||
|
{
|
||||||
|
trans_perspective a = *this;
|
||||||
|
sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0;
|
||||||
|
shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1;
|
||||||
|
tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2;
|
||||||
|
shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0;
|
||||||
|
sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1;
|
||||||
|
ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2;
|
||||||
|
w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0;
|
||||||
|
w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1;
|
||||||
|
w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::premultiply(const trans_affine& b)
|
||||||
|
{
|
||||||
|
trans_perspective a = *this;
|
||||||
|
sx = a.sx *b.sx + a.shx*b.shy;
|
||||||
|
shx = a.sx *b.shx + a.shx*b.sy;
|
||||||
|
tx = a.sx *b.tx + a.shx*b.ty + a.tx;
|
||||||
|
shy = a.shy*b.sx + a.sy *b.shy;
|
||||||
|
sy = a.shy*b.shx + a.sy *b.sy;
|
||||||
|
ty = a.shy*b.tx + a.sy *b.ty + a.ty;
|
||||||
|
w0 = a.w0 *b.sx + a.w1 *b.shy;
|
||||||
|
w1 = a.w0 *b.shx + a.w1 *b.sy;
|
||||||
|
w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
const trans_perspective&
|
||||||
|
trans_perspective::multiply_inv(const trans_perspective& m)
|
||||||
|
{
|
||||||
|
trans_perspective t = m;
|
||||||
|
t.invert();
|
||||||
|
return multiply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
const trans_perspective&
|
||||||
|
trans_perspective::multiply_inv(const trans_affine& m)
|
||||||
|
{
|
||||||
|
trans_affine t = m;
|
||||||
|
t.invert();
|
||||||
|
return multiply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
const trans_perspective&
|
||||||
|
trans_perspective::premultiply_inv(const trans_perspective& m)
|
||||||
|
{
|
||||||
|
trans_perspective t = m;
|
||||||
|
t.invert();
|
||||||
|
return *this = t.multiply(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
const trans_perspective&
|
||||||
|
trans_perspective::premultiply_inv(const trans_affine& m)
|
||||||
|
{
|
||||||
|
trans_perspective t(m);
|
||||||
|
t.invert();
|
||||||
|
return *this = t.multiply(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::translate(double x, double y)
|
||||||
|
{
|
||||||
|
tx += x;
|
||||||
|
ty += y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective& trans_perspective::rotate(double a)
|
||||||
|
{
|
||||||
|
multiply(trans_affine_rotation(a));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective& trans_perspective::scale(double s)
|
||||||
|
{
|
||||||
|
multiply(trans_affine_scaling(s));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective& trans_perspective::scale(double x, double y)
|
||||||
|
{
|
||||||
|
multiply(trans_affine_scaling(x, y));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_perspective::transform(double* px, double* py) const
|
||||||
|
{
|
||||||
|
double x = *px;
|
||||||
|
double y = *py;
|
||||||
|
double m = 1.0 / (x*w0 + y*w1 + w2);
|
||||||
|
*px = m * (x*sx + y*shx + tx);
|
||||||
|
*py = m * (x*shy + y*sy + ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_perspective::transform_affine(double* x, double* y) const
|
||||||
|
{
|
||||||
|
double tmp = *x;
|
||||||
|
*x = tmp * sx + *y * shx + tx;
|
||||||
|
*y = tmp * shy + *y * sy + ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_perspective::transform_2x2(double* x, double* y) const
|
||||||
|
{
|
||||||
|
double tmp = *x;
|
||||||
|
*x = tmp * sx + *y * shx;
|
||||||
|
*y = tmp * shy + *y * sy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_perspective::inverse_transform(double* x, double* y) const
|
||||||
|
{
|
||||||
|
trans_perspective t(*this);
|
||||||
|
if(t.invert()) t.transform(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline void trans_perspective::store_to(double* m) const
|
||||||
|
{
|
||||||
|
*m++ = sx; *m++ = shy; *m++ = w0;
|
||||||
|
*m++ = shx; *m++ = sy; *m++ = w1;
|
||||||
|
*m++ = tx; *m++ = ty; *m++ = w2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective& trans_perspective::load_from(const double* m)
|
||||||
|
{
|
||||||
|
sx = *m++; shy = *m++; w0 = *m++;
|
||||||
|
shx = *m++; sy = *m++; w1 = *m++;
|
||||||
|
tx = *m++; ty = *m++; w2 = *m++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline const trans_perspective&
|
||||||
|
trans_perspective::from_affine(const trans_affine& a)
|
||||||
|
{
|
||||||
|
sx = a.sx; shy = a.shy; w0 = 0;
|
||||||
|
shx = a.shx; sy = a.sy; w1 = 0;
|
||||||
|
tx = a.tx; ty = a.ty; w2 = 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline double trans_perspective::determinant() const
|
||||||
|
{
|
||||||
|
return sx * (sy * w2 - ty * w1) +
|
||||||
|
shx * (ty * w0 - shy * w2) +
|
||||||
|
tx * (shy * w1 - sy * w0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline double trans_perspective::determinant_reciprocal() const
|
||||||
|
{
|
||||||
|
return 1.0 / determinant();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::is_valid(double epsilon) const
|
||||||
|
{
|
||||||
|
return std::fabs(sx) > epsilon && std::fabs(sy) > epsilon && std::fabs(w2) > epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::is_identity(double epsilon) const
|
||||||
|
{
|
||||||
|
return is_equal_eps(sx, 1.0, epsilon) &&
|
||||||
|
is_equal_eps(shy, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(w0, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(shx, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(sy, 1.0, epsilon) &&
|
||||||
|
is_equal_eps(w1, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(tx, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(ty, 0.0, epsilon) &&
|
||||||
|
is_equal_eps(w2, 1.0, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline bool trans_perspective::is_equal(const trans_perspective& m,
|
||||||
|
double epsilon) const
|
||||||
|
{
|
||||||
|
return is_equal_eps(sx, m.sx, epsilon) &&
|
||||||
|
is_equal_eps(shy, m.shy, epsilon) &&
|
||||||
|
is_equal_eps(w0, m.w0, epsilon) &&
|
||||||
|
is_equal_eps(shx, m.shx, epsilon) &&
|
||||||
|
is_equal_eps(sy, m.sy, epsilon) &&
|
||||||
|
is_equal_eps(w1, m.w1, epsilon) &&
|
||||||
|
is_equal_eps(tx, m.tx, epsilon) &&
|
||||||
|
is_equal_eps(ty, m.ty, epsilon) &&
|
||||||
|
is_equal_eps(w2, m.w2, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline double trans_perspective::scale() const
|
||||||
|
{
|
||||||
|
double x = 0.707106781 * sx + 0.707106781 * shx;
|
||||||
|
double y = 0.707106781 * shy + 0.707106781 * sy;
|
||||||
|
return std::sqrt(x*x + y*y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
inline double trans_perspective::rotation() const
|
||||||
|
{
|
||||||
|
double x1 = 0.0;
|
||||||
|
double y1 = 0.0;
|
||||||
|
double x2 = 1.0;
|
||||||
|
double y2 = 0.0;
|
||||||
|
transform(&x1, &y1);
|
||||||
|
transform(&x2, &y2);
|
||||||
|
return std::atan2(y2-y1, x2-x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
void trans_perspective::translation(double* dx, double* dy) const
|
||||||
|
{
|
||||||
|
*dx = tx;
|
||||||
|
*dy = ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
void trans_perspective::scaling(double* x, double* y) const
|
||||||
|
{
|
||||||
|
double x1 = 0.0;
|
||||||
|
double y1 = 0.0;
|
||||||
|
double x2 = 1.0;
|
||||||
|
double y2 = 1.0;
|
||||||
|
trans_perspective t(*this);
|
||||||
|
t *= trans_affine_rotation(-rotation());
|
||||||
|
t.transform(&x1, &y1);
|
||||||
|
t.transform(&x2, &y2);
|
||||||
|
*x = x2 - x1;
|
||||||
|
*y = y2 - y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
void trans_perspective::scaling_abs(double* x, double* y) const
|
||||||
|
{
|
||||||
|
*x = std::sqrt(sx * sx + shx * shx);
|
||||||
|
*y = std::sqrt(shy * shy + sy * sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ namespace agg
|
|||||||
const trans_affine& trans_affine::parl_to_parl(const double* src,
|
const trans_affine& trans_affine::parl_to_parl(const double* src,
|
||||||
const double* dst)
|
const double* dst)
|
||||||
{
|
{
|
||||||
m0 = src[2] - src[0];
|
sx = src[2] - src[0];
|
||||||
m1 = src[3] - src[1];
|
shy = src[3] - src[1];
|
||||||
m2 = src[4] - src[0];
|
shx = src[4] - src[0];
|
||||||
m3 = src[5] - src[1];
|
sy = src[5] - src[1];
|
||||||
m4 = src[0];
|
tx = src[0];
|
||||||
m5 = src[1];
|
ty = src[1];
|
||||||
invert();
|
invert();
|
||||||
multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1],
|
multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1],
|
||||||
dst[4] - dst[0], dst[5] - dst[1],
|
dst[4] - dst[0], dst[5] - dst[1],
|
||||||
@@ -69,15 +69,15 @@ namespace agg
|
|||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
const trans_affine& trans_affine::multiply(const trans_affine& m)
|
const trans_affine& trans_affine::multiply(const trans_affine& m)
|
||||||
{
|
{
|
||||||
double t0 = m0 * m.m0 + m1 * m.m2;
|
double t0 = sx * m.sx + shy * m.shx;
|
||||||
double t2 = m2 * m.m0 + m3 * m.m2;
|
double t2 = shx * m.sx + sy * m.shx;
|
||||||
double t4 = m4 * m.m0 + m5 * m.m2 + m.m4;
|
double t4 = tx * m.sx + ty * m.shx + m.tx;
|
||||||
m1 = m0 * m.m1 + m1 * m.m3;
|
shy = sx * m.shy + shy * m.sy;
|
||||||
m3 = m2 * m.m1 + m3 * m.m3;
|
sy = shx * m.shy + sy * m.sy;
|
||||||
m5 = m4 * m.m1 + m5 * m.m3 + m.m5;
|
ty = tx * m.shy + ty * m.sy + m.ty;
|
||||||
m0 = t0;
|
sx = t0;
|
||||||
m2 = t2;
|
shx = t2;
|
||||||
m4 = t4;
|
tx = t4;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,18 +85,18 @@ namespace agg
|
|||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
const trans_affine& trans_affine::invert()
|
const trans_affine& trans_affine::invert()
|
||||||
{
|
{
|
||||||
double d = determinant();
|
double d = determinant_reciprocal();
|
||||||
|
|
||||||
double t0 = m3 * d;
|
double t0 = sy * d;
|
||||||
m3 = m0 * d;
|
sy = sx * d;
|
||||||
m1 = -m1 * d;
|
shy = -shy * d;
|
||||||
m2 = -m2 * d;
|
shx = -shx * d;
|
||||||
|
|
||||||
double t4 = -m4 * t0 - m5 * m2;
|
double t4 = -tx * t0 - ty * shx;
|
||||||
m5 = -m4 * m1 - m5 * m3;
|
ty = -tx * shy - ty * sy;
|
||||||
|
|
||||||
m0 = t0;
|
sx = t0;
|
||||||
m4 = t4;
|
tx = t4;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,55 +104,55 @@ namespace agg
|
|||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
const trans_affine& trans_affine::flip_x()
|
const trans_affine& trans_affine::flip_x()
|
||||||
{
|
{
|
||||||
m0 = -m0;
|
sx = -sx;
|
||||||
m1 = -m1;
|
shy = -shy;
|
||||||
m4 = -m4;
|
tx = -tx;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
const trans_affine& trans_affine::flip_y()
|
const trans_affine& trans_affine::flip_y()
|
||||||
{
|
{
|
||||||
m2 = -m2;
|
shx = -shx;
|
||||||
m3 = -m3;
|
sy = -sy;
|
||||||
m5 = -m5;
|
ty = -ty;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
const trans_affine& trans_affine::reset()
|
const trans_affine& trans_affine::reset()
|
||||||
{
|
{
|
||||||
m0 = m3 = 1.0;
|
sx = sy = 1.0;
|
||||||
m1 = m2 = m4 = m5 = 0.0;
|
shy = shx = tx = ty = 0.0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
inline bool is_equal_eps(double v1, double v2, double epsilon)
|
|
||||||
{
|
|
||||||
return fabs(v1 - v2) < epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
bool trans_affine::is_identity(double epsilon) const
|
bool trans_affine::is_identity(double epsilon) const
|
||||||
{
|
{
|
||||||
return is_equal_eps(m0, 1.0, epsilon) &&
|
return is_equal_eps(sx, 1.0, epsilon) &&
|
||||||
is_equal_eps(m1, 0.0, epsilon) &&
|
is_equal_eps(shy, 0.0, epsilon) &&
|
||||||
is_equal_eps(m2, 0.0, epsilon) &&
|
is_equal_eps(shx, 0.0, epsilon) &&
|
||||||
is_equal_eps(m3, 1.0, epsilon) &&
|
is_equal_eps(sy, 1.0, epsilon) &&
|
||||||
is_equal_eps(m4, 0.0, epsilon) &&
|
is_equal_eps(tx, 0.0, epsilon) &&
|
||||||
is_equal_eps(m5, 0.0, epsilon);
|
is_equal_eps(ty, 0.0, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
bool trans_affine::is_valid(double epsilon) const
|
||||||
|
{
|
||||||
|
return std::fabs(sx) > epsilon && std::fabs(sy) > epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
bool trans_affine::is_equal(const trans_affine& m, double epsilon) const
|
bool trans_affine::is_equal(const trans_affine& m, double epsilon) const
|
||||||
{
|
{
|
||||||
return is_equal_eps(m0, m.m0, epsilon) &&
|
return is_equal_eps(sx, m.sx, epsilon) &&
|
||||||
is_equal_eps(m1, m.m1, epsilon) &&
|
is_equal_eps(shy, m.shy, epsilon) &&
|
||||||
is_equal_eps(m2, m.m2, epsilon) &&
|
is_equal_eps(shx, m.shx, epsilon) &&
|
||||||
is_equal_eps(m3, m.m3, epsilon) &&
|
is_equal_eps(sy, m.sy, epsilon) &&
|
||||||
is_equal_eps(m4, m.m4, epsilon) &&
|
is_equal_eps(tx, m.tx, epsilon) &&
|
||||||
is_equal_eps(m5, m.m5, epsilon);
|
is_equal_eps(ty, m.ty, epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
@@ -164,18 +164,18 @@ namespace agg
|
|||||||
double y2 = 0.0;
|
double y2 = 0.0;
|
||||||
transform(&x1, &y1);
|
transform(&x1, &y1);
|
||||||
transform(&x2, &y2);
|
transform(&x2, &y2);
|
||||||
return atan2(y2-y1, x2-x1);
|
return std::atan2(y2-y1, x2-x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
void trans_affine::translation(double* dx, double* dy) const
|
void trans_affine::translation(double* dx, double* dy) const
|
||||||
{
|
{
|
||||||
*dx = m4;
|
*dx = tx;
|
||||||
*dy = m5;
|
*dy = ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
void trans_affine::scaling(double* sx, double* sy) const
|
void trans_affine::scaling(double* x, double* y) const
|
||||||
{
|
{
|
||||||
double x1 = 0.0;
|
double x1 = 0.0;
|
||||||
double y1 = 0.0;
|
double y1 = 0.0;
|
||||||
@@ -185,8 +185,8 @@ namespace agg
|
|||||||
t *= trans_affine_rotation(-rotation());
|
t *= trans_affine_rotation(-rotation());
|
||||||
t.transform(&x1, &y1);
|
t.transform(&x1, &y1);
|
||||||
t.transform(&x2, &y2);
|
t.transform(&x2, &y2);
|
||||||
*sx = x2 - x1;
|
*x = x2 - x1;
|
||||||
*sy = y2 - y1;
|
*y = y2 - y1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user