6#include "tilesmanager_p.h"
15#define TILES_MAXSIZE 2000000
19static bool rankedTilesLessThan(
const TileNode *t1,
const TileNode *t2)
22 if (t1->dirty == t2->dirty) {
23 return t1->distance < t2->distance;
29class TilesManager::Private
34 bool hasPixmap(
const NormalizedRect &rect,
const TileNode &tile)
const;
36 void setPixmap(
const QPixmap *pixmap,
const NormalizedRect &rect, TileNode &tile,
bool isPartialPixmap);
41 static void markDirty(TileNode &tile);
46 void deleteTiles(
const TileNode &tile);
48 void markParentDirty(
const TileNode &tile);
71 qulonglong totalPixels;
79TilesManager::Private::Private()
91TilesManager::TilesManager(
int pageNumber,
int width,
int height,
Rotation rotation)
94 d->pageNumber = pageNumber;
97 d->rotation = rotation;
100 const double dim = 0.25;
101 for (
int i = 0; i < 16; ++i) {
104 d->tiles[i].rect =
NormalizedRect(x * dim, y * dim, x * dim + dim, y * dim + dim);
108TilesManager::~TilesManager()
110 for (
const TileNode &tile : d->tiles) {
111 d->deleteTiles(tile);
117void TilesManager::Private::deleteTiles(
const TileNode &tile)
120 totalPixels -= tile.pixmap->width() * tile.pixmap->height();
124 if (tile.nTiles > 0) {
125 for (
int i = 0; i < tile.nTiles; ++i) {
126 deleteTiles(tile.tiles[i]);
133void TilesManager::setSize(
int width,
int height)
135 if (width == d->width && height == d->height) {
145int TilesManager::width()
const
150int TilesManager::height()
const
155void TilesManager::setRotation(
Rotation rotation)
157 if (rotation == d->rotation) {
161 d->rotation = rotation;
164Rotation TilesManager::rotation()
const
169void TilesManager::markDirty()
171 for (TileNode &tile : d->tiles) {
172 TilesManager::Private::markDirty(tile);
176void TilesManager::Private::markDirty(TileNode &tile)
180 for (
int i = 0; i < tile.nTiles; ++i) {
181 markDirty(tile.tiles[i]);
187 const NormalizedRect rotatedRect = TilesManager::fromRotatedRect(rect, d->rotation);
188 if (!d->requestRect.isNull()) {
189 if (!(d->requestRect == rect)) {
203 if (d->rotation % 2) {
216 for (TileNode &tile : d->tiles) {
217 d->setPixmap(pixmap, rotatedRect, tile, isPartialPixmap);
221void TilesManager::Private::setPixmap(
const QPixmap *pixmap,
const NormalizedRect &rect, TileNode &tile,
bool isPartialPixmap)
223 QRect pixmapRect = TilesManager::toRotatedRect(rect, rotation).geometry(width, height);
226 if (!tile.rect.intersects(rect)) {
230 if (isPartialPixmap && tile.pixmap !=
nullptr && !tile.partial) {
236 if (!((tile.rect & rect) == tile.rect)) {
238 if (tile.nTiles > 0) {
239 for (
int i = 0; i < tile.nTiles; ++i) {
240 setPixmap(pixmap, rect, tile.tiles[i], isPartialPixmap);
244 tile.pixmap =
nullptr;
254 if (tile.nTiles == 0) {
255 tile.dirty = isPartialPixmap;
256 tile.partial = isPartialPixmap;
259 if (!splitBigTiles(tile, rect)) {
261 totalPixels -= tile.pixmap->width() * tile.pixmap->height();
264 tile.rotation = rotation;
266 const NormalizedRect rotatedRect = TilesManager::toRotatedRect(tile.rect, rotation);
268 totalPixels += tile.pixmap->width() * tile.pixmap->height();
270 tile.pixmap =
nullptr;
274 totalPixels -= tile.pixmap->width() * tile.pixmap->height();
276 tile.pixmap =
nullptr;
279 for (
int i = 0; i < tile.nTiles; ++i) {
280 setPixmap(pixmap, rect, tile.tiles[i], isPartialPixmap);
284 QRect tileRect = tile.rect.geometry(width, height);
289 if (tileRect.
width() * tileRect.
height() >= TILES_MAXSIZE || isPartialPixmap) {
290 tile.dirty = isPartialPixmap;
291 tile.partial = isPartialPixmap;
293 totalPixels -= tile.pixmap->width() * tile.pixmap->height();
295 tile.pixmap =
nullptr;
298 for (
int i = 0; i < tile.nTiles; ++i) {
299 setPixmap(pixmap, rect, tile.tiles[i], isPartialPixmap);
303 for (
int i = 0; i < tile.nTiles; ++i) {
304 deleteTiles(tile.tiles[i]);
305 tile.tiles[i].pixmap =
nullptr;
309 tile.tiles =
nullptr;
314 totalPixels -= tile.pixmap->width() * tile.pixmap->height();
317 tile.rotation = rotation;
319 const NormalizedRect rotatedRect = TilesManager::toRotatedRect(tile.rect, rotation);
321 totalPixels += tile.pixmap->width() * tile.pixmap->height();
323 tile.pixmap =
nullptr;
325 tile.dirty = isPartialPixmap;
326 tile.partial = isPartialPixmap;
334 for (
const TileNode &tile : std::as_const(d->tiles)) {
335 if (!d->hasPixmap(rotatedRect, tile)) {
343bool TilesManager::Private::hasPixmap(
const NormalizedRect &rect,
const TileNode &tile)
const
346 if (rectIntersection.
width() <= 0 || rectIntersection.
height() <= 0) {
350 if (tile.nTiles == 0) {
351 return tile.isValid();
359 for (
int i = 0; i < tile.nTiles; ++i) {
360 if (!hasPixmap(rect, tile.tiles[i])) {
373 for (TileNode &tile : d->tiles) {
374 d->tilesAt(rotatedRect, tile, result, tileLeaf);
382 if (!tile.rect.intersects(rect)) {
388 splitBigTiles(tile, rect);
390 if ((tileLeaf == TerminalTile && tile.nTiles == 0) || (tileLeaf == PixmapTile && tile.pixmap)) {
393 rotatedRect = TilesManager::toRotatedRect(tile.rect, rotation);
395 rotatedRect = tile.rect;
398 if (tile.pixmap && tileLeaf == PixmapTile && tile.rotation != rotation) {
400 int angleToRotate = (rotation - tile.rotation) * 90;
401 int xOffset = 0, yOffset = 0;
403 switch (angleToRotate) {
407 w = tile.pixmap->width();
408 h = tile.pixmap->height();
413 yOffset = -tile.pixmap->height();
414 w = tile.pixmap->height();
415 h = tile.pixmap->width();
419 xOffset = -tile.pixmap->width();
420 yOffset = -tile.pixmap->height();
421 w = tile.pixmap->width();
422 h = tile.pixmap->height();
426 xOffset = -tile.pixmap->width();
428 w = tile.pixmap->height();
429 h = tile.pixmap->width();
434 p.rotate(angleToRotate);
435 p.translate(xOffset, yOffset);
436 p.drawPixmap(0, 0, *tile.pixmap);
440 tile.pixmap = rotatedPixmap;
441 tile.rotation = rotation;
443 result.
append(
Tile(rotatedRect, tile.pixmap, tile.isValid()));
445 for (
int i = 0; i < tile.nTiles; ++i) {
446 tilesAt(rect, tile.tiles[i], result, tileLeaf);
451qulonglong TilesManager::totalMemory()
const
453 return 4 * d->totalPixels;
456void TilesManager::cleanupPixmapMemory(qulonglong numberOfBytes,
const NormalizedRect &visibleRect,
int visiblePageNumber)
459 for (TileNode &tile : d->tiles) {
460 d->rankTiles(tile, rankedTiles, visibleRect, visiblePageNumber);
462 std::sort(rankedTiles.
begin(), rankedTiles.
end(), rankedTilesLessThan);
464 while (numberOfBytes > 0 && !rankedTiles.
isEmpty()) {
465 TileNode *tile = rankedTiles.
takeLast();
471 if (tile->rect.intersects(visibleRect)) {
475 qulonglong pixels = tile->pixmap->width() * tile->pixmap->height();
476 d->totalPixels -= pixels;
477 if (numberOfBytes < 4 * pixels) {
480 numberOfBytes -= 4 * pixels;
484 tile->pixmap =
nullptr;
486 tile->partial =
true;
488 d->markParentDirty(*tile);
492void TilesManager::Private::markParentDirty(
const TileNode &tile)
498 if (!tile.parent->dirty) {
499 tile.parent->dirty =
true;
500 markParentDirty(*tile.parent);
512 if (visibleRect.
isNull() && visiblePageNumber < 0) {
518 if (!visibleRect.
isNull()) {
522 tile.distance = qAbs(viewportCenter.
x - tileCenter.
x) + qAbs(viewportCenter.
y - tileCenter.
y);
525 if (pageNumber < visiblePageNumber) {
526 tile.distance = 1 - tile.rect.bottom;
528 tile.distance = tile.rect.top;
531 rankedTiles.
append(&tile);
533 for (
int i = 0; i < tile.nTiles; ++i) {
534 rankTiles(tile.tiles[i], rankedTiles, visibleRect, visiblePageNumber);
539bool TilesManager::isRequesting(
const NormalizedRect &rect,
int pageWidth,
int pageHeight)
const
541 return rect == d->requestRect && pageWidth == d->requestWidth && pageHeight == d->requestHeight;
544void TilesManager::setRequest(
const NormalizedRect &rect,
int pageWidth,
int pageHeight)
546 d->requestRect = rect;
547 d->requestWidth = pageWidth;
548 d->requestHeight = pageHeight;
551bool TilesManager::Private::splitBigTiles(TileNode &tile,
const NormalizedRect &rect)
553 QRect tileRect = tile.rect.geometry(width, height);
554 if (tileRect.
width() * tileRect.
height() < TILES_MAXSIZE) {
562void TilesManager::Private::split(TileNode &tile,
const NormalizedRect &rect)
564 if (tile.nTiles != 0) {
568 if (rect.
isNull() || !tile.rect.intersects(rect)) {
573 tile.tiles =
new TileNode[4];
574 double hCenter = (tile.rect.left + tile.rect.right) / 2;
575 double vCenter = (tile.rect.top + tile.rect.bottom) / 2;
577 tile.tiles[0].rect =
NormalizedRect(tile.rect.left, tile.rect.top, hCenter, vCenter);
578 tile.tiles[1].rect =
NormalizedRect(hCenter, tile.rect.top, tile.rect.right, vCenter);
579 tile.tiles[2].rect =
NormalizedRect(tile.rect.left, vCenter, hCenter, tile.rect.bottom);
580 tile.tiles[3].rect =
NormalizedRect(hCenter, vCenter, tile.rect.right, tile.rect.bottom);
582 for (
int i = 0; i < tile.nTiles; ++i) {
583 tile.tiles[i].parent = &tile;
584 splitBigTiles(tile.tiles[i], rect);
650bool TileNode::isValid()
const
652 return pixmap && !dirty;
665Tile::Private::Private()
672 : d(new
Tile::Private)
679Tile::Tile(
const Tile &t)
680 : d(new
Tile::Private)
683 d->pixmap = t.d->pixmap;
684 d->isValid = t.d->isValid;
687Tile &Tile::operator=(
const Tile &other)
689 if (
this == &other) {
693 d->rect = other.d->rect;
694 d->pixmap = other.d->pixmap;
695 d->isValid = other.d->isValid;
NormalizedPoint is a helper class which stores the coordinates of a normalized point.
double x
The normalized x coordinate.
double y
The normalized y coordinate.
A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
double bottom
The normalized bottom coordinate.
double right
The normalized right coordinate.
NormalizedPoint center() const
Returns the center of the rectangle.
double left
The normalized left coordinate.
QRect geometry(int xScale, int yScale) const
Returns the rectangle mapped to a reference area of xScale x yScale.
double top
The normalized top coordinate.
bool isNull() const
Returns whether this normalized rectangle is a null normalized rect.
This class represents a rectangular portion of a page.
NormalizedRect rect() const
Location of the tile.
bool isValid() const
True if the pixmap is available and updated.
QPixmap * pixmap() const
Pixmap (may also be NULL)
bool isValid(QStringView ifopt)
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
@ Rotation270
Rotated 2700 degrees clockwise.
@ Rotation90
Rotated 90 degrees clockwise.
@ Rotation180
Rotated 180 degrees clockwise.
void append(QList< T > &&value)
bool isEmpty() const const
QPixmap copy(const QRect &rectangle) const const
QPoint topLeft() const const
QRect translated(const QPoint &offset) const const