GeoDataPlacemark.cpp 13.9 KB
Newer Older
Torsten Rahn's avatar
Torsten Rahn committed
1
//
2
// This file is part of the Marble Virtual Globe.
Torsten Rahn's avatar
Torsten Rahn committed
3 4 5 6 7
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
Jens-Michael Hoffmann's avatar
Jens-Michael Hoffmann committed
8 9
// Copyright 2004-2007 Torsten Rahn <tackat@kde.org>
// Copyright 2007      Inge Wallin  <ingwa@kde.org>
Patrick Spendrin's avatar
Patrick Spendrin committed
10
// Copyright 2008-2009      Patrick Spendrin <ps_ml@gmx.de>
Torsten Rahn's avatar
Torsten Rahn committed
11 12 13
//


14
// Own
15
#include "GeoDataPlacemark.h"
Torsten Rahn's avatar
Torsten Rahn committed
16

Bruno Bigras's avatar
Bruno Bigras committed
17 18 19
// Private
#include "GeoDataPlacemark_p.h"

20
#include "GeoDataMultiGeometry.h"
21
#include "GeoDataCoordinates.h"
22
#include "osm/OsmPlacemarkData.h"
23

24
// Qt
25
#include <QDataStream>
26
#include "MarbleDebug.h"
27
#include "GeoDataTrack.h"
28
#include "GeoDataModel.h"
29
#include <QString>
30
#include <QXmlStreamWriter>
31

32
namespace Marble
Claudiu Covaci's avatar
Claudiu Covaci committed
33
{
Patrick Spendrin's avatar
Patrick Spendrin committed
34
GeoDataPlacemark::GeoDataPlacemark()
35
    : GeoDataFeature( new GeoDataPlacemarkPrivate )
Torsten Rahn's avatar
Torsten Rahn committed
36
{
37
    p()->m_geometry->setParent( this );
Torsten Rahn's avatar
Torsten Rahn committed
38 39
}

40
GeoDataPlacemark::GeoDataPlacemark( const GeoDataPlacemark& other )
41
    : GeoDataFeature( other )
42
{
43 44 45 46 47 48
    // FIXME: temporary (until detach() is called) violates following invariant
    // which could lead to crashes
//    Q_ASSERT( this == p()->m_geometry->parent() );

    // FIXME: fails as well when "other" is a copy where detach wasn't called
//    Q_ASSERT( other.p()->m_geometry == 0 || &other == other.p()->m_geometry->parent() );
49 50
}

Patrick Spendrin's avatar
Patrick Spendrin committed
51
GeoDataPlacemark::GeoDataPlacemark( const QString& name )
52
    : GeoDataFeature( new GeoDataPlacemarkPrivate )
Claudiu Covaci's avatar
Claudiu Covaci committed
53
{
54
    d->m_name = name;
55
    p()->m_geometry->setParent( this );
Claudiu Covaci's avatar
Claudiu Covaci committed
56 57 58
}

GeoDataPlacemark::~GeoDataPlacemark()
Torsten Rahn's avatar
Torsten Rahn committed
59
{
60
    // nothing to do
Torsten Rahn's avatar
Torsten Rahn committed
61 62
}

63 64
GeoDataPlacemark &GeoDataPlacemark::operator=( const GeoDataPlacemark &other )
{
65
    GeoDataFeature::operator=( other );
66 67 68 69

    return *this;
}

70 71
bool GeoDataPlacemark::operator==( const GeoDataPlacemark& other ) const
{ 
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    if ( !equals(other) ||
         p()->m_countrycode != other.p()->m_countrycode ||
         p()->m_area != other.p()->m_area ||
         p()->m_population != other.p()->m_population ||
         p()->m_state != other.p()->m_state ) {
        return false;
    }

    if ( !p()->m_geometry && !other.p()->m_geometry ) {
        return true;
    } else if ( (!p()->m_geometry && other.p()->m_geometry) ||
                (p()->m_geometry && !other.p()->m_geometry) ) {
        return false;
    }

    if ( p()->m_geometry->nodeType() != other.p()->m_geometry->nodeType() ) {
        return false;
    }

    if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
        GeoDataPolygon *thisPoly = dynamic_cast<GeoDataPolygon*>( p()->m_geometry );
        GeoDataPolygon *otherPoly = dynamic_cast<GeoDataPolygon*>( other.p()->m_geometry );
        Q_ASSERT( thisPoly && otherPoly );

        if ( *thisPoly != *otherPoly ) {
            return false;
        }
    } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataLineStringType ) {
        GeoDataLineString *thisLine = dynamic_cast<GeoDataLineString*>( p()->m_geometry );
        GeoDataLineString *otherLine = dynamic_cast<GeoDataLineString*>( other.p()->m_geometry );
        Q_ASSERT( thisLine && otherLine );

        if ( *thisLine != *otherLine ) {
            return false;
        }
    } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataModelType ) {
        GeoDataModel *thisModel = dynamic_cast<GeoDataModel*>( p()->m_geometry );
        GeoDataModel *otherModel = dynamic_cast<GeoDataModel*>( other.p()->m_geometry );
        Q_ASSERT( thisModel && otherModel );

        if ( *thisModel != *otherModel ) {
            return false;
        }
    /*} else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) {
        GeoDataMultiGeometry *thisMG = dynamic_cast<GeoDataMultiGeometry*>( p()->m_geometry );
        GeoDataMultiGeometry *otherMG = dynamic_cast<GeoDataMultiGeometry*>( other.p()->m_geometry );
        Q_ASSERT( thisMG && otherMG );

        if ( *thisMG != *otherMG ) {
            return false;
        } */ // Does not have equality operators. I guess they need to be implemented soon.
    } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataTrackType ) {
        GeoDataTrack *thisTrack = dynamic_cast<GeoDataTrack*>( p()->m_geometry );
        GeoDataTrack *otherTrack = dynamic_cast<GeoDataTrack*>( other.p()->m_geometry );
        Q_ASSERT( thisTrack && otherTrack );

        if ( *thisTrack != *otherTrack ) {
            return false;
        }
    } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataMultiTrackType ) {
        GeoDataMultiTrack *thisMT = dynamic_cast<GeoDataMultiTrack*>( p()->m_geometry );
        GeoDataMultiTrack *otherMT = dynamic_cast<GeoDataMultiTrack*>( other.p()->m_geometry );
        Q_ASSERT( thisMT && otherMT );

        if ( *thisMT != *otherMT ) {
            return false;
        }
    } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataPointType ) {
        GeoDataPoint *thisPoint = dynamic_cast<GeoDataPoint*>( p()->m_geometry );
        GeoDataPoint *otherPoint = dynamic_cast<GeoDataPoint*>( other.p()->m_geometry );
        Q_ASSERT( thisPoint && otherPoint );

        if ( *thisPoint != *otherPoint ) {
            return false;
        }
    }

    return true;
}

