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