alaCarte Maps
Renderer for OpenStreetMap tiles
way_renderer.cpp
Go to the documentation of this file.
1 
23 #include <boost/unordered_map.hpp>
24 #include <boost/math/constants/constants.hpp>
25 
26 #include "general/geodata.hpp"
27 #include "general/way.hpp"
28 #include "general/node.hpp"
29 
30 #include "server/style.hpp"
31 
34 #include "way_renderer.hpp"
35 
41 void WayRenderer::addWayPath(cairo_t* cr)
42 {
43  cairo_new_path(cr);
44  if (path != NULL) {
45  cairo_append_path(cr, path);
46  return;
47  }
48 
49  const std::vector<NodeId>& children = way->getNodeIDs();
50  paintLine(cr, children);
51 
52  path = cairo_copy_path(cr);
53 
54  double x0, y0, x1, y1;
55  cairo_path_extents(cr, &x0, &y0, &x1, &y1);
56  bounds = FloatRect(x0, y0, x1, y1);
57 }
58 
61  int width, FloatPoint& best, double& angle)
62 {
63  cairo_path_data_t *data, last_move_to, current;
64  double diff;
65  double bestDiff = -std::numeric_limits<double>::infinity();
66  double dx, dy;
67  double length;
68 
69  for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
70  data = &path->data[i];
71  switch (data->header.type) {
72  case CAIRO_PATH_MOVE_TO:
73  last_move_to = data[1];
74  current = data[1];
75  break;
76 
77  case CAIRO_PATH_CLOSE_PATH:
78  data = (&last_move_to) - 1;
79  case CAIRO_PATH_LINE_TO:
80  dx = current.point.x - data[1].point.x;
81  dy = current.point.y - data[1].point.y;
82 
83  length = sqrt(dx*dx + dy*dy);
84  diff = length - width;
85  if (diff > 0 && diff > bestDiff) {
86  if (abs(dx) > 0)
87  angle = atan(dy/dx);
88  else
89  angle = -boost::math::constants::pi<double>()/2.0;
90  best.x = current.point.x - dx * 0.5;
91  best.y = current.point.y - dy * 0.5;
92  bestDiff = diff;
93  }
94 
95  current = data[1];
96  break;
97 
98  case CAIRO_PATH_CURVE_TO:
99  current = data[3];
100  break;
101  }
102  }
103 
104  return (bestDiff > 0);
105 }
106 
108 void WayRenderer::getShieldPosition(cairo_path_t* path, std::list<FloatPoint>& positions)
109 {
110  cairo_path_data_t *data, last_move_to, current;
111  double dis = RENDERER_SHIELD_DISTANCE;
112  double dx, dy;
113  for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
114  data = &path->data[i];
115  switch (data->header.type) {
116  case CAIRO_PATH_MOVE_TO:
117  last_move_to = data[1];
118  current = data[1];
119  break;
120 
121  case CAIRO_PATH_CLOSE_PATH:
122  data = (&last_move_to) - 1;
123  case CAIRO_PATH_LINE_TO:
124  dx = current.point.x - data[1].point.x;
125  dy = current.point.y - data[1].point.y;
126  dis += sqrt(dx*dx + dy*dy);
127  if (dis > RENDERER_SHIELD_DISTANCE)
128  {
129  positions.push_back(FloatPoint(current.point.x - 0.5*dx,
130  current.point.y - 0.5*dy));
131  dis = 0;
132  }
133 
134  current = data[1];
135  break;
136 
137  case CAIRO_PATH_CURVE_TO:
138  current = data[3];
139  break;
140  }
141  }
142 }
143 
144 WayRenderer::WayRenderer(const shared_ptr<Geodata>& data,
145  WayId wid,
146  const Style* s,
147  const cairo_matrix_t* transform)
148  : ObjectRenderer(data, s, transform)
149  , path(NULL)
150  , way(data->getWay(wid))
151 {
152 }
153 
155 {
156  if (path != NULL)
157  cairo_path_destroy(path);
158 }
159 
160 void WayRenderer::fill(cairo_t* cr, AssetCache& cache)
161 {
162  if (!way->isClosed())
163  return;
164 
165  addWayPath(cr);
166 
167  cairo_save(cr);
168 
169  const string& bg = s->fill_image.str();
170  if (!bg.empty()) {
171  cairo_pattern_t* pattern = cairo_pattern_create_for_surface(cache.getImage(bg));
172  cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
173  cairo_set_source(cr, pattern);
174  cairo_fill(cr);
175  cairo_pattern_destroy(pattern);
176  } else {
177  cairo_set_source_rgba(cr, COLOR2RGBA(s->fill_color));
178  cairo_fill(cr);
179  }
180 
181  cairo_restore(cr);
182 }
183 
184 void WayRenderer::casing(cairo_t* cr)
185 {
186  if (s->casing_width <= 0.0)
187  return;
188 
189  addWayPath(cr);
190 
191  cairo_save(cr);
192 
195  cairo_set_source_rgba(cr, COLOR2RGBA(s->casing_color));
196 
197  if (s->casing_dashes.size() > 0)
198  cairo_set_dash(cr, s->casing_dashes.data(), s->casing_dashes.size(), 0.0);
199  cairo_set_line_width(cr, s->casing_width*2 + s->width);
200 
201  cairo_stroke(cr);
202 
203  cairo_restore(cr);
204 }
205 
206 void WayRenderer::stroke(cairo_t* cr, AssetCache& cache)
207 {
208  if (s->width <= 0.0)
209  return;
210 
211  addWayPath(cr);
212 
213  cairo_save(cr);
214 
215  setLineCap(cr, s->linecap);
216  setLineJoin(cr, s->linejoin);
217  cairo_set_source_rgba(cr, COLOR2RGBA(s->color));
218  const string& image = s->image.str();
219  cairo_pattern_t* pattern = NULL;
220  if (!image.empty()) {
221  pattern = cairo_pattern_create_for_surface(cache.getImage(image));
222  cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
223  cairo_set_source(cr, pattern);
224  }
225 
226  if (s->dashes.size() > 0)
227  cairo_set_dash(cr, s->dashes.data(), s->dashes.size(), 0.0);
228  cairo_set_line_width(cr, s->width);
229 
230  cairo_stroke(cr);
231 
232  if (pattern != NULL)
233  cairo_pattern_destroy(pattern);
234 
235  cairo_restore(cr);
236 }
237 
238 void WayRenderer::label(cairo_t* cr,
239  std::list<shared_ptr<Label> >& labels, AssetCache& cache)
240 {
241  if (s->text.str().size() == 0 || s->font_size <= 0.0)
242  return;
243 
244  // make sure path is initialized
245  addWayPath(cr);
246  cairo_new_path(cr);
247 
248  cairo_save(cr);
249 
250  cairo_set_font_size(cr, s->font_size);
251 
252  cairo_select_font_face(cr,
253  s->font_family.c_str(),
254  s->font_style == Style::STYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
255  s->font_weight == Style::WEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL
256  );
257 
258  cairo_text_extents_t textSize;
259  cairo_text_extents(cr, s->text.c_str(), &textSize);
260 
262  {
263  // request a centered label
264  addLabel(labels, bounds.getCenter() + FloatPoint(0.0, s->text_offset), &textSize);
265  }
266  else if (s->text_position == Style::POSITION_LINE)
267  {
268  FloatPoint best;
269  double angle = 0;
270  bool placed = getTextPosition(path, textSize.width, best, angle);
271 
272  if (placed) {
273  cairo_translate(cr, best.x, best.y);
274  cairo_rotate(cr, angle);
275  cairo_translate(cr, 0, s->text_offset);
276 
277  cairo_move_to(cr, -textSize.width/2.0 - textSize.x_bearing,
278  -textSize.height/2.0 - textSize.y_bearing);
279 
280  cairo_text_path(cr, s->text.c_str());
281 
282  if (s->text_halo_radius > 0.0)
283  {
284  cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
285  cairo_set_line_width(cr, s->text_halo_radius*2.0);
286  cairo_set_source_rgba(cr, COLOR2RGBA(s->text_halo_color));
287  cairo_stroke_preserve(cr);
288  }
289  cairo_set_source_rgba(cr, COLOR2RGBA(s->text_color));
290  cairo_fill(cr);
291  }
292  }
293 
294  cairo_restore(cr);
295 }
296 
297 void WayRenderer::shield(cairo_t* cr,
298  std::list<shared_ptr<Shield> >& shields,
299  AssetCache& cache)
300 {
301  if (s->shield_text.str().size() == 0 || s->font_size <= 0.0)
302  return;
303 
304  // make sure path is initialized
305  addWayPath(cr);
306  cairo_new_path(cr);
307 
308  cairo_save(cr);
309 
310  cairo_set_font_size(cr, s->font_size);
311 
312  cairo_select_font_face(cr,
313  s->font_family.c_str(),
314  s->font_style == Style::STYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
315  s->font_weight == Style::WEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL
316  );
317 
318  cairo_text_extents_t textSize;
319  cairo_text_extents(cr, s->shield_text.c_str(), &textSize);
320 
321  std::list<FloatPoint> positions;
322  getShieldPosition(path, positions);
323 
324  for (FloatPoint& p : positions)
325  {
326  addShield(shields, p, &textSize);
327  }
328 
329  cairo_restore(cr);
330 }
MaybeCachedString shield_text
Definition: style.hpp:120
basic_rect< double > FloatRect
Definition: rect.hpp:170
void setLineCap(cairo_t *cr, Style::LineCap cap)
float text_halo_radius
Definition: style.hpp:99
void casing(cairo_t *cr)
float casing_width
Definition: style.hpp:85
bool getTextPosition(cairo_path_t *transformedPath, int width, FloatPoint &best, double &angle)
Find the best fitting segment on a cairo path and return angle.
void stroke(cairo_t *cr, AssetCache &cache)
const cairo_matrix_t * transform
LineJoin casing_linejoin
Definition: style.hpp:104
float text_offset
Definition: style.hpp:91
void fill(cairo_t *cr, AssetCache &cache)
const string & str() const
Returns the internal string.
cairo_path_t * path
MaybeCachedString image
Definition: style.hpp:81
MaybeCachedString fill_image
Definition: style.hpp:82
bool isClosed() const
Definition: way.hpp:46
LineCap casing_linecap
Definition: style.hpp:103
#define COLOR2RGBA(_X)
const shared_ptr< Geodata > & data
MaybeCachedString font_family
Definition: style.hpp:93
Color text_color
Definition: style.hpp:90
void label(cairo_t *cr, std::list< shared_ptr< Label > > &labels, AssetCache &cache)
FontWeight font_weight
Definition: style.hpp:94
LineJoin linejoin
Definition: style.hpp:102
void shield(cairo_t *cr, std::list< shared_ptr< Shield > > &shields, AssetCache &cache)
A Style stores the MapCSS properties for a single Node or Way, or a Relation of type multipolygon...
Definition: style.hpp:35
FloatRect bounds
is set by addWayPath for ways or in transformLocation for nodes
Color color
Definition: style.hpp:78
std::vector< double > casing_dashes
Definition: style.hpp:126
float font_size
Definition: style.hpp:92
void paintLine(cairo_t *cr, const std::vector< NodeId > &nodeIDs, bool reverse=false, bool connect=false) const
This file is part of alaCarte.
basic_vector2< double > FloatPoint
Definition: point.hpp:145
Color fill_color
Definition: style.hpp:79
WayRenderer(const shared_ptr< Geodata > &data, WayId wid, const Style *s, const cairo_matrix_t *transform)
LineCap linecap
Definition: style.hpp:101
void setLineJoin(cairo_t *cr, Style::LineJoin join)
TextPosition text_position
Definition: style.hpp:89
void addLabel(std::list< shared_ptr< Label > > &labels, const FloatPoint &p, const cairo_text_extents_t *textSize) const
used by node and way renderer to place a shield.
cairo_surface_t * getImage(string path)
float width
Definition: style.hpp:84
const char * c_str() const
Returns the internal c string.
void addShield(std::list< shared_ptr< Shield > > &shields, const FloatPoint &p, const cairo_text_extents_t *textSize) const
used by node and way renderer to place a shield.
std::vector< double > dashes
Definition: style.hpp:125
FontStyle font_style
Definition: style.hpp:95
#define RENDERER_SHIELD_DISTANCE
This file is part of alaCarte.
Color text_halo_color
Definition: style.hpp:98
void addWayPath(cairo_t *cr)
This file is part of alaCarte.
void getShieldPosition(cairo_path_t *transformedPath, std::list< FloatPoint > &positions)
Find the best fitting segment on a cairo path for a shield.
virtual ~WayRenderer()
const std::vector< NodeId > & getNodeIDs() const
Definition: way.hpp:45
Color casing_color
Definition: style.hpp:86
MaybeCachedString text
Definition: style.hpp:88
const Style * s
basic_vector2< T > getCenter() const
Definition: rect.hpp:116