Transformation matrix

This commit is contained in:
Jay Berkenbilt 2018-12-24 16:28:08 -05:00
parent 3440ea7d3c
commit daeb5a85b6
5 changed files with 190 additions and 0 deletions

90
libqpdf/QPDFMatrix.cc Normal file
View File

@ -0,0 +1,90 @@
#include <qpdf/QPDFMatrix.hh>
#include <qpdf/QUtil.hh>
QPDFMatrix::QPDFMatrix() :
a(1.0),
b(0.0),
c(0.0),
d(1.0),
e(0.0),
f(0.0)
{
}
QPDFMatrix::QPDFMatrix(double a, double b, double c,
double d, double e, double f) :
a(a),
b(b),
c(c),
d(d),
e(e),
f(f)
{
}
std::string
QPDFMatrix::unparse() const
{
return (QUtil::double_to_string(a, 5) + " " +
QUtil::double_to_string(b, 5) + " " +
QUtil::double_to_string(c, 5) + " " +
QUtil::double_to_string(d, 5) + " " +
QUtil::double_to_string(e, 5) + " " +
QUtil::double_to_string(f, 5));
}
void
QPDFMatrix::concat(QPDFMatrix const& other)
{
double ap = (this->a * other.a) + (this->c * other.b);
double bp = (this->b * other.a) + (this->d * other.b);
double cp = (this->a * other.c) + (this->c * other.d);
double dp = (this->b * other.c) + (this->d * other.d);
double ep = (this->a * other.e) + (this->c * other.f) + this->e;
double fp = (this->b * other.e) + (this->d * other.f) + this->f;
this-> a = ap;
this-> b = bp;
this-> c = cp;
this-> d = dp;
this-> e = ep;
this-> f = fp;
}
void
QPDFMatrix::scale(double sx, double sy)
{
concat(QPDFMatrix(sx, 0, 0, sy, 0, 0));
}
void
QPDFMatrix::translate(double tx, double ty)
{
concat(QPDFMatrix(1, 0, 0, 1, tx, ty));
}
void
QPDFMatrix::rotatex90(int angle)
{
switch (angle)
{
case 90:
concat(QPDFMatrix(0, 1, -1, 0, 0, 0));
break;
case 180:
concat(QPDFMatrix(-1, 0, 0, -1, 0, 0));
break;
case 270:
concat(QPDFMatrix(0, -1, 1, 0, 0, 0));
break;
default:
// ignore
break;
}
}
void
QPDFMatrix::transform(double x, double y, double& xp, double& yp)
{
xp = (this->a * x) + (this->c * y) + this->e;
yp = (this->b * x) + (this->d * y) + this->f;
}

View File

@ -41,6 +41,7 @@ SRCS_libqpdf = \
libqpdf/QPDFAnnotationObjectHelper.cc \
libqpdf/QPDFExc.cc \
libqpdf/QPDFFormFieldObjectHelper.cc \
libqpdf/QPDFMatrix.cc \
libqpdf/QPDFNameTreeObjectHelper.cc \
libqpdf/QPDFNumberTreeObjectHelper.cc \
libqpdf/QPDFObjGen.cc \

View File

@ -0,0 +1,43 @@
#ifndef QPDFMATRIX_HH
#define QPDFMATRIX_HH
#include <qpdf/DLL.h>
#include <string>
class QPDFMatrix
{
public:
QPDF_DLL
QPDFMatrix();
QPDF_DLL
QPDFMatrix(double a, double b, double c,
double d, double e, double f);
QPDF_DLL
std::string unparse() const;
// This is not part of the public API. Just provide the methods we
// need as we need them.
QPDF_DLL
void concat(QPDFMatrix const& other);
QPDF_DLL
void scale(double sx, double sy);
QPDF_DLL
void translate(double tx, double ty);
// Any value other than 90, 180, or 270 is ignored
QPDF_DLL
void rotatex90(int angle);
QPDF_DLL
void transform(double x, double y, double& xp, double& yp);
private:
double a;
double b;
double c;
double d;
double e;
double f;
};
#endif // QPDFMATRIX_HH

View File

@ -12,6 +12,7 @@ BINS_libtests = \
input_source \
json \
lzw \
matrix \
md5 \
numrange \
pointer_holder \

55
libtests/matrix.cc Normal file
View File

@ -0,0 +1,55 @@
#include <qpdf/QPDFMatrix.hh>
#include <qpdf/QUtil.hh>
#include <assert.h>
#include <iostream>
static void check(QPDFMatrix const& m, std::string const& exp)
{
std::string u = m.unparse();
if (u != exp)
{
std::cout << "got " << u << ", wanted " << exp << std::endl;
}
}
static void check_xy(double x, double y, std::string const& exp)
{
std::string u = (QUtil::double_to_string(x, 2) + " " +
QUtil::double_to_string(y, 2));
if (u != exp)
{
std::cout << "got " << u << ", wanted " << exp << std::endl;
}
}
int main()
{
QPDFMatrix m;
check(m, "1.00000 0.00000 0.00000 1.00000 0.00000 0.00000");
m.translate(10, 20);
check(m, "1.00000 0.00000 0.00000 1.00000 10.00000 20.00000");
m.scale(1.5, 2);
check(m, "1.50000 0.00000 0.00000 2.00000 10.00000 20.00000");
m.translate(30, 40);
check(m, "1.50000 0.00000 0.00000 2.00000 55.00000 100.00000");
m.concat(QPDFMatrix(1, 2, 3, 4, 5, 6));
check(m, "1.50000 4.00000 4.50000 8.00000 62.50000 112.00000");
m.rotatex90(90);
check(m, "4.50000 8.00000 -1.50000 -4.00000 62.50000 112.00000");
m.rotatex90(180);
check(m, "-4.50000 -8.00000 1.50000 4.00000 62.50000 112.00000");
m.rotatex90(270);
check(m, "-1.50000 -4.00000 -4.50000 -8.00000 62.50000 112.00000");
m.rotatex90(180);
check(m, "1.50000 4.00000 4.50000 8.00000 62.50000 112.00000");
m.rotatex90(12345);
check(m, "1.50000 4.00000 4.50000 8.00000 62.50000 112.00000");
double xp = 0;
double yp = 0;
m.transform(240, 480, xp, yp);
check_xy(xp, yp, "2582.50 4912.00");
std::cout << "matrix tests done" << std::endl;
return 0;
}