From 2eb97a373256ca7bb6969a81abdb99ec58ca80b9 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz <wp_xxyyzz@8e941d3f-bd1b-0410-a28a-d453659cc2b4> Date: Fri, 14 Mar 2025 19:20:10 +0000 Subject: [PATCH] LazMapViewer: Fix drawing of missing tiles. Issue #39111. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9682 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../addons/bgra_drawingengine/mvde_bgra.pas | 3 +- .../source/addons/plugins/mvplugins.pas | 2 +- components/lazmapviewer/source/mvengine.pas | 109 +++++++++++++----- .../lazmapviewer/source/mvmapviewer.pas | 12 +- 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/components/lazmapviewer/source/addons/bgra_drawingengine/mvde_bgra.pas b/components/lazmapviewer/source/addons/bgra_drawingengine/mvde_bgra.pas index f3823984f..8e5ef33e2 100644 --- a/components/lazmapviewer/source/addons/bgra_drawingengine/mvde_bgra.pas +++ b/components/lazmapviewer/source/addons/bgra_drawingengine/mvde_bgra.pas @@ -234,7 +234,8 @@ end; procedure TMvBGRADrawingEngine.FillRect(X1, Y1, X2, Y2: Integer); begin - FBuffer.CanvasBGRA.FillRect(X1, Y1, X2, Y2); +// FBuffer.CanvasBGRA.FillRect(X1, Y1, X2, Y2); + FBuffer.FillRect(X1, Y1, X2, Y2, BrushColor); end; function TMvBGRADrawingEngine.GetPenStyle: TPenStyle; diff --git a/components/lazmapviewer/source/addons/plugins/mvplugins.pas b/components/lazmapviewer/source/addons/plugins/mvplugins.pas index df0fc420d..5addb3eb3 100644 --- a/components/lazmapviewer/source/addons/plugins/mvplugins.pas +++ b/components/lazmapviewer/source/addons/plugins/mvplugins.pas @@ -51,7 +51,7 @@ type procedure SetPosition(AValue: TTileInfoPosition); protected procedure AfterDrawTile(AMapView: TMapView; ADrawingEngine: TMvCustomDrawingEngine; - ATileID: TTileID; ARect: TRect; var Handled: Boolean); override; + ATileID: TTileID; ARect: TRect; var {%H-}Handled: Boolean); override; public constructor Create(AOwner: TComponent); override; published diff --git a/components/lazmapviewer/source/mvengine.pas b/components/lazmapviewer/source/mvengine.pas index 1b441bee0..66699e774 100644 --- a/components/lazmapviewer/source/mvengine.pas +++ b/components/lazmapviewer/source/mvengine.pas @@ -123,7 +123,7 @@ type 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); - function CalculateVisibleTiles(const aWin: TMapWindow; out Area: TArea): Boolean; + function CalculateVisibleTiles(const aWin: TMapWindow; out AFullyCovered: Boolean): TArea; function IsCurrentWin(const aWin: TMapWindow) : boolean; protected procedure AdjustZoomCenter(var AWin: TMapWindow); @@ -355,36 +355,58 @@ begin CalculateWin(AWin); end; -// Returns whether the view area is not covered fully with a tiles -function TMapViewerEngine.CalculateVisibleTiles(const aWin: TMapWindow; out - Area: TArea): Boolean; +{ Calculates the range of tile ids needed to cover the window with a map. + Returns AFullyCovered=false when not the entire windows is covered by the + map tiles. } +function TMapViewerEngine.CalculateVisibleTiles(const AWin: TMapWindow; + out AFullyCovered: Boolean): TArea; var - MaxX, MaxY, startX, startY: int64; - WorldMax: Int64; + maxX, maxY, startX, startY: Int64; + worldMax: Int64; begin - Area := Default(TArea); - Result := (aWin.X <= 0) and (aWin.Y <= 0); - WorldMax := Int64(1) shl AWin.Zoom - 1; - MaxX := Int64(aWin.Width) div TileSize.CX + 1; - MaxY := Int64(aWin.Height) div TileSize.CY + 1; - if (MaxX > WorldMax) or (MaxY > WorldMax) then + Result := Default(TArea); + + AFullyCovered := true; + if (AWin.X > 0) or (AWin.Y > 0) then + AFullyCovered := false; + + worldMax := Int64(1) shl AWin.Zoom - 1; + maxX := Int64(AWin.Width) div TileSize.CX + 1; + maxY := Int64(AWin.Height) div TileSize.CY + 1; + if maxY > worldMax then begin - Result := False; - MaxX := Min(WorldMax, MaxX); - MaxY := Min(WorldMax, MaxY); + maxY := worldMax; + AFullyCovered := false; end; - startX := -aWin.X div TileSize.CX; - startY := -aWin.Y div TileSize.CY; - if (startX < 0) or (startY < 0) then + if (not Cyclic) and (maxX > worldMax) then begin - startX := Max(0, startX); - startY := Max(0, startY); - Result := False; + maxX := worldMax; + AFullyCovered := false; + end; + + startX := Max(0, -AWin.X div TileSize.CX); + startY := Max(0, -AWin.Y div TileSize.CY); + + Result.Left := startX; + if Cyclic then + Result.Right := Result.Left + maxX + else + if startX + maxX < worldMax then + Result.Right := startX + maxX + else + begin + Result.Right := worldMax; + AFullyCovered := false; + end; + + Result.Top := startY; + if startY + maxY < worldMax then + Result.Bottom := startY + maxY + else + begin + Result.Bottom := worldMax; + AFullyCovered := false; end; - Area.Left := startX; - Area.Right := startX + MaxX; - Area.Top := startY; - Area.Bottom := startY + MaxY; end; procedure TMapViewerEngine.CalculateWin(var AWin: TMapWindow); @@ -1096,6 +1118,7 @@ var iTile, numTiles, XShift: Integer; Tiles: TTileIdArray = nil; foundInCache: Boolean; + fullyCovered: Boolean; procedure AddJob; var @@ -1112,6 +1135,34 @@ var end; end; + procedure EraseAround; + var + x, y: Integer; + begin + // Erase part above the map + y := AWin.Y; + if y > 0 then + EraseBackground(Rect(0, 0, AWin.Width, y)); + + // Erase part below the map + y := AWin.Y + (numTiles - 1 - TilesVis.Top) * TileSize.CX; + if y < AWin.Height then + EraseBackground(Rect(0, y, AWin.Width, AWin.Height)); + + if not Cyclic then + begin + // Erase part at the left of the map + x := AWin.X; + if x > 0 then + EraseBackground(Rect(0, 0, x, AWin.Height)); + + // Erase part at the right of the map + x := AWin.X + (numTiles - 1 - TilesVis.Left) * TileSize.CX; + if x < AWin.Width then + EraseBackground(Rect(x, 0, AWin.Width, AWin.Height)); + end; + end; + (* procedure EraseAround; var T, L, B, R: Integer; @@ -1144,6 +1195,7 @@ var AWin.Height) ); end; + *) begin if not(Active) then @@ -1154,12 +1206,15 @@ begin Exit; end; - if not CalculateVisibleTiles(AWin, TilesVis) then + numTiles := 1 shl AWin.Zoom; + TilesVis := CalculateVisibleTiles(AWin, fullyCovered); + if not fullyCovered then EraseAround; +// 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 X := TilesVis.Left to TilesVis.Right do diff --git a/components/lazmapviewer/source/mvmapviewer.pas b/components/lazmapviewer/source/mvmapviewer.pas index 9af15cc12..efbaadfb3 100644 --- a/components/lazmapviewer/source/mvmapviewer.pas +++ b/components/lazmapviewer/source/mvmapviewer.pas @@ -3116,11 +3116,10 @@ const Canvas.FillRect(0, 0, ClientWidth, ClientHeight); end; - procedure FullRedraw; + procedure ObjectsDraw; var W: Integer; begin - Engine.Redraw; W := ClientWidth; if Cyclic then W := Min(1 shl Zoom * TileSize.CX, W); @@ -3129,13 +3128,20 @@ const if Assigned(FBeforeDrawObjectsEvent) then FBeforeDrawObjectsEvent(Self); - DrawObjects(Default(TTileId), 0, 0, W - 1, ClientHeight); + DrawObjects(Default(TTileID), 0, 0, W - 1, ClientHeight); GetPluginManager.AfterDrawObjects(Self); if Assigned(FAfterDrawObjectsEvent) then FAfterDrawObjectsEvent(Self); + end; + + procedure FullRedraw; + begin + Engine.Redraw; + ObjectsDraw; DrawingEngine.PaintToCanvas(Canvas); + if DebugTiles then // DebugTiles is deprecated DrawCenter;