17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-20 21:04:37 +02:00

feat(editor): heightmap terrain from the terrain model of GUGiK, fitted to the tracks of the scenery

- editorNmt: squares of 500 m of the NMT at 1 m from the WCS service of geoportal.gov.pl, as GeoTIFF, fetched in the
  background, kept in editor/cache/nmt and sampled in the coordinates of the scenery, placed as its orthophoto is
- the terrain panel's Terrain model section: Fit to the tracks moves the model up or down by the median of the
  differences to the formation of the tracks (Biała Podlaska, built at 0: -145.73 m, 0.28 m around it); Along the tracks
  and Around the camera make the chunks as the model comes in; each path gets its formation and slopes 1:1.5 as a modifier
  of the terrain, laid over each other into one corridor, bridges and tunnels keep the model; the orthophoto is turned
  on and laid onto the new ground
- the http client of the orthophoto in editorHttp, shared; fill_from_nearest in editormodeshared.h
- after the generator of Hirek (MaszynaTerrainGenerator): the WCS requests, the cache of squares, the corridor by envelopes
- self-tests nmtfit, nmtmake, nmtwait
This commit is contained in:
maj00r
2026-10-18 12:56:25 +02:00
parent 16348c655a
commit 5af699fba4
12 changed files with 1245 additions and 234 deletions

224
editor/editorHttp.cpp Normal file
View File

@@ -0,0 +1,224 @@
/*
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/editorHttp.hpp"
#if defined(_WIN32)
#include <winhttp.h>
#elif defined(EU07_WITH_CURL)
#include <curl/curl.h>
#endif
#include <mutex>
namespace editor_http
{
struct client::platform
{
#if defined(_WIN32)
HINTERNET session{nullptr};
#elif defined(EU07_WITH_CURL)
CURL *curl{nullptr};
#endif
};
#if defined(_WIN32)
client::client() :
m_platform(std::make_unique<platform>())
{
wchar_t const *agent = L"MaSzyna-editor";
#ifdef WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
m_platform->session = ::WinHttpOpen(agent, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
#endif
if (m_platform->session == nullptr) // automatic proxy needs windows 8.1+
m_platform->session = ::WinHttpOpen(agent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (m_platform->session != nullptr)
::WinHttpSetTimeouts(m_platform->session, 10000, 10000, 15000, 20000);
}
client::~client()
{
if (m_platform->session != nullptr)
::WinHttpCloseHandle(m_platform->session);
}
bool client::get(std::string const &Url, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &Stop)
{
Out.clear();
if (m_platform->session == nullptr)
{
Error = "WinHttpOpen failed (" + std::to_string(::GetLastError()) + ")";
return false;
}
std::wstring const url(Url.begin(), Url.end()); // the requests are plain ascii
URL_COMPONENTS parts{};
parts.dwStructSize = sizeof(parts);
parts.dwSchemeLength = static_cast<DWORD>(-1);
parts.dwHostNameLength = static_cast<DWORD>(-1);
parts.dwUrlPathLength = static_cast<DWORD>(-1);
parts.dwExtraInfoLength = static_cast<DWORD>(-1);
if (!::WinHttpCrackUrl(url.c_str(), 0, 0, &parts))
{
Error = "invalid url";
return false;
}
std::wstring const host(parts.lpszHostName, parts.dwHostNameLength);
std::wstring const path = std::wstring(parts.lpszUrlPath, parts.dwUrlPathLength) + std::wstring(parts.lpszExtraInfo, parts.dwExtraInfoLength);
HINTERNET connection = ::WinHttpConnect(m_platform->session, host.c_str(), parts.nPort, 0);
HINTERNET request = connection ? ::WinHttpOpenRequest(connection, L"GET", path.c_str(), nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES,
parts.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0)
: nullptr;
auto const close = [&]() {
if (request != nullptr)
::WinHttpCloseHandle(request);
if (connection != nullptr)
::WinHttpCloseHandle(connection);
};
if (request == nullptr || !::WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || !::WinHttpReceiveResponse(request, nullptr))
{
Error = "WinHTTP error " + std::to_string(::GetLastError());
close();
return false;
}
DWORD status{0};
DWORD statussize{sizeof(status)};
::WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statussize, WINHTTP_NO_HEADER_INDEX);
for (;;)
{
if (Stop())
{
Error = "cancelled";
close();
return false;
}
DWORD available{0};
if (!::WinHttpQueryDataAvailable(request, &available))
{
Error = "WinHTTP error " + std::to_string(::GetLastError());
close();
return false;
}
if (available == 0)
break;
std::size_t const offset = Out.size();
Out.resize(offset + available);
DWORD received{0};
if (!::WinHttpReadData(request, Out.data() + offset, available, &received))
{
Error = "WinHTTP error " + std::to_string(::GetLastError());
close();
return false;
}
Out.resize(offset + received);
}
close();
if (status != 200)
{
Error = "HTTP " + std::to_string(status);
return false;
}
return true;
}
#elif defined(EU07_WITH_CURL)
client::client() :
m_platform(std::make_unique<platform>())
{
static std::once_flag initialized;
std::call_once(initialized, []() { ::curl_global_init(CURL_GLOBAL_DEFAULT); });
m_platform->curl = ::curl_easy_init();
}
client::~client()
{
if (m_platform->curl != nullptr)
::curl_easy_cleanup(m_platform->curl);
}
bool client::get(std::string const &Url, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &Stop)
{
Out.clear();
if (m_platform->curl == nullptr)
{
Error = "curl_easy_init failed";
return false;
}
auto const write = +[](char *Data, std::size_t Size, std::size_t Count, void *User) -> std::size_t {
auto *out = static_cast<std::vector<std::uint8_t> *>(User);
out->insert(out->end(), Data, Data + Size * Count);
return Size * Count;
};
auto const progress = +[](void *User, curl_off_t, curl_off_t, curl_off_t, curl_off_t) -> int { return (*static_cast<stop_check const *>(User))() ? 1 : 0; };
::curl_easy_reset(m_platform->curl);
::curl_easy_setopt(m_platform->curl, CURLOPT_URL, Url.c_str());
::curl_easy_setopt(m_platform->curl, CURLOPT_USERAGENT, "MaSzyna-editor");
::curl_easy_setopt(m_platform->curl, CURLOPT_FOLLOWLOCATION, 1L);
::curl_easy_setopt(m_platform->curl, CURLOPT_NOSIGNAL, 1L);
::curl_easy_setopt(m_platform->curl, CURLOPT_CONNECTTIMEOUT, 10L);
::curl_easy_setopt(m_platform->curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
::curl_easy_setopt(m_platform->curl, CURLOPT_LOW_SPEED_TIME, 20L);
::curl_easy_setopt(m_platform->curl, CURLOPT_WRITEFUNCTION, write);
::curl_easy_setopt(m_platform->curl, CURLOPT_WRITEDATA, &Out);
::curl_easy_setopt(m_platform->curl, CURLOPT_NOPROGRESS, 0L);
::curl_easy_setopt(m_platform->curl, CURLOPT_XFERINFOFUNCTION, progress);
::curl_easy_setopt(m_platform->curl, CURLOPT_XFERINFODATA, const_cast<stop_check *>(&Stop));
CURLcode const code = ::curl_easy_perform(m_platform->curl);
if (code != CURLE_OK)
{
Error = ::curl_easy_strerror(code);
return false;
}
long status{0};
::curl_easy_getinfo(m_platform->curl, CURLINFO_RESPONSE_CODE, &status);
if (status != 200)
{
Error = "HTTP " + std::to_string(status);
return false;
}
return true;
}
#else
client::client() = default;
client::~client() = default;
bool client::get(std::string const &, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &)
{
Out.clear();
Error = "no http client in this build";
return false;
}
#endif
bool available()
{
#if defined(_WIN32) || defined(EU07_WITH_CURL)
return true;
#else
return false;
#endif
}
} // namespace editor_http