17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-18 07:59:19 +02:00
Files
maszyna/editor/orthophoto.cppm
maj00r c15e200e37 Merge the track layout editor into cpp20-modules, ported to modules
The editor branch was written against headers and the PCH, both of which this
branch has done away with, so its own files were ported rather than merged: the
five headers it added are now interface units and their .cpp files module
implementation units.

- editor/{puwg1992,polandmap,turnouts,orthophoto} become eu07.editor.* modules,
  application/planpanel becomes eu07.application.planpanel. The plan tool keeps
  to its own module rather than joining the eu07.simcore partitions: it stands on
  the editor's libraries and eu07.application.uilayer, not on the simulation core,
  so :editoruilayer can export import it without a cycle.
- glm arrives by import eu07.glm, never by include, as the rest of the tree does.
  maj0sted is header-only and glm-free, so its headers stay includes in the global
  module fragment - every unit that names those types includes them itself, since
  a global fragment is not visible across units.
- the one textual conflict was :editoruilayer's include block against this
  branch's imports; resolved this branch's way plus the planpanel import.

Builds with clang 22 (-DWITH_BETTER_RENDERER=OFF) and starts into the editor on
empty ground with -editor alone.
2026-09-13 12:36:21 +02:00

140 lines
4.9 KiB
C++

/*
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/.
*/
module;
#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <deque>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "maj0sted/editor/tile_cache.hpp"
export module eu07.editor.orthophoto;
export {
namespace editor
{
// orthophoto backdrop for the plan view. the tiling scheme, the cache and the retry policy come
// from the track layout library, which already speaks EPSG:2180; this adds what a native build
// needs and the web one got from the browser - the download itself, the decode and the texture.
//
// downloads run on worker threads, but nothing else does: finished transfers are handed back on
// the thread that calls collect(), so both the library's cache and the graphics API are only ever
// touched from there.
class orthophoto_source
{
public:
struct ready_tile
{
maj0sted::editor::TileBBox box;
unsigned int texture{0};
};
// default: Geoportal ortophoto on the fine 100 m grid. pass topo config and a coarse
// grid zoom (e.g. 1000) for the zoomed-out topographic underlay
explicit orthophoto_source(maj0sted::editor::WmsConfig Config = maj0sted::editor::WmsConfig::geoportal_ortho(), int const Gridzoom = maj0sted::editor::TileGrid::kLevel,
std::string Cachesubdir = "orto");
~orthophoto_source();
orthophoto_source(orthophoto_source const &) = delete;
orthophoto_source &operator=(orthophoto_source const &) = delete;
// kicks off fetches for the view (capped) and returns every already-uploaded tile that still
// intersects it - including ones outside the fetch window, so a zoom cannot blink them away.
// tiles still on their way simply aren't in the answer yet; call again next frame
std::vector<ready_tile> collect(maj0sted::editor::TileBBox const &View, int const Maxtiles = 400);
// how many tiles are still being fetched, for the panel to report
std::size_t pending() const;
// how many tiles gave up after exhausting their retries
std::size_t failed() const;
private:
// types
struct transfer
{
std::string url;
maj0sted::editor::TileService::DoneFn done;
bool ok{false};
std::vector<std::uint8_t> bytes;
std::string content_type;
};
// methods
void worker();
// decodes the cached bytes of a tile and uploads them; returns 0 when the image is unusable
unsigned int upload(maj0sted::editor::TileKey const &Key);
// imagery of a given piece of ground never changes, so a fetched tile is kept on disk and the
// next session starts with it instead of going back to a service that is slow and flaky
std::string tile_path(maj0sted::editor::TileKey const &Key) const;
bool load_from_disk(maj0sted::editor::TileKey const &Key);
void save_to_disk(maj0sted::editor::TileKey const &Key);
// members
maj0sted::editor::TileService m_service;
int m_gridzoom{maj0sted::editor::TileGrid::kLevel};
std::string m_cachesubdir{"orto"};
std::unordered_map<maj0sted::editor::TileKey, unsigned int, maj0sted::editor::TileKeyHash> m_textures;
mutable std::mutex m_mutex;
std::condition_variable m_wakeup;
std::deque<transfer> m_queued;
std::deque<transfer> m_finished;
std::vector<std::thread> m_workers;
std::atomic<bool> m_quitting{false};
std::atomic<std::size_t> m_inflight{0};
std::unordered_set<maj0sted::editor::TileKey, maj0sted::editor::TileKeyHash> m_failedkeys;
};
// a single WMS image covering an arbitrary box, for views too coarse for the tile grid - the whole
// country will not fit into 100 m cells. one request is in flight at a time: asking for a different
// box supersedes whatever was being fetched
class wms_image
{
public:
explicit wms_image(maj0sted::editor::WmsConfig Config);
~wms_image();
wms_image(wms_image const &) = delete;
wms_image &operator=(wms_image const &) = delete;
// asks for the given box at the given size and returns the texture currently available, which
// may still be the previous box's until the new one arrives; 0 when there is nothing to show yet
unsigned int texture_for(maj0sted::editor::TileBBox const &Box, int const Pixels);
// the box the returned texture actually covers
maj0sted::editor::TileBBox const &covered() const { return m_covered; }
bool loading() const { return m_loading.load(); }
private:
void worker();
maj0sted::editor::WmsConfig m_config;
maj0sted::editor::TileBBox m_requested{};
maj0sted::editor::TileBBox m_inflightbox{};
maj0sted::editor::TileBBox m_covered{};
unsigned int m_texture{0};
mutable std::mutex m_mutex;
std::condition_variable m_wakeup;
std::string m_url;
bool m_haswork{false};
std::vector<std::uint8_t> m_bytes;
bool m_hasresult{false};
std::thread m_worker;
std::atomic<bool> m_quitting{false};
std::atomic<bool> m_loading{false};
};
} // namespace editor
} // export