mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 21:37:31 +01: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:
@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "editor/editorOrthophoto.hpp"
|
||||
#include "editor/editorHttp.hpp"
|
||||
|
||||
#include "rendering/renderer.h"
|
||||
#include "scene/scene.h"
|
||||
@@ -19,11 +20,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "imgui/imgui.h"
|
||||
#include "stb/stb_image.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <winhttp.h>
|
||||
#elif defined(EU07_WITH_CURL)
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
@@ -49,212 +45,14 @@ constexpr std::size_t upload_budget{16u << 20}; // bytes of texture data uploade
|
||||
constexpr std::size_t vertex_budget{60000}; // ImGui uses 16-bit indices and not every backend supports vertex offsets
|
||||
constexpr float near_w{0.5f};
|
||||
|
||||
using stop_check = std::function<bool()>;
|
||||
using stop_check = editor_http::stop_check;
|
||||
using http_client = editor_http::client;
|
||||
|
||||
double steady_seconds()
|
||||
{
|
||||
return std::chrono::duration<double>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// minimal blocking https GET; one instance per worker thread
|
||||
|
||||
class http_client
|
||||
{
|
||||
public:
|
||||
http_client();
|
||||
~http_client();
|
||||
http_client(http_client const &) = delete;
|
||||
http_client &operator=(http_client const &) = delete;
|
||||
|
||||
bool get(std::string const &Url, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &Stop);
|
||||
|
||||
private:
|
||||
#if defined(_WIN32)
|
||||
HINTERNET m_session{nullptr};
|
||||
#elif defined(EU07_WITH_CURL)
|
||||
CURL *m_curl{nullptr};
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
http_client::http_client()
|
||||
{
|
||||
wchar_t const *agent = L"MaSzyna-editor";
|
||||
#ifdef WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
|
||||
m_session = ::WinHttpOpen(agent, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
#endif
|
||||
if (m_session == nullptr) // automatic proxy needs windows 8.1+
|
||||
m_session = ::WinHttpOpen(agent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
if (m_session != nullptr)
|
||||
::WinHttpSetTimeouts(m_session, 10000, 10000, 15000, 20000);
|
||||
}
|
||||
|
||||
http_client::~http_client()
|
||||
{
|
||||
if (m_session != nullptr)
|
||||
::WinHttpCloseHandle(m_session);
|
||||
}
|
||||
|
||||
bool http_client::get(std::string const &Url, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &Stop)
|
||||
{
|
||||
Out.clear();
|
||||
if (m_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_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)
|
||||
|
||||
http_client::http_client()
|
||||
{
|
||||
static std::once_flag initialized;
|
||||
std::call_once(initialized, []() { ::curl_global_init(CURL_GLOBAL_DEFAULT); });
|
||||
m_curl = ::curl_easy_init();
|
||||
}
|
||||
|
||||
http_client::~http_client()
|
||||
{
|
||||
if (m_curl != nullptr)
|
||||
::curl_easy_cleanup(m_curl);
|
||||
}
|
||||
|
||||
bool http_client::get(std::string const &Url, std::vector<std::uint8_t> &Out, std::string &Error, stop_check const &Stop)
|
||||
{
|
||||
Out.clear();
|
||||
if (m_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_curl);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_URL, Url.c_str());
|
||||
::curl_easy_setopt(m_curl, CURLOPT_USERAGENT, "MaSzyna-editor");
|
||||
::curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_CONNECTTIMEOUT, 10L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_LOW_SPEED_TIME, 20L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &Out);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, progress);
|
||||
::curl_easy_setopt(m_curl, CURLOPT_XFERINFODATA, const_cast<stop_check *>(&Stop));
|
||||
|
||||
CURLcode const code = ::curl_easy_perform(m_curl);
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
Error = ::curl_easy_strerror(code);
|
||||
return false;
|
||||
}
|
||||
long status{0};
|
||||
::curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
if (status != 200)
|
||||
{
|
||||
Error = "HTTP " + std::to_string(status);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
http_client::http_client() = default;
|
||||
http_client::~http_client() = default;
|
||||
|
||||
bool http_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
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user