bool GeoDataPlacemark::operator!=( const GeoDataPlacemark& other ) const
{
    return !this->operator==( other );
155 156
}

157 158 159 160 161 162
GeoDataPlacemarkPrivate* GeoDataPlacemark::p()
{
    return static_cast<GeoDataPlacemarkPrivate*>(d);
}

const GeoDataPlacemarkPrivate* GeoDataPlacemark::p() const
163
{
164
    return static_cast<GeoDataPlacemarkPrivate*>(d);
165 166
}

167 168
GeoDataGeometry* GeoDataPlacemark::geometry()
{
169 170
    detach();
    p()->m_geometry->setParent( this );
171 172 173 174
    return p()->m_geometry;
}

const GeoDataGeometry* GeoDataPlacemark::geometry() const
175
{
176
    return p()->m_geometry;
177 178
}

179 180 181 182 183 184 185 186 187 188 189 190
const OsmPlacemarkData& GeoDataPlacemark::osmData() const
{
    QVariant &placemarkVariantData = extendedData().valueRef( OsmPlacemarkData::osmHashKey() ).valueRef();
    if ( !placemarkVariantData.canConvert<OsmPlacemarkData>() ) {
        extendedData().addValue( GeoDataData( OsmPlacemarkData::osmHashKey(), QVariant::fromValue( OsmPlacemarkData() ) ) );
        placemarkVariantData = extendedData().valueRef( OsmPlacemarkData::osmHashKey() ).valueRef();
    }

    OsmPlacemarkData &osmData = *reinterpret_cast<OsmPlacemarkData*>( placemarkVariantData.data() );
    return osmData;
}

