Swiftray  1.0
shape-context.h
Go to the documentation of this file.
1 #include <QPainterPath>
2 #include <QString>
3 #include <QTransform>
5 
6 #include <boost/math/constants/constants.hpp>
7 #include <boost/numeric/ublas/assignment.hpp>
8 #include <boost/numeric/ublas/io.hpp>
9 #include <boost/numeric/ublas/matrix.hpp>
10 
11 #pragma once
12 
13 namespace Parser {
14 
15 namespace ublas = boost::numeric::ublas;
16 typedef ublas::matrix<double> matrix_t;
17 
18 class ShapeContext : public BaseContext {
19 public:
20  ShapeContext(BaseContext const &parent) : BaseContext(parent) {
21  //qInfo() << "<shape>";
22  this->transform_ = ublas::identity_matrix<double>(3, 3);
23  working_path_ = QPainterPath();
24  }
25 
26  void check_style() {
27  if (this->id_.isEmpty() && this->class_name_.isEmpty()) return;
28  SVGStyleSelector::NodePtr node;
29  SVGNode mockup("path", this->id_, this->class_name_);
30  node.ptr = &mockup;
31  // TODO(Rewrite declaration for node to process only simple rules)
32  auto decls = svgpp_style_selector->declarationsForNode(node);
33  for (auto &decl : decls) {
34  if (decl.d->property.isEmpty())
35  continue;
36  if (decl.d->property == "fill") {
37  if (decl.d->values.size() > 0) {
38  QColor c(decl.d->values[0].toString());
39  style().fill_paint_ = color_t(c.red(), c.green(), c.blue());
40  }
41  } else if (decl.d->property == "stroke") {
42  if (decl.d->values.size() > 0) {
43  QColor c(decl.d->values[0].toString());
44  style().stroke_paint_ = color_t(c.red(), c.green(), c.blue());
45  }
46  }
47  }
48  }
49 
50  void on_exit_element() {
51  check_style();
52  QPainterPath mapped_path = qtransform().map(working_path_);
53  ShapePtr shape = make_shared<PathShape>(mapped_path);
54  QString layer_name = this->strokeColor() == "N/A" ? this->fillColor() : this->strokeColor();
55  if (this->strokeColor() == "N/A" && this->fillColor() != "N/A") ((PathShape *) shape.get())->setFilled(true);
56  svgpp_add_shape(shape, layer_name);
57  }
58 
59  // Path Events Policy methods
60  void path_move_to(double x, double y, tag::coordinate::absolute) {
61  working_path_.moveTo(x, y);
62  }
63 
64  void path_line_to(double x, double y, tag::coordinate::absolute) {
65  working_path_.lineTo(x, y);
66  }
67 
68  void path_cubic_bezier_to(double x1, double y1, double x2, double y2,
69  double x, double y, tag::coordinate::absolute) {
70  working_path_.cubicTo(x1, y1, x2, y2,
71  x, y);
72  }
73 
74  void path_quadratic_bezier_to(double x1, double y1, double x, double y,
75  tag::coordinate::absolute) {
76  working_path_.quadTo(x1, y1, x, y);
77  }
78 
79  void path_elliptical_arc_to(double rx, double ry, double x_axis_rotation,
80  bool large_arc_flag, bool sweep_flag, double x2,
81  double y2, tag::coordinate::absolute) {
82  const QPointF &currentPos = working_path_.currentPosition();
83  // TODO (Support rotated arc)
84  // https://github.com/inkcut/inkcut/blob/ab27cf57ce5a5bd3bcaeef77bac28e4d6f92895a/inkcut/core/svg.py
85  const double x1 = currentPos.x(), y1 = currentPos.y(),
86  x1prime = (x1 - x2) / 2, y1prime = (y1 - y2) / 2,
87  lamb = (x1prime * x1prime) / (rx * rx) +
88  (y1prime * y1prime) / (ry * ry);
89 
90  if (lamb >= 1) {
91  ry = sqrt(lamb) * ry;
92  rx = sqrt(lamb) * rx;
93  }
94 
95  // Back to https://www.w3.org/TR/SVG/implnote.html F.6.5
96  double radicand = (rx * rx * ry * ry - rx * rx * y1prime * y1prime -
97  ry * ry * x1prime * x1prime);
98  radicand /= (rx * rx * y1prime * y1prime + ry * ry * x1prime * x1prime);
99 
100  if (radicand < 0) {
101  radicand = 0;
102  }
103 
104  const double factor =
105  (large_arc_flag == sweep_flag ? -1 : 1) * sqrt(radicand);
106  const double cxprime = factor * rx * y1prime / ry,
107  cyprime = -factor * ry * x1prime / rx,
108  cx = cxprime + (x1 + x2) / 2, cy = cyprime + (y1 + y2) / 2,
109  start_theta = -atan2((y1 - cy) * rx, (x1 - cx) * ry),
110  start_phi = -atan2(y1 - cy, x1 - cx),
111  end_phi = -atan2(y2 - cy, x2 - cx);
112  double sweep_length = end_phi - start_phi;
113 
114  if (sweep_length < 0 && !sweep_flag) {
115  sweep_length += 2 * 3.1415926;
116  }
117 
118  if (sweep_length > 0 && sweep_flag) {
119  sweep_length -= 2 * 3.1415926;
120  }
121 
122  working_path_.arcTo(cx - rx, cy - ry, rx * 2, ry * 2,
123  start_theta * 360 / 2 / 3.1415926,
124  sweep_length * 360 / 2 / 3.1415926);
125  }
126 
128  working_path_.closeSubpath();
129  }
130 
131  void path_exit() {
132  }
133 
134  // Marker Events Policy method
135  // TODO (Truly support marker)
136  void marker(marker_vertex v, double x, double y, double directionality,
137  unsigned marker_index) {
138  if (marker_index >= markers_.size())
139  markers_.resize(marker_index + 1);
140  MarkerPos &m = markers_[marker_index];
141  m.v = v;
142  m.x = x;
143  m.y = y;
144  m.directionality = directionality;
145  }
146 
147  string type() {
148  return "path";
149  }
150 
151  using BaseContext::set;
152  using StylableContext::set;
153 
154 private:
155  struct MarkerPos {
156  marker_vertex v;
157  double x, y, directionality;
158  };
159 
160  typedef std::vector<MarkerPos> Markers;
161  Markers markers_;
162 
163  QPainterPath working_path_;
164 };
165 
166 }
Definition: base-context.h:10
QString id_
Definition: base-context.h:79
void set(tag::attribute::width, double val)
Definition: object-context.h:9
QString class_name_
Definition: base-context.h:80
Definition: shape-context.h:18
void path_quadratic_bezier_to(double x1, double y1, double x, double y, tag::coordinate::absolute)
Definition: shape-context.h:74
string type()
Definition: shape-context.h:147
void marker(marker_vertex v, double x, double y, double directionality, unsigned marker_index)
Definition: shape-context.h:136
void path_line_to(double x, double y, tag::coordinate::absolute)
Definition: shape-context.h:64
ShapeContext(BaseContext const &parent)
Definition: shape-context.h:20
void check_style()
Definition: shape-context.h:26
void path_exit()
Definition: shape-context.h:131
void path_close_subpath()
Definition: shape-context.h:127
void path_cubic_bezier_to(double x1, double y1, double x2, double y2, double x, double y, tag::coordinate::absolute)
Definition: shape-context.h:68
void path_elliptical_arc_to(double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x2, double y2, tag::coordinate::absolute)
Definition: shape-context.h:79
void path_move_to(double x, double y, tag::coordinate::absolute)
Definition: shape-context.h:60
void on_exit_element()
Definition: shape-context.h:50
void set(svgpp::tag::attribute::display, svgpp::tag::value::none)
Definition: stylable-context.h:150
QString fillColor()
Definition: stylable-context.h:400
QString strokeColor()
Definition: stylable-context.h:387
Style & style()
Definition: stylable-context.h:269
QTransform qtransform()
Definition: transformable-context.h:28
matrix_t transform_
Definition: transformable-context.h:80
Definition: path-shape.h:7
Definition: svg-style-selector.h:7
Definition: base-context.h:8
SVGStyleSelector * svgpp_style_selector
Definition: svgpp-impl.cpp:218
boost::tuple< unsigned char, unsigned char, unsigned char > color_t
Definition: svgpp-color-factory.h:7
ublas::matrix< double > matrix_t
Definition: shape-context.h:16
void svgpp_add_shape(ShapePtr &shape, QString &layer_name)
Definition: svgpp-impl.cpp:268
shared_ptr< Shape > ShapePtr
Definition: shape.h:137
SVGPPPaint fill_paint_
Definition: stylable-context.h:28
SVGPPPaint stroke_paint_
Definition: stylable-context.h:28