mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 14:59:43 +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:
@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
@@ -240,4 +241,67 @@ inline glm::dvec3 level(glm::dvec3 const &Vector)
|
||||
return glm::length(flat) > 1e-9 ? glm::normalize(flat) : glm::dvec3{0.0, 0.0, 1.0};
|
||||
}
|
||||
|
||||
// a point inside the polygon, by the number of its edges a ray along +x from it crosses
|
||||
inline bool point_in_polygon(std::vector<glm::dvec2> const &Polygon, glm::dvec2 const &Point)
|
||||
{
|
||||
bool result{false};
|
||||
for (std::size_t i = 0, j = Polygon.size() - 1; i < Polygon.size(); j = i++)
|
||||
{
|
||||
auto const &a{Polygon[i]};
|
||||
auto const &b{Polygon[j]};
|
||||
if ((a.y > Point.y) != (b.y > Point.y) && Point.x < a.x + (b.x - a.x) * (Point.y - a.y) / (b.y - a.y))
|
||||
result = !result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// the square of the side from (West, South), the axes the polygon's, touches the polygon: a corner of it inside the polygon, a
|
||||
// vertex of the polygon inside it, or an edge crossing an edge. A side of 0: the point inside the polygon
|
||||
inline bool square_touches(std::vector<glm::dvec2> const &Polygon, double const West, double const South, double const Size)
|
||||
{
|
||||
if (Polygon.size() < 3)
|
||||
return false;
|
||||
glm::dvec2 const corners[]{{West, South}, {West + Size, South}, {West + Size, South + Size}, {West, South + Size}};
|
||||
for (auto const &corner : corners)
|
||||
if (point_in_polygon(Polygon, corner))
|
||||
return true;
|
||||
if (Size <= 0.0)
|
||||
return false;
|
||||
for (auto const &point : Polygon)
|
||||
if (point.x >= West && point.x <= West + Size && point.y >= South && point.y <= South + Size)
|
||||
return true;
|
||||
// two segments crossing, by the sides each one's ends lie on of the other
|
||||
auto const side = [](glm::dvec2 const &A, glm::dvec2 const &B, glm::dvec2 const &P) { return (B.x - A.x) * (P.y - A.y) - (B.y - A.y) * (P.x - A.x); };
|
||||
auto const crossing = [&](glm::dvec2 const &A, glm::dvec2 const &B, glm::dvec2 const &C, glm::dvec2 const &D) {
|
||||
return ((side(A, B, C) > 0.0) != (side(A, B, D) > 0.0)) && ((side(C, D, A) > 0.0) != (side(C, D, B) > 0.0));
|
||||
};
|
||||
for (std::size_t i = 0, j = Polygon.size() - 1; i < Polygon.size(); j = i++)
|
||||
for (int k = 0; k < 4; ++k)
|
||||
if (crossing(Polygon[j], Polygon[i], corners[k], corners[(k + 1) % 4]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// the squares of a grid of the size, from 0 along both axes, the polygon touches, by their indices along the axes
|
||||
inline std::vector<std::pair<int, int>> squares_in(std::vector<glm::dvec2> const &Polygon, double const Size)
|
||||
{
|
||||
std::vector<std::pair<int, int>> result;
|
||||
if (Polygon.size() < 3 || Size <= 0.0)
|
||||
return result;
|
||||
glm::dvec2 low{Polygon.front()};
|
||||
glm::dvec2 high{Polygon.front()};
|
||||
for (auto const &point : Polygon)
|
||||
{
|
||||
low = glm::min(low, point);
|
||||
high = glm::max(high, point);
|
||||
}
|
||||
auto const first{glm::ivec2{static_cast<int>(std::floor(low.x / Size)), static_cast<int>(std::floor(low.y / Size))}};
|
||||
auto const last{glm::ivec2{static_cast<int>(std::floor(high.x / Size)), static_cast<int>(std::floor(high.y / Size))}};
|
||||
for (int y = first.y; y <= last.y; ++y)
|
||||
for (int x = first.x; x <= last.x; ++x)
|
||||
if (square_touches(Polygon, x * Size, y * Size, Size))
|
||||
result.emplace_back(x, y);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace geometry
|
||||
|
||||
Reference in New Issue
Block a user