191 192 193 194 195
void GeoDataPlacemark::setOsmData( const OsmPlacemarkData &osmData )
{
    extendedData().addValue( GeoDataData( OsmPlacemarkData::osmHashKey(), QVariant::fromValue( osmData ) ) );
}

196 197 198 199 200 201 202 203 204 205 206
OsmPlacemarkData& GeoDataPlacemark::osmData()
{
    return const_cast<OsmPlacemarkData&>( (static_cast<const GeoDataPlacemark*>(this) )->osmData() );
}

bool GeoDataPlacemark::hasOsmData() const
{
    QVariant &placemarkVariantData = extendedData().valueRef( OsmPlacemarkData::osmHashKey() ).valueRef();
    return placemarkVariantData.canConvert<OsmPlacemarkData>();
}

207
const GeoDataLookAt *GeoDataPlacemark::lookAt() const
208
{
209
    return dynamic_cast<const GeoDataLookAt*>( abstractView() );
210 211
}

212
GeoDataLookAt *GeoDataPlacemark::lookAt()
213
{
214
    return dynamic_cast<GeoDataLookAt*>( abstractView() );
215 216
}

217 218 219 220 221 222 223 224 225 226 227 228 229
bool GeoDataPlacemark::placemarkLayoutOrderCompare(const GeoDataPlacemark *left, const GeoDataPlacemark *right)
{
    if (left->d->m_zoomLevel != right->d->m_zoomLevel) {
        return (left->d->m_zoomLevel < right->d->m_zoomLevel); // lower zoom level comes first
    }

    if (left->d->m_popularity != right->d->m_popularity) {
        return left->d->m_popularity > right->d->m_popularity; // higher popularity comes first
    }

    return left < right; // lower pointer value comes first
}

230
GeoDataCoordinates GeoDataPlacemark::coordinate( const QDateTime &dateTime, bool *iconAtCoordinates ) const
231
{
232 233
    bool hasIcon = false;
    GeoDataCoordinates coord;
234
 
235
    if( p()->m_geometry ) {
236 237
        // Beware: comparison between pointers, not strings.
        if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataPointType ) {
238
            hasIcon = true;
Bernhard Beschow's avatar
Bernhard Beschow committed
239
            coord = static_cast<const GeoDataPoint *>( p()->m_geometry )->coordinates();
240
        } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) {
Bernhard Beschow's avatar
Bernhard Beschow committed
241
            const GeoDataMultiGeometry *multiGeometry = static_cast<const GeoDataMultiGeometry *>( p()->m_geometry );
242 243 244

            QVector<GeoDataGeometry*>::ConstIterator it = multiGeometry->constBegin();
            QVector<GeoDataGeometry*>::ConstIterator end = multiGeometry->constEnd();
245
            for ( ; it != end; ++it ) {
246
                if ( (*it)->nodeType() == GeoDataTypes::GeoDataPointType ) {
247 248
                    hasIcon = true;
                    break;
249 250 251
                }
            }

252 253
            coord = p()->m_geometry->latLonAltBox().center();
        } else if ( p()->m_geometry->nodeType() == GeoDataTypes::GeoDataTrackType ) {
Bernhard Beschow's avatar
Bernhard Beschow committed
254
            const GeoDataTrack *track = static_cast<const GeoDataTrack *>( p()->m_geometry );
255 256 257 258
            hasIcon = track->size() != 0 && track->firstWhen() <= dateTime;
            coord = track->coordinatesAt( dateTime );
        } else {
            coord = p()->m_geometry->latLonAltBox().center();
259
        }
Patrick Spendrin's avatar
Patrick Spendrin committed
260
    }
261

262 263 264 265
    if ( iconAtCoordinates != 0 ) {
        *iconAtCoordinates = hasIcon;
    }
    return coord;
Torsten Rahn's avatar
Torsten Rahn committed
266 267
}

268
void GeoDataPlacemark::coordinate( qreal& lon, qreal& lat, qreal& alt ) const
Torsten Rahn's avatar
Torsten Rahn committed
269
{
270
    coordinate().geoCoordinates( lon, lat, alt );
Torsten Rahn's avatar
Torsten Rahn committed
271 272
}

273
void GeoDataPlacemark::setCoordinate( qreal lon, qreal lat, qreal alt, GeoDataPoint::Unit _unit)
Torsten Rahn's avatar
Torsten Rahn committed
274
{
275
    setGeometry( new GeoDataPoint(lon, lat, alt, _unit ) );
Torsten Rahn's avatar
 
Torsten Rahn committed
276 277
}

