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
+221
-112
@@ -2,8 +2,8 @@
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
@@ -19,44 +19,44 @@
|
||||
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
||||
#define AGG_TRANS_AFFINE_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
const double affine_epsilon = 1e-14; // About of precision of doubles
|
||||
const double affine_epsilon = 1e-14;
|
||||
|
||||
//============================================================trans_affine
|
||||
//
|
||||
// See Implementation agg_trans_affine.cpp
|
||||
//
|
||||
// Affine transformation are linear transformations in Cartesian coordinates
|
||||
// (strictly speaking not only in Cartesian, but for the beginning we will
|
||||
// think so). They are rotation, scaling, translation and skewing.
|
||||
// After any affine transformation a line segment remains a line segment
|
||||
// and it will never become a curve.
|
||||
// (strictly speaking not only in Cartesian, but for the beginning we will
|
||||
// think so). They are rotation, scaling, translation and skewing.
|
||||
// After any affine transformation a line segment remains a line segment
|
||||
// and it will never become a curve.
|
||||
//
|
||||
// There will be no math about matrix calculations, since it has been
|
||||
// There will be no math about matrix calculations, since it has been
|
||||
// described many times. Ask yourself a very simple question:
|
||||
// "why do we need to understand and use some matrix stuff instead of just
|
||||
// "why do we need to understand and use some matrix stuff instead of just
|
||||
// rotating, scaling and so on". The answers are:
|
||||
//
|
||||
// 1. Any combination of transformations can be done by only 4 multiplications
|
||||
// and 4 additions in floating point.
|
||||
// 2. One matrix transformation is equivalent to the number of consecutive
|
||||
// discrete transformations, i.e. the matrix "accumulates" all transformations
|
||||
// in the order of their settings. Suppose we have 4 transformations:
|
||||
// discrete transformations, i.e. the matrix "accumulates" all transformations
|
||||
// in the order of their settings. Suppose we have 4 transformations:
|
||||
// * rotate by 30 degrees,
|
||||
// * scale X to 2.0,
|
||||
// * scale Y to 1.5,
|
||||
// * move to (100, 100).
|
||||
// The result will depend on the order of these transformations,
|
||||
// * scale X to 2.0,
|
||||
// * scale Y to 1.5,
|
||||
// * move to (100, 100).
|
||||
// The result will depend on the order of these transformations,
|
||||
// and the advantage of matrix is that the sequence of discret calls:
|
||||
// rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
|
||||
// rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
|
||||
// will have exactly the same result as the following matrix transformations:
|
||||
//
|
||||
//
|
||||
// affine_matrix m;
|
||||
// m *= rotate_matrix(30);
|
||||
// m *= rotate_matrix(30);
|
||||
// m *= scaleX_matrix(2.0);
|
||||
// m *= scaleY_matrix(1.5);
|
||||
// m *= move_matrix(100,100);
|
||||
@@ -64,7 +64,7 @@ namespace agg
|
||||
// m.transform_my_point_at_last(x, y);
|
||||
//
|
||||
// What is the good of it? In real life we will set-up the matrix only once
|
||||
// and then transform many points, let alone the convenience to set any
|
||||
// and then transform many points, let alone the convenience to set any
|
||||
// combination of transformations.
|
||||
//
|
||||
// So, how to use it? Very easy - literally as it's shown above. Not quite,
|
||||
@@ -77,71 +77,87 @@ namespace agg
|
||||
// m.transform(&x, &y);
|
||||
//
|
||||
// The affine matrix is all you need to perform any linear transformation,
|
||||
// but all transformations have origin point (0,0). It means that we need to
|
||||
// but all transformations have origin point (0,0). It means that we need to
|
||||
// use 2 translations if we want to rotate someting around (100,100):
|
||||
//
|
||||
//
|
||||
// m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0)
|
||||
// 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)
|
||||
//----------------------------------------------------------------------
|
||||
class trans_affine
|
||||
struct trans_affine
|
||||
{
|
||||
public:
|
||||
double sx, shy, shx, sy, tx, ty;
|
||||
|
||||
//------------------------------------------ Construction
|
||||
// Construct an identity matrix - it does not transform anything
|
||||
// Identity matrix
|
||||
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
|
||||
trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) :
|
||||
m0(v0), m1(v1), m2(v2), m3(v3), m4(v4), m5(v5)
|
||||
// Custom matrix. Usually used in derived classes
|
||||
trans_affine(double v0, double v1, double v2,
|
||||
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.
|
||||
trans_affine(const double* rect, const double* parl)
|
||||
{
|
||||
parl_to_parl(rect, parl);
|
||||
}
|
||||
// Custom matrix from m[6]
|
||||
explicit trans_affine(const double* m) :
|
||||
sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5])
|
||||
{}
|
||||
|
||||
// Construct a matrix to transform a rectangle to a parallelogram.
|
||||
trans_affine(double x1, double y1, double x2, double y2,
|
||||
// Rectangle to a parallelogram.
|
||||
trans_affine(double x1, double y1, double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
rect_to_parl(x1, y1, x2, y2, parl);
|
||||
}
|
||||
|
||||
// Construct a matrix to transform a parallelogram to a rectangle.
|
||||
trans_affine(const double* parl,
|
||||
// Parallelogram to a rectangle.
|
||||
trans_affine(const double* parl,
|
||||
double x1, double y1, double x2, double 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
|
||||
// Calculate a matrix to transform a parallelogram to another one.
|
||||
// src and dst are pointers to arrays of three points
|
||||
// (double[6], x,y,...) that identify three corners of the
|
||||
// parallelograms assuming implicit fourth points.
|
||||
// There are also transformations rectangtle to parallelogram and
|
||||
// parellelogram to rectangle
|
||||
const trans_affine& parl_to_parl(const double* src,
|
||||
// transform a parallelogram to another one. Src and dst are
|
||||
// pointers to arrays of three points (double[6], x1,y1,...) that
|
||||
// identify three corners of the parallelograms assuming implicit
|
||||
// fourth point. The arguments are arrays of double[6] mapped
|
||||
// to x1,y1, x2,y2, x3,y3 where the coordinates are:
|
||||
// *-----------------*
|
||||
// / (x3,y3)/
|
||||
// / /
|
||||
// /(x1,y1) (x2,y2)/
|
||||
// *-----------------*
|
||||
const trans_affine& parl_to_parl(const double* src,
|
||||
const double* dst);
|
||||
|
||||
const trans_affine& rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const trans_affine& rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl);
|
||||
|
||||
const trans_affine& parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
const trans_affine& parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2);
|
||||
|
||||
|
||||
//------------------------------------------ Operations
|
||||
// Reset - actually load an identity matrix
|
||||
// Reset - load an identity matrix
|
||||
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
|
||||
const trans_affine& multiply(const trans_affine& m);
|
||||
|
||||
@@ -154,8 +170,8 @@ namespace agg
|
||||
// Multiply inverse of "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply_inv(const trans_affine& m);
|
||||
|
||||
// Invert matrix. Do not try to invert degenerate matrices,
|
||||
// there's no check for validity. If you set scale to 0 and
|
||||
// Invert matrix. Do not try to invert degenerate matrices,
|
||||
// there's no check for validity. If you set scale to 0 and
|
||||
// then try to invert matrix, expect unpredictable result.
|
||||
const trans_affine& invert();
|
||||
|
||||
@@ -169,38 +185,38 @@ namespace agg
|
||||
// Store matrix to an array [6] of double
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------- Operators
|
||||
|
||||
// Multiply current matrix to another one
|
||||
|
||||
// Multiply the matrix by another one
|
||||
const trans_affine& operator *= (const trans_affine& 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)
|
||||
{
|
||||
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.
|
||||
trans_affine operator * (const trans_affine& m) const
|
||||
{
|
||||
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.
|
||||
trans_affine operator / (const trans_affine& m) const
|
||||
{
|
||||
@@ -227,86 +243,136 @@ namespace agg
|
||||
}
|
||||
|
||||
//-------------------------------------------- Transformations
|
||||
// Direct transformation x and y
|
||||
// Direct transformation of x and y
|
||||
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;
|
||||
|
||||
// Inverse transformation x and y. It works slower than the
|
||||
// direct transformation, so if the performance is critical
|
||||
// it's better to invert() the matrix and then use transform()
|
||||
// Inverse transformation of x and y. It works slower than the
|
||||
// direct transformation. For massive operations it's better to
|
||||
// invert() the matrix and then use direct transformations.
|
||||
void inverse_transform(double* x, double* y) const;
|
||||
|
||||
//-------------------------------------------- Auxiliary
|
||||
// Calculate the determinant of matrix
|
||||
double determinant() const
|
||||
{
|
||||
return 1.0 / (m0 * m3 - m1 * m2);
|
||||
return sx * sy - shy * shx;
|
||||
}
|
||||
|
||||
// Get the average scale (by X and Y).
|
||||
// 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).
|
||||
// Basically used to calculate the approximation_scale when
|
||||
// decomposinting curves into line segments.
|
||||
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
|
||||
bool is_identity(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if two matrices are equal
|
||||
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;
|
||||
void translation(double* dx, double* dy) const;
|
||||
void scaling(double* sx, double* sy) const;
|
||||
void scaling_abs(double* sx, double* sy) 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;
|
||||
void scaling(double* x, double* y) const;
|
||||
void scaling_abs(double* x, double* y) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform(double* x, double* y) const
|
||||
{
|
||||
double tx = *x;
|
||||
*x = tx * m0 + *y * m2 + m4;
|
||||
*y = tx * m1 + *y * m3 + m5;
|
||||
double tmp = *x;
|
||||
*x = tmp * sx + *y * shx + tx;
|
||||
*y = tmp * shy + *y * sy + ty;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform_2x2(double* x, double* y) const
|
||||
{
|
||||
double tx = *x;
|
||||
*x = tx * m0 + *y * m2;
|
||||
*y = tx * m1 + *y * m3;
|
||||
double tmp = *x;
|
||||
*x = tmp * sx + *y * shx;
|
||||
*y = tmp * shy + *y * sy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::inverse_transform(double* x, double* y) const
|
||||
{
|
||||
double d = determinant();
|
||||
double a = (*x - m4) * d;
|
||||
double b = (*y - m5) * d;
|
||||
*x = a * m3 - b * m2;
|
||||
*y = b * m0 - a * m1;
|
||||
double d = determinant_reciprocal();
|
||||
double a = (*x - tx) * d;
|
||||
double b = (*y - ty) * d;
|
||||
*x = a * sy - b * shx;
|
||||
*y = b * sx - a * shy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline double trans_affine::scale() const
|
||||
{
|
||||
double x = M_SQRT1_2 * m0 + M_SQRT1_2 * m2;
|
||||
double y = M_SQRT1_2 * m1 + M_SQRT1_2 * m3;
|
||||
return sqrt(x*x + y*y);
|
||||
double x = M_SQRT1_2 * sx + M_SQRT1_2 * shx;
|
||||
double y = M_SQRT1_2 * shy + M_SQRT1_2 * sy;
|
||||
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;
|
||||
t.invert();
|
||||
multiply(t);
|
||||
return *this;
|
||||
return multiply(t);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@@ -333,29 +398,39 @@ namespace agg
|
||||
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
|
||||
// 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
|
||||
// modern processors. Besides, this operation is not going to be invoked too
|
||||
// modern processors. Besides, this operation is not going to be invoked too
|
||||
// often.
|
||||
class trans_affine_rotation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_rotation(double a) :
|
||||
trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
|
||||
trans_affine_rotation(double a) :
|
||||
trans_affine(std::cos(a), std::sin(a), -std::sin(a), std::cos(a), 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================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
|
||||
{
|
||||
public:
|
||||
trans_affine_scaling(double sx, double sy) :
|
||||
trans_affine(sx, 0.0, 0.0, sy, 0.0, 0.0)
|
||||
trans_affine_scaling(double x, double y) :
|
||||
trans_affine(x, 0.0, 0.0, y, 0.0, 0.0)
|
||||
{}
|
||||
|
||||
trans_affine_scaling(double s) :
|
||||
trans_affine_scaling(double s) :
|
||||
trans_affine(s, 0.0, 0.0, s, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
@@ -365,8 +440,8 @@ namespace agg
|
||||
class trans_affine_translation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_translation(double tx, double ty) :
|
||||
trans_affine(1.0, 0.0, 0.0, 1.0, tx, ty)
|
||||
trans_affine_translation(double x, double y) :
|
||||
trans_affine(1.0, 0.0, 0.0, 1.0, x, y)
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -375,33 +450,67 @@ namespace agg
|
||||
class trans_affine_skewing : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_skewing(double sx, double sy) :
|
||||
trans_affine(1.0, tan(sy), tan(sx), 1.0, 0.0, 0.0)
|
||||
trans_affine_skewing(double x, double y) :
|
||||
trans_affine(1.0, std::tan(y), std::tan(x), 1.0, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//===============================================trans_affine_line_segment
|
||||
// Rotate, Scale and Translate, associating 0...dist with line segment
|
||||
// Rotate, Scale and Translate, associating 0...dist with line segment
|
||||
// x1,y1,x2,y2
|
||||
class trans_affine_line_segment : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_line_segment(double x1, double y1, double x2, double y2,
|
||||
trans_affine_line_segment(double x1, double y1, double x2, double y2,
|
||||
double dist)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//============================================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
|
||||
#define AGG_TRANS_PERSPECTIVE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_simul_eq.h"
|
||||
#include <cmath>
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//=======================================================trans_perspective
|
||||
class trans_perspective
|
||||
struct trans_perspective
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
trans_perspective() : m_valid(false) {}
|
||||
double sx, shy, w0, shx, sy, w1, tx, ty, w2;
|
||||
|
||||
//------------------------------------------------------- Construction
|
||||
// Identity matrix
|
||||
trans_perspective() :
|
||||
sx (1), shy(0), w0(0),
|
||||
shx(0), sy (1), w1(0),
|
||||
tx (0), ty (0), w2(1) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Arbitrary quadrangle transformations
|
||||
trans_perspective(const double* src, const double* dst)
|
||||
{
|
||||
quad_to_quad(src, dst);
|
||||
}
|
||||
// Custom matrix
|
||||
trans_perspective(double v0, double v1, double v2,
|
||||
double v3, double v4, double v5,
|
||||
double v6, double v7, double v8) :
|
||||
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]) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Direct transformations
|
||||
// From affine
|
||||
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,
|
||||
const double* quad)
|
||||
{
|
||||
rect_to_quad(x1, y1, x2, y2, quad);
|
||||
}
|
||||
const double* quad);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Reverse transformations
|
||||
// Quadrilateral to rectangle
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Set the transformations using two arbitrary quadrangles.
|
||||
void quad_to_quad(const double* src, const double* dst)
|
||||
// Multiply the matrix by inverse of another one
|
||||
const trans_perspective& operator /= (const trans_perspective& m)
|
||||
{
|
||||
|
||||
double left[8][8];
|
||||
double right[8][1];
|
||||
|
||||
unsigned i;
|
||||
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);
|
||||
return multiply_inv(m);
|
||||
}
|
||||
const trans_perspective& operator /= (const trans_affine& m)
|
||||
{
|
||||
return multiply_inv(m);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Set the direct transformations, i.e., rectangle -> quadrangle
|
||||
void rect_to_quad(double x1, double y1, double x2, double y2,
|
||||
const double* quad)
|
||||
// Multiply the matrix by another one and return
|
||||
// the result in a separete matrix.
|
||||
trans_perspective operator * (const trans_perspective& m) const
|
||||
{
|
||||
double src[8];
|
||||
src[0] = src[6] = x1;
|
||||
src[2] = src[4] = x2;
|
||||
src[1] = src[3] = y1;
|
||||
src[5] = src[7] = y2;
|
||||
quad_to_quad(src, quad);
|
||||
return trans_perspective(*this).multiply(m);
|
||||
}
|
||||
trans_perspective operator * (const trans_affine& m) const
|
||||
{
|
||||
return trans_perspective(*this).multiply(m);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Set the reverse transformations, i.e., quadrangle -> rectangle
|
||||
void quad_to_rect(const double* quad,
|
||||
double x1, double y1, double x2, double y2)
|
||||
// Multiply the matrix by inverse of another one
|
||||
// and return the result in a separete matrix.
|
||||
trans_perspective operator / (const trans_perspective& m) const
|
||||
{
|
||||
double dst[8];
|
||||
dst[0] = dst[6] = x1;
|
||||
dst[2] = dst[4] = x2;
|
||||
dst[1] = dst[3] = y1;
|
||||
dst[5] = dst[7] = y2;
|
||||
quad_to_quad(quad, dst);
|
||||
return trans_perspective(*this).multiply_inv(m);
|
||||
}
|
||||
trans_perspective operator / (const trans_affine& m) const
|
||||
{
|
||||
return trans_perspective(*this).multiply_inv(m);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Check if the equations were solved successfully
|
||||
bool is_valid() const { return m_valid; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Transform a point (x, y)
|
||||
void transform(double* x, double* y) const
|
||||
// Calculate and return the inverse matrix
|
||||
trans_perspective operator ~ () const
|
||||
{
|
||||
double tx = *x;
|
||||
double ty = *y;
|
||||
double d = 1.0 / (m_mtx[6][0] * tx + m_mtx[7][0] * ty + 1.0);
|
||||
*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;
|
||||
trans_perspective ret = *this;
|
||||
ret.invert();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
@@ -153,17 +241,16 @@ namespace agg
|
||||
double y;
|
||||
|
||||
iterator_x() {}
|
||||
iterator_x(double tx, double ty, double step, const double m[8][1]) :
|
||||
den(m[6][0] * tx + m[7][0] * ty + 1.0),
|
||||
den_step(m[6][0] * step),
|
||||
nom_x(m[0][0] + m[1][0] * tx + m[2][0] * ty),
|
||||
nom_x_step(m[1][0] * step),
|
||||
nom_y(m[3][0] + m[4][0] * tx + m[5][0] * ty),
|
||||
nom_y_step(m[4][0] * step),
|
||||
iterator_x(double px, double py, double step, const trans_perspective& m) :
|
||||
den(px * m.w0 + py * m.w1 + m.w2),
|
||||
den_step(m.w0 * step),
|
||||
nom_x(px * m.sx + py * m.shx + m.tx),
|
||||
nom_x_step(step * m.sx),
|
||||
nom_y(px * m.shy + py * m.sy + m.ty),
|
||||
nom_y_step(step * m.shy),
|
||||
x(nom_x / den),
|
||||
y(nom_y / den)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void operator ++ ()
|
||||
{
|
||||
@@ -179,14 +266,467 @@ namespace agg
|
||||
//--------------------------------------------------------------------
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user