Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/agg/agg_trans_affine.h')
-rw-r--r--src/agg/agg_trans_affine.h518
1 files changed, 518 insertions, 0 deletions
diff --git a/src/agg/agg_trans_affine.h b/src/agg/agg_trans_affine.h
new file mode 100644
index 000000000..1a6116388
--- /dev/null
+++ b/src/agg/agg_trans_affine.h
@@ -0,0 +1,518 @@
+//----------------------------------------------------------------------------
+// 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 <math.h>
+#include "agg_basics.h"
+
+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 trans_affine
+ {
+ 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 separete 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 separete 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 = cos(a);
+ double sa = 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. 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
+ // 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_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, tan(y), 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(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(cos(a), 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
+