1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:17:34 +00:00

Maps: Load tiles starting from center

The information the user is most interested in is usually in the center,
so we should start loading tiles from the center and move outwards.
Since tiles are loaded in draw order, simply drawing them in this order
achieves the desired effect. The current center-outwards loading
algorithm is a basic spiral algorithm, but others may be evaluated
later.
This commit is contained in:
kleines Filmröllchen 2023-09-19 00:54:03 +02:00 committed by Jelle Raaijmakers
parent a54e283901
commit 614ff9c46e

View file

@ -361,6 +361,82 @@ void MapWidget::clear_tile_queue()
m_tiles.remove_all_matching([](auto, auto const& value) -> bool { return !value; });
}
// Iterates from the center (0,0) outwards, towards a certain width or height (inclusive).
// The current iteration algorithm is a basic generator-like spiral algorithm adapted for C++ iterators.
template<Integral T>
class CenterOutwardsIterable {
public:
using ElementType = T;
constexpr CenterOutwardsIterable(T width, T height)
: m_width(move(width))
, m_height(move(height))
{
}
struct Iterator {
T width;
T height;
T index { 0 };
T current_x { 0 };
T current_y { 0 };
Gfx::Point<T> last_valid_position { current_x, current_y };
constexpr Iterator(T width, T height)
: width(move(width))
, height(move(height))
{
}
constexpr Iterator end() const
{
auto end = *this;
end.index = AK::max(width, height) * AK::max(width, height);
return end;
}
constexpr bool is_end() const { return *this == end(); }
constexpr bool operator==(Iterator const& other) const { return index == other.index; }
constexpr bool operator!=(Iterator const& other) const { return index != other.index; }
constexpr Gfx::Point<T> operator*() const { return last_valid_position; }
constexpr Iterator operator++()
{
auto found_valid_position = false;
while (!found_valid_position && !is_end()) {
// Translating the coordinates makes the range check simpler:
T xp = current_x + width / 2;
T yp = current_y + height / 2;
if (xp >= 0 && xp <= width && yp >= 0 && yp <= height) {
last_valid_position = { current_x, current_y };
found_valid_position = true;
}
// Figure out in which of the four squares we are.
if (AK::abs(current_x) <= AK::abs(current_y) && (current_x != current_y || current_x >= 0))
current_x += ((current_y >= 0) ? 1 : -1);
else
current_y += ((current_x >= 0) ? -1 : 1);
++index;
}
return *this;
}
};
constexpr Iterator begin() { return Iterator { m_width, m_height }; }
constexpr Iterator end() { return begin().end(); }
private:
T m_width;
T m_height;
};
void MapWidget::paint_map(GUI::Painter& painter)
{
int center_tile_x = longitude_to_tile_x(m_center.longitude, m_zoom);
@ -371,18 +447,17 @@ void MapWidget::paint_map(GUI::Painter& painter)
// Draw grid around center tile
int grid_width = (width() + TILE_SIZE - 1) / TILE_SIZE;
int grid_height = (height() + TILE_SIZE - 1) / TILE_SIZE;
for (int dy = -(grid_height / 2) - 1; dy < ((grid_height + 2 - 1) / 2) + 1; ++dy) {
for (int dx = -(grid_width / 2) - 1; dx < ((grid_width + 2 - 1) / 2) + 1; ++dx) {
int tile_x = center_tile_x + dx;
int tile_y = center_tile_y + dy;
for (auto const delta : CenterOutwardsIterable { grid_width + 1, grid_height + 1 }) {
int tile_x = center_tile_x + delta.x();
int tile_y = center_tile_y + delta.y();
// Only draw tiles that exist
if (tile_x < 0 || tile_y < 0 || tile_x > pow(2, m_zoom) - 1 || tile_y > pow(2, m_zoom) - 1)
continue;
auto tile_rect = Gfx::IntRect {
static_cast<int>(width() / 2 + dx * TILE_SIZE - offset_x),
static_cast<int>(height() / 2 + dy * TILE_SIZE - offset_y),
static_cast<int>(width() / 2 + delta.x() * TILE_SIZE - offset_x),
static_cast<int>(height() / 2 + delta.y() * TILE_SIZE - offset_y),
TILE_SIZE,
TILE_SIZE,
};
@ -437,7 +512,6 @@ void MapWidget::paint_map(GUI::Painter& painter)
}
}
}
}
// Draw markers
for (auto const& marker : m_markers) {