17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-29 06:57:29 +01:00

Georeference a new map against a point in Poland

"New map" now asks what is being started. A fictional scenery keeps its own
frame, where coordinates mean nothing outside it. A real one pins the
scenery's zero to a point picked off a map of Poland, so the plan is drawn
in EPSG:2180 - the frame the layout library already works in, and the one
Geoportal serves imagery in.

The projection is the standard transverse Mercator series for PUWG 1992 on
GRS80. Checked against known values: the central meridian comes out at
easting 500000 exactly, Warszawa at 637382/486757, Krakow at 567614/244588,
Gdansk at 477038/720937.

The map behind the picker is a schematic border outline plus the larger
cities, projected from geographic coordinates on first use. It is coarse on
purpose - it is there to point at a region, not to measure against - and the
dialog says so. No network is involved.
This commit is contained in:
maj00r
2026-07-31 19:32:00 +02:00
committed by maj00r
parent 3fbc1aaaaf
commit bf82c35734
8 changed files with 454 additions and 6 deletions

92
editor/polandmap.cpp Normal file
View File

@@ -0,0 +1,92 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "editor/polandmap.h"
#include "editor/puwg1992.h"
namespace editor
{
namespace
{
// geographic coordinates, degrees, as (latitude, longitude); projected to EPSG:2180 on first use so
// the numbers stay readable and there is a single place where the frame is decided
struct geo_point
{
double latitude;
double longitude;
};
// the border walked clockwise from the north-west corner: Baltic coast, the Kaliningrad and
// Lithuanian borders, the Bug, the Carpathians and Sudetes, then the Nysa and Odra back north.
// tens of kilometres of error in places - this is a locator sketch, nothing more
constexpr geo_point kOutline[]{
{53.93, 14.27}, {54.05, 14.60}, {54.18, 15.58}, {54.42, 16.41}, {54.58, 16.86}, {54.76, 17.55},
{54.79, 18.40}, {54.60, 18.65}, {54.52, 18.55}, {54.35, 18.95}, {54.37, 19.35}, {54.45, 19.64},
{54.37, 20.50}, {54.35, 21.50}, {54.36, 22.00}, {54.36, 22.79}, {54.25, 23.20}, {54.15, 23.48},
{53.95, 23.90}, {53.20, 23.93}, {52.70, 23.85}, {52.30, 23.60}, {52.07, 23.62}, {51.55, 23.55},
{50.87, 24.15}, {50.72, 24.15}, {50.40, 23.70}, {50.28, 23.50}, {49.80, 22.92}, {49.20, 22.68},
{49.09, 22.55}, {49.25, 22.00}, {49.42, 21.75}, {49.35, 21.00}, {49.40, 20.50}, {49.20, 20.10},
{49.40, 19.80}, {49.40, 19.50}, {49.40, 19.20}, {49.51, 18.85}, {49.75, 18.63}, {49.95, 18.05},
{50.10, 17.70}, {50.31, 17.38}, {50.45, 16.90}, {50.20, 16.60}, {50.40, 16.35}, {50.44, 16.25},
{50.75, 15.80}, {50.75, 15.55}, {50.85, 15.00}, {50.87, 14.82}, {51.30, 14.95}, {51.60, 14.75},
{52.00, 14.70}, {52.35, 14.55}, {52.59, 14.65}, {52.85, 14.40}, {53.10, 14.35}, {53.55, 14.30},
{53.75, 14.28}};
struct named_geo_point
{
char const *name;
geo_point position;
};
constexpr named_geo_point kPlaces[]{
{"Warszawa", {52.23, 21.01}}, {"Krakow", {50.06, 19.94}}, {"Lodz", {51.77, 19.46}},
{"Wroclaw", {51.11, 17.03}}, {"Poznan", {52.41, 16.93}}, {"Gdansk", {54.35, 18.65}},
{"Szczecin", {53.43, 14.55}}, {"Bydgoszcz", {53.12, 18.01}}, {"Lublin", {51.25, 22.57}},
{"Bialystok", {53.13, 23.16}}, {"Katowice", {50.26, 19.02}}, {"Rzeszow", {50.04, 22.00}},
{"Olsztyn", {53.78, 20.49}}, {"Kielce", {50.87, 20.63}}, {"Zielona Gora", {51.94, 15.51}},
{"Opole", {50.67, 17.93}}, {"Torun", {53.02, 18.61}}, {"Gorzow Wlkp.", {52.73, 15.24}},
{"Koszalin", {54.19, 16.18}}, {"Czestochowa", {50.81, 19.12}}};
} // namespace
std::vector<glm::dvec2> const &poland_outline()
{
static std::vector<glm::dvec2> const outline = []() {
std::vector<glm::dvec2> points;
points.reserve(std::size(kOutline));
for (auto const &point : kOutline)
{
points.push_back(puwg1992(point.latitude, point.longitude));
}
return points;
}();
return outline;
}
std::vector<map_place> const &poland_places()
{
static std::vector<map_place> const places = []() {
std::vector<map_place> result;
result.reserve(std::size(kPlaces));
for (auto const &place : kPlaces)
{
result.push_back({place.name, puwg1992(place.position.latitude, place.position.longitude)});
}
return result;
}();
return places;
}
} // namespace editor

34
editor/polandmap.h Normal file
View File

@@ -0,0 +1,34 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <string>
#include <vector>
#include <glm/glm.hpp>
namespace editor
{
// a named point to start a scenery from, in EPSG:2180 metres
struct map_place
{
std::string name;
glm::dvec2 position;
};
// schematic outline of the country's border, in EPSG:2180 metres. coarse on purpose: it is here so
// a region can be pointed at, not so anything can be measured against it
std::vector<glm::dvec2> const &poland_outline();
// larger cities, to put the view somewhere recognisable before picking the exact spot
std::vector<map_place> const &poland_places();
} // namespace editor

73
editor/puwg1992.cpp Normal file
View File

@@ -0,0 +1,73 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "editor/puwg1992.h"
namespace editor
{
namespace
{
// PUWG 1992: a single transverse Mercator zone over the whole country, on the GRS80 ellipsoid
double const kSemiMajor = 6378137.0;
double const kFlattening = 1.0 / 298.257222101;
double const kCentralMeridian = 19.0; // degrees east
double const kScaleFactor = 0.9993;
double const kFalseEasting = 500000.0;
double const kFalseNorthing = -5300000.0;
} // namespace
glm::dvec2 puwg1992(double const Latitude, double const Longitude)
{
auto const e2 = 2.0 * kFlattening - kFlattening * kFlattening;
auto const ep2 = e2 / (1.0 - e2);
auto const lat = glm::radians(Latitude);
auto const dlon = glm::radians(Longitude - kCentralMeridian);
auto const sinlat = std::sin(lat);
auto const coslat = std::cos(lat);
auto const tanlat = std::tan(lat);
// radius of curvature in the prime vertical, and the series terms of the standard
// transverse Mercator expansion (Snyder); good to millimetres over a zone this size
auto const n = kSemiMajor / std::sqrt(1.0 - e2 * sinlat * sinlat);
auto const t = tanlat * tanlat;
auto const c = ep2 * coslat * coslat;
auto const a = dlon * coslat;
// meridional arc from the equator
auto const m =
kSemiMajor * ((1.0 - e2 / 4.0 - 3.0 * e2 * e2 / 64.0 - 5.0 * e2 * e2 * e2 / 256.0) * lat -
(3.0 * e2 / 8.0 + 3.0 * e2 * e2 / 32.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(2.0 * lat) +
(15.0 * e2 * e2 / 256.0 + 45.0 * e2 * e2 * e2 / 1024.0) * std::sin(4.0 * lat) -
(35.0 * e2 * e2 * e2 / 3072.0) * std::sin(6.0 * lat));
auto const a2 = a * a;
auto const a3 = a2 * a;
auto const a4 = a3 * a;
auto const a5 = a4 * a;
auto const a6 = a5 * a;
auto const easting = kFalseEasting + kScaleFactor * n *
(a + (1.0 - t + c) * a3 / 6.0 +
(5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * ep2) * a5 / 120.0);
auto const northing = kFalseNorthing + kScaleFactor *
(m + n * tanlat *
(a2 / 2.0 + (5.0 - t + 9.0 * c + 4.0 * c * c) * a4 / 24.0 +
(61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * ep2) * a6 / 720.0));
return {easting, northing};
}
} // namespace editor

22
editor/puwg1992.h Normal file
View File

@@ -0,0 +1,22 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <glm/glm.hpp>
namespace editor
{
// projects geographic coordinates onto PUWG 1992 (EPSG:2180) - the frame the track layout library
// works in, and the one Geoportal serves its imagery in. latitude and longitude in degrees, result
// in metres as (easting, northing).
glm::dvec2 puwg1992(double const Latitude, double const Longitude);
} // namespace editor