Skip to content

Commit 5842b63

Browse files
matteblairtallytalwar
authored andcommittedMar 6, 2019
Refactor Client Data Source Interfaces (#2043)
* Fix onFeaturePick in Android demo Property map is null when pick result is empty * Refactor MapData and ClientGeoJsonSource to prevent repeated tiling operations * Use CXX_STANDARD CMake property instead of explicit compiler flag Setting '-std=c++14' as a public compile flag causes compile commands for all files to include that flag - this breaks compiling Obj-C (not Obj-C++) files on iOS * Create builder structs for ClientGeoJsonSource to reduce data copies * Update nativeAddFeature for geometry builders * Update Android demo MainActivity for MapData changes * Refactor TGMapData to reduce re-tiling and data copies * Update demo MapViewController for TGMapData changes * Simplify iOS MapData classes * Consolidate TGMapFeature subclasses and add docs * Apply some clang-tidy suggestions * Fixup merge * fixup: generate tiles after setting geojson (iOS)
1 parent e2cadc1 commit 5842b63

24 files changed

+679
-618
lines changed
 

‎core/CMakeLists.txt

+1-4
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
277277
endif()
278278

279279
# C++14 is required for compiling tangram-core and for using the interface headers.
280-
# Making this option PUBLIC declares it as a requirement for targets linking against tangram-core.
281-
target_compile_options(tangram-core
282-
PUBLIC -std=c++14
283-
)
280+
set_property(TARGET tangram-core PROPERTY CXX_STANDARD 14)
284281

285282
# We include GLSL shader sources into the library by generating header files with the source text
286283
# printed into a string constant. A CMake script generates one of these headers for each shader source

‎core/include/tangram/data/clientGeoJsonSource.h

+37-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <mutex>
77

8-
98
namespace Tangram {
109

1110
class Platform;
@@ -14,34 +13,61 @@ struct Properties;
1413

1514
struct ClientGeoJsonData;
1615

16+
struct PolylineBuilderData;
17+
18+
struct PolylineBuilder {
19+
PolylineBuilder();
20+
~PolylineBuilder();
21+
void beginPolyline(size_t numberOfPoints);
22+
void addPoint(LngLat point);
23+
std::unique_ptr<PolylineBuilderData> data;
24+
};
25+
26+
struct PolygonBuilderData;
27+
28+
struct PolygonBuilder {
29+
PolygonBuilder();
30+
~PolygonBuilder();
31+
void beginPolygon(size_t numberOfRings);
32+
void beginRing(size_t numberOfPoints);
33+
void addPoint(LngLat point);
34+
std::unique_ptr<PolygonBuilderData> data;
35+
};
36+
1737
class ClientGeoJsonSource : public TileSource {
1838

1939
public:
2040

2141
ClientGeoJsonSource(Platform& _platform, const std::string& _name,
2242
const std::string& _url, bool generateCentroids = false,
2343
TileSource::ZoomOptions _zoomOptions = {});
24-
~ClientGeoJsonSource();
44+
45+
~ClientGeoJsonSource() override;
2546

2647
// http://www.iana.org/assignments/media-types/application/geo+json
27-
virtual const char* mimeType() const override { return "application/geo+json"; };
48+
const char* mimeType() const override { return "application/geo+json"; };
2849

2950
// Add geometry from a GeoJSON string
3051
void addData(const std::string& _data);
31-
void addPoint(const Properties& _tags, LngLat _point);
32-
void addLine(const Properties& _tags, const Coordinates& _line);
33-
void addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly);
34-
void generateLabelCentroidFeature();
3552

36-
virtual void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
53+
void addPointFeature(Properties&& properties, LngLat coordinates);
54+
55+
void addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline);
56+
57+
void addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon);
58+
59+
// Transform added feature data into tiles.
60+
void generateTiles();
61+
62+
void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
3763
std::shared_ptr<TileTask> createTask(TileID _tileId) override;
3864

39-
virtual void cancelLoadingTile(TileTask& _task) override {};
40-
virtual void clearData() override;
65+
void cancelLoadingTile(TileTask& _task) override {};
66+
void clearData() override;
4167

4268
protected:
4369

44-
virtual std::shared_ptr<TileData> parse(const TileTask& _task) const override;
70+
std::shared_ptr<TileData> parse(const TileTask& _task) const override;
4571

4672
std::unique_ptr<ClientGeoJsonData> m_store;
4773

‎core/src/data/clientGeoJsonSource.cpp

+86-82
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,51 @@ geojsonvt::Options options() {
3636

3737
struct ClientGeoJsonData {
3838
std::unique_ptr<geojsonvt::GeoJSONVT> tiles;
39-
mapbox::geometry::feature_collection<double> features;
39+
geometry::feature_collection<double> features;
4040
std::vector<Properties> properties;
4141
};
4242

43+
struct PolylineBuilderData : mapbox::geometry::line_string<double> {};
44+
45+
PolylineBuilder::PolylineBuilder() {
46+
data = std::make_unique<PolylineBuilderData>();
47+
}
48+
49+
PolylineBuilder::~PolylineBuilder() = default;
50+
51+
void PolylineBuilder::beginPolyline(size_t numberOfPoints) {
52+
data->reserve(numberOfPoints);
53+
}
54+
55+
void PolylineBuilder::addPoint(Tangram::LngLat point) {
56+
data->emplace_back(point.longitude, point.latitude);
57+
}
58+
59+
struct PolygonBuilderData : mapbox::geometry::polygon<double> {};
60+
61+
PolygonBuilder::PolygonBuilder() {
62+
data = std::make_unique<PolygonBuilderData>();
63+
}
64+
65+
PolygonBuilder::~PolygonBuilder() = default;
66+
67+
void PolygonBuilder::beginPolygon(size_t numberOfRings) {
68+
data->reserve(numberOfRings);
69+
}
70+
71+
void PolygonBuilder::beginRing(size_t numberOfPoints) {
72+
data->emplace_back();
73+
data->back().reserve(numberOfPoints);
74+
}
75+
76+
void PolygonBuilder::addPoint(LngLat point) {
77+
data->back().emplace_back(point.longitude, point.latitude);
78+
}
79+
4380
std::shared_ptr<TileTask> ClientGeoJsonSource::createTask(TileID _tileId) {
4481
return std::make_shared<TileTask>(_tileId, shared_from_this());
4582
}
4683

47-
4884
// TODO: pass scene's resourcePath to constructor to be used with `stringFromFile`
4985
ClientGeoJsonSource::ClientGeoJsonSource(Platform& _platform, const std::string& _name,
5086
const std::string& _url, bool _generateCentroids,
@@ -63,6 +99,7 @@ ClientGeoJsonSource::ClientGeoJsonSource(Platform& _platform, const std::string&
6399
LOGE("Unable to retrieve data from '%s': %s", _url.c_str(), response.error);
64100
} else {
65101
addData(std::string(response.content.begin(), response.content.end()));
102+
generateTiles();
66103
}
67104
m_hasPendingData = false;
68105
};
@@ -72,7 +109,7 @@ ClientGeoJsonSource::ClientGeoJsonSource(Platform& _platform, const std::string&
72109

73110
}
74111

75-
ClientGeoJsonSource::~ClientGeoJsonSource() {}
112+
ClientGeoJsonSource::~ClientGeoJsonSource() = default;
76113

77114
struct add_centroid {
78115

@@ -81,10 +118,7 @@ struct add_centroid {
81118
bool operator()(const geometry::polygon<double>& geom) {
82119
if (geom.empty()) { return false; }
83120
pt = centroid(geom.front().begin(), geom.front().end()-1);
84-
if (std::isnan(pt.x) || std::isnan(pt.y)) {
85-
return false;
86-
}
87-
return true;
121+
return !(std::isnan(pt.x) || std::isnan(pt.y));
88122
}
89123

90124
bool operator()(const geometry::multi_polygon<double>& geom) {
@@ -115,7 +149,7 @@ struct prop_visitor {
115149
Properties& props;
116150
std::string& key;
117151
void operator()(std::string v) {
118-
props.set(key, v);
152+
props.set(key, std::move(v));
119153
}
120154
void operator()(bool v) {
121155
props.set(key, double(v));
@@ -136,47 +170,22 @@ struct prop_visitor {
136170
}
137171
};
138172

139-
void ClientGeoJsonSource::generateLabelCentroidFeature() {
140-
for (const auto &feat : m_store->features) {
141-
geometry::point<double> centroid;
142-
const auto& properties = m_store->properties[feat.id.get<uint64_t>()];
143-
if (geometry::geometry<double>::visit(feat.geometry, add_centroid{ centroid })) {
144-
uint64_t id = m_store->features.size();
145-
m_store->features.emplace_back(centroid, id);
146-
m_store->properties.push_back(properties);
147-
auto& props = m_store->properties.back();
148-
props.set("label_placement", 1.0);
149-
}
150-
}
151-
}
152-
153-
void ClientGeoJsonSource::addData(const std::string& _data) {
173+
void ClientGeoJsonSource::generateTiles() {
154174

155175
std::lock_guard<std::mutex> lock(m_mutexStore);
156176

157-
const auto json = geojson::parse(_data);
158-
auto features = geojsonvt::geojson::visit(json, geojsonvt::ToFeatureCollection{});
159-
160-
for (auto& feature : features) {
161-
162-
feature.id = uint64_t(m_store->properties.size());
163-
m_store->properties.emplace_back();
164-
Properties& props = m_store->properties.back();
165-
166-
for (const auto& prop : feature.properties) {
167-
auto key = prop.first;
168-
prop_visitor visitor = {props, key};
169-
mapbox::util::apply_visitor(visitor, prop.second);
170-
}
171-
feature.properties.clear();
172-
}
173-
174-
m_store->features.insert(m_store->features.end(),
175-
std::make_move_iterator(features.begin()),
176-
std::make_move_iterator(features.end()));
177-
178177
if (m_generateCentroids) {
179-
generateLabelCentroidFeature();
178+
for (const auto &feat : m_store->features) {
179+
geometry::point<double> centroid;
180+
const auto& properties = m_store->properties[feat.id.get<uint64_t>()];
181+
if (geometry::geometry<double>::visit(feat.geometry, add_centroid{ centroid })) {
182+
uint64_t id = m_store->features.size();
183+
m_store->features.emplace_back(centroid, id);
184+
m_store->properties.push_back(properties);
185+
auto& props = m_store->properties.back();
186+
props.set("label_placement", 1.0);
187+
}
188+
}
180189
}
181190

182191
m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
@@ -210,65 +219,61 @@ void ClientGeoJsonSource::clearData() {
210219
m_generation++;
211220
}
212221

213-
void ClientGeoJsonSource::addPoint(const Properties& _tags, LngLat _point) {
222+
void ClientGeoJsonSource::addData(const std::string& _data) {
214223

215224
std::lock_guard<std::mutex> lock(m_mutexStore);
216225

217-
geometry::point<double> geom { _point.longitude, _point.latitude };
226+
const auto json = geojson::parse(_data);
227+
auto features = geojsonvt::geojson::visit(json, geojsonvt::ToFeatureCollection{});
218228

219-
uint64_t id = m_store->features.size();
229+
for (auto& feature : features) {
220230

221-
m_store->features.emplace_back(geom, id);
222-
m_store->properties.emplace_back(_tags);
231+
feature.id = uint64_t(m_store->properties.size());
232+
m_store->properties.emplace_back();
233+
Properties& props = m_store->properties.back();
223234

224-
m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
225-
m_generation++;
226-
}
235+
for (const auto& prop : feature.properties) {
236+
auto key = prop.first;
237+
prop_visitor visitor = {props, key};
238+
mapbox::util::apply_visitor(visitor, prop.second);
239+
}
240+
feature.properties.clear();
241+
}
227242

228-
void ClientGeoJsonSource::addLine(const Properties& _tags, const Coordinates& _line) {
243+
m_store->features.insert(m_store->features.end(),
244+
std::make_move_iterator(features.begin()),
245+
std::make_move_iterator(features.end()));
246+
}
229247

248+
void ClientGeoJsonSource::addPointFeature(Properties&& properties, LngLat coordinates) {
230249

231250
std::lock_guard<std::mutex> lock(m_mutexStore);
232251

233-
geometry::line_string<double> geom;
234-
for (auto& p : _line) {
235-
geom.emplace_back(p.longitude, p.latitude);
236-
}
252+
geometry::point<double> geom {coordinates.longitude, coordinates.latitude};
237253

238254
uint64_t id = m_store->features.size();
239-
240255
m_store->features.emplace_back(geom, id);
241-
m_store->properties.emplace_back(_tags);
242-
243-
m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
244-
m_generation++;
256+
m_store->properties.emplace_back(properties);
245257
}
246258

247-
void ClientGeoJsonSource::addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly) {
248-
259+
void ClientGeoJsonSource::addPolylineFeature(Properties&& properties, PolylineBuilder&& polyline) {
249260

250261
std::lock_guard<std::mutex> lock(m_mutexStore);
251262

252-
geometry::polygon<double> geom;
253-
for (auto& ring : _poly) {
254-
geom.emplace_back();
255-
auto &line = geom.back();
256-
for (auto& p : ring) {
257-
line.emplace_back(p.longitude, p.latitude);
258-
}
259-
}
260-
261263
uint64_t id = m_store->features.size();
264+
auto geom = std::move(polyline.data);
265+
m_store->features.emplace_back(*geom, id);
266+
m_store->properties.emplace_back(properties);
267+
}
262268

263-
m_store->features.emplace_back(geom, id);
264-
m_store->properties.emplace_back(_tags);
269+
void ClientGeoJsonSource::addPolygonFeature(Properties&& properties, PolygonBuilder&& polygon) {
265270

266-
if (m_generateCentroids) {
267-
generateLabelCentroidFeature();
268-
}
271+
std::lock_guard<std::mutex> lock(m_mutexStore);
269272

270-
m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
271-
m_generation++;
273+
uint64_t id = m_store->features.size();
274+
auto geom = std::move(polygon.data);
275+
m_store->features.emplace_back(*geom, id);
276+
m_store->properties.emplace_back(properties);
272277
}
273278

274279
struct add_geometry {
@@ -356,7 +361,6 @@ std::shared_ptr<TileData> ClientGeoJsonSource::parse(const TileTask& _task) cons
356361
}
357362
}
358363

359-
360364
return data;
361365
}
362366

0 commit comments

Comments
 (0)
Please sign in to comment.