1
#include "Map/MapFeature.h"
2
#include "Map/Relation.h"
4
#include "Map/TrackPoint.h"
5
#include "Command/Command.h"
6
#include "Command/DocumentCommands.h"
7
#include "Command/FeatureCommands.h"
8
#include "Command/RelationCommands.h"
9
#include "Command/RoadCommands.h"
10
#include "Command/TrackPointCommands.h"
11
#include "Map/MapDocument.h"
12
#include "Map/MapLayer.h"
13
#include "PaintStyle/EditPaintStyle.h"
14
#include "PaintStyle/TagSelector.h"
16
#include <QtCore/QUuid>
17
#include <QProgressDialog>
21
const QString encodeAttributes(const QString & text);
23
static QString randomId()
25
return QUuid::createUuid().toString();
28
void copyTags(MapFeature* Dest, MapFeature* Src)
30
for (unsigned int i=0; i<Src->tagSize(); ++i)
31
Dest->setTag(Src->tagKey(i),Src->tagValue(i));
34
class MapFeaturePrivate
38
: TagsSize(0), LastActor(MapFeature::User), theLayer(0),
39
PossiblePaintersUpToDate(false),
40
PixelPerMForPainter(-1), CurrentPainter(0), HasPainter(false),
41
theFeature(0), LastPartNotification(0),
42
Time(QDateTime::currentDateTime()), Deleted(false), Uploaded(false)
45
parentDashes << 1 << 5;
47
MapFeaturePrivate(const MapFeaturePrivate& other)
48
: Tags(other.Tags), TagsSize(other.TagsSize), LastActor(other.LastActor), theLayer(0),
49
PossiblePaintersUpToDate(false),
50
PixelPerMForPainter(-1), CurrentPainter(0), HasPainter(false),
51
theFeature(0), LastPartNotification(0),
52
Time(other.Time), Deleted(false), Uploaded(false)
55
parentDashes << 1 << 5;
58
void updatePainters(double PixelPerM);
59
void blankPainters(double PixelPerM);
60
void initVersionNumber();
63
std::vector<std::pair<QString, QString> > Tags;
64
unsigned int TagsSize;
65
MapFeature::ActorType LastActor;
67
QVector<const FeaturePainter*> PossiblePainters;
68
bool PossiblePaintersUpToDate;
69
double PixelPerMForPainter;
70
const FeaturePainter* CurrentPainter;
72
MapFeature* theFeature;
73
std::vector<MapFeature*> Parents;
74
unsigned int LastPartNotification;
78
QVector<qreal> parentDashes;
84
void MapFeaturePrivate::initVersionNumber()
90
MapFeature::MapFeature()
93
p = new MapFeaturePrivate;
97
MapFeature::MapFeature(const MapFeature& other) : QObject()
99
p = new MapFeaturePrivate(*other.p);
100
p->theFeature = this;
103
MapFeature::~MapFeature(void)
105
while (sizeParents())
106
getParent(0)->remove(this);
108
p->theLayer->notifyIdUpdate(p->Id,0);
112
void MapFeature::setVersionNumber(int vn)
114
p->VersionNumber = vn;
117
int MapFeature::versionNumber() const
119
return p->VersionNumber;
122
void MapFeature::setLayer(MapLayer* aLayer)
124
p->theLayer = aLayer;
128
MapLayer* MapFeature::layer()
133
void MapFeature::setLastUpdated(MapFeature::ActorType A)
138
MapFeature::ActorType MapFeature::lastUpdated() const
140
if (p->theLayer->className() == "DirtyMapLayer")
141
return MapFeature::User;
146
void MapFeature::setId(const QString& id)
150
p->theLayer->notifyIdUpdate(p->Id,0);
151
p->theLayer->notifyIdUpdate(id,this);
156
const QString& MapFeature::id() const
162
p->theLayer->notifyIdUpdate(p->Id,const_cast<MapFeature*>(this));
167
qint64 MapFeature::idToLong() const
172
QString s = stripToOSMId(id());
173
qint64 l = s.toLongLong(&ok);
177
return (((qint64)this) * -1);
181
QString MapFeature::xmlId() const
183
return stripToOSMId(id());
186
bool MapFeature::hasOSMId() const
188
if (p->Id.left(5) == "node_")
190
if (p->Id.left(4) == "way_")
192
if (p->Id.left(4) == "rel_")
197
const QDateTime& MapFeature::time() const
202
void MapFeature::setTime(const QDateTime& time)
208
const QString& MapFeature::user() const
213
void MapFeature::setUser(const QString& user)
219
bool MapFeature::isDirty() const
221
return (p->theLayer->className() == "DirtyMapLayer");
224
void MapFeature::setUploaded(bool state)
229
bool MapFeature::isUploaded() const
234
bool MapFeature::isUploadable() const
236
return (p->theLayer->isUploadable());
239
void MapFeature::setDeleted(bool delState)
241
p->Deleted = delState;
244
bool MapFeature::isDeleted() const
249
void MapFeature::setTag(unsigned int index, const QString& key, const QString& value, bool addToTagList)
253
p->PixelPerMForPainter = -1;
254
for (i=0; i<p->Tags.size(); ++i)
255
if (p->Tags[i].first == key)
257
p->Tags[i].second = value;
260
if (i == p->Tags.size()) {
261
p->Tags.insert(p->Tags.begin() + index, std::make_pair(key,value));
264
if (p->theLayer && addToTagList)
265
if (p->theLayer->getDocument())
266
p->theLayer->getDocument()->addToTagList(key, value);
270
void MapFeature::setTag(const QString& key, const QString& value, bool addToTagList)
272
p->PixelPerMForPainter = -1;
273
for (unsigned int i=0; i<p->Tags.size(); ++i)
274
if (p->Tags[i].first == key)
276
p->Tags[i].second = value;
280
p->Tags.push_back(std::make_pair(key,value));
282
if (p->theLayer && addToTagList)
283
if (p->theLayer->getDocument())
284
p->theLayer->getDocument()->addToTagList(key, value);
288
void MapFeature::clearTags()
290
p->PixelPerMForPainter = -1;
296
void MapFeature::invalidatePainter()
298
p->PossiblePaintersUpToDate = false;
299
p->PixelPerMForPainter = -1;
302
void MapFeature::clearTag(const QString& k)
304
for (unsigned int i=0; i<p->Tags.size(); ++i)
305
if (p->Tags[i].first == k)
307
p->PixelPerMForPainter = -1;
308
p->Tags.erase(p->Tags.begin()+i);
315
void MapFeature::removeTag(unsigned int idx)
317
p->PixelPerMForPainter = -1;
318
p->Tags.erase(p->Tags.begin()+idx);
323
unsigned int MapFeature::tagSize() const
328
QString MapFeature::tagValue(unsigned int i) const
330
return p->Tags[i].second;
333
QString MapFeature::tagKey(unsigned int i) const
335
return p->Tags[i].first;
338
unsigned int MapFeature::findKey(const QString &k) const
340
for (unsigned int i=0; i<p->TagsSize; ++i)
341
if (p->Tags[i].first == k)
343
return p->Tags.size();
346
QString MapFeature::tagValue(const QString& k, const QString& Default) const
348
for (unsigned int i=0; i<p->TagsSize; ++i)
349
if (p->Tags[i].first == k)
350
return p->Tags[i].second;
354
void MapFeaturePrivate::updatePainters(double PixelPerM)
356
//if the object has no tags or only the created_by tag, we don't check for style
357
//search is about 15 times faster like that !!!
358
//However, still match features with no tags and no parent, i.e. "lost" trackpoints
359
if ( (theFeature->layer()->isTrack()) && MerkaartorPreferences::instance()->getDisableStyleForTracks() ) return blankPainters(PixelPerM);
361
if ( (theFeature->layer()->isTrack()) || theFeature->sizeParents() ) {
363
for (i=0; i<theFeature->tagSize(); ++i)
364
if ((theFeature->tagKey(i) != "created_by") && (theFeature->tagKey(i) != "ele"))
367
if (i == theFeature->tagSize()) return blankPainters(PixelPerM);
370
if (PixelPerMForPainter < 0)
372
PossiblePainters.clear();
373
QVector<const FeaturePainter*> DefaultPainters;
374
for (int i=0; i<M_STYLE->painterSize(); ++i)
376
const FeaturePainter* Current = M_STYLE->getPainter(i);
377
switch (Current->matchesTag(theFeature)) {
378
case TagSelect_Match:
379
PossiblePainters.push_back(Current);
381
case TagSelect_DefaultMatch:
382
DefaultPainters.push_back(Current);
388
if (!PossiblePainters.size())
389
PossiblePainters = DefaultPainters;
390
PossiblePaintersUpToDate = true;
391
HasPainter = PossiblePainters.size();
394
PixelPerMForPainter = PixelPerM;
395
for (int i=0; i<PossiblePainters.size(); ++i)
396
if (PossiblePainters[i]->matchesZoom(PixelPerM))
398
CurrentPainter = PossiblePainters[i];
403
void MapFeaturePrivate::blankPainters(double PixelPerM)
406
PixelPerMForPainter = PixelPerM;
407
PossiblePainters.clear();
411
const FeaturePainter* MapFeature::getEditPainter(double PixelPerM) const
413
if (p->PixelPerMForPainter != PixelPerM)
414
p->updatePainters(PixelPerM);
415
return p->CurrentPainter;
418
const FeaturePainter* MapFeature::getCurrentEditPainter() const
420
return p->CurrentPainter;
423
bool MapFeature::hasEditPainter() const
425
return p->HasPainter;
428
void MapFeature::setParent(MapFeature* F)
430
if (std::find(p->Parents.begin(),p->Parents.end(),F) == p->Parents.end())
431
p->Parents.push_back(F);
434
void MapFeature::unsetParent(MapFeature* F)
436
for (unsigned int i=0; i<p->Parents.size(); ++i)
437
if (p->Parents[i] == F)
439
p->Parents.erase(p->Parents.begin()+i);
444
unsigned int MapFeature::sizeParents() const
446
return p->Parents.size();
449
MapFeature* MapFeature::getParent(unsigned int i)
451
return p->Parents[i];
454
const MapFeature* MapFeature::getParent(unsigned int i) const
456
return p->Parents[i];
460
void MapFeature::notifyChanges()
462
static unsigned int Id = 0;
465
p->theLayer->invalidateRenderPriority();
468
void MapFeature::notifyParents(unsigned int Id)
470
if (Id != p->LastPartNotification)
472
p->LastPartNotification = Id;
473
for (unsigned int i=0; i<p->Parents.size(); ++i)
474
p->Parents[i]->partChanged(this, Id);
478
QString MapFeature::tagsToXML(unsigned int lvl)
481
for (unsigned int i=0; i<tagSize(); ++i)
483
S += QString(lvl*2, ' ') + QString("<tag k=\"%1\" v=\"%2\"/>\n").arg(encodeAttributes(tagKey(i))).arg(encodeAttributes(tagValue(i)));
488
bool MapFeature::tagsToXML(QDomElement xParent)
492
for (unsigned int i=0; i<tagSize(); ++i)
494
QDomElement e = xParent.ownerDocument().createElement("tag");
495
xParent.appendChild(e);
497
e.setAttribute("k", tagKey(i));
498
e.setAttribute("v", tagValue(i));
504
void MapFeature::tagsFromXML(MapDocument* d, MapFeature * f, QDomElement e)
507
QDomElement c = e.firstChildElement();
509
if (c.tagName() == "tag") {
510
f->setTag(c.attribute("k"),c.attribute("v"));
512
c = c.nextSiblingElement();
516
QString MapFeature::stripToOSMId(const QString& id)
518
int f = id.lastIndexOf("_");
520
return id.right(id.length()-(f+1));
524
QVector<qreal> MapFeature::getParentDashes() const
526
return p->parentDashes;
529
Relation * MapFeature::GetSingleParentRelation(MapFeature * mapFeature)
531
unsigned int parents = mapFeature->sizeParents();
536
Relation * parentRelation = NULL;
539
for (i=0; i<parents; i++)
541
MapFeature * parent = mapFeature->getParent(i);
542
Relation * rel = dynamic_cast<Relation*>(parent);
550
if (rel->layer()->isEnabled())
551
parentRelation = rel;
554
return parentRelation;
558
TrackPoint* MapFeature::getTrackPointOrCreatePlaceHolder(MapDocument *theDocument, MapLayer *theLayer, const QString& Id)
560
TrackPoint* Part = dynamic_cast<TrackPoint*>(theDocument->getFeature("node_"+Id));
563
Part = dynamic_cast<TrackPoint*>(theDocument->getFeature(Id));
566
Part = new TrackPoint(Coord(0,0));
567
if (Id.startsWith('{'))
570
Part->setId("node_"+Id);
571
Part->setLastUpdated(MapFeature::NotYetDownloaded);
578
Road* MapFeature::getWayOrCreatePlaceHolder(MapDocument *theDocument, MapLayer *theLayer, const QString& Id)
580
Road* Part = dynamic_cast<Road*>(theDocument->getFeature("way_"+Id));
583
Part = dynamic_cast<Road*>(theDocument->getFeature(Id));
587
if (Id.startsWith('{'))
590
Part->setId("way_"+Id);
591
Part->setLastUpdated(MapFeature::NotYetDownloaded);
598
Relation* MapFeature::getRelationOrCreatePlaceHolder(MapDocument *theDocument, MapLayer *theLayer, const QString& Id)
600
Relation* Part = dynamic_cast<Relation*>(theDocument->getFeature("rel_"+Id));
603
Part = dynamic_cast<Relation*>(theDocument->getFeature(Id));
607
if (Id.startsWith('{'))
610
Part->setId("rel_"+Id);
611
Part->setLastUpdated(MapFeature::NotYetDownloaded);
618
void MapFeature::mergeTags(MapDocument* theDocument, CommandList* L, MapFeature* Dest, MapFeature* Src)
620
for (unsigned int i=0; i<Src->tagSize(); ++i)
622
QString k = Src->tagKey(i);
623
QString v1 = Src->tagValue(i);
624
unsigned int j = Dest->findKey(k);
625
if (j == Dest->tagSize())
626
L->add(new SetTagCommand(Dest,k,v1, theDocument->getDirtyOrOriginLayer(Dest->layer())));
629
QString v2 = Dest->tagValue(j);
630
if (v1 != v2 && k !="created_by")
632
L->add(new SetTagCommand(Dest,k,QString("%1;%2").arg(v2).arg(v1), theDocument->getDirtyOrOriginLayer(Dest->layer())));
639
QString MapFeature::toMainHtml(QString type, QString systemtype)
642
QString name(tagValue("name",""));
644
desc = QString("<big><b>%1</b></big><br/><small>(%2)</small>").arg(name).arg(id());
646
desc = QString("<big><b>%1</b></big>").arg(id());
649
"<html><head/><body>"
650
"<small><i>" + type + "</i></small><br/>"
654
if (!user().isEmpty())
655
S += QApplication::translate("MapFeature", "<i>last: </i><b>%1</b> by <b>%2</b>").arg(time().toString(Qt::SystemLocaleDate)).arg(user());
657
S += QApplication::translate("MapFeature", "<i>last: </i><b>%1</b>").arg(time().toString(Qt::SystemLocaleDate));
661
int f = id().lastIndexOf("_");
664
"<a href='/api/" + M_PREFS->apiVersion() + "/" + systemtype + "/" + xmlId() + "/history'>"+QApplication::translate("MapFeature", "History")+"</a>";
665
if (systemtype == "node") {
667
"<a href='/api/" + M_PREFS->apiVersion() + "/" + systemtype + "/" + xmlId() + "/ways'>"+QApplication::translate("MapFeature", "Referenced by ways")+"</a>";
670
"<a href='/api/" + M_PREFS->apiVersion() + "/" + systemtype + "/" + xmlId() + "/relations'>"+QApplication::translate("MapFeature", "Referenced by relation")+"</a>";
672
S += "</body></html>";
677
bool MapFeature::QRectInterstects(const QRect& r, const QLine& l, QPoint& a, QPoint& b)
679
QLineF lF = QLineF(l);
684
if (QLineF(r.topLeft(), r.bottomLeft()).intersect(lF, &pF) == QLineF::BoundedIntersection) {
688
if (QLineF(r.bottomLeft(), r.bottomRight()).intersect(lF, &pF) == QLineF::BoundedIntersection) {
697
if (QLineF(r.bottomRight(), r.topRight()).intersect(lF, &pF) == QLineF::BoundedIntersection) {
706
if (QLineF(r.topRight(), r.topLeft()).intersect(lF, &pF) == QLineF::BoundedIntersection) {
716
if (hasP1 && hasP2) {
717
#if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0))
718
double la1 = QLineF(a,b).angleTo(lF);
720
double la1 = QLineF(a,b).angle(lF);
722
if (la1 > 15.0 && la1 < 345.0) {