forked from osm2pgsql-dev/osm2pgsql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreprojection-generic-proj6.cpp
More file actions
118 lines (93 loc) · 3.4 KB
/
Copy pathreprojection-generic-proj6.cpp
File metadata and controls
118 lines (93 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
#include "format.hpp"
#include "reprojection.hpp"
#include <proj.h>
namespace {
/**
* Generic projection using proj library (version 6 and above).
*/
class generic_reprojection_t : public reprojection_t
{
public:
explicit generic_reprojection_t(int srs)
: m_target_srs(srs), m_context(proj_context_create()),
m_transformation(create_transformation(PROJ_LATLONG, srs)),
m_transformation_tile(create_transformation(srs, PROJ_SPHERE_MERC))
{}
geom::point_t reproject(geom::point_t point) const noexcept override
{
return transform(m_transformation.get(), point);
}
geom::point_t target_to_tile(geom::point_t point) const override
{
return transform(m_transformation_tile.get(), point);
}
int target_srs() const noexcept override { return m_target_srs; }
char const *target_desc() const noexcept override { return ""; }
private:
struct pj_context_deleter_t
{
void operator()(PJ_CONTEXT *ctx) const noexcept
{
proj_context_destroy(ctx);
}
};
struct pj_deleter_t
{
void operator()(PJ *p) const noexcept { proj_destroy(p); }
};
char const *errormsg() const noexcept
{
return proj_errno_string(proj_context_errno(m_context.get()));
}
std::unique_ptr<PJ, pj_deleter_t> create_transformation(int from,
int to) const
{
assert(m_context);
std::string const source = fmt::format("epsg:{}", from);
std::string const target = fmt::format("epsg:{}", to);
std::unique_ptr<PJ, pj_deleter_t> const trans{proj_create_crs_to_crs(
m_context.get(), source.c_str(), target.c_str(), nullptr)};
if (!trans) {
throw fmt_error("Invalid projection from {} to {}: {}", from, to,
errormsg());
}
std::unique_ptr<PJ, pj_deleter_t> trans_vis{
proj_normalize_for_visualization(m_context.get(), trans.get())};
if (!trans_vis) {
throw fmt_error("Invalid projection from {} to {}: {}", from, to,
errormsg());
}
return trans_vis;
}
static geom::point_t transform(PJ *transformation,
geom::point_t point) noexcept
{
PJ_COORD c_in;
c_in.lpzt.z = 0.0;
c_in.lpzt.t = HUGE_VAL;
c_in.lpzt.lam = point.x();
c_in.lpzt.phi = point.y();
auto const c_out = proj_trans(transformation, PJ_FWD, c_in);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
return {c_out.xy.x, c_out.xy.y};
}
int m_target_srs;
std::unique_ptr<PJ_CONTEXT, pj_context_deleter_t> m_context;
std::unique_ptr<PJ, pj_deleter_t> m_transformation;
/**
* The projection used for tiles. Currently this is fixed to be Spherical
* Mercator. You will usually have tiles in the same projection as used
* for PostGIS, but it is theoretically possible to have your PostGIS data
* in, say, lat/lon but still create tiles in Spherical Mercator.
*/
std::unique_ptr<PJ, pj_deleter_t> m_transformation_tile;
};
} // anonymous namespace
std::shared_ptr<reprojection_t> reprojection_t::make_generic_projection(int srs)
{
return std::make_shared<generic_reprojection_t>(srs);
}
std::string get_proj_version()
{
return fmt::format("{}", proj_info().version);
}