CARLA
Loading...
Searching...
No Matches
Frame.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "Frame.h"
8
9#include <cmath>
10#include <sstream>
11
12namespace twinmodel {
13
14 namespace {
15
16 // WGS84 ellipsoid, and the unit scale factor pyproj's +k=1 asks for.
17 constexpr double kSemiMajor = 6378137.0;
18 constexpr double kFlattening = 1.0 / 298.257223563;
19 constexpr double kScale = 1.0;
20
21 constexpr double kDegToRad = M_PI / 180.0;
22 constexpr double kRadToDeg = 180.0 / M_PI;
23
24 } // namespace
25
26 std::string LocalFrame::GetProjString() const {
27 std::ostringstream out;
28 out.precision(12);
29 out << "+proj=tmerc +lat_0=" << _origin_lat << " +lon_0=" << _origin_lon
30 << " +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs";
31 return out.str();
32 }
33
34 void LocalFrame::ToLocal(double lon, double lat, double &x, double &y) const {
35 // Kruger series, the same transverse Mercator PROJ applies for +proj=tmerc.
36 const double e2 = kFlattening * (2.0 - kFlattening);
37 const double ep2 = e2 / (1.0 - e2);
38 const double phi = lat * kDegToRad;
39 const double phi0 = _origin_lat * kDegToRad;
40 const double dl = (lon - _origin_lon) * kDegToRad;
41
42 const double sin_phi = std::sin(phi);
43 const double cos_phi = std::cos(phi);
44 const double tan_phi = std::tan(phi);
45 const double nu = kSemiMajor / std::sqrt(1.0 - e2 * sin_phi * sin_phi);
46 const double t = tan_phi * tan_phi;
47 const double c = ep2 * cos_phi * cos_phi;
48 const double a = dl * cos_phi;
49
50 auto meridian = [&](double p) {
51 return kSemiMajor * ((1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0 - 5.0 * e2 * e2 * e2 / 256.0) * p
52 - (3.0 * e2 / 8.0 + 3.0 * e2 * e2 / 32.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(2.0 * p)
53 + (15.0 * e2 * e2 / 256.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(4.0 * p)
54 - (35.0 * e2 * e2 * e2 / 3072.0) * std::sin(6.0 * p));
55 };
56
57 x = kScale * nu * (a + (1.0 - t + c) * a * a * a / 6.0
58 + (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ep2) * std::pow(a, 5) / 120.0);
59 y = kScale * (meridian(phi) - meridian(phi0) + nu * tan_phi *
60 (a * a / 2.0 + (5.0 - t + 9.0 * c + 4.0 * c * c) * std::pow(a, 4) / 24.0
61 + (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ep2) * std::pow(a, 6) / 720.0));
62 }
63
64 void LocalFrame::ToWGS84(double x, double y, double &lon, double &lat) const {
65 const double e2 = kFlattening * (2.0 - kFlattening);
66 const double ep2 = e2 / (1.0 - e2);
67 const double e1 = (1.0 - std::sqrt(1.0 - e2)) / (1.0 + std::sqrt(1.0 - e2));
68 const double phi0 = _origin_lat * kDegToRad;
69
70 auto meridian = [&](double p) {
71 return kSemiMajor * ((1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0 - 5.0 * e2 * e2 * e2 / 256.0) * p
72 - (3.0 * e2 / 8.0 + 3.0 * e2 * e2 / 32.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(2.0 * p)
73 + (15.0 * e2 * e2 / 256.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(4.0 * p)
74 - (35.0 * e2 * e2 * e2 / 3072.0) * std::sin(6.0 * p));
75 };
76
77 const double m = meridian(phi0) + y / kScale;
78 const double mu = m / (kSemiMajor * (1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0
79 - 5.0 * e2 * e2 * e2 / 256.0));
80 const double phi1 = mu
81 + (3.0 * e1 / 2.0 - 27.0 * e1 * e1 * e1 / 32.0) * std::sin(2.0 * mu)
82 + (21.0 * e1 * e1 / 16.0 - 55.0 * e1 * e1 * e1 * e1 / 32.0) * std::sin(4.0 * mu)
83 + (151.0 * e1 * e1 * e1 / 96.0) * std::sin(6.0 * mu);
84
85 const double sin_phi1 = std::sin(phi1);
86 const double cos_phi1 = std::cos(phi1);
87 const double tan_phi1 = std::tan(phi1);
88 const double c1 = ep2 * cos_phi1 * cos_phi1;
89 const double t1 = tan_phi1 * tan_phi1;
90 const double n1 = kSemiMajor / std::sqrt(1.0 - e2 * sin_phi1 * sin_phi1);
91 const double r1 = kSemiMajor * (1.0 - e2) / std::pow(1.0 - e2 * sin_phi1 * sin_phi1, 1.5);
92 const double d = x / (n1 * kScale);
93
94 const double phi = phi1 - (n1 * tan_phi1 / r1) *
95 (d * d / 2.0 - (5.0 + 3.0 * t1 + 10.0 * c1 - 4.0 * c1 * c1 - 9.0 * ep2) * std::pow(d, 4) / 24.0
96 + (61.0 + 90.0 * t1 + 298.0 * c1 + 45.0 * t1 * t1 - 252.0 * ep2 - 3.0 * c1 * c1)
97 * std::pow(d, 6) / 720.0);
98 const double dl = (d - (1.0 + 2.0 * t1 + c1) * d * d * d / 6.0
99 + (5.0 - 2.0 * c1 + 28.0 * t1 - 3.0 * c1 * c1 + 8.0 * ep2 + 24.0 * t1 * t1)
100 * std::pow(d, 5) / 120.0) / cos_phi1;
101
102 lat = phi * kRadToDeg;
103 lon = _origin_lon + dl * kRadToDeg;
104 }
105
106} // namespace twinmodel
float y
float x
void ToWGS84(double x, double y, double &lon, double &lat) const
Definition Frame.cpp:64
std::string GetProjString() const
The +proj string written as the OpenDRIVE <geoReference>.
Definition Frame.cpp:26
void ToLocal(double lon, double lat, double &x, double &y) const
Definition Frame.cpp:34