519 lines
18 KiB
C++
519 lines
18 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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.
|
|
// This software is provided "as is" without express or implied
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// Contact: mcseem@antigrain.com
|
|
// mcseemagg@yahoo.com
|
|
// http://www.antigrain.com
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Affine transformation classes.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
|
#define AGG_TRANS_AFFINE_INCLUDED
|
|
|
|
#include <cmath>
|
|
#include "agg_basics.h"
|
|
#include <mapnik/config.hpp>
|
|
|
|
namespace agg
|
|
{
|
|
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.
|
|
//
|
|
// 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
|
|
// 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:
|
|
// * 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,
|
|
// and the advantage of matrix is that the sequence of discret calls:
|
|
// 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 *= scaleX_matrix(2.0);
|
|
// m *= scaleY_matrix(1.5);
|
|
// m *= move_matrix(100,100);
|
|
//
|
|
// 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
|
|
// combination of transformations.
|
|
//
|
|
// So, how to use it? Very easy - literally as it's shown above. Not quite,
|
|
// let us write a correct example:
|
|
//
|
|
// agg::trans_affine m;
|
|
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);
|
|
// m *= agg::trans_affine_scaling(2.0, 1.5);
|
|
// m *= agg::trans_affine_translation(100.0, 100.0);
|
|
// 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
|
|
// 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)
|
|
//----------------------------------------------------------------------
|
|
struct MAPNIK_DECL trans_affine
|
|
{
|
|
static const trans_affine identity;
|
|
double sx, shy, shx, sy, tx, ty;
|
|
|
|
//------------------------------------------ Construction
|
|
// Identity matrix
|
|
trans_affine() :
|
|
sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0)
|
|
{}
|
|
|
|
// 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)
|
|
{}
|
|
|
|
// 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])
|
|
{}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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
|
|
// 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 double* parl);
|
|
|
|
const trans_affine& parl_to_rect(const double* parl,
|
|
double x1, double y1,
|
|
double x2, double y2);
|
|
|
|
|
|
//------------------------------------------ Operations
|
|
// 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);
|
|
|
|
// Multiply "m" to "this" and assign the result to "this"
|
|
const trans_affine& premultiply(const trans_affine& m);
|
|
|
|
// Multiply matrix to inverse of another one
|
|
const trans_affine& multiply_inv(const trans_affine& m);
|
|
|
|
// 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
|
|
// then try to invert matrix, expect unpredictable result.
|
|
const trans_affine& invert();
|
|
|
|
// Mirroring around X
|
|
const trans_affine& flip_x();
|
|
|
|
// Mirroring around Y
|
|
const trans_affine& flip_y();
|
|
|
|
//------------------------------------------- Load/Store
|
|
// Store matrix to an array [6] of double
|
|
void store_to(double* m) const
|
|
{
|
|
*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)
|
|
{
|
|
sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++;
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------- Operators
|
|
|
|
// Multiply the matrix by another one
|
|
const trans_affine& operator *= (const trans_affine& m)
|
|
{
|
|
return multiply(m);
|
|
}
|
|
|
|
// Multiply the matrix by inverse of another one
|
|
const trans_affine& operator /= (const trans_affine& m)
|
|
{
|
|
return multiply_inv(m);
|
|
}
|
|
|
|
// Multiply the matrix by another one and return
|
|
// the result in a separate matrix.
|
|
trans_affine operator * (const trans_affine& m) const
|
|
{
|
|
return trans_affine(*this).multiply(m);
|
|
}
|
|
|
|
// Multiply the matrix by inverse of another one
|
|
// and return the result in a separate matrix.
|
|
trans_affine operator / (const trans_affine& m) const
|
|
{
|
|
return trans_affine(*this).multiply_inv(m);
|
|
}
|
|
|
|
// Calculate and return the inverse matrix
|
|
trans_affine operator ~ () const
|
|
{
|
|
trans_affine ret = *this;
|
|
return ret.invert();
|
|
}
|
|
|
|
// Equal operator with default epsilon
|
|
bool operator == (const trans_affine& m) const
|
|
{
|
|
return is_equal(m, affine_epsilon);
|
|
}
|
|
|
|
// Not Equal operator with default epsilon
|
|
bool operator != (const trans_affine& 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, 2x2 matrix only, no translation
|
|
void transform_2x2(double* x, double* y) const;
|
|
|
|
// 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 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).
|
|
// 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 with caution considering
|
|
// possible degenerate cases.
|
|
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;
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
inline void trans_affine::transform(double* x, double* y) const
|
|
{
|
|
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 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_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 = 0.707106781 * sx + 0.707106781 * shx;
|
|
double y = 0.707106781 * shy + 0.707106781 * sy;
|
|
return 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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline const trans_affine& trans_affine::premultiply(const trans_affine& m)
|
|
{
|
|
trans_affine t = m;
|
|
return *this = t.multiply(*this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m)
|
|
{
|
|
trans_affine t = m;
|
|
t.invert();
|
|
return multiply(t);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m)
|
|
{
|
|
trans_affine t = m;
|
|
t.invert();
|
|
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 = sqrt(sx * sx + shx * shx);
|
|
*y = sqrt(shy * shy + sy * sy);
|
|
}
|
|
|
|
//====================================================trans_affine_rotation
|
|
// Rotation matrix. std::sin() and std::cos() are calculated twice for the same angle.
|
|
// There's no harm because the performance of std::sin()/cos() is very good on all
|
|
// 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(std::cos(a), std::sin(a), -std::sin(a), std::cos(a), 0.0, 0.0)
|
|
{}
|
|
};
|
|
|
|
//====================================================trans_affine_scaling
|
|
// Scaling matrix. x, y - scale coefficients by X and Y respectively
|
|
class trans_affine_scaling : public trans_affine
|
|
{
|
|
public:
|
|
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(s, 0.0, 0.0, s, 0.0, 0.0)
|
|
{}
|
|
};
|
|
|
|
//================================================trans_affine_translation
|
|
// Translation matrix
|
|
class trans_affine_translation : public trans_affine
|
|
{
|
|
public:
|
|
trans_affine_translation(double x, double y) :
|
|
trans_affine(1.0, 0.0, 0.0, 1.0, x, y)
|
|
{}
|
|
};
|
|
|
|
//====================================================trans_affine_skewing
|
|
// Sckewing (shear) matrix
|
|
class trans_affine_skewing : public trans_affine
|
|
{
|
|
public:
|
|
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
|
|
// 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,
|
|
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_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 / sqrt(x * x + y * y), y / sqrt(x * x + y * y))
|
|
{}
|
|
};
|
|
|
|
}
|
|
|
|
|
|
#endif
|