mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 02:58:37 +01:00
feat(editor): the download area drawn on the topo map: a polygon is the boundary of what the editor downloads, the orthophoto and the terrain model alike. Drawn from the settings of the orthophoto (Download area, Draw on the map, the top view on): a click puts a point, a point dragged moves, Shift+click removes it, Backspace takes the last one back, Enter closes the area, Esc gives up; it's kept in the scenery as //$a lines in PUWG 1992, so it stays on the ground when the origin moves. Inside it everything the settings ask for, the standard imagery, the 4K one where it's ticked and covers the place, the squares of the terrain model where the scenery has its terrain, goes to the disk cache in the background, nothing decoded nor uploaded, only while no tile around the camera waits and not while the scenery is driven, with its progress, Pause and Retry under it; outside it nothing is asked for, around the camera, along the tracks or ahead of the laying, nor shown. The workers of the orthophoto are 8, at most 3 of them on the tiles around the camera, each holding an image decoded, the rest downloading the area. The 4K tiles: an image the tile no longer wants once it comes, as a 4K one asked for before the camera moved on, isn't uploaded (the 64 MB and the mipmaps of it), nor decoded where a newer job of the tile waits; no two jobs of one tile run at once; a standard tile coming blank twice is remembered by a .blank file, not downloaded again on each return; a 4K tile is uploaded only in a frame with no other upload. Selftests orthoarea, orthostats, orthohires, orthoareapause; unit tests of the tiles a triangle, a concave polygon, a thin band and a polygon about a corner touch (geometry::squares_in, square_touches)
This commit is contained in:
@@ -1506,6 +1506,8 @@ bool editor_mode::update()
|
||||
background->PushClipRect(ImVec2(editor_ui::view_min().x, editor_ui::view_min().y), ImVec2(editor_ui::view_max().x, editor_ui::view_max().y), true);
|
||||
draw_orthophoto();
|
||||
draw_nmt_pending();
|
||||
area_update();
|
||||
draw_download_area();
|
||||
|
||||
// --- ImGuizmo: in-viewport transform gizmo for the selected node ---
|
||||
render_gizmo();
|
||||
@@ -2288,6 +2290,11 @@ void editor_mode::load_orthophoto_settings()
|
||||
}
|
||||
m_orthophoto.settings(config);
|
||||
m_orthophoto_origin_edit = {config.north, config.east};
|
||||
// the area the imagery and the terrain model are downloaded in, none in a scenery which has none
|
||||
m_orthophoto_area_mark = scene::Layers.empty() ? std::vector<std::string>{} : scene::Layers.marked(scene::layer_handle{1}, "//$a");
|
||||
m_orthophoto.area(editor_orthophoto::read_area(m_orthophoto_area_mark));
|
||||
if (false == m_orthophoto.area().empty())
|
||||
WriteLog(format("Editor: the download area of the scenery, %zu points, %d tiles of the orthophoto", m_orthophoto.area().size(), m_orthophoto.stats().area_tiles));
|
||||
}
|
||||
|
||||
void editor_mode::save_orthophoto_settings()
|
||||
@@ -2384,7 +2391,7 @@ void editor_mode::render_orthophoto_ui()
|
||||
};
|
||||
|
||||
auto const stats = m_orthophoto.stats();
|
||||
if (stats.failed > 0)
|
||||
if (stats.failed > 0 || stats.area_failed > 0)
|
||||
{
|
||||
ImGui::Text(STR_C("Tiles: %d shown, %d loading, %d failed"), stats.resident, stats.loading, stats.failed);
|
||||
ImGui::SameLine();
|
||||
@@ -2392,6 +2399,10 @@ void editor_mode::render_orthophoto_ui()
|
||||
m_orthophoto.retry_failed();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
render_download_area_ui(stats);
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode(STR_C("More settings")))
|
||||
{
|
||||
if (ImGui::Checkbox(STR_C("Fit to terrain"), &config.drape))
|
||||
@@ -3055,6 +3066,11 @@ bool editor_mode::save()
|
||||
m_orthophoto_mark = map;
|
||||
scene::Layers.mark(scene::layer_handle{1}, "//$o", {map});
|
||||
}
|
||||
if (auto const area{editor_orthophoto::area_lines(m_orthophoto.area())}; false == m_orthophoto_scenery.empty() && area != m_orthophoto_area_mark)
|
||||
{
|
||||
m_orthophoto_area_mark = area;
|
||||
scene::Layers.mark(scene::layer_handle{1}, "//$a", area);
|
||||
}
|
||||
auto const terrainadded{false == rootstatements.empty() || false == statements.empty()};
|
||||
auto const controls{turntable_controls(rootstatements)};
|
||||
auto const noses{nose_controls(rootstatements)};
|
||||
@@ -6181,6 +6197,8 @@ void editor_mode::enter()
|
||||
EditorModeFlag = true;
|
||||
|
||||
load_orthophoto_settings();
|
||||
m_orthophoto.area_paused(m_area_paused);
|
||||
m_nmt.prefetch_paused(m_area_paused);
|
||||
|
||||
Application.set_cursor(GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
@@ -6211,6 +6229,9 @@ void editor_mode::exit()
|
||||
m_fill_last.clear();
|
||||
m_orthophoto.cancel_pending();
|
||||
m_orthophoto.detach_scene(); // the layer is an editor aid, keep it out of the other modes
|
||||
// the download of the area held while the scenery is driven, it goes on once the editor is back
|
||||
m_orthophoto.area_paused(true);
|
||||
m_nmt.prefetch_paused(true);
|
||||
scene::Layers.show_all(); // likewise for hidden scenery layers, the other modes get the scenery as it was defined
|
||||
|
||||
// drop selection so a stale/dangling node pointer isn't used on the next editor session
|
||||
@@ -6484,6 +6505,12 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
// an open list or menu takes this Esc for itself, the selection behind it stays
|
||||
if (ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel))
|
||||
break;
|
||||
// the download area being drawn given up, the one before stays
|
||||
if (is_press(Action) && m_area_drawing.active)
|
||||
{
|
||||
area_finish(false);
|
||||
break;
|
||||
}
|
||||
if (is_press(Action))
|
||||
{
|
||||
road_cancel();
|
||||
@@ -6526,6 +6553,13 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
break;
|
||||
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
// the download area: the last point taken back
|
||||
if (is_press(Action) && m_area_drawing.active)
|
||||
{
|
||||
if (false == m_area_drawing.points.empty())
|
||||
m_area_drawing.points.pop_back();
|
||||
break;
|
||||
}
|
||||
// area fill: remove the last outline point
|
||||
if (is_press(Action) && ui()->mode() == nodebank_panel::FILL && !m_fill_points.empty())
|
||||
m_fill_points.pop_back();
|
||||
@@ -6540,6 +6574,13 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
|
||||
case GLFW_KEY_ENTER:
|
||||
case GLFW_KEY_KP_ENTER:
|
||||
// the download area closed, from three points on
|
||||
if (is_press(Action) && m_area_drawing.active)
|
||||
{
|
||||
if (m_area_drawing.points.size() >= 3)
|
||||
area_finish(true);
|
||||
break;
|
||||
}
|
||||
if (is_press(Action) && ui()->mode() == nodebank_panel::TRACK && m_lay.active)
|
||||
lay_enter();
|
||||
if (is_press(Action) && m_route.trace.active && route_active())
|
||||
@@ -6600,6 +6641,17 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const
|
||||
return;
|
||||
}
|
||||
|
||||
// the download area drawn on the map takes the left button while it's drawn
|
||||
if (m_area_drawing.active && Button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
{
|
||||
if (is_press(Action))
|
||||
area_click(Global.shiftState);
|
||||
else
|
||||
m_area_drawing.dragged = -1;
|
||||
m_input.mouse.button(Button, Action);
|
||||
return;
|
||||
}
|
||||
|
||||
// the chunk, spacing and water tools of the terrain work on a click (Shift: the other way round)
|
||||
if (terrain_clicking() && Button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
{
|
||||
|
||||
@@ -471,6 +471,20 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
// the chunks waiting for the terrain model and the tiles of the imagery asked for outlined where they will be, so it's seen
|
||||
// what's on its way
|
||||
void draw_nmt_pending() const;
|
||||
// the download area: a polygon drawn on the map, the boundary of what the orthophoto and the terrain model download in the
|
||||
// background, none of them asking for anything outside it (application/editormodenmt.cpp)
|
||||
void area_start();
|
||||
// Keep: the area drawn taken, else the one before stays
|
||||
void area_finish(bool const Keep);
|
||||
// a press of the left button while drawing: a point added, or the one under the cursor taken to drag, Shift: removed
|
||||
void area_click(bool const Shift);
|
||||
void area_update();
|
||||
// a point of the area (x, z) where it's drawn: over the map of the top view, on the ground in the 3d view
|
||||
glm::dvec3 area_point(glm::dvec2 const &Point) const;
|
||||
void draw_download_area() const;
|
||||
void render_download_area_ui(editor_orthophoto::statistics const &Stats);
|
||||
// the chunk of the terrain (x, z) touches the area, or there's none
|
||||
bool in_download_area(glm::dvec2 const &Low, glm::dvec2 const &High) const;
|
||||
// over the 3d view while the terrain panel isn't seen
|
||||
void render_nmt_banner();
|
||||
bool nmt_busy() const;
|
||||
@@ -712,6 +726,16 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
std::size_t m_ortho_waiting{0}; // squares of the terrain model asked for and not in yet, the same
|
||||
std::string m_orthophoto_scenery; // scenery whose origin is loaded
|
||||
std::string m_orthophoto_mark;
|
||||
std::vector<std::string> m_orthophoto_area_mark; // the lines of the download area as the scenery keeps them
|
||||
// the download area being drawn on the map: its points in the world (x, z), the one dragged
|
||||
struct area_drawing
|
||||
{
|
||||
bool active{false};
|
||||
std::vector<glm::dvec2> points;
|
||||
int dragged{-1};
|
||||
} m_area_drawing;
|
||||
std::vector<glm::dvec2> m_nmt_prefetched; // the download area the terrain model was given
|
||||
bool m_area_paused{false}; // the download of the area held by the button; out of the editor it's held anyway
|
||||
glm::dvec2 m_orthophoto_origin_edit{0.0}; // origin being typed in (northing, easting); applied when editing ends
|
||||
|
||||
// hierarchy management
|
||||
|
||||
@@ -33,6 +33,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -511,7 +512,12 @@ std::vector<heightmap::chunk_key> editor_mode::nmt_keys_around() const
|
||||
auto const first{-(m_terrain_add_count - 1) / 2};
|
||||
for (int dz = 0; dz < m_terrain_add_count; ++dz)
|
||||
for (int dx = 0; dx < m_terrain_add_count; ++dx)
|
||||
result.push_back({centre.first + first + dx, centre.second + first + dz});
|
||||
{
|
||||
heightmap::chunk_key const key{centre.first + first + dx, centre.second + first + dz};
|
||||
// none outside the download area
|
||||
if (auto const low{heightmap::chunk_corner(key)}; in_download_area(low, low + glm::dvec2{heightmap::chunk_size}))
|
||||
result.push_back(key);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -529,7 +535,7 @@ std::vector<heightmap::chunk_key> editor_mode::nmt_keys_along_tracks() const
|
||||
auto const low{heightmap::chunk_corner(key)};
|
||||
// the chunk reaches within the band of the track
|
||||
glm::dvec2 const nearest{std::clamp(place.position.x, low.x, low.x + heightmap::chunk_size), std::clamp(place.position.z, low.y, low.y + heightmap::chunk_size)};
|
||||
if (glm::distance(nearest, glm::dvec2{place.position.x, place.position.z}) <= m_nmt_state.band)
|
||||
if (glm::distance(nearest, glm::dvec2{place.position.x, place.position.z}) <= m_nmt_state.band && in_download_area(low, low + glm::dvec2{heightmap::chunk_size}))
|
||||
keys.insert(key);
|
||||
}
|
||||
}
|
||||
@@ -890,6 +896,12 @@ std::size_t editor_mode::nmt_shape_tracks(std::vector<TTrack *> const *Only)
|
||||
void editor_mode::nmt_update()
|
||||
{
|
||||
auto &state{m_nmt_state};
|
||||
// the squares of the model in the download area to the disk cache, where the scenery is placed and its terrain is there
|
||||
if (auto const wanted{m_nmt.placed() && m_streamer.active() ? m_orthophoto.area() : std::vector<glm::dvec2>{}}; wanted != m_nmt_prefetched)
|
||||
{
|
||||
m_nmt_prefetched = wanted;
|
||||
m_nmt.prefetch(wanted);
|
||||
}
|
||||
nmt_offer();
|
||||
nmt_follow_tracks();
|
||||
if (state.stage != nmt_state::automatic::idle)
|
||||
@@ -1007,6 +1019,9 @@ void editor_mode::nmt_grow()
|
||||
if (false == laying && false == m_streamer.active())
|
||||
return;
|
||||
auto const at{m_extend.active ? m_extend.mouse : m_lay.active ? m_lay.mouse : glm::dvec3{Camera.Pos}};
|
||||
// nothing asked for outside the download area
|
||||
if (false == in_download_area({at.x - 100.0, at.z - 100.0}, {at.x + 100.0, at.z + 100.0}))
|
||||
return;
|
||||
// the model under it, for the heights of the points laid where there's no terrain yet, as over the base map
|
||||
m_nmt.request({at.x - 100.0, at.z - 100.0}, {at.x + 100.0, at.z + 100.0});
|
||||
if (m_streamer.resident() == 0)
|
||||
@@ -1023,7 +1038,8 @@ void editor_mode::nmt_grow()
|
||||
auto const low{heightmap::chunk_corner(key)};
|
||||
glm::dvec2 const nearest{std::clamp(cursor.x, low.x, low.x + heightmap::chunk_size), std::clamp(cursor.y, low.y, low.y + heightmap::chunk_size)};
|
||||
auto const distance{glm::distance(nearest, cursor)};
|
||||
if (distance <= grow_reach && false == m_streamer.exists(key) && false == state.given_up.contains(key) && std::find(state.pending.begin(), state.pending.end(), key) == state.pending.end())
|
||||
if (distance <= grow_reach && false == m_streamer.exists(key) && false == state.given_up.contains(key) && std::find(state.pending.begin(), state.pending.end(), key) == state.pending.end() &&
|
||||
in_download_area(low, low + glm::dvec2{heightmap::chunk_size}))
|
||||
missing.emplace_back(distance, key);
|
||||
}
|
||||
if (missing.empty())
|
||||
@@ -1359,6 +1375,202 @@ void editor_mode::draw_nmt_pending() const
|
||||
square(low, high, 90, 170, 255, STR("Terrain model loading"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// the download area
|
||||
|
||||
void editor_mode::area_start()
|
||||
{
|
||||
auto &drawing{m_area_drawing};
|
||||
drawing = {};
|
||||
drawing.active = true;
|
||||
// the area there is taken up to be changed
|
||||
for (auto const &point : m_orthophoto.area())
|
||||
drawing.points.push_back(m_orthophoto.to_world(point));
|
||||
// drawn on the map of the top view
|
||||
if (false == m_orthophoto.enabled())
|
||||
m_orthophoto.enabled(true);
|
||||
if (false == Global.EditorOrtho)
|
||||
toggle_ortho();
|
||||
WriteLog("Editor: drawing the download area");
|
||||
}
|
||||
|
||||
void editor_mode::area_finish(bool const Keep)
|
||||
{
|
||||
auto &drawing{m_area_drawing};
|
||||
if (Keep && drawing.points.size() >= 3)
|
||||
{
|
||||
std::vector<glm::dvec2> polygon;
|
||||
for (auto const &point : drawing.points)
|
||||
polygon.push_back(m_orthophoto.to_puwg(point));
|
||||
m_orthophoto.area(std::move(polygon));
|
||||
WriteLog(format("Editor: the download area of %zu points, %d tiles of the orthophoto", drawing.points.size(), m_orthophoto.stats().area_tiles));
|
||||
}
|
||||
drawing = {};
|
||||
}
|
||||
|
||||
glm::dvec3 editor_mode::area_point(glm::dvec2 const &Point) const
|
||||
{
|
||||
double height{Camera.Pos.y - 2.0};
|
||||
if (false == Global.EditorOrtho && false == m_streamer.height_at(Point.x, Point.y, height) && false == nmt_ground(Point.x, Point.y, height))
|
||||
height = 0.0;
|
||||
return {Point.x, height, Point.y};
|
||||
}
|
||||
|
||||
void editor_mode::area_click(bool const Shift)
|
||||
{
|
||||
auto &drawing{m_area_drawing};
|
||||
screen_projection const projection;
|
||||
// the point under the cursor, within 10 pixels
|
||||
int nearest{-1};
|
||||
auto best{100.0f};
|
||||
for (std::size_t i = 0; i < drawing.points.size(); ++i)
|
||||
if (auto const distance{projection.mouse_distance2(area_point(drawing.points[i]))}; distance < best)
|
||||
{
|
||||
best = distance;
|
||||
nearest = static_cast<int>(i);
|
||||
}
|
||||
if (nearest >= 0)
|
||||
{
|
||||
if (Shift)
|
||||
drawing.points.erase(drawing.points.begin() + nearest);
|
||||
else
|
||||
drawing.dragged = nearest;
|
||||
return;
|
||||
}
|
||||
if (Shift)
|
||||
return;
|
||||
auto const cursor{std::as_const(*this).cursor_ground()};
|
||||
drawing.points.emplace_back(cursor.x, cursor.z);
|
||||
}
|
||||
|
||||
void editor_mode::area_update()
|
||||
{
|
||||
auto &drawing{m_area_drawing};
|
||||
if (false == drawing.active || drawing.dragged < 0)
|
||||
return;
|
||||
if (false == ImGui::IsMouseDown(0) || drawing.dragged >= static_cast<int>(drawing.points.size()))
|
||||
{
|
||||
drawing.dragged = -1;
|
||||
return;
|
||||
}
|
||||
auto const cursor{std::as_const(*this).cursor_ground()};
|
||||
drawing.points[drawing.dragged] = {cursor.x, cursor.z};
|
||||
}
|
||||
|
||||
void editor_mode::draw_download_area() const
|
||||
{
|
||||
auto const &drawing{m_area_drawing};
|
||||
std::vector<glm::dvec2> points;
|
||||
if (drawing.active)
|
||||
points = drawing.points;
|
||||
else
|
||||
for (auto const &point : m_orthophoto.area())
|
||||
points.push_back(m_orthophoto.to_world(point));
|
||||
// shown while it's drawn, with the settings of the orthophoto open, and over the map of the top view
|
||||
if (points.empty() || (false == drawing.active && false == m_orthophoto_window && false == Global.EditorOrthoMap))
|
||||
return;
|
||||
screen_projection const projection;
|
||||
auto *drawlist{ImGui::GetBackgroundDrawList()};
|
||||
// the tiles of the area as they are: in the disk cache, failed; the ones waiting left clear
|
||||
if (false == drawing.active && m_orthophoto_window)
|
||||
for (auto const &square : m_orthophoto.area_squares())
|
||||
{
|
||||
if (square.state == 0)
|
||||
continue;
|
||||
std::array<ImVec2, 4> corners;
|
||||
auto seen{true};
|
||||
glm::dvec2 const at[]{square.low, {square.high.x, square.low.y}, square.high, {square.low.x, square.high.y}};
|
||||
for (int i = 0; i < 4 && seen; ++i)
|
||||
seen = projection.project(area_point(at[i]), corners[i]);
|
||||
if (seen)
|
||||
drawlist->AddQuadFilled(corners[0], corners[1], corners[2], corners[3], square.state == 1 ? IM_COL32(90, 220, 120, 45) : IM_COL32(240, 80, 70, 80));
|
||||
}
|
||||
auto const edge{IM_COL32(80, 220, 255, 230)};
|
||||
auto const closing{IM_COL32(80, 220, 255, drawing.active ? 110 : 230)};
|
||||
// the edge back to the first point from three points on
|
||||
auto const edges{points.size() >= 3 ? points.size() : points.size() - 1};
|
||||
for (std::size_t i = 0; i < edges; ++i)
|
||||
{
|
||||
auto const last{i + 1 == points.size()};
|
||||
projection.line(drawlist, area_point(points[i]), area_point(points[(i + 1) % points.size()]), last ? closing : edge, 2.0f);
|
||||
}
|
||||
if (false == drawing.active)
|
||||
return;
|
||||
// the points, the one under the cursor larger, and the line on to the cursor
|
||||
ImVec2 screen;
|
||||
for (auto const &point : points)
|
||||
if (projection.project(area_point(point), screen))
|
||||
drawlist->AddCircleFilled(screen, projection.mouse_distance2(area_point(point)) < 100.0f ? 6.0f : 4.0f, edge);
|
||||
if (false == points.empty() && drawing.dragged < 0 && false == ImGui::GetIO().WantCaptureMouse)
|
||||
{
|
||||
auto const cursor{std::as_const(*this).cursor_ground()};
|
||||
projection.line(drawlist, area_point(points.back()), area_point({cursor.x, cursor.z}), closing, 1.5f);
|
||||
}
|
||||
}
|
||||
|
||||
bool editor_mode::in_download_area(glm::dvec2 const &Low, glm::dvec2 const &High) const
|
||||
{
|
||||
auto const &area{m_orthophoto.area()};
|
||||
if (area.empty())
|
||||
return true;
|
||||
// the square in PUWG: the easting grows to the west of the scenery, the northing with z
|
||||
auto const &config{m_orthophoto.settings()};
|
||||
return geometry::square_touches(area, config.east - High.x, config.north + Low.y, High.x - Low.x);
|
||||
}
|
||||
|
||||
void editor_mode::render_download_area_ui(editor_orthophoto::statistics const &Stats)
|
||||
{
|
||||
auto &drawing{m_area_drawing};
|
||||
ImGui::TextUnformatted(STR_C("Download area"));
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", STR_C("A polygon drawn on the map: what the settings ask for inside it, the orthophoto and the terrain model,\n"
|
||||
"goes to the disk cache in the background, and nothing outside it is downloaded, also around the camera"));
|
||||
if (drawing.active)
|
||||
{
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.3f, 1.0f), "%s", STR_C("Click the points of the area on the map. Enter closes it, Backspace takes the last point back, Esc gives up;\n"
|
||||
"a point dragged moves, Shift+click removes it"));
|
||||
ImGui::Text(STR_C("%zu points"), drawing.points.size());
|
||||
ImGui::SameLine();
|
||||
if (drawing.points.size() >= 3 && ImGui::Button(STR_C("Done")))
|
||||
area_finish(true);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(STR_C("Cancel")))
|
||||
area_finish(false);
|
||||
return;
|
||||
}
|
||||
auto const &area{m_orthophoto.area()};
|
||||
if (ImGui::Button(area.empty() ? STR_C("Draw on the map") : STR_C("Draw again")))
|
||||
area_start();
|
||||
if (area.empty())
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("%s", STR_C("none: the tiles around the camera, wherever it is"));
|
||||
return;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(STR_C("Remove")))
|
||||
m_orthophoto.area({});
|
||||
ImGui::Text(STR_C("Area: %d of %d tiles in the cache, %d failed"), Stats.area_cached, Stats.area_tiles, Stats.area_failed);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(m_area_paused ? STR_C("Resume") : STR_C("Pause")))
|
||||
{
|
||||
m_area_paused = false == m_area_paused;
|
||||
m_orthophoto.area_paused(m_area_paused);
|
||||
m_nmt.prefetch_paused(m_area_paused);
|
||||
}
|
||||
if (auto const terrain{m_nmt.prefetched()}; terrain.total > 0)
|
||||
{
|
||||
ImGui::Text(STR_C("Terrain model: %d of %d squares in the cache, %d failed"), terrain.cached, terrain.total, terrain.failed);
|
||||
// the ones there are only looked up again
|
||||
if (terrain.failed > 0)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton((std::string{STR_C("Retry")} + "##terrainarea").c_str()))
|
||||
m_nmt.prefetch(m_nmt_prefetched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void editor_mode::render_nmt_banner()
|
||||
{
|
||||
auto const &state{m_nmt_state};
|
||||
|
||||
@@ -124,6 +124,8 @@ editor_mode::selftest_result editor_mode::selftest_dispatch(std::string const &c
|
||||
// terrainturn <palette entry> <degrees> the textures of the palette entry turned
|
||||
// terrainwater <index> <material> [size] material and repeat of a body of water; terrainwaterdefault <material>
|
||||
// orthophoto <north> <east> <radius> <fit 0|1> [in scene 0|1] the imagery layer on, placed and fitted as given
|
||||
// orthoarea <x> <z>... | clear the download area through the points of the world, as drawn on the map; orthoareapause 0|1
|
||||
// orthohires 0|1 the 4K tiles on or off; orthostats logs the tiles, the area and the requests made
|
||||
// join <x> <z> <x> <z> [radius] [variant] [transitions 0|1] the free ends at the points joined, as a drag from one to the other
|
||||
// layto <x> <z> <x> <z> <layout 0..3> <radius> from the free end at the first point towards the second, as a drag in the layout
|
||||
// layclicks <layout 0..3> <radius> <x> <z>... clicks of the lay tool at the points, a free end within 3 m joined
|
||||
|
||||
@@ -73,6 +73,46 @@ editor_mode::selftest_result editor_mode::selftest_terrain(std::string const &co
|
||||
WriteLog(format("SELFTEST orthophoto at %.0f %.0f, radius %d, %s%s", config.north, config.east, config.radius, config.drape ? "fitted" : "flat", config.in_scene ? ", in the scene" : ""));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "orthoarea")
|
||||
{
|
||||
// the download area through the points of the world (x, z), as drawn on the map; clear: none
|
||||
std::vector<glm::dvec2> polygon;
|
||||
if (words.str().find(" clear") == std::string::npos)
|
||||
for (glm::dvec2 point{0.0}; words >> point.x >> point.y;)
|
||||
polygon.push_back(m_orthophoto.to_puwg(point));
|
||||
m_orthophoto.area(polygon);
|
||||
WriteLog(format("SELFTEST orthoarea: %zu points, %d tiles", m_orthophoto.area().size(), m_orthophoto.stats().area_tiles));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "orthoareapause")
|
||||
{
|
||||
int paused{1};
|
||||
words >> paused;
|
||||
m_area_paused = paused != 0;
|
||||
m_orthophoto.area_paused(m_area_paused);
|
||||
m_nmt.prefetch_paused(m_area_paused);
|
||||
WriteLog(format("SELFTEST orthoareapause %d", paused));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "orthohires")
|
||||
{
|
||||
int hires{1};
|
||||
words >> hires;
|
||||
auto config{m_orthophoto.settings()};
|
||||
config.hires = hires != 0;
|
||||
m_orthophoto.settings(config);
|
||||
WriteLog(format("SELFTEST orthohires %d", hires));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "orthostats")
|
||||
{
|
||||
auto const stats{m_orthophoto.stats()};
|
||||
auto const terrain{m_nmt.prefetched()};
|
||||
WriteLog(format("SELFTEST orthostats: shown %d, loading %d, failed %d; area %d of %d in the cache, %d failed%s; requests %d, uploads %d, stale %d; terrain area %d of %d, %d failed",
|
||||
stats.resident, stats.loading, stats.failed, stats.area_cached, stats.area_tiles, stats.area_failed, stats.area_paused ? ", paused" : "", stats.requests, stats.uploads, stats.stale, terrain.cached,
|
||||
terrain.total, terrain.failed));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "nmtfit")
|
||||
{
|
||||
// the heights of the terrain model fitted to the tracks, as the button of the terrain panel does
|
||||
|
||||
Reference in New Issue
Block a user