summaryrefslogtreecommitdiffstats
path: root/src/svg/svg-affine.cpp
blob: 336eecaedaba5d025f27a0336409b98875d0f770 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * SVG data parser
 *
 * Authors:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *   Raph Levien <raph@acm.org>
 *
 * Copyright (C) 1999-2002 Lauris Kaplinski
 * Copyright (C) 1999 Raph Levien
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <glib.h>
#include <2geom/transforms.h>
#include "svg.h"
#include "preferences.h"

std::string
sp_svg_transform_write(Geom::Affine const &transform)
{
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();

    // this must be a bit grater than EPSILON
    double e = 1e-5 * transform.descrim();
    int prec = prefs->getInt("/options/svgoutput/numericprecision", 8);
    int min_exp = prefs->getInt("/options/svgoutput/minimumexponent", -8);

    // Special case: when all fields of the affine are zero,
    // the optimized transformation is scale(0)
    if (transform[0] == 0 && transform[1] == 0 && transform[2] == 0 &&
        transform[3] == 0 && transform[4] == 0 && transform[5] == 0)
    {
        return "scale(0)";
    }


    std::stringstream c(""); // string buffer

    if (transform.isIdentity()) {
        // We are more or less identity, so no transform attribute needed:
        return {};
    } else if (transform.isScale()) {
        // We are more or less a uniform scale
        c << "scale(";
        c << sp_svg_number_write_de(transform[0], prec, min_exp);
        if (Geom::are_near(transform[0], transform[3], e)) {
            c << ")";
        } else {
            c << ",";
            c << sp_svg_number_write_de(transform[3], prec, min_exp);
            c << ")";
        }
    } else if (transform.isTranslation()) {
        // We are more or less a pure translation
        c  << "translate(";
        c << sp_svg_number_write_de(transform[4], prec, min_exp);
        if (Geom::are_near(transform[5], 0.0, e)) {
            c << ")";
        } else {
            c << ",";
            c << sp_svg_number_write_de(transform[5], prec, min_exp);
            c << ")";
        }
    } else if (transform.isRotation()) {
        // We are more or less a pure rotation
        c << "rotate(";
        double angle = std::atan2(transform[1], transform[0]) * (180 / M_PI);
        c << sp_svg_number_write_de(angle, prec, min_exp);
        c << ")";
    } else if (transform.withoutTranslation().isRotation()) {
        // Solution found by Johan Engelen
        // Refer to the matrix in svg-affine-test.h

        // We are a rotation about a special axis
        c << "rotate(";
        double angle = std::atan2(transform[1], transform[0]) * (180 / M_PI);
        c << sp_svg_number_write_de(angle, prec, min_exp);
        c << ",";

        Geom::Affine const& m = transform;
        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]);

        c << sp_svg_number_write_de(tx, prec, min_exp);
        c << ",";

        double ty = (m[1]*tx + m[5]) / (1 - m[3]);
        c << sp_svg_number_write_de(ty, prec, min_exp);
        c << ")";
    } else if (transform.isHShear()) {
        // We are more or less a pure skewX
        c << "skewX(";
        double angle = atan(transform[2]) * (180 / M_PI);
        c << sp_svg_number_write_de(angle, prec, min_exp);
        c << ")";
    } else if (transform.isVShear()) {
        // We are more or less a pure skewY
        c << "skewY(";
        double angle = atan(transform[1]) * (180 / M_PI);

        c << sp_svg_number_write_de(angle, prec, min_exp);
        c << ")";
    } else {
        c << "matrix(";
        c << sp_svg_number_write_de(transform[0], prec, min_exp);
        c << ",";
        c << sp_svg_number_write_de(transform[1], prec, min_exp);
        c << ",";
        c << sp_svg_number_write_de(transform[2], prec, min_exp);
        c << ",";
        c << sp_svg_number_write_de(transform[3], prec, min_exp);
        c << ",";
        c << sp_svg_number_write_de(transform[4], prec, min_exp);
        c << ",";
        c << sp_svg_number_write_de(transform[5], prec, min_exp);
        c << ")";
    }

    assert(c.str().length() <= 256);
    return c.str();

}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :