3 #include "common/linec.h"
4 #include "map/bitmapline.h"
5 #include "map/textpathitem.h"
8 #include "rastertile.h"
12 #define TEXT_EXTENT 160
13 #define TSSLPT_SIZE 0.005 /* ll */
15 typedef QSet
<Coordinates
> PointSet
;
17 static const float C1
= 0.866025f
; /* sqrt(3)/2 */
18 static const QColor tsslptPen
= QColor("#eb49eb");
19 static const QColor tsslptBrush
= QColor("#80eb49eb");
21 static const Style
*style(qreal ratio
)
23 static ENC::Style
s(ratio
);
27 static double area(const QVector
<Coordinates
> &polygon
)
31 for (int i
= 0; i
< polygon
.size() - 1; i
++) {
32 const Coordinates
&pi
= polygon
.at(i
);
33 const Coordinates
&pj
= polygon
.at(i
+1);
34 area
+= pi
.lon() * pj
.lat();
35 area
-= pi
.lat() * pj
.lon();
42 static Coordinates
centroid(const QVector
<Coordinates
> &polygon
)
44 Q_ASSERT(polygon
.size() > 3);
45 Q_ASSERT(polygon
.first() == polygon
.last());
47 double cx
= 0, cy
= 0;
48 double factor
= 1.0 / (6.0 * area(polygon
));
50 for (int i
= 0; i
< polygon
.size() - 1; i
++) {
51 const Coordinates
&pi
= polygon
.at(i
);
52 const Coordinates
&pj
= polygon
.at(i
+1);
53 double f
= (pi
.lon() * pj
.lat() - pj
.lon() * pi
.lat());
54 cx
+= (pi
.lon() + pj
.lon()) * f
;
55 cy
+= (pi
.lat() + pj
.lat()) * f
;
58 return Coordinates(cx
* factor
, cy
* factor
);
61 static double angle(uint type
, const QVariant
¶m
)
65 return (bt
== RDOCAL
|| bt
== I_RDOCAL
|| bt
== CURENT
)
66 ? 90 + param
.toDouble() : NAN
;
69 static bool showLabel(const QImage
*img
, const Range
&range
, int zoom
, int type
)
71 if (type
>>16 == I_DISMAR
)
74 int limit
= (!range
.size())
75 ? range
.min() : range
.min() + (range
.size() + 1) / 2;
76 if ((img
|| (type
>>16 == SOUNDG
)) && (zoom
< limit
))
82 QPainterPath
RasterTile::painterPath(const Polygon
&polygon
) const
86 for (int i
= 0; i
< polygon
.size(); i
++) {
87 const QVector
<Coordinates
> &subpath
= polygon
.at(i
);
90 p
.reserve(subpath
.size());
92 for (int j
= 0; j
< subpath
.size(); j
++) {
93 const Coordinates
&c
= subpath
.at(j
);
103 QPolygonF
RasterTile::polyline(const QVector
<Coordinates
> &path
) const
106 polygon
.reserve(path
.size());
108 for (int i
= 0; i
< path
.size(); i
++)
109 polygon
.append(ll2xy(path
.at(i
)));
114 QVector
<QPolygonF
> RasterTile::polylineM(const QVector
<Coordinates
> &path
) const
116 QVector
<QPolygonF
> polys
;
120 polygon
.reserve(path
.size());
122 for (int i
= 0; i
< path
.size(); i
++) {
123 const Coordinates
&c
= path
.at(i
);
129 polys
.append(polygon
);
134 polygon
.append(ll2xy(c
));
137 if (!polygon
.isEmpty())
138 polys
.append(polygon
);
143 QPolygonF
RasterTile::tsslptArrow(const Coordinates
&c
, qreal angle
) const
145 Coordinates t
[3], r
[4];
149 t
[1] = Coordinates(t
[0].lon() - qCos(angle
- M_PI
/3) * TSSLPT_SIZE
,
150 t
[0].lat() - qSin(angle
- M_PI
/3) * TSSLPT_SIZE
);
151 t
[2] = Coordinates(t
[0].lon() - qCos(angle
- M_PI
+ M_PI
/3) * TSSLPT_SIZE
,
152 t
[0].lat() - qSin(angle
- M_PI
+ M_PI
/3) * TSSLPT_SIZE
);
155 r
[0] = l
.pointAt(0.25);
156 r
[1] = l
.pointAt(0.75);
157 r
[2] = Coordinates(r
[0].lon() - C1
* TSSLPT_SIZE
* qCos(angle
- M_PI
/2),
158 r
[0].lat() - C1
* TSSLPT_SIZE
* qSin(angle
- M_PI
/2));
159 r
[3] = Coordinates(r
[1].lon() - C1
* TSSLPT_SIZE
* qCos(angle
- M_PI
/2),
160 r
[1].lat() - C1
* TSSLPT_SIZE
* qSin(angle
- M_PI
/2));
162 polygon
<< ll2xy(t
[0]) << ll2xy(t
[2]) << ll2xy(r
[1]) << ll2xy(r
[3])
163 << ll2xy(r
[2]) << ll2xy(r
[0]) << ll2xy(t
[1]);
168 void RasterTile::drawArrows(QPainter
*painter
,
169 const QList
<MapData::Poly
> &polygons
)
171 for (int i
= 0; i
< polygons
.size(); i
++) {
172 const MapData::Poly
&poly
= polygons
.at(i
);
174 if (poly
.type()>>16 == TSSLPT
) {
175 QPolygonF
polygon(tsslptArrow(centroid(poly
.path().first()),
176 deg2rad(180 - poly
.param().toDouble())));
178 painter
->setPen(QPen(tsslptPen
, 1));
179 painter
->setBrush(QBrush(tsslptBrush
));
180 painter
->drawPolygon(polygon
);
185 void RasterTile::drawPolygons(QPainter
*painter
,
186 const QList
<MapData::Poly
> &polygons
)
188 for (int n
= 0; n
< _style
->drawOrder().size(); n
++) {
189 for (int i
= 0; i
< polygons
.size(); i
++) {
190 const MapData::Poly
&poly
= polygons
.at(i
);
191 if (poly
.type() != _style
->drawOrder().at(n
))
193 const Style::Polygon
&style
= _style
->polygon(poly
.type());
195 if (!style
.img().isNull()) {
196 for (int i
= 0; i
< poly
.path().size(); i
++)
197 BitmapLine::draw(painter
, polylineM(poly
.path().at(i
)),
200 if (style
.brush() != Qt::NoBrush
) {
201 painter
->setPen(Qt::NoPen
);
202 painter
->setBrush(style
.brush());
203 painter
->drawPath(painterPath(poly
.path()));
205 if (style
.pen() != Qt::NoPen
) {
206 painter
->setPen(style
.pen());
207 for (int i
= 0; i
< poly
.path().size(); i
++) {
208 QVector
<QPolygonF
> outline(polylineM(poly
.path().at(i
)));
209 for (int j
= 0; j
< outline
.size(); j
++)
210 painter
->drawPolyline(outline
.at(j
));
218 void RasterTile::drawLines(QPainter
*painter
, const QList
<MapData::Line
> &lines
)
220 painter
->setBrush(Qt::NoBrush
);
222 for (int i
= 0; i
< lines
.size(); i
++) {
223 const MapData::Line
&line
= lines
.at(i
);
224 const Style::Line
&style
= _style
->line(line
.type());
226 if (!style
.img().isNull()) {
227 BitmapLine::draw(painter
, polyline(line
.path()), style
.img());
228 } else if (style
.pen() != Qt::NoPen
) {
229 painter
->setPen(style
.pen());
230 painter
->drawPolyline(polyline(line
.path()));
235 void RasterTile::drawTextItems(QPainter
*painter
,
236 const QList
<TextItem
*> &textItems
)
238 for (int i
= 0; i
< textItems
.size(); i
++)
239 textItems
.at(i
)->paint(painter
);
242 void RasterTile::processPolygons(const QList
<MapData::Poly
> &polygons
,
243 QList
<TextItem
*> &textItems
)
245 for (int i
= 0; i
< polygons
.size(); i
++) {
246 const MapData::Poly
&poly
= polygons
.at(i
);
247 uint type
= poly
.type()>>16;
249 if (!(type
== HRBFAC
|| type
== I_TRNBSN
250 || poly
.type() == SUBTYPE(I_BERTHS
, 6)))
252 const Style::Point
&style
= _style
->point(poly
.type());
253 const QImage
*img
= style
.img().isNull() ? 0 : &style
.img();
257 TextPointItem
*item
= new TextPointItem(
258 ll2xy(centroid(poly
.path().first())).toPoint(),
259 0, 0, img
, 0, 0, 0, 0);
260 if (item
->isValid() && !item
->collides(textItems
))
261 textItems
.append(item
);
267 void RasterTile::processPoints(QList
<MapData::Point
> &points
,
268 QList
<TextItem
*> &textItems
, QList
<TextItem
*> &lights
)
270 PointSet lightsSet
, signalsSet
;
273 std::sort(points
.begin(), points
.end());
275 /* Lights & Signals */
276 for (i
= 0; i
< points
.size(); i
++) {
277 const MapData::Point
&point
= points
.at(i
);
278 if (point
.type()>>16 == LIGHTS
)
279 lightsSet
.insert(point
.pos());
280 else if (point
.type()>>16 == FOGSIG
)
281 signalsSet
.insert(point
.pos());
286 /* Everything else */
287 for ( ; i
< points
.size(); i
++) {
288 const MapData::Point
&point
= points
.at(i
);
289 QPoint
pos(ll2xy(point
.pos()).toPoint());
290 const Style::Point
&style
= _style
->point(point
.type());
292 const QString
*label
= point
.label().isEmpty() ? 0 : &(point
.label());
293 const QImage
*img
= style
.img().isNull() ? 0 : &style
.img();
294 const QFont
*fnt
= showLabel(img
, _zoomRange
, _zoom
, point
.type())
295 ? _style
->font(style
.textFontSize()) : 0;
296 const QColor
*color
= &style
.textColor();
297 const QColor
*hColor
= style
.haloColor().isValid()
298 ? &style
.haloColor() : 0;
299 double rotate
= angle(point
.type(), point
.param());
301 if ((!label
|| !fnt
) && !img
)
304 TextPointItem
*item
= new TextPointItem(pos
, label
, fnt
, img
, color
,
305 hColor
, 0, 2, rotate
);
306 if (item
->isValid() && !item
->collides(textItems
)) {
307 textItems
.append(item
);
308 if (lightsSet
.contains(point
.pos()))
309 lights
.append(new TextPointItem(pos
, 0, 0, _style
->light(), 0,
311 if (signalsSet
.contains(point
.pos()))
312 lights
.append(new TextPointItem(pos
, 0, 0, _style
->signal(), 0,
319 void RasterTile::processLines(const QList
<MapData::Line
> &lines
,
320 QList
<TextItem
*> &textItems
)
322 for (int i
= 0; i
< lines
.size(); i
++) {
323 const MapData::Line
&line
= lines
.at(i
);
324 const Style::Line
&style
= _style
->line(line
.type());
326 if (style
.img().isNull() && style
.pen() == Qt::NoPen
)
328 if (line
.label().isEmpty() || style
.textFontSize() == Style::None
)
331 const QFont
*fnt
= _style
->font(style
.textFontSize());
332 const QColor
*color
= &style
.textColor();
334 TextPathItem
*item
= new TextPathItem(polyline(line
.path()),
335 &line
.label(), _rect
, fnt
, color
, 0);
336 if (item
->isValid() && !item
->collides(textItems
))
337 textItems
.append(item
);
343 void RasterTile::fetchData(QList
<MapData::Poly
> &polygons
,
344 QList
<MapData::Line
> &lines
, QList
<MapData::Point
> &points
)
346 QPoint
ttl(_rect
.topLeft());
348 QRectF
polyRect(ttl
, QPointF(ttl
.x() + _rect
.width(), ttl
.y()
350 RectD
polyRectD(_transform
.img2proj(polyRect
.topLeft()),
351 _transform
.img2proj(polyRect
.bottomRight()));
352 RectC
polyRectC(polyRectD
.toRectC(_proj
, 20));
353 QRectF
pointRect(QPointF(ttl
.x() - TEXT_EXTENT
, ttl
.y() - TEXT_EXTENT
),
354 QPointF(ttl
.x() + _rect
.width() + TEXT_EXTENT
, ttl
.y() + _rect
.height()
356 RectD
pointRectD(_transform
.img2proj(pointRect
.topLeft()),
357 _transform
.img2proj(pointRect
.bottomRight()));
358 RectC
pointRectC(pointRectD
.toRectC(_proj
, 20));
361 _map
->lines(polyRectC
, &lines
);
362 _map
->polygons(polyRectC
, &polygons
);
363 _map
->points(pointRectC
, &points
);
365 _atlas
->polys(polyRectC
, &polygons
, &lines
);
366 _atlas
->points(pointRectC
, &points
);
370 void RasterTile::render()
372 QList
<MapData::Line
> lines
;
373 QList
<MapData::Poly
> polygons
;
374 QList
<MapData::Point
> points
;
375 QList
<TextItem
*> textItems
, lights
;
377 _pixmap
.setDevicePixelRatio(_ratio
);
378 _pixmap
.fill(Qt::transparent
);
380 fetchData(polygons
, lines
, points
);
382 processPolygons(polygons
, textItems
);
383 processPoints(points
, textItems
, lights
);
384 processLines(lines
, textItems
);
386 QPainter
painter(&_pixmap
);
387 painter
.setRenderHint(QPainter::SmoothPixmapTransform
);
388 painter
.setRenderHint(QPainter::Antialiasing
);
389 painter
.translate(-_rect
.x(), -_rect
.y());
391 drawPolygons(&painter
, polygons
);
392 drawLines(&painter
, lines
);
393 drawArrows(&painter
, polygons
);
395 drawTextItems(&painter
, lights
);
396 drawTextItems(&painter
, textItems
);
398 qDeleteAll(textItems
);
401 //painter.setPen(Qt::red);
402 //painter.setBrush(Qt::NoBrush);
403 //painter.drawRect(QRect(_rect.topLeft(), _pixmap.size()));
408 RasterTile::RasterTile(const Projection
&proj
, const Transform
&transform
,
409 const MapData
*data
, int zoom
, const Range
&zoomRange
, const QRect
&rect
,
411 _proj(proj
), _transform(transform
), _map(data
), _atlas(0), _zoom(zoom
),
412 _zoomRange(zoomRange
), _rect(rect
), _ratio(ratio
),
413 _pixmap(rect
.width() * ratio
, rect
.height() * ratio
), _valid(false)
415 _style
= style(ratio
);
418 RasterTile::RasterTile(const Projection
&proj
, const Transform
&transform
,
419 AtlasData
*data
, int zoom
, const Range
&zoomRange
, const QRect
&rect
,
421 _proj(proj
), _transform(transform
), _map(0), _atlas(data
), _zoom(zoom
),
422 _zoomRange(zoomRange
), _rect(rect
), _ratio(ratio
),
423 _pixmap(rect
.width() * ratio
, rect
.height() * ratio
), _valid(false)
425 _style
= style(ratio
);