Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
svg-affine.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * SVG data parser
4 *
5 * Authors:
6 * Lauris Kaplinski <lauris@kaplinski.com>
7 * Raph Levien <raph@acm.org>
8 *
9 * Copyright (C) 1999-2002 Lauris Kaplinski
10 * Copyright (C) 1999 Raph Levien
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include <cstring>
16#include <string>
17#include <cstdlib>
18#include <cstdio>
19#include <glib.h>
20#include <2geom/transforms.h>
21#include "svg.h"
22#include "preferences.h"
23
24std::string
26{
28
29 // this must be a bit grater than EPSILON
30 double e = 1e-5 * transform.descrim();
31 int prec = prefs->getInt("/options/svgoutput/numericprecision", 8);
32 int min_exp = prefs->getInt("/options/svgoutput/minimumexponent", -8);
33
34 // Special case: when all fields of the affine are zero,
35 // the optimized transformation is scale(0)
36 if (transform[0] == 0 && transform[1] == 0 && transform[2] == 0 &&
37 transform[3] == 0 && transform[4] == 0 && transform[5] == 0)
38 {
39 return "scale(0)";
40 }
41
42
43 std::stringstream c(""); // string buffer
44
45 if (transform.isIdentity()) {
46 // We are more or less identity, so no transform attribute needed:
47 return {};
48 } else if (transform.isScale()) {
49 // We are more or less a uniform scale
50 c << "scale(";
51 c << sp_svg_number_write_de(transform[0], prec, min_exp);
52 if (Geom::are_near(transform[0], transform[3], e)) {
53 c << ")";
54 } else {
55 c << ",";
56 c << sp_svg_number_write_de(transform[3], prec, min_exp);
57 c << ")";
58 }
59 } else if (transform.isTranslation()) {
60 // We are more or less a pure translation
61 c << "translate(";
62 c << sp_svg_number_write_de(transform[4], prec, min_exp);
63 if (Geom::are_near(transform[5], 0.0, e)) {
64 c << ")";
65 } else {
66 c << ",";
67 c << sp_svg_number_write_de(transform[5], prec, min_exp);
68 c << ")";
69 }
70 } else if (transform.isRotation()) {
71 // We are more or less a pure rotation
72 c << "rotate(";
73 double angle = std::atan2(transform[1], transform[0]) * (180 / M_PI);
74 c << sp_svg_number_write_de(angle, prec, min_exp);
75 c << ")";
76 } else if (transform.withoutTranslation().isRotation()) {
77 // Solution found by Johan Engelen
78 // Refer to the matrix in svg-affine-test.h
79
80 // We are a rotation about a special axis
81 c << "rotate(";
82 double angle = std::atan2(transform[1], transform[0]) * (180 / M_PI);
83 c << sp_svg_number_write_de(angle, prec, min_exp);
84 c << ",";
85
86 Geom::Affine const& m = transform;
87 double tx = (m[2]*m[5]+m[4]-m[4]*m[3]) / (1-m[3]-m[0]+m[0]*m[3]-m[2]*m[1]);
88
89 c << sp_svg_number_write_de(tx, prec, min_exp);
90 c << ",";
91
92 double ty = (m[1]*tx + m[5]) / (1 - m[3]);
93 c << sp_svg_number_write_de(ty, prec, min_exp);
94 c << ")";
95 } else if (transform.isHShear()) {
96 // We are more or less a pure skewX
97 c << "skewX(";
98 double angle = atan(transform[2]) * (180 / M_PI);
99 c << sp_svg_number_write_de(angle, prec, min_exp);
100 c << ")";
101 } else if (transform.isVShear()) {
102 // We are more or less a pure skewY
103 c << "skewY(";
104 double angle = atan(transform[1]) * (180 / M_PI);
105
106 c << sp_svg_number_write_de(angle, prec, min_exp);
107 c << ")";
108 } else {
109 c << "matrix(";
110 c << sp_svg_number_write_de(transform[0], prec, min_exp);
111 c << ",";
112 c << sp_svg_number_write_de(transform[1], prec, min_exp);
113 c << ",";
114 c << sp_svg_number_write_de(transform[2], prec, min_exp);
115 c << ",";
116 c << sp_svg_number_write_de(transform[3], prec, min_exp);
117 c << ",";
118 c << sp_svg_number_write_de(transform[4], prec, min_exp);
119 c << ",";
120 c << sp_svg_number_write_de(transform[5], prec, min_exp);
121 c << ")";
122 }
123
124 assert(c.str().length() <= 256);
125 return c.str();
126
127}
128
129/*
130 Local Variables:
131 mode:c++
132 c-file-style:"stroustrup"
133 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
134 indent-tabs-mode:nil
135 fill-column:99
136 End:
137*/
138// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
3x3 matrix representing an affine transformation.
Definition affine.h:70
bool isHShear(Coord eps=EPSILON) const
Check whether this matrix represents pure horizontal shearing.
Definition affine.cpp:256
Coord descrim() const
Calculate the descriminant.
Definition affine.cpp:434
bool isScale(Coord eps=EPSILON) const
Check whether this matrix represents pure scaling.
Definition affine.cpp:147
bool isVShear(Coord eps=EPSILON) const
Check whether this matrix represents pure vertical shearing.
Definition affine.cpp:281
bool isIdentity(Coord eps=EPSILON) const
Check whether this matrix is an identity matrix.
Definition affine.cpp:109
bool isTranslation(Coord eps=EPSILON) const
Check whether this matrix represents a pure translation.
Definition affine.cpp:123
Affine withoutTranslation() const
Definition affine.h:169
bool isRotation(Coord eps=EPSILON) const
Check whether this matrix represents a pure rotation.
Definition affine.cpp:206
Preference storage class.
Definition preferences.h:66
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
double c[8][4]
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Singleton class to access the preferences file in a convenient way.
std::string sp_svg_transform_write(Geom::Affine const &transform)
std::string sp_svg_number_write_de(double val, unsigned int tprec, int min_exp)
Affine transformation classes.