source: subversion/applications/editors/merkaartor/PaintStyle/PaintStyle.cpp @ 13989

Last change on this file since 13989 was 13446, checked in by Chris Browet, 11 years ago

ADD : Initial support for multiple projections via proj4. Enable in Config.pri with PROJ=1
FIX : Crash during OSM import (fixes #1536)
ADD : Option (in Manager) to autoload/autoshow the World

File size: 32.3 KB
Line 
1#include "PaintStyle.h"
2#include "Map/Painting.h"
3#include "Map/Projection.h"
4#include "Map/TrackPoint.h"
5#include "Map/Relation.h"
6#include "Map/Road.h"
7#include "Utils/LineF.h"
8#include "Utils/SvgCache.h"
9
10#include <QtCore/QString>
11#include <QtGui/QPainter>
12#include <QtGui/QPainterPath>
13#include <QMatrix>
14#include <QDomElement>
15#include <math.h>
16
17FeaturePainter::FeaturePainter()
18: theSelector(0),
19  ZoomLimitSet(false), ZoomUnder(0), ZoomUpper(10e6),
20  DrawBackground(false), BackgroundScale(0), BackgroundOffset(3),
21  DrawForeground(false), ForegroundScale(0), ForegroundOffset(2),
22  ForegroundDashSet(false),
23  DrawTouchup(false), TouchupScale(0), TouchupOffset(1),
24  TouchupDashSet(false),
25  ForegroundFill(false), DrawTrafficDirectionMarks(false),
26  DrawIcon(false), IconScale(0), IconOffset(0),
27  DrawLabel(false), LabelScale(0), LabelOffset(0),
28  DrawLabelBackground(false), LabelHalo(false), LabelArea(false)
29{
30}
31
32FeaturePainter::FeaturePainter(const FeaturePainter& f)
33: theSelector(0),
34  ZoomLimitSet(f.ZoomLimitSet), ZoomUnder(f.ZoomUnder), ZoomUpper(f.ZoomUpper),
35  DrawBackground(f.DrawBackground), BackgroundColor(f.BackgroundColor),
36  BackgroundScale(f.BackgroundScale), BackgroundOffset(f.BackgroundOffset),
37  DrawForeground(f.DrawForeground), ForegroundColor(f.ForegroundColor),
38  ForegroundScale(f.ForegroundScale), ForegroundOffset(f.ForegroundOffset),
39  ForegroundDashSet(f.ForegroundDashSet), ForegroundDash(f.ForegroundDash), ForegroundWhite(f.ForegroundWhite),
40  DrawTouchup(f.DrawTouchup), TouchupColor(f.TouchupColor),
41  TouchupScale(f.TouchupScale), TouchupOffset(f.TouchupOffset),
42  TouchupDashSet(f.TouchupDashSet),
43  TouchupDash(f.TouchupDash), TouchupWhite(f.TouchupWhite),
44  ForegroundFill(f.ForegroundFill), ForegroundFillFillColor(f.ForegroundFillFillColor),
45  DrawTrafficDirectionMarks(f.DrawTrafficDirectionMarks),
46  DrawIcon(f.DrawIcon), IconName(f.IconName), IconScale(f.IconScale), IconOffset(f.IconOffset),
47  DrawLabel(f.DrawLabel), LabelTag(f.LabelTag), LabelColor(f.LabelColor), LabelScale(f.LabelScale), LabelOffset(f.LabelOffset),
48  DrawLabelBackground(f.DrawLabelBackground), LabelBackgroundColor(f.LabelBackgroundColor), LabelBackgroundTag(f.LabelBackgroundTag),
49  LabelFont(f.LabelFont), LabelHalo(f.LabelHalo), LabelArea(f.LabelArea)
50{
51        if (f.theSelector)
52                theSelector = f.theSelector->copy();
53
54}
55
56FeaturePainter& FeaturePainter::operator=(const FeaturePainter& f)
57{
58        if (&f == this) return *this;
59        delete theSelector;
60        if (f.theSelector)
61                theSelector = f.theSelector->copy();
62        else
63                theSelector = 0;
64        ZoomLimitSet = f.ZoomLimitSet;
65        ZoomUnder = f.ZoomUnder;
66        ZoomUpper = f.ZoomUpper;
67        DrawBackground = f.DrawBackground;
68        BackgroundColor = f.BackgroundColor;
69        BackgroundScale = f.BackgroundScale;
70        BackgroundOffset = f.BackgroundOffset;
71        DrawForeground = f.DrawForeground;
72        ForegroundColor = f.ForegroundColor;
73        ForegroundScale = f.ForegroundScale;
74        ForegroundOffset = f.ForegroundOffset;
75        ForegroundDashSet = f.ForegroundDashSet ;
76        ForegroundDash = f.ForegroundDash;
77        ForegroundWhite = f.ForegroundWhite;
78        DrawTouchup = f.DrawTouchup;
79        TouchupColor = f.TouchupColor;
80        TouchupScale = f.TouchupScale;
81        TouchupOffset = f.TouchupOffset;
82        TouchupDashSet = f.TouchupDashSet;
83        TouchupDash = f.TouchupDash;
84        TouchupWhite = f.TouchupWhite;
85        ForegroundFill = f.ForegroundFill;
86        ForegroundFillFillColor = f.ForegroundFillFillColor;
87        DrawTrafficDirectionMarks = f.DrawTrafficDirectionMarks;
88        DrawIcon = f.DrawIcon;
89        IconName = f.IconName;
90        IconScale = f.IconScale;
91        IconOffset = f.IconOffset;
92        DrawLabel = f.DrawLabel;
93        LabelColor = f.LabelColor;
94        LabelScale = f.LabelScale;
95        LabelOffset = f.LabelOffset;
96        DrawLabelBackground = f.DrawLabelBackground;
97        LabelBackgroundColor = f.LabelBackgroundColor;
98        LabelFont = f.LabelFont;
99        LabelTag = f.LabelTag;
100        LabelBackgroundTag = f.LabelBackgroundTag;
101        LabelHalo = f.LabelHalo;
102        LabelArea = f.LabelArea;
103        return *this;
104}
105
106FeaturePainter::~FeaturePainter()
107{
108        delete theSelector;
109}
110
111QString paddedHexa(unsigned int i)
112{
113        QString r=QString::number(i,16);
114        if (r.length() < 2)
115                r = "0"+r;
116        return r;
117}
118
119QString asXML(const QColor& c)
120{
121        return "#"+paddedHexa(c.red())+paddedHexa(c.green())+paddedHexa(c.blue())+paddedHexa(c.alpha());
122}
123
124QString colorAsXML(const QString& name, const QColor& c)
125{
126        return
127                name+"Color=\""+asXML(c)+"\"\n";
128}
129
130QString boundaryAsXML(const QString& name, const QColor& c, double Scale, double Offset)
131{
132        return
133                name+"Color=\""+asXML(c)+"\" "+name+"Scale=\""+QString::number(Scale)+"\" "+name+"Offset=\""+QString::number(Offset)+"\"\n";
134}
135
136QString iconAsXML(const QString& name, const QString& fn, double Scale, double Offset)
137{
138        return
139                name+"=\""+fn+"\" "+name+"Scale=\""+QString::number(Scale)+"\" "+name+"Offset=\""+QString::number(Offset)+"\"\n";
140}
141
142QColor toColor(const QString& s)
143{
144        return
145                QColor(
146                        s.mid(1,2).toInt(0,16),
147                        s.mid(3,2).toInt(0,16),
148                        s.mid(5,2).toInt(0,16),
149                        s.mid(7,2).toInt(0,16));
150}
151
152
153QString FeaturePainter::toXML(QString filename) const
154{
155        QString r;
156        r += "<painter\n";
157        if (ZoomLimitSet)
158                r += " zoomUnder=\""+QString::number(ZoomUnder)+"\" zoomUpper=\""+QString::number(ZoomUpper)+"\"\n";
159        if (DrawBackground)
160                r += " " + boundaryAsXML("background",BackgroundColor, BackgroundScale, BackgroundOffset);
161        if (DrawForeground)
162                r += " " + boundaryAsXML("foreground",ForegroundColor, ForegroundScale, ForegroundOffset);
163        if (ForegroundDashSet && DrawForeground)
164                r += " foregroundDashDown=\""+QString::number(ForegroundDash)+"\" foregroundDashUp=\""+QString::number(ForegroundWhite)+"\"\n";
165        if (DrawTouchup)
166                r += " " + boundaryAsXML("touchup",TouchupColor, TouchupScale, TouchupOffset);
167        if (TouchupDashSet && DrawTouchup)
168                r += " touchupDashDown=\""+QString::number(TouchupDash)+"\" touchupDashUp=\""+QString::number(TouchupWhite)+"\"\n";
169        if (ForegroundFill)
170                r += " fillColor=\""+::asXML(ForegroundFillFillColor)+"\"\n";
171        if (!IconName.isEmpty() && DrawIcon)
172        {
173                QString iconFilename;
174        if (!IconName.startsWith(':')) {
175            iconFilename = QFileInfo(filename).absoluteDir().relativeFilePath(QFileInfo(IconName).absoluteFilePath());
176        } else {
177            iconFilename = IconName;
178        }
179                r += " " + iconAsXML("icon",iconFilename, IconScale, IconOffset);
180        }
181        if (DrawTrafficDirectionMarks)
182                r += " drawTrafficDirectionMarks=\"yes\"";
183        else
184                r += " drawTrafficDirectionMarks=\"no\"";
185        if (DrawLabel) {
186                r += " " + boundaryAsXML("label",LabelColor, LabelScale, LabelOffset);
187                r += " labelFont=\"" + LabelFont.toString() + "\"";
188                r += " labelTag=\"" + LabelTag + "\"";
189                if (LabelHalo)
190                        r += " labelHalo=\"yes\"";
191                if (LabelArea)
192                        r += " labelArea=\"yes\"";
193        }
194        if (DrawLabelBackground) {
195                r += " labelBackgroundColor=\""+::asXML(LabelBackgroundColor)+"\"";
196                r += " labelBackgroundTag=\""+ LabelBackgroundTag +"\"\n";
197        }
198        r += ">\n";
199
200
201        if (theSelector)
202                r += "  <selector expr=\""+theSelector->asExpression(false)+"\"/>\n";
203        r += "</painter>\n";
204        return r;
205}
206
207FeaturePainter FeaturePainter::fromXML(const QDomElement& e, QString filename)
208{
209        FeaturePainter FP;
210
211        if (e.hasAttribute("zoomUnder") || e.hasAttribute("zoomUpper"))
212                FP.zoomBoundary(e.attribute("zoomUnder","0").toDouble(),e.attribute("zoomUpper","10e6").toDouble());
213        if (e.hasAttribute("foregroundColor"))
214        {
215                FP.foreground(
216                        toColor(e.attribute("foregroundColor")),e.attribute("foregroundScale").toDouble(),e.attribute("foregroundOffset").toDouble());
217                if (e.hasAttribute("foregroundDashDown"))
218                        FP.foregroundDash(e.attribute("foregroundDashDown").toDouble(),e.attribute("foregroundDashUp").toDouble());
219        }
220        if (e.hasAttribute("backgroundColor"))
221                FP.background(
222                        toColor(e.attribute("backgroundColor")),e.attribute("backgroundScale").toDouble(),e.attribute("backgroundOffset").toDouble());
223        if (e.hasAttribute("touchupColor"))
224        {
225                FP.touchup(
226                        toColor(e.attribute("touchupColor")),e.attribute("touchupScale").toDouble(),e.attribute("touchupOffset").toDouble());
227                if (e.hasAttribute("touchupDashDown"))
228                        FP.touchupDash(e.attribute("touchupDashDown").toDouble(),e.attribute("touchupDashUp").toDouble());
229        }
230        if (e.hasAttribute("fillColor"))
231                FP.foregroundFill(toColor(e.attribute("fillColor")));
232        if (e.hasAttribute("icon"))
233        {
234                QString iconFilename = e.attribute("icon");
235                if (!QFileInfo(iconFilename).isAbsolute())
236                        iconFilename = QFileInfo(filename).absolutePath().append("/").append(iconFilename);
237                FP.setIcon(iconFilename,e.attribute("iconScale", "0.0").toDouble(),e.attribute("iconOffset", "0.0").toDouble());
238        }
239        if (e.attribute("drawTrafficDirectionMarks") == "yes")
240                FP.drawTrafficDirectionMarks();
241        if (e.hasAttribute("labelColor"))
242        {
243                FP.label(
244                        toColor(e.attribute("labelColor")),e.attribute("labelScale").toDouble(),e.attribute("labelOffset").toDouble());
245                FP.setLabelFont(e.attribute("labelFont"));
246                FP.labelTag(e.attribute("labelTag"));
247                if (e.hasAttribute("labelHalo"))
248                        FP.labelHalo((e.attribute("labelHalo") == "yes"));
249                if (e.hasAttribute("labelArea"))
250                        FP.labelArea((e.attribute("labelArea") == "yes"));
251                if (e.hasAttribute("labelBackgroundColor"))
252                        FP.labelBackground(toColor(e.attribute("labelBackgroundColor")));
253                if (e.hasAttribute("labelBackgroundTag"))
254                        FP.labelBackgroundTag(e.attribute("labelBackgroundTag"));
255        }
256        QDomNode n = e.firstChild();
257        std::vector<std::pair<QString,QString> > Pairs;
258        while (!n.isNull())
259        {
260                if (n.isElement())
261                {
262                        QDomElement t = n.toElement();
263                        if (t.tagName() == "selector")
264                        {
265                                if (t.attribute("key") != "")
266                                        Pairs.push_back(std::make_pair(t.attribute("key"),t.attribute("value")));
267                                else
268                                {
269                                        FP.setSelector(t.attribute("expr"));
270                                        return FP;
271                                }
272                        }
273                }
274                n = n.nextSibling();
275        }
276        if (Pairs.size() == 1)
277                FP.setSelector(new TagSelectorIs(Pairs[0].first,Pairs[0].second));
278        else if (Pairs.size())
279        {
280                bool Same = true;
281                for (unsigned int i=1; i<Pairs.size(); ++i)
282                        if (Pairs[0].first != Pairs[i].first)
283                                Same = false;
284                if (Same)
285                {
286                        std::vector<QString> Options;
287                        for (unsigned int i=0; i<Pairs.size(); ++i)
288                                Options.push_back(Pairs[i].second);
289                        FP.setSelector(new TagSelectorIsOneOf(Pairs[0].first,Options));
290                }
291                else
292                {
293                        std::vector<TagSelector*> Options;
294                        for (unsigned int i=0; i<Pairs.size(); ++i)
295                                Options.push_back(new TagSelectorIs(Pairs[i].first,Pairs[i].second));
296                        FP.setSelector(new TagSelectorOr(Options));
297                }
298        }
299
300        return FP;
301}
302
303
304QString FeaturePainter::userName() const
305{
306        if (theSelector)
307                return theSelector->asExpression(false);
308        return "Unnamed";
309}
310
311std::pair<double, double> FeaturePainter::zoomBoundaries() const
312{
313        if (ZoomLimitSet)
314                return std::make_pair(ZoomUnder,ZoomUpper);
315        return std::make_pair(0.0,0.0);
316}
317
318QColor FeaturePainter::fillColor() const
319{
320        if (!ForegroundFill)
321                return QColor();
322        return ForegroundFillFillColor;
323}
324
325bool FeaturePainter::isFilled() const
326{
327        return ForegroundFill;
328}
329
330FeaturePainter& FeaturePainter::drawTrafficDirectionMarks()
331{
332        DrawTrafficDirectionMarks = true;
333        return *this;
334}
335
336FeaturePainter& FeaturePainter::zoomBoundary(double anUnder, double anUpper)
337{
338        ZoomLimitSet = true;
339        ZoomUnder = anUnder;
340        ZoomUpper = anUpper;
341        return *this;
342}
343
344FeaturePainter& FeaturePainter::fillActive(bool b)
345{
346        ForegroundFill = b;
347        if (ForegroundFill && !ForegroundFillFillColor.isValid())
348                ForegroundFillFillColor.setRgb(0,0,0);
349        return *this;
350}
351
352FeaturePainter& FeaturePainter::foregroundFill(QColor FillColor)
353{
354        ForegroundFill = true;
355        ForegroundFillFillColor = FillColor;
356        return *this;
357}
358
359FeaturePainter& FeaturePainter::backgroundActive(bool b)
360{
361        DrawBackground = b;
362        return *this;
363}
364
365FeaturePainter& FeaturePainter::background(QColor Color, double Scale, double Offset)
366{
367        DrawBackground = true;
368        BackgroundColor = Color;
369        BackgroundScale = Scale;
370        BackgroundOffset = Offset;
371        return *this;
372}
373
374LineParameters FeaturePainter::backgroundBoundary() const
375{
376        LineParameters P;
377        P.Draw = DrawBackground;
378        P.Color = BackgroundColor;
379        P.Proportional = BackgroundScale;
380        P.Fixed = BackgroundOffset;
381        P.Dashed = false;
382        P.DashOn = P.DashOff = 0;
383        return P;
384}
385
386FeaturePainter& FeaturePainter::touchupActive(bool b)
387{
388        DrawTouchup = b;
389        return *this;
390}
391
392FeaturePainter& FeaturePainter::touchupDash(double Dash, double White)
393{
394        TouchupDashSet = true;
395        TouchupDash = Dash;
396        TouchupWhite = White;
397        return *this;
398}
399
400FeaturePainter& FeaturePainter::touchup(QColor Color, double Scale, double Offset)
401{
402        DrawTouchup = true;
403        TouchupColor = Color;
404        TouchupScale = Scale;
405        TouchupOffset = Offset;
406        TouchupDashSet = false;
407        return *this;
408}
409
410FeaturePainter& FeaturePainter::foregroundActive(bool b)
411{
412        DrawForeground = b;
413        return *this;
414}
415
416FeaturePainter& FeaturePainter::foregroundDash(double Dash, double White)
417{
418        ForegroundDashSet = true;
419        ForegroundDash = Dash;
420        ForegroundWhite = White;
421        return *this;
422}
423
424FeaturePainter& FeaturePainter::foreground(QColor Color, double Scale, double Offset)
425{
426        DrawForeground = true;
427        ForegroundColor = Color;
428        ForegroundScale = Scale;
429        ForegroundOffset = Offset;
430        ForegroundDashSet = false;
431        return *this;
432}
433
434void FeaturePainter::clearForegroundDash()
435{
436        ForegroundDashSet = false;
437}
438
439FeaturePainter& FeaturePainter::labelActive(bool b)
440{
441        DrawLabel = b;
442        return *this;
443}
444
445FeaturePainter& FeaturePainter::labelHalo(bool b)
446{
447        LabelHalo = b;
448        return *this;
449}
450
451FeaturePainter& FeaturePainter::labelArea(bool b)
452{
453        LabelArea = b;
454        return *this;
455}
456
457FeaturePainter& FeaturePainter::labelTag(const QString& val)
458{
459        LabelTag = val;
460        return *this;
461}
462
463FeaturePainter& FeaturePainter::labelBackgroundTag(const QString& val)
464{
465        LabelBackgroundTag = val;
466        return *this;
467}
468
469FeaturePainter& FeaturePainter::label(QColor Color, double Scale, double Offset)
470{
471        DrawLabel = true;
472        LabelColor = Color;
473        LabelScale = Scale;
474        LabelOffset = Offset;
475        return *this;
476}
477
478FeaturePainter& FeaturePainter::labelBackgroundActive(bool b)
479{
480        DrawLabelBackground = b;
481        if (DrawLabelBackground && !LabelBackgroundColor.isValid())
482                LabelBackgroundColor.setRgb(0,0,0);
483        return *this;
484}
485
486FeaturePainter& FeaturePainter::labelBackground(QColor bgColor)
487{
488        DrawLabelBackground = true;
489        LabelBackgroundColor = bgColor;
490        return *this;
491}
492
493FeaturePainter& FeaturePainter::setLabelFont(const QString& descFont)
494{
495        LabelFont.fromString(descFont);
496        return *this;
497}
498
499QColor FeaturePainter::labelBackgroundColor() const
500{
501        if (!DrawLabelBackground)
502                return QColor();
503        return LabelBackgroundColor;
504}
505
506QFont FeaturePainter::getLabelFont() const
507{
508        return LabelFont;
509}
510
511QString FeaturePainter::getLabelTag() const
512{
513        return LabelTag;
514}
515
516bool FeaturePainter::getLabelHalo() const
517{
518        return LabelHalo;
519}
520
521bool FeaturePainter::getLabelArea() const
522{
523        return LabelArea;
524}
525
526QString FeaturePainter::getLabelBackgroundTag() const
527{
528        return LabelBackgroundTag;
529}
530
531LineParameters FeaturePainter::foregroundBoundary() const
532{
533        LineParameters P;
534        P.Draw = DrawForeground;
535        P.Color = ForegroundColor;
536        P.Proportional = ForegroundScale;
537        P.Fixed = ForegroundOffset;
538        P.Dashed = ForegroundDashSet;
539        P.DashOn = ForegroundDash;
540        P.DashOff = ForegroundWhite;
541        if (!P.Dashed)
542                P.DashOff = P.DashOn = 0;
543        return P;
544}
545
546void FeaturePainter::clearTouchupDash()
547{
548        TouchupDashSet = false;
549}
550
551LineParameters FeaturePainter::touchupBoundary() const
552{
553        LineParameters P;
554        P.Draw = DrawTouchup;
555        P.Color = TouchupColor;
556        P.Proportional = TouchupScale;
557        P.Fixed = TouchupOffset;
558        P.Dashed = TouchupDashSet;
559        P.DashOn = TouchupDash;
560        P.DashOff = TouchupWhite;
561        if (!P.Dashed)
562                P.DashOff = P.DashOn = 0;
563        return P;
564}
565
566LineParameters FeaturePainter::labelBoundary() const
567{
568        LineParameters P;
569        P.Draw = DrawLabel;
570        P.Color = LabelColor;
571        P.Proportional = LabelScale;
572        P.Fixed = LabelOffset;
573        P.Dashed = false;
574        if (!P.Dashed)
575                P.DashOff = P.DashOn = 0.0;
576        return P;
577}
578
579FeaturePainter& FeaturePainter::setIcon(const QString& Name, double Scale, double Offset)
580{
581        DrawIcon = true;
582        IconName = Name;
583        IconScale = Scale;
584        IconOffset = Offset;
585        return *this;
586}
587
588IconParameters FeaturePainter::icon() const
589{
590        IconParameters P;
591        P.Draw = DrawIcon;
592        P.Name = IconName;
593        P.Proportional = IconScale;
594        P.Fixed = IconOffset;
595        return P;
596}
597
598FeaturePainter& FeaturePainter::iconActive(bool b)
599{
600        DrawIcon = b;
601        return *this;
602}
603
604void FeaturePainter::setSelector(const QString& anExpression)
605{
606        delete theSelector;
607        theSelector = TagSelector::parse(anExpression);
608}
609
610void FeaturePainter::setSelector(TagSelector* aSel)
611{
612        delete theSelector;
613        theSelector = aSel;
614}
615
616TagSelectorMatchResult FeaturePainter::matchesTag(const MapFeature* F) const
617{
618        TagSelectorMatchResult res;
619
620        if (!theSelector) return TagSelect_NoMatch;
621        // Special casing for multipolygon roads
622        if (const Road* R = dynamic_cast<const Road*>(F))
623        {
624                // TODO create a isPartOfMultiPolygon(R) function for this
625                for (unsigned int i=0; i<R->sizeParents(); ++i)
626                {
627                        if (const Relation* Parent = dynamic_cast<const Relation*>(R->getParent(i)))
628                                if (Parent->tagValue("type","") == "multipolygon")
629                                        return TagSelect_NoMatch;
630                }
631        }
632        if ((res = theSelector->matches(F)))
633                return res;
634        // Special casing for multipolygon relations
635        if (const Relation* R = dynamic_cast<const Relation*>(F))
636        {
637                for (unsigned int i=0; i<R->size(); ++i)
638                        if ((res = theSelector->matches(R->get(i))))
639                                return res;
640        }
641        return TagSelect_NoMatch;
642}
643
644bool FeaturePainter::matchesZoom(double PixelPerM) const
645{
646        if (ZoomLimitSet)
647                return (ZoomUnder <= PixelPerM) && (PixelPerM <= ZoomUpper);
648        return true;
649}
650/*
651void buildPathFromRoad(Road *R, const Projection &theProjection, QPainterPath &Path)
652{
653        Path.moveTo(theProjection.project(R->get(0)));
654        for (unsigned int i=1; i<R->size(); ++i)
655                Path.lineTo(theProjection.project(R->get(i)));
656}
657
658void buildPathFromRelation(Relation *R, const Projection &theProjection, QPainterPath &Path)
659{
660        for (unsigned int i=0; i<R->size(); ++i)
661                if (Road* M = dynamic_cast<Road*>(R->get(i)))
662                        buildPathFromRoad(M, theProjection, Path);
663}
664
665*/
666void FeaturePainter::drawBackground(Road* R, QPainter& thePainter, const Projection& theProjection) const
667{
668        if (!DrawBackground && !ForegroundFill) return;
669
670        thePainter.setPen(Qt::NoPen);
671        if (DrawBackground)
672        {
673                double PixelPerM = theProjection.pixelPerM();
674                double WW = PixelPerM*R->widthOf()*BackgroundScale+BackgroundOffset;
675                if (WW >= 0)
676                {
677                        QPen thePen(BackgroundColor,WW);
678                        thePen.setCapStyle(Qt::RoundCap);
679                        ////thePainter.strokePath(R->getPath(),thePen);
680                        thePainter.setPen(thePen);
681                }
682        }
683
684        if (ForegroundFill && (R->size() > 2))
685        {
686                thePainter.setBrush(ForegroundFillFillColor);
687        }
688        else
689                thePainter.setBrush(Qt::NoBrush);
690
691        if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
692                thePainter.save();
693                thePainter.setOpacity(qreal(M_PREFS->getAreaOpacity()) / 100);
694        }
695        thePainter.drawPath(R->getPath());
696        if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
697                thePainter.restore();
698        }
699        //thePainter.setBrush(Qt::NoBrush);
700        //thePainter.drawPath(R->getPath());
701        //thePainter.setPen(thePen);
702        //QPointF p1, p2;
703        //p1 = QPointF(R->getPath().elementAt(0));
704        //for (int i=1; i<R->getPath().elementCount(); i++) {
705        //      p2 = QPointF(R->getPath().elementAt(i));
706        //      thePainter.drawLine(p1, p2);
707        //      p1 = p2;
708        //}
709}
710
711void FeaturePainter::drawBackground(Relation* R, QPainter& thePainter, const Projection& /* theProjection */) const
712{
713        if (!DrawBackground) return;
714//      double PixelPerM = theProjection.pixelPerM();
715//      double WW = PixelPerM*widthOf(R)*BackgroundScale+BackgroundOffset;
716        double WW = BackgroundOffset;
717        if (WW < 0) return;
718        QPen thePen(BackgroundColor,WW);
719        thePen.setCapStyle(Qt::RoundCap);
720        thePainter.setPen(thePen);
721        thePainter.setBrush(Qt::NoBrush);
722        thePainter.drawPath(R->getPath());
723}
724
725void FeaturePainter::drawForeground(Road* R, QPainter& thePainter, const Projection& theProjection) const
726{
727        if (!DrawForeground) return;
728
729        double WW = 0.0;
730        if (DrawForeground)
731        {
732                double PixelPerM = theProjection.pixelPerM();
733                WW = PixelPerM*R->widthOf()*ForegroundScale+ForegroundOffset;
734                if (WW < 0) return;
735                QPen thePen(ForegroundColor,WW);
736                thePen.setCapStyle(Qt::RoundCap);
737                if (ForegroundDashSet)
738                {
739                        QVector<qreal> Pattern;
740                        Pattern << ForegroundDash << ForegroundWhite;
741                        thePen.setDashPattern(Pattern);
742                }
743                thePainter.setPen(thePen);
744        }
745        else
746                thePainter.setPen(Qt::NoPen);
747        //if (ForegroundFill && (R->size() > 2))
748        //{
749        //      thePainter.setBrush(ForegroundFillFillColor);
750        //}
751        //else
752                thePainter.setBrush(Qt::NoBrush);
753
754        //if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
755        //      thePainter.save();
756        //      thePainter.setOpacity(qreal(M_PREFS->getAreaOpacity()) / 100);
757        //}
758        //thePainter.drawPath(R->getPath());
759        //if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
760        //      thePainter.restore();
761        //}
762        thePainter.drawPath(R->getPath());
763}
764
765void FeaturePainter::drawForeground(Relation* R, QPainter& thePainter, const Projection& /* theProjection */) const
766{
767        if (!DrawForeground && !ForegroundFill) return;
768
769        double WW = 0.0;
770        if (DrawForeground)
771        {
772//              double PixelPerM = theProjection.pixelPerM();
773//              double WW = PixelPerM*widthOf(R)*ForegroundScale+ForegroundOffset;
774                WW = ForegroundOffset;
775                if (WW < 0) return;
776                QPen thePen(ForegroundColor,WW);
777                thePen.setCapStyle(Qt::RoundCap);
778                if (ForegroundDashSet)
779                {
780                        QVector<qreal> Pattern;
781                        Pattern << ForegroundDash << ForegroundWhite;
782                        thePen.setDashPattern(Pattern);
783                }
784                thePainter.setPen(thePen);
785        }
786        else
787                thePainter.setPen(Qt::NoPen);
788        if (ForegroundFill)
789        {
790                thePainter.setBrush(ForegroundFillFillColor);
791        }
792        else
793                thePainter.setBrush(Qt::NoBrush);
794
795        if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
796                thePainter.save();
797                thePainter.setOpacity(qreal(M_PREFS->getAreaOpacity()) / 100);
798        }
799        thePainter.drawPath(R->getPath());
800        if (M_PREFS->getAreaOpacity() != 100 && ForegroundFill) {
801                thePainter.restore();
802        }
803}
804
805
806void FeaturePainter::drawTouchup(TrackPoint* Pt, QPainter& thePainter, const Projection& theProjection) const
807{
808        bool IconError = false;
809        if (DrawIcon && (IconName != "") )
810        {
811                double PixelPerM = theProjection.pixelPerM();
812                double WW = PixelPerM*IconScale+IconOffset;
813
814        QPixmap pm = getPixmapFromFile(IconName,int(WW));
815                if (pm.isNull())
816                        IconError = true;
817                else {
818                        QPoint C(theProjection.project(Pt));
819                        // cbro-20090109: Don't draw the dot if there is an icon
820                        // thePainter.fillRect(QRect(C-QPoint(2,2),QSize(4,4)),QColor(0,0,0,128));
821                        thePainter.drawPixmap( int(C.x()-pm.width()/2), int(C.y()-pm.height()/2) , pm);
822                }
823        }
824        if (!DrawIcon || (IconName == "") || IconError) 
825        {
826                QColor theColor = QColor(0,0,0,128);
827                if (DrawForeground)
828                        theColor = ForegroundColor;
829                else 
830                        if (DrawBackground)
831                                theColor =BackgroundColor;
832
833                QPointF P(theProjection.project(Pt));
834                if (Pt->findKey("_waypoint_") != Pt->tagSize()) {
835                        QRectF R(P-QPointF(4,4),QSize(8,8)); 
836                        thePainter.fillRect(R,QColor(255,0,0,128)); 
837                }
838               
839                QRectF R(P-QPointF(2,2),QSize(4,4));
840                        thePainter.fillRect(R,theColor);
841        }
842}
843
844void FeaturePainter::drawTouchup(Road* R, QPainter& thePainter, const Projection& theProjection) const
845{
846        if (DrawTouchup)
847        {
848                double PixelPerM = theProjection.pixelPerM();
849                double WW = PixelPerM*R->widthOf()*TouchupScale+TouchupOffset;
850                if (WW > 0)
851                {
852                        QPen thePen(TouchupColor,WW);
853                        thePen.setCapStyle(Qt::FlatCap);
854                        if (TouchupDashSet)
855                        {
856                                QVector<qreal> Pattern;
857                                Pattern << TouchupDash << TouchupWhite;
858                                thePen.setDashPattern(Pattern);
859                        }
860                        thePainter.strokePath(R->getPath(),thePen);
861                }
862        }
863        if ( ((DrawTrafficDirectionMarks) && (M_PREFS->getDirectionalArrowsVisible() == DirectionalArrows_Oneway)) ||  M_PREFS->getDirectionalArrowsVisible() == DirectionalArrows_Always)
864        {
865                MapFeature::TrafficDirectionType TT = trafficDirection(R);
866                if ( (TT != MapFeature::UnknownDirection) || (M_PREFS->getDirectionalArrowsVisible() == DirectionalArrows_Always) ) 
867                {
868                        double theWidth = theProjection.pixelPerM()*R->widthOf()-4;
869                        if (theWidth > 8)
870                                theWidth = 8;
871                        double DistFromCenter = 2*(theWidth+4);
872                        if (theWidth > 0)
873                        {
874                                for (unsigned int i=1; i<R->size(); ++i)
875                                {
876                                        QPointF FromF(theProjection.project(R->getNode(i-1)));
877                                        QPointF ToF(theProjection.project(R->getNode(i)));
878                                        if (distance(FromF,ToF) > (DistFromCenter*2+4))
879                                        {
880                                                QPointF H(FromF+ToF);
881                                                H *= 0.5;
882                                                double A = angle(FromF-ToF);
883                                                QPointF T(DistFromCenter*cos(A),DistFromCenter*sin(A));
884                                                QPointF V1(theWidth*cos(A+M_PI/6),theWidth*sin(A+M_PI/6));
885                                                QPointF V2(theWidth*cos(A-M_PI/6),theWidth*sin(A-M_PI/6));
886                                                if ( M_PREFS->getDirectionalArrowsVisible() == DirectionalArrows_Oneway )
887                                                {
888                                                        if ( (TT == MapFeature::OtherWay) || (TT == MapFeature::BothWays) )
889                                                        {
890                                                                thePainter.setPen(QColor(0,0,0));
891                                                                thePainter.drawLine(H+T,H+T-V1);
892                                                                thePainter.drawLine(H+T,H+T-V2);
893                                                        }
894                                                        if ( (TT == MapFeature::OneWay) || (TT == MapFeature::BothWays) )
895                                                        {
896                                                                thePainter.setPen(QColor(0,0,0));
897                                                                thePainter.drawLine(H-T,H-T+V1);
898                                                                thePainter.drawLine(H-T,H-T+V2);
899                                                        }
900                                                } 
901                                                else
902                                                {
903                                                        thePainter.setPen(QColor(255,0,0));
904                                                        thePainter.drawLine(H-T,H-T+V1);
905                                                        thePainter.drawLine(H-T,H-T+V2);
906                                                }
907                                        }
908                                }
909                        }
910                }
911        }
912}
913
914#define LABEL_PATH_DISTANCE 3
915#define LABEL_STRAIGHT_DISTANCE 50
916#define BG_SPACING 6
917#define BG_PEN_SZ 2
918
919void FeaturePainter::drawPointLabel(QPoint C, QString str, QString strBg, QPainter& thePainter, const Projection& theProjection) const
920{
921        LineParameters lp = labelBoundary();
922        double PixelPerM = theProjection.pixelPerM();
923        double WW = PixelPerM*lp.Proportional+lp.Fixed;
924        if (WW < 10) return;
925
926        QFont font = getLabelFont();
927        font.setPixelSize(int(WW));
928    QFontMetrics metrics(font);
929
930        int modX = 0;
931        int modY = 0;
932        QPainterPath textPath;
933        QPainterPath bgPath;
934
935        if (!str.isEmpty()) {
936                modX = - (metrics.width(str)/2);
937                if (DrawIcon && (IconName != "") )
938                {
939                        QPixmap pm(IconName);
940                        modY = - pm.height();
941                        if (DrawLabelBackground)
942                                modY -= BG_SPACING;
943                }
944
945                thePainter.save();
946
947                textPath.addText(modX, modY, font, str);
948                thePainter.translate(C);
949
950        }
951        if (DrawLabelBackground && !strBg.isEmpty()) {
952                modX = - (metrics.width(strBg)/2);
953                if (DrawIcon && (IconName != "") )
954                {
955                        QPixmap pm(IconName);
956                        modY = - pm.height();
957                        if (DrawLabelBackground)
958                                modY -= BG_SPACING;
959                }
960
961                thePainter.save();
962                textPath.addText(modX, modY, font, strBg);
963                thePainter.translate(C);
964
965                bgPath.addRect(textPath.boundingRect().adjusted(-BG_SPACING, -BG_SPACING, BG_SPACING, BG_SPACING));
966                thePainter.setPen(QPen(LabelColor, BG_PEN_SZ));
967                thePainter.setBrush(LabelBackgroundColor);
968                thePainter.drawPath(bgPath);
969        }
970        if (getLabelHalo()) {
971                thePainter.setPen(QPen(Qt::white, font.pixelSize()/5));
972                thePainter.drawPath(textPath);
973        }
974        thePainter.setPen(Qt::NoPen);
975        thePainter.setBrush(LabelColor);
976        thePainter.drawPath(textPath);
977
978        thePainter.restore();
979
980        if (DrawLabelBackground && !strBg.isEmpty()) {
981                QRegion rg = thePainter.clipRegion();
982                rg -= textPath.boundingRect().toRect().translated(C);
983                thePainter.setClipRegion(rg);
984        }
985}
986
987
988void FeaturePainter::drawLabel(TrackPoint* Pt, QPainter& thePainter, const Projection& theProjection) const
989{
990        if (!DrawLabel)
991                return;
992
993        QString str = Pt->tagValue(getLabelTag(), "");
994        QString strBg = Pt->tagValue(getLabelBackgroundTag(), "");
995
996        if (str.isEmpty() && strBg.isEmpty())
997                return;
998
999        QPoint C(theProjection.project(Pt));
1000        drawPointLabel(C, str, strBg, thePainter, theProjection);
1001}
1002
1003void FeaturePainter::drawLabel(Road* R, QPainter& thePainter, const Projection& theProjection) const
1004{
1005        if (!DrawLabel)
1006                return;
1007
1008        QString str = R->tagValue(getLabelTag(), "");
1009        QString strBg = R->tagValue(getLabelBackgroundTag(), "");
1010        if (str.isEmpty() && strBg.isEmpty())
1011                return;
1012
1013        if (getLabelArea()) {
1014                QPoint C(theProjection.project(R->boundingBox().center()));
1015                drawPointLabel(C, str, strBg, thePainter, theProjection);
1016                return;
1017        }
1018
1019        LineParameters lp = labelBoundary();
1020        double PixelPerM = theProjection.pixelPerM();
1021        double WW = PixelPerM*R->widthOf()*lp.Proportional+lp.Fixed;
1022        if (WW < 10) return;
1023        //double WWR = qMax(PixelPerM*R->widthOf()*BackgroundScale+BackgroundOffset, PixelPerM*R->widthOf()*ForegroundScale+ForegroundOffset);
1024
1025        QPainterPath textPath;
1026    QFont font = getLabelFont();
1027
1028        if (!str.isEmpty()) {
1029                QRegion rg = thePainter.clipRegion();
1030                font.setPixelSize(int(WW));
1031                QFontMetrics metrics(font);
1032
1033                if (font.pixelSize() >= 5 && R->getPath().length() > metrics.width(str)) {
1034                        thePainter.setFont(font);
1035
1036                        int repeat = int((R->getPath().length() / ((metrics.width(str) * LABEL_PATH_DISTANCE))) - 0.5);
1037                        int numSegment = repeat+1;
1038                        qreal lenSegment = R->getPath().length() / numSegment;
1039                        qreal startSegment = 0;
1040                        QPainterPath textPath;
1041                        do {
1042                                QRegion rg = thePainter.clipRegion();
1043
1044                                qreal curLen = startSegment + ((lenSegment - metrics.width(str)) / 2);
1045                                int modIncrement = 1;
1046                                qreal modAngle = 0;
1047                                int modY = 0;
1048                                if (cos(angToRad(R->getPath().angleAtPercent((startSegment+(lenSegment/2))/R->getPath().length()))) < 0) {
1049                                        modIncrement = -1;
1050                                        modAngle = 180.0;
1051                                        curLen += metrics.width(str);
1052                                }
1053                                for (int i = 0; i < str.length(); ++i) {
1054                                        qreal t = R->getPath().percentAtLength(curLen);
1055                                        QPointF pt = R->getPath().pointAtPercent(t);
1056                                        qreal angle = R->getPath().angleAtPercent(t);
1057                                        modY = (metrics.ascent()/2)-3;
1058
1059                                        QMatrix m;
1060                                        m.translate(pt.x(), pt.y());
1061                                        m.rotate(-angle+modAngle);
1062
1063                                        QPainterPath charPath;
1064                                        charPath.addText(0, modY, font, str.mid(i, 1));
1065                                        charPath = charPath * m;
1066                                       
1067                                        textPath.addPath(charPath);
1068
1069                                        qreal incremenet = metrics.width(str[i]);
1070                                        curLen += (incremenet * modIncrement);
1071                                }
1072                                startSegment += lenSegment;
1073                        } while (--repeat >= 0);
1074
1075                        if (getLabelHalo()) {
1076                                thePainter.setPen(QPen(Qt::white, font.pixelSize()/6));
1077                                thePainter.drawPath(textPath);
1078                        }
1079                        thePainter.setPen(Qt::NoPen);
1080                        thePainter.setBrush(LabelColor);
1081                        thePainter.drawPath(textPath);
1082                        thePainter.setClipRegion(rg);
1083                }
1084        }
1085        if (DrawLabelBackground && !strBg.isEmpty()) {
1086                QRegion rg = thePainter.clipRegion();
1087                font.setPixelSize(int(WW));
1088                QFontMetrics metrics(font);
1089
1090                int repeat = int((R->getPath().length() / (metrics.width(strBg) * LABEL_STRAIGHT_DISTANCE)) - 0.5);
1091                int numSegment = repeat+1;
1092                qreal lenSegment = R->getPath().length() / numSegment;
1093                qreal startSegment = 0;
1094                do {
1095
1096                        int modX = 0;
1097                        int modY = 0;
1098
1099                        qreal curLen = startSegment + (lenSegment / 2);
1100                        qreal t = R->getPath().percentAtLength(curLen);
1101                        QPointF pt = R->getPath().pointAtPercent(t);
1102
1103                        modX = - (metrics.width(strBg)/2);
1104                        //modX = WW;
1105                        modY = (metrics.ascent()/2);
1106
1107                        QPainterPath textPath, bgPath;
1108                        textPath.addText(modX, modY, font, strBg);
1109                        bgPath.addRect(textPath.boundingRect().adjusted(-BG_SPACING, -BG_SPACING, BG_SPACING, BG_SPACING));
1110
1111                        bool rgContains = false;
1112                        for (int i=0; i<rg.rects().size(); i++) {
1113                                if (rg.rects()[i].contains(bgPath.boundingRect().toRect().translated(pt.toPoint()))) {
1114                                        rgContains = true;
1115                                        break;
1116                                }
1117                        }
1118                        if (rgContains) {
1119                                thePainter.save();
1120                                thePainter.translate(pt);
1121
1122                                thePainter.setPen(QPen(LabelColor, BG_PEN_SZ));
1123                                thePainter.setBrush(LabelBackgroundColor);
1124                                thePainter.drawPath(bgPath);
1125
1126                                if (getLabelHalo()) {
1127                                        thePainter.setPen(QPen(Qt::white, font.pixelSize()/5));
1128                                        thePainter.drawPath(textPath);
1129                                }
1130                                thePainter.setPen(Qt::NoPen);
1131                                thePainter.setBrush(LabelColor);
1132                                thePainter.drawPath(textPath);
1133
1134                                thePainter.restore();
1135
1136                                rg -= bgPath.boundingRect().toRect().translated(pt.toPoint());
1137                        }
1138
1139                        startSegment += lenSegment;
1140                } while (--repeat >= 0);
1141
1142                thePainter.setClipRegion(rg);
1143        }
1144}
1145
1146/* GlobalPainter */
1147
1148GlobalPainter::GlobalPainter()
1149: DrawBackground(false)
1150{
1151}
1152
1153GlobalPainter::GlobalPainter(const GlobalPainter& f)
1154: DrawBackground(f.DrawBackground), BackgroundColor(f.BackgroundColor)
1155{
1156}
1157
1158GlobalPainter& GlobalPainter::operator=(const GlobalPainter& f)
1159{
1160        if (&f == this) return *this;
1161
1162        DrawBackground = f.DrawBackground;
1163        BackgroundColor = f.BackgroundColor;
1164
1165        return *this;
1166}
1167
1168GlobalPainter::~GlobalPainter()
1169{
1170}
1171
1172QString GlobalPainter::toXML() const
1173{
1174        QString r;
1175        r += "<global\n";
1176        if (DrawBackground)
1177                r += " " + colorAsXML("background",BackgroundColor);
1178        r += "/>\n";
1179        return r;
1180}
1181
1182GlobalPainter GlobalPainter::fromXML(const QDomElement& e)
1183{
1184        GlobalPainter FP;
1185
1186        if (e.hasAttribute("backgroundColor")) {
1187                FP.backgroundActive(true);
1188                FP.background(toColor(e.attribute("backgroundColor")));
1189        }
1190
1191        return FP;
1192}
1193
1194GlobalPainter& GlobalPainter::backgroundActive(bool b)
1195{
1196        DrawBackground = b;
1197        return *this;
1198}
1199
1200bool GlobalPainter::getDrawBackground() const
1201{
1202        return DrawBackground;
1203}
1204
1205GlobalPainter& GlobalPainter::background(QColor Color)
1206{
1207        DrawBackground = true;
1208        BackgroundColor = Color;
1209        return *this;
1210}
1211
1212QColor GlobalPainter::getBackgroundColor() const
1213{
1214        return BackgroundColor;
1215}
1216
1217/* */
1218
1219PaintStyleLayer::~PaintStyleLayer()
1220{
1221}
1222
1223void PaintStyle::add(PaintStyleLayer *aLayer)
1224{
1225        Layers.push_back(aLayer);
1226}
1227
1228unsigned int PaintStyle::size() const
1229{
1230        return Layers.size();
1231}
1232
1233PaintStyleLayer* PaintStyle::get(unsigned int i)
1234{
1235        return Layers[i];
1236}
1237
1238
1239
Note: See TracBrowser for help on using the repository browser.