Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgTransformParser.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QtGlobal>
10
11//#include "kis_debug.h"
12
13#include <boost/config/warning_disable.hpp>
14#include <boost/phoenix/fusion.hpp>
15#include <boost/phoenix/operator.hpp>
16#include <boost/phoenix/stl.hpp>
17#include <boost/spirit/include/qi.hpp>
18
19namespace Private
20{
21
22struct matrix
23{
24 qreal a = 0;
25 qreal b = 0;
26 qreal c = 0;
27 qreal d = 0;
28 qreal e = 0;
29 qreal f = 0;
30};
31
33{
34 qreal tx = 0.0;
35 qreal ty = 0.0;
36};
37
38struct scale
39{
40 qreal sx = 0;
41 qreal sy = 0;
42 bool syPresent = false;
43};
44
45struct rotate
46{
47 qreal angle = 0;
48 qreal cx = 0;
49 qreal cy = 0;
50};
51
52struct skewX
53{
54 qreal angle = 0;
55};
56
57struct skewY
58{
59 qreal angle = 0;
60};
61
63{
65
67 : transform(QTransform(m.a, m.b, m.c, m.d, m.e, m.f))
68 {
69 }
70
72 : transform(QTransform::fromTranslate(t.tx, t.ty))
73 {
74 }
75
77 : transform(QTransform::fromScale(sc.sx, sc.syPresent ? sc.sy : sc.sx))
78 {
79 }
80
82 transform.rotate(r.angle);
83 if (r.cx != 0.0 || r.cy != 0.0) {
84 transform =
85 QTransform::fromTranslate(-r.cx, -r.cy) *
86 transform *
87 QTransform::fromTranslate(r.cx, r.cy);
88 }
89 }
90
91 transform_unit(const skewX &sx) {
92 const qreal deg2rad = qreal(0.017453292519943295769);
93 const qreal value = tan(deg2rad * sx.angle);
94 transform.shear(value, 0);
95 }
96
97 transform_unit(const skewY &sy) {
98 const qreal deg2rad = qreal(0.017453292519943295769);
99 const qreal value = tan(deg2rad * sy.angle);
100 transform.shear(0, value);
101 }
102
103 QTransform transform;
104};
105}
106
107// We need to tell fusion about our transform_unit struct
108// to make it a first-class fusion citizen. This has to
109// be in global scope.
110
113 (qreal, a)
114 (qreal, b)
115 (qreal, c)
116 (qreal, d)
117 (qreal, e)
118 (qreal, f)
119 )
120
123 (qreal, tx)
124 (qreal, ty)
125 )
126
129 (qreal, sx)
130 (qreal, sy)
131 (bool, syPresent)
132 )
133
136 (qreal, angle)
137 (qreal, cx)
138 (qreal, cy)
139 )
140
143 (qreal, angle)
144 )
145
148 (qreal, angle)
149 )
150
151#define BOOST_SPIRIT_DEBUG 1
152
153namespace Private
154{
155 // Define our grammar
156
157 namespace qi = boost::spirit::qi;
158 namespace ascii = boost::spirit::ascii;
159
160 template <typename Iterator>
161 struct transform_unit_parser : qi::grammar<Iterator, std::vector<transform_unit>(), ascii::space_type>
162 {
163 transform_unit_parser() : transform_unit_parser::base_type(start)
164 {
165 namespace phoenix = boost::phoenix;
166 using qi::lit;
167 using qi::double_;
168 using ascii::char_;
169 using qi::cntrl;
170 using phoenix::at_c;
171 using phoenix::push_back;
172 using namespace qi::labels;
173
174
175 comma %= -char_(',');
176
177 matrix_rule %=
178 lit("matrix")
179 >> '('
180 >> double_ >> comma
181 >> double_ >> comma
182 >> double_ >> comma
183 >> double_ >> comma
184 >> double_ >> comma
185 >> double_ >> comma
186 >> ')';
187
188 translate_rule %=
189 lit("translate")
190 >> '(' >> double_ >> comma >> -double_ >> ')';
191
192 scale_rule %=
193 lit("scale")
194 >> '('
195 >> double_ >> comma
196 >> -double_ [at_c<2>(_val) = true]
197 >> ')';
198
199
200 // due to braces "-(...)" we cannot use automated
201 // semantic actions without relayouting the structure
202 rotate_rule =
203 lit("rotate")
204 >> '('
205 >> double_ [at_c<0>(_val) = _1]
206 >> comma
207 >> -(double_ [at_c<1>(_val) = _1]
208 >> comma
209 >> double_ [at_c<2>(_val) = _1])
210 >> ')';
211
212 skewX_rule %= lit("skewX") >> '(' >> double_ >> ')';
213 skewY_rule %= lit("skewY") >> '(' >> double_ >> ')';
214
215 start %=
216 (matrix_rule | translate_rule | scale_rule |
217 rotate_rule | skewX_rule | skewY_rule) %
218 (cntrl | comma);
219 }
220
221 qi::rule<Iterator, std::vector<transform_unit>(), ascii::space_type> start;
222 qi::rule<Iterator, translate(), ascii::space_type> translate_rule;
223 qi::rule<Iterator, matrix(), ascii::space_type> matrix_rule;
224 qi::rule<Iterator, scale(), ascii::space_type> scale_rule;
225 qi::rule<Iterator, rotate(), ascii::space_type> rotate_rule;
226 qi::rule<Iterator, skewX(), ascii::space_type> skewX_rule;
227 qi::rule<Iterator, skewY(), ascii::space_type> skewY_rule;
228 qi::rule<Iterator> comma;
229 };
230}
231
232
234 : m_isValid(false)
235{
236 using boost::spirit::ascii::space;
237 typedef std::string::const_iterator iterator_type;
238 typedef Private::transform_unit_parser<iterator_type> transform_unit_parser;
239
240 transform_unit_parser g; // Our grammar
241 const std::string str = _str.toStdString();
242
243 std::vector<Private::transform_unit> transforms;
244 iterator_type iter = str.begin();
245 iterator_type end = str.end();
246 bool r = phrase_parse(iter, end, g, space, transforms);
247
248 if (r && iter == end) {
249 m_isValid = true;
250
251 for (const Private::transform_unit &t : transforms) {
252 m_transform = t.transform * m_transform;
253 }
254 }
255}
257{
258 return m_isValid;
259}
260
262{
263 return m_transform;
264}
265
266
float value(const T *src, size_t ch)
BOOST_FUSION_ADAPT_STRUCT(Private::matrix,(qreal, a)(qreal, b)(qreal, c)(qreal, d)(qreal, e)(qreal, f)) BOOST_FUSION_ADAPT_STRUCT(Private
SvgTransformParser(const QString &str)
QTransform transform() const
Eigen::Matrix3f fromScale(qreal sx, qreal sy)
Eigen::Matrix3f fromTranslate(const QPointF &pt)
transform_unit(const translate &t)