TinyPlanetProcessor.cpp 7.59 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
// This file is part of the Marble Virtual Globe.
//
// 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.
//
// Copyright 2016      David Kolozsvari <freedawson@gmail.com>
//

#include "TinyPlanetProcessor.h"

#include "BaseClipper.h"

#include "GeoDataPlacemark.h"
#include "OsmPlacemarkData.h"
17
#include "OsmObjectManager.h"
18
19
20

#include <QDebug>
#include <QPolygonF>
21
#include <QPair>
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

TinyPlanetProcessor::TinyPlanetProcessor(GeoDataDocument* document) :
    PlacemarkFilter(document)
{

}

void TinyPlanetProcessor::process()
{
    // ?
}

GeoDataDocument *TinyPlanetProcessor::cutToTiles(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY)
{
    unsigned int N = pow(2, zoomLevel);

    GeoDataDocument* tile = new GeoDataDocument();
    QString tileName = QString("%1/%2/%3").arg(zoomLevel).arg(tileX).arg(tileY);
    tile->setName(tileName);

    GeoDataLatLonBox tileBoundary;
    qreal north = BaseClipper::tileY2lat(tileY, N);
    qreal south = BaseClipper::tileY2lat(tileY+1, N);
    qreal west = BaseClipper::tileX2lon(tileX, N);
    qreal east = BaseClipper::tileX2lon(tileX+1, N);

    tileBoundary.setBoundaries(north, south, east, west);

    BaseClipper clipper;
51
    clipper.initClipRect(tileBoundary, 20);
52

53
    foreach (GeoDataPlacemark* placemark, placemarks()) {
54
55
56

        if(tileBoundary.intersects(placemark->geometry()->latLonAltBox())) {

57
58
59
60
61
62
63
            if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) {
                GeoDataPolygon* marblePolygon = static_cast<GeoDataPolygon*>(placemark->geometry());
                int index = -1;

                using PolygonPair = QPair<GeoDataPlacemark*, QPolygonF>;
                QVector<PolygonPair> newMarblePolygons;

64
                bool const isClockwise = marblePolygon->outerBoundary().isClockwise();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
65
                QPolygonF outerBoundaryPolygon = BaseClipper::toQPolygon(marblePolygon->outerBoundary(), !isClockwise);
66
67
68
69

                QVector<QPolygonF> outerBoundaries;
                clipper.clipPolyObject(outerBoundaryPolygon, outerBoundaries, true);

Dennis Nienhüser's avatar
Dennis Nienhüser committed
70
                //                qDebug() << "Size(s) after:";
71
72
                foreach(const QPolygonF& polygon, outerBoundaries) {

Dennis Nienhüser's avatar
Dennis Nienhüser committed
73
                    //                    qDebug() << polygon.size();
74
75
76

                    PolygonPair newMarblePolygon = qMakePair(new GeoDataPlacemark(), polygon);
                    GeoDataPolygon* geometry = new GeoDataPolygon();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
77
                    geometry->setOuterBoundary(BaseClipper::toLineString<GeoDataLinearRing>(polygon, !isClockwise));
78
79
80
81
82
83
84
85
86
87
                    newMarblePolygon.first->setGeometry(geometry);

                    copyTags(*placemark, *(newMarblePolygon.first));
                    OsmObjectManager::initializeOsmData(newMarblePolygon.first);

                    placemark->osmData().memberReference(index);
                    copyTags(placemark->osmData().memberReference(index),
                             newMarblePolygon.first->osmData().memberReference(index));

                    newMarblePolygons.push_back(newMarblePolygon);
88
89
                }

90
91
                foreach (const GeoDataLinearRing& innerBoundary, marblePolygon->innerBoundaries()) {
                    ++index;
92
                    bool const isClockwise = innerBoundary.isClockwise();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
93
                    QPolygonF innerBoundaryPolygon = BaseClipper::toQPolygon(innerBoundary, !isClockwise);
94
95

                    QVector<QPolygonF> clippedPolygons;
96

97
                    clipper.clipPolyObject(innerBoundaryPolygon, clippedPolygons, true);
98

99
100
101
102
103
                    foreach (const QPolygonF& polygon, clippedPolygons) {
                        bool isAdded = false;
                        foreach (const PolygonPair& newMarblePolygon, newMarblePolygons) {
                            if(!polygon.intersected(newMarblePolygon.second).isEmpty()) {
                                GeoDataPolygon* geometry = static_cast<GeoDataPolygon*>(newMarblePolygon.first->geometry());
Dennis Nienhüser's avatar
Dennis Nienhüser committed
104
                                geometry->appendInnerBoundary(BaseClipper::toLineString<GeoDataLinearRing>(polygon, !isClockwise));
105

106
                                OsmObjectManager::initializeOsmData(newMarblePolygon.first);
107

108
109
                                OsmPlacemarkData& innerRingData = newMarblePolygon.first->osmData().memberReference(geometry->innerBoundaries().size()-1);
                                OsmPlacemarkData& placemarkInnerRingData = placemark->osmData().memberReference(index);
110

111
                                copyTags(placemarkInnerRingData, innerRingData);
112

113
114
115
                                isAdded = true;
                            }
                        }
116

117
118
119
120
121
                        if(!isAdded) {
                            qDebug() << "Polygon not added. Why?";
                        }
                    }
                }
122

123
124
                foreach (const PolygonPair& newMarblePolygon, newMarblePolygons) {
                    tile->append(newMarblePolygon.first);
125
                }
126

127
128
129
130
131
            } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) {
                GeoDataLineString* marbleWay = static_cast<GeoDataLineString*>(placemark->geometry());

                QVector<QPolygonF> clippedPolygons;

Dennis Nienhüser's avatar
Dennis Nienhüser committed
132
                QPolygonF way = BaseClipper::toQPolygon(*marbleWay);
133
134
135

                clipper.clipPolyObject(way, clippedPolygons, false);

Dennis Nienhüser's avatar
Dennis Nienhüser committed
136
137
                //                qDebug() << "Size  before:" << way.size();
                //                qDebug() << "Size(s) after:";
138
139
                foreach(const QPolygonF& polygon, clippedPolygons) {

Dennis Nienhüser's avatar
Dennis Nienhüser committed
140
                    //                    qDebug() << polygon.size();
141

Dennis Nienhüser's avatar
Dennis Nienhüser committed
142
                    GeoDataLineString* newMarbleWay = new GeoDataLineString(BaseClipper::toLineString<GeoDataLineString>(polygon));
143
144
145

                    GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
                    newPlacemark->setGeometry(newMarbleWay);
146
                    copyTags(*placemark, *newPlacemark);
147
148
149
150
151

                    tile->append(newPlacemark);
                }
            } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) {

Dennis Nienhüser's avatar
Dennis Nienhüser committed
152
                GeoDataLinearRing* marbleClosedWay = static_cast<GeoDataLinearRing*>(placemark->geometry());
153

Dennis Nienhüser's avatar
Dennis Nienhüser committed
154
                QVector<QPolygonF> clippedPolygons;
155

Dennis Nienhüser's avatar
Dennis Nienhüser committed
156
                QPolygonF closedWay = BaseClipper::toQPolygon(*marbleClosedWay);
157

Dennis Nienhüser's avatar
Dennis Nienhüser committed
158
                clipper.clipPolyObject(closedWay, clippedPolygons, true);
159

Dennis Nienhüser's avatar
Dennis Nienhüser committed
160
161
                //                    qDebug() << "Size(s) after:";
                foreach(const QPolygonF& polygon, clippedPolygons) {
162

Dennis Nienhüser's avatar
Dennis Nienhüser committed
163
                    //                        qDebug() << polygon.size();
164

Dennis Nienhüser's avatar
Dennis Nienhüser committed
165
                    GeoDataLinearRing* newMarbleWay = new GeoDataLinearRing(BaseClipper::toLineString<GeoDataLinearRing>(polygon));
166

Dennis Nienhüser's avatar
Dennis Nienhüser committed
167
168
169
                    GeoDataPlacemark* newPlacemark = new GeoDataPlacemark();
                    newPlacemark->setGeometry(newMarbleWay);
                    copyTags(*placemark, *newPlacemark);
170

Dennis Nienhüser's avatar
Dennis Nienhüser committed
171
172
                    tile->append(newPlacemark);
                }
173
174
175
176
177
178
179
180
181
182

            } else {
                tile->append(placemark);
            }
        }
    }


    return tile;
}
183
184
185

void TinyPlanetProcessor::copyTags(const GeoDataPlacemark &source, GeoDataPlacemark &target) const
{
Dennis Nienhüser's avatar
Dennis Nienhüser committed
186
    copyTags(source.osmData(), target.osmData());
187
}
188
189
190
191
192
193
194

void TinyPlanetProcessor::copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData &targetOsmData) const
{
    for (auto iter=originalPlacemarkData.tagsBegin(), end=originalPlacemarkData.tagsEnd(); iter != end; ++iter) {
        targetOsmData.addTag(iter.key(), iter.value());
    }
}