From 870c3252cbfd1f990ae1d94a977935ee1c840694 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Thu, 13 Mar 2025 15:50:11 +0000 Subject: [PATCH] LazMapViewer: Fix incorrect painting of stretched and missing tiles when Cyclic is true. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9680 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/lazmapviewer/source/mvcache.pas | 2 +- components/lazmapviewer/source/mvengine.pas | 131 ++++++++++++------ .../lazmapviewer/source/mvmapviewer.pas | 7 +- 3 files changed, 94 insertions(+), 46 deletions(-) diff --git a/components/lazmapviewer/source/mvcache.pas b/components/lazmapviewer/source/mvcache.pas index f189d58fb..29e907793 100644 --- a/components/lazmapviewer/source/mvcache.pas +++ b/components/lazmapviewer/source/mvcache.pas @@ -498,7 +498,7 @@ end; the rectangle coordinates to get an upscaled preview of the originally requested tile. The function returns true in this case. If the requested tile already is in the cache, or no containing tile is found - the function returns false indicating that not preview image must be + the function returns false indicating that no preview image must be generated. } function TPictureCache.GetPreviewFromCache(const MapProvider: TMapProvider; var TileId: TTileId; out ARect: TRect): boolean; diff --git a/components/lazmapviewer/source/mvengine.pas b/components/lazmapviewer/source/mvengine.pas index 372edef06..0b8e6f4c5 100644 --- a/components/lazmapviewer/source/mvengine.pas +++ b/components/lazmapviewer/source/mvengine.pas @@ -122,7 +122,7 @@ type procedure CalculateWin(var AWin: TMapWindow); function DegreesToPixelsEPSG3395(const AWin: TMapWindow; APt: TRealPoint): TPoint; function DegreesToPixelsEPSG3857(const AWin: TMapWindow; APt: TRealPoint): TPoint; - procedure Redraw(const aWin: TMapWindow; const paintOnly: Boolean = False); + procedure Redraw(const aWin: TMapWindow; const PaintOnly: Boolean = False); function CalculateVisibleTiles(const aWin: TMapWindow; out Area: TArea): Boolean; function IsCurrentWin(const aWin: TMapWindow) : boolean; protected @@ -132,7 +132,7 @@ type procedure evDownload(Data: TObject; Job: TJob); procedure TileDownloaded(Data: PtrInt); procedure EraseBackground(const R: TRect); - procedure DrawTileFromCache(constref ATile: TTileId; constref AWin: TMapWindow); + procedure DrawTileFromCache(constref ATile: TTileId; constref AWin: TMapWindow; out FoundInCache: Boolean); procedure DrawStretchedTile(const TileId: TTileID; X, Y: Integer; TileImg: TPictureCacheItem; const R: TRect); Procedure DrawTile(const TileId: TTileId; X,Y: integer; TileImg: TPictureCacheItem); Procedure DoDrag(Sender: TDragObj); @@ -1089,12 +1089,13 @@ begin end; procedure TMapViewerEngine.Redraw(const aWin: TMapWindow; - const paintOnly: Boolean); + const PaintOnly: Boolean); var TilesVis: TArea; x, y, px, py: Integer; iTile, numTiles, XShift: Integer; Tiles: TTileIdArray = nil; + foundInCache: Boolean; tile: TTileID; previewDrawn: Boolean; previewImg: TPictureCacheItem; @@ -1105,8 +1106,8 @@ var lTile: TEnvTile; lJob: TEventJob; begin - lTile:=TEnvTile.Create(Tiles[iTile], aWin); - lJob := TEventJob.Create(@evDownload, lTile, False, // owns data + lTile := TEnvTile.Create(Tiles[iTile], aWin); + lJob := TEventJob.Create(@evDownload, lTile, False, // owns data GetTileName(Tiles[iTile])); if not Queue.AddUniqueJob(lJob, Self) then begin @@ -1159,11 +1160,12 @@ begin if not CalculateVisibleTiles(AWin, TilesVis) then EraseAround; + SetLength(Tiles, (TilesVis.Bottom - TilesVis.Top + 1) * (TilesVis.Right - TilesVis.Left + 1)); iTile := Low(Tiles); numTiles := 1 shl AWin.Zoom; XShift := IfThen(aWin.X > 0, numTiles - aWin.X div TileSize.CX - 1, 0); - for y := TilesVis.Top to TilesVis.Bottom do + for Y := TilesVis.Top to TilesVis.Bottom do for X := TilesVis.Left to TilesVis.Right do begin if FCyclic then @@ -1177,6 +1179,14 @@ begin Tiles[iTile].Y := Y; Tiles[iTile].Z := AWin.Zoom; + DrawTileFromCache(Tiles[iTile], AWin, foundInCache); + if (not foundInCache) and (not PaintOnly) and IsValidTile(AWin, Tiles[iTile]) then + begin + AddJob; + inc(iTile); + end; + + (* if Cache.InCache(AWin.MapProvider, Tiles[iTile]) then DrawTileFromCache(Tiles[iTile], AWin) else @@ -1202,12 +1212,15 @@ begin if not previewDrawn then DrawTile(Tiles[iTile], px, py, nil); // Draw blank tile if preview cannot be generated + + // !!!!!!!!!!!!!!!!!!!!!! if not paintOnly and IsValidTile(AWin, Tiles[iTile]) then begin AddJob; inc(iTile); end; end; + *) end; SetLength(Tiles, iTile); end; @@ -1416,47 +1429,83 @@ end; procedure TMapViewerEngine.EraseBackground(const R: TRect); begin if Assigned(FOnEraseBackground) then - FOnEraseBackground(R); + FOnEraseBackground(R); end; -procedure TMapViewerEngine.DrawTileFromCache(constref ATile: TTileId; constref - AWin: TMapWindow); +procedure TMapViewerEngine.DrawTileFromCache(constref ATile: TTileID; + constref AWin: TMapWindow; out FoundInCache: Boolean); var img: TPictureCacheItem; - X, Y: integer; - worldWidth : Integer; - numTiles : Integer; - baseX : Integer; -begin - if IsCurrentWin(AWin)then + X, Y: Integer; + worldWidth: Integer; + numTiles: Integer; + baseX: Integer; + tile: TTileID; + R: TRect; + normalDraw: Boolean = true; + + procedure DrawTheTile(ATileID: TTileID; X, Y: Integer; AImg: TPictureCacheItem); begin - Cache.GetFromCache(AWin.MapProvider, ATile, img); - Y := AWin.Y + ATile.Y * TileSize.CY; // begin of Y - if Cyclic then - begin - baseX := AWin.X + ATile.X * TileSize.CX; // begin of X - numTiles := 1 shl AWin.Zoom; - worldWidth := numTiles * TileSize.CX; - // From the center to the left (western) hemisphere - X := baseX; - while (X + TileSize.CX >= 0) do - begin - DrawTile(ATile, X, Y, img); - X := X - worldWidth; - end; - // From the center to the right (eastern) hemisphere - X := baseX + worldWidth; - while ((X - TileSize.CX) <= AWin.Width) do - begin - DrawTile(ATile, X, Y, img); - X := X + worldWidth; - end; - end else - begin - X := AWin.X + ATile.X * TileSize.CX; // begin of X - DrawTile(ATile, X, Y, img); - end; + if normalDraw then + DrawTile(ATileID, X, Y, AImg) // Covers the "missing tile" case when AImg = nil + else + DrawStretchedTile(ATileID, X, Y, AImg, R); end; + +begin + if not IsCurrentWin(AWin) then + exit; + + // When no cache image can be found (img = nil) we will have to draw a "missing tile" + img := nil; + FoundInCache := false; + + if Cache.InCache(AWin.MapProvider, ATile) then + begin + // Image is found in cache: Load it into "img". It can be drawn directly. + Cache.GetFromCache(AWin.MapProvider, ATile, img); + FoundInCache := true; + end else + if FDrawPreviewTiles then + begin + // Image is not found in cache, but there is another one which can be + // scaled to fit. Find the cache parameters for this image. + tile := ATile; + if Cache.GetPreviewFromCache(AWin.MapProvider, tile, R) then + begin + // Load cache image into "img". It must be stretch-drawn. + Cache.GetFromCache(AWin.MapProvider, tile, img); + normalDraw := false; + end; + end; + + X := AWin.X + ATile.X * TileSize.CX; // begin of X + Y := AWin.Y + ATile.Y * TileSize.CY; // begin of Y + + if Cyclic then + begin + baseX := X; + numTiles := 1 shl AWin.Zoom; + worldWidth := numTiles * TileSize.CX; + + // Center, plus western hemisphere (left) + X := baseX; + while (X + TileSize.CX >= 0) do + begin + DrawTheTile(ATile, X, Y, img); + X := X - worldWidth; + end; + + // From the center to the right (eastern) hemisphere + X := baseX + worldWidth; + while (X <= AWin.Width) do + begin + DrawTheTile(ATile, X, Y, img); + X := X + worldWidth; + end; + end + else + DrawTheTile(ATile, X, Y, img); end; function TMapViewerEngine.ValidProvider(const AProvider: String): Boolean; diff --git a/components/lazmapviewer/source/mvmapviewer.pas b/components/lazmapviewer/source/mvmapviewer.pas index e0a552c66..9af15cc12 100644 --- a/components/lazmapviewer/source/mvmapviewer.pas +++ b/components/lazmapviewer/source/mvmapviewer.pas @@ -3098,7 +3098,7 @@ procedure TMapView.Paint; const FREE_DRAG = 0; //(TILE_SIZE * TILE_SIZE) div 4; - procedure DrawCenter; + procedure DrawCenter; deprecated 'Use plugin'; var C: TPoint; begin @@ -3136,7 +3136,7 @@ const FAfterDrawObjectsEvent(Self); DrawingEngine.PaintToCanvas(Canvas); - if DebugTiles then + if DebugTiles then // DebugTiles is deprecated DrawCenter; GetPluginManager.AfterPaint(Self); @@ -3154,7 +3154,7 @@ const begin DrawingEngine.PaintToCanvas(Canvas); DrawingEngine.PaintToCanvas(Canvas, O); - if DebugTiles then + if DebugTiles then // DebugTiles is deprecated DrawCenter; end else @@ -3681,7 +3681,6 @@ begin DrawingEngine.FillPixels(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, InactiveColor); end; - procedure TMapView.DoDrawTileInfo(const TileID: TTileID; X, Y: Integer); begin DrawingEngine.PenColor := clGray;