278
void GeoDataPlacemark::setCoordinate( const GeoDataCoordinates &point )
279
{
280
    setGeometry ( new GeoDataPoint( point ) );
281 282
}

283 284 285 286 287
void GeoDataPlacemark::setCoordinate( const GeoDataPoint &point )
{
    setGeometry ( new GeoDataPoint( point ) );
}

288
void GeoDataPlacemark::setGeometry( GeoDataGeometry *entry )
289
{
290
    detach();
291
    delete p()->m_geometry;
292
    p()->m_geometry = entry;
293
    p()->m_geometry->setParent( this );
294 295
}

296 297 298

QString GeoDataPlacemark::displayName() const
{
Dennis Nienhüser's avatar
Dennis Nienhüser committed
299 300 301 302 303
    if (hasOsmData()) {
        OsmPlacemarkData const &data = osmData();
        QStringList const uiLanguages = QLocale::system().uiLanguages();
        foreach (const QString &uiLanguage, uiLanguages) {
            for (auto tagIter = data.tagsBegin(), end = data.tagsEnd(); tagIter != end; ++tagIter) {
304 305
                if (tagIter.key().startsWith(QLatin1String("name:"))) {
                    QStringRef const tagLanguage = tagIter.key().midRef(5);
306
                    if (tagLanguage == uiLanguage) {
307
                        return tagIter.value();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
308
                    }
309 310 311 312 313 314 315 316 317 318
                }
            }
        }
    }

    return name();
}



319
qreal GeoDataPlacemark::area() const
Torsten Rahn's avatar
 
Torsten Rahn committed
320
{
321
    return p()->m_area;
Torsten Rahn's avatar
 
Torsten Rahn committed
322 323
}

324
void GeoDataPlacemark::setArea( qreal area )
Torsten Rahn's avatar
 
Torsten Rahn committed
325
{
326
    detach();
327
    p()->m_geometry->setParent( this );
328
    p()->m_area = area;
Torsten Rahn's avatar
 
Torsten Rahn committed
329 330
}

331
qint64 GeoDataPlacemark::population() const
Torsten Rahn's avatar
 
Torsten Rahn committed
332
{
333
    return p()->m_population;
Torsten Rahn's avatar
 
Torsten Rahn committed
334 335 336 337
}

void GeoDataPlacemark::setPopulation( qint64 population )
{
338
    detach();
339
    p()->m_geometry->setParent( this );
340
    p()->m_population = population;
Torsten Rahn's avatar
Torsten Rahn committed
341 342
}

Bastian Holst's avatar
Bastian Holst committed
343 344 345 346 347 348 349 350
const QString GeoDataPlacemark::state() const
{
    return p()->m_state;
}

void GeoDataPlacemark::setState( const QString &state )
{
    detach();
351
    p()->m_geometry->setParent( this );
Bastian Holst's avatar
Bastian Holst committed
352 353 354
    p()->m_state = state;
}

355
const QString GeoDataPlacemark::countryCode() const
Torsten Rahn's avatar
Torsten Rahn committed
356
{
357
    return p()->m_countrycode;
Torsten Rahn's avatar
Torsten Rahn committed
358 359
}

360
void GeoDataPlacemark::setCountryCode( const QString &countrycode )
Torsten Rahn's avatar
Torsten Rahn committed
361
{
362
    detach();
363
    p()->m_geometry->setParent( this );
364
    p()->m_countrycode = countrycode;
Torsten Rahn's avatar
Torsten Rahn committed
365 366
}

367 368 369 370 371 372 373 374
bool GeoDataPlacemark::isBalloonVisible() const
{
    return p()->m_isBalloonVisible;
}

void GeoDataPlacemark::setBalloonVisible( bool visible )
{
    detach();
375
    p()->m_geometry->setParent( this );
376 377 378
    p()->m_isBalloonVisible = visible;
}

379
void GeoDataPlacemark::pack( QDataStream& stream ) const
Torsten Rahn's avatar
Torsten Rahn committed
380 381 382
{
    GeoDataFeature::pack( stream );

383 384 385
    stream << p()->m_countrycode;
    stream << p()->m_area;
    stream << p()->m_population;
Thibaut Gridel's avatar
Thibaut Gridel committed
386 387 388 389 390 391 392 393 394
    if ( p()->m_geometry )
    {
        stream << p()->m_geometry->geometryId();
        p()->m_geometry->pack( stream );
    }
    else
    {
        stream << InvalidGeometryId;
    }
Torsten Rahn's avatar
Torsten Rahn committed
395 396
}

397 398 399 400 401 402 403 404 405 406 407 408 409
QXmlStreamWriter& GeoDataPlacemark::pack( QXmlStreamWriter& stream ) const
{
    stream.writeStartElement( "placemark" );

    stream.writeEndElement();
    return stream;
}

QXmlStreamWriter& GeoDataPlacemark::operator <<( QXmlStreamWriter& stream ) const
{
    pack( stream );
    return stream;
}
Torsten Rahn's avatar
Torsten Rahn committed
410

411
void GeoDataPlacemark::unpack( QDataStream& stream )
Torsten Rahn's avatar
Torsten Rahn committed
412
{
413
    detach();
414
    p()->m_geometry->setParent( this );
Torsten Rahn's avatar
Torsten Rahn committed
415 416
    GeoDataFeature::unpack( stream );

417 418 419
    stream >> p()->m_countrycode;
    stream >> p()->m_area;
    stream >> p()->m_population;
Patrick Spendrin's avatar
Patrick Spendrin committed
420 421 422
    int geometryId;
    stream >> geometryId;
    switch( geometryId ) {
423
        case InvalidGeometryId:
Patrick Spendrin's avatar
Patrick Spendrin committed
424 425
            break;
        case GeoDataPointId:
Laurent Montel's avatar
Laurent Montel committed
426
            {
427
            GeoDataPoint* point = new GeoDataPoint;
Patrick Spendrin's avatar
Patrick Spendrin committed
428
            point->unpack( stream );
429 430
            delete p()->m_geometry;
            p()->m_geometry = point;
Laurent Montel's avatar
Laurent Montel committed
431
            }
Patrick Spendrin's avatar
Patrick Spendrin committed
432 433
            break;
        case GeoDataLineStringId:
Laurent Montel's avatar
Laurent Montel committed
434
            {
435
            GeoDataLineString* lineString = new GeoDataLineString;
Patrick Spendrin's avatar
Patrick Spendrin committed
436
            lineString->unpack( stream );
437 438
            delete p()->m_geometry;
            p()->m_geometry = lineString;
Laurent Montel's avatar
Laurent Montel committed
439
            }
Patrick Spendrin's avatar
Patrick Spendrin committed
440 441
            break;
        case GeoDataLinearRingId:
Laurent Montel's avatar
Laurent Montel committed
442
            {
443
            GeoDataLinearRing* linearRing = new GeoDataLinearRing;
Patrick Spendrin's avatar
Patrick Spendrin committed
444
            linearRing->unpack( stream );
445 446
            delete p()->m_geometry;
            p()->m_geometry = linearRing;
Laurent Montel's avatar
Laurent Montel committed
447
            }
Patrick Spendrin's avatar
Patrick Spendrin committed
448 449
            break;
        case GeoDataPolygonId:
Laurent Montel's avatar
Laurent Montel committed
450
            {
451
            GeoDataPolygon* polygon = new GeoDataPolygon;
Patrick Spendrin's avatar
Patrick Spendrin committed
452
            polygon->unpack( stream );
453 454
            delete p()->m_geometry;
            p()->m_geometry = polygon;
Laurent Montel's avatar
Laurent Montel committed
455
            }
Patrick Spendrin's avatar
Patrick Spendrin committed
456 457
            break;
        case GeoDataMultiGeometryId:
Laurent Montel's avatar
Laurent Montel committed
458
            {
459
            GeoDataMultiGeometry* multiGeometry = new GeoDataMultiGeometry;
Patrick Spendrin's avatar
Patrick Spendrin committed
460
            multiGeometry->unpack( stream );
461 462
            delete p()->m_geometry;
            p()->m_geometry = multiGeometry;
Laurent Montel's avatar
Laurent Montel committed
463
            }
Patrick Spendrin's avatar
Patrick Spendrin committed
464 465 466 467 468
            break;
        case GeoDataModelId:
            break;
        default: break;
    };
Torsten Rahn's avatar
Torsten Rahn committed
469
}
470 471

}