1 #pragma once
2
3 #include <mapbox/geojsonvt/simplify.hpp>
4 #include <mapbox/geojsonvt/types.hpp>
5 #include <mapbox/geometry.hpp>
6
7 #include <algorithm>
8 #include <cmath>
9
10 namespace mapbox {
11 namespace geojsonvt {
12 namespace detail {
13
14 struct project {
15 const double tolerance;
16 using result_type = vt_geometry;
17
operator ()mapbox::geojsonvt::detail::project18 vt_point operator()(const geometry::point<double>& p) {
19 const double sine = std::sin(p.y * M_PI / 180);
20 const double x = p.x / 360 + 0.5;
21 const double y =
22 std::max(std::min(0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI, 1.0), 0.0);
23 return { x, y, 0.0 };
24 }
25
operator ()mapbox::geojsonvt::detail::project26 vt_line_string operator()(const geometry::line_string<double>& points) {
27 vt_line_string result;
28 const size_t len = points.size();
29
30 if (len == 0)
31 return result;
32
33 result.reserve(len);
34
35 for (const auto& p : points) {
36 result.push_back(operator()(p));
37 }
38
39 for (size_t i = 0; i < len - 1; ++i) {
40 const auto& a = result[i];
41 const auto& b = result[i + 1];
42 // use Manhattan distance instead of Euclidian to avoid expensive square root
43 // computation
44 result.dist += std::abs(b.x - a.x) + std::abs(b.y - a.y);
45 }
46
47 simplify(result, tolerance);
48
49 return result;
50 }
51
operator ()mapbox::geojsonvt::detail::project52 vt_linear_ring operator()(const geometry::linear_ring<double>& ring) {
53 vt_linear_ring result;
54 const size_t len = ring.size();
55
56 if (len == 0)
57 return result;
58
59 result.reserve(len);
60
61 for (const auto& p : ring) {
62 result.push_back(operator()(p));
63 }
64
65 double area = 0.0;
66
67 for (size_t i = 0; i < len - 1; ++i) {
68 const auto& a = result[i];
69 const auto& b = result[i + 1];
70 area += a.x * b.y - b.x * a.y;
71 }
72 result.area = std::abs(area / 2);
73
74 simplify(result, tolerance);
75
76 return result;
77 }
78
operator ()mapbox::geojsonvt::detail::project79 vt_geometry operator()(const geometry::geometry<double>& geometry) {
80 return geometry::geometry<double>::visit(geometry, project{ tolerance });
81 }
82
83 // Handles polygon, multi_*, geometry_collection.
84 template <class T>
operator ()mapbox::geojsonvt::detail::project85 auto operator()(const T& vector) {
86 typename vt_geometry_type<T>::type result;
87 result.reserve(vector.size());
88 for (const auto& e : vector) {
89 result.push_back(operator()(e));
90 }
91 return result;
92 }
93 };
94
convert(const geometry::feature_collection<double> & features,const double tolerance)95 inline vt_features convert(const geometry::feature_collection<double>& features,
96 const double tolerance) {
97 vt_features projected;
98 projected.reserve(features.size());
99 for (const auto& feature : features) {
100 projected.emplace_back(
101 geometry::geometry<double>::visit(feature.geometry, project{ tolerance }),
102 feature.properties, feature.id);
103 }
104 return projected;
105 }
106
107 } // namespace detail
108 } // namespace geojsonvt
109 } // namespace mapbox
110