Recent

Author Topic: LazMapViewer v.0.2.7  (Read 1325 times)

lar

  • Newbie
  • Posts: 5
LazMapViewer v.0.2.7
« on: February 22, 2024, 08:55:38 pm »
I created a small component to serve as an interface to the LazMapViewer package (lazmapviewerpkg). It retrieves a map image into a bitmap on which a user can then do their own custom drawing (like layers in a GIS) without needing to add the windowed TMapView control to their project. The component was working fine under v.0.2.5 of the package (obtained from the Lazarus Online Package Manager) but with the latest trunk version 0.2.7 it fails to draw the retrieved map tiles onto the drawing engine's internal bitmap image. The component's source code is as follows (for v.0.2.7 the TileImg type was changed from TLazIntfImage to TPictureCacheItem as required):
Code: Pascal  [Select][+][-]
  1. unit webmapserver;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Graphics,  mvengine, mvdrawingengine, mvtypes,
  9.   mvmapprovider, IntfGraphics, FileUtil, LazFileUtils, Dialogs;
  10.  
  11. type
  12.   TMapServer = class(TComponent)
  13.   private
  14.     Width: Integer;
  15.     Height: Integer;
  16.     Engine: TMapViewerEngine;
  17.     DrawingEngine: TMvCustomDrawingEngine;
  18.     BuiltinDrawingEngine: TMvCustomDrawingEngine;
  19.   protected
  20.     procedure DoDrawTile(const TileId: TTileId; X, Y: Integer; TileImg: TLazIntfImage);
  21.   public
  22.     constructor Create(AOwner: TComponent); override;
  23.     destructor  Destroy; override;
  24.     procedure SetMapProvider(aValue: String);
  25.     procedure GetMapImage(Lon, Lat: Double; W, H, Z: Integer; var aBitmap: TBitmap);
  26.   end;
  27.  
  28. implementation
  29.  
  30. uses
  31.  mvde_intfgraphics, mvdlefpc;
  32.  
  33. constructor TMapServer.Create(AOwner: TComponent);
  34. begin
  35.   inherited Create(AOwner);
  36.   Width := 300;
  37.   Height := 300;
  38.   Engine := TMapViewerEngine.Create(self);
  39.   Engine.CachePath := SysUtils.GetTempDir(False) + 'cache/';
  40.   Engine.CacheOnDisk := true;
  41.   Engine.UseThreads := True;
  42.   Engine.MapProvider:= 'OpenStreetMap Mapnik';
  43.   Engine.OnDrawTile := @DoDrawTile;
  44.   Engine.DrawTitleInGuiThread := false;
  45.   Engine.DownloadEngine := TMvDEFpc.Create(self);
  46.   Engine.DownloadEngine.Name := 'BuiltInDLE';
  47.   BuiltinDrawingEngine := TMvIntfGraphicsDrawingEngine.Create(self);
  48.   BuiltinDrawingEngine.Name := 'BuiltInDE';
  49.   BuiltinDrawingEngine.CreateBuffer(Width, Height);
  50.   DrawingEngine := BuiltinDrawingEngine;
  51. end;
  52.  
  53. destructor TMapServer.Destroy;
  54. begin
  55.   if DeleteDirectory(Engine.CachePath, True) then
  56.     RemoveDirUTF8(Engine.CachePath);
  57.   inherited Destroy;
  58. end;
  59.  
  60. procedure TMapServer.DoDrawTile(const TileId: TTileId; X, Y: integer;
  61.   TileImg: TLazIntfImage);
  62. begin
  63.   if Assigned(TileImg) then begin
  64.     DrawingEngine.DrawLazIntfImage(X, Y, TileImg);
  65.   end
  66.   else begin
  67.     DrawingEngine.BrushColor := clWhite;
  68.     DrawingEngine.BrushStyle := bsSolid;
  69.     DrawingEngine.FillRect(X, Y, X + TILE_SIZE, Y + TILE_SIZE);
  70.   end;
  71. end;
  72.  
  73. procedure TMapServer.SetMapProvider(aValue: String);
  74. begin
  75.   try
  76.     Engine.MapProvider := aValue;
  77.   except
  78.     raise;
  79.   end;
  80. end;
  81.  
  82. procedure TMapServer.GetMapImage(Lon, Lat: Double; W, H, Z: Integer;
  83.   var aBitmap:TBitmap);
  84. var
  85.   LonLat: TRealPoint;
  86.   TmpBitmap: TBitmap;
  87. begin
  88.   if aBitmap = nil then exit;
  89.   Engine.Active := False;
  90.   Engine.Zoom := Z;
  91.   LonLat.Lon := Lon;
  92.   LonLat.Lat := Lat;
  93.   Engine.Center := LonLat;
  94.   Engine.SetSize(W, H);
  95.   DrawingEngine.CreateBuffer(W, H);
  96.   Engine.Active := True;
  97.   Engine.Jobqueue.WaitAllJobTerminated(Engine);
  98.   TmpBitmap := DrawingEngine.SaveToImage(TBitmap) as TBitmap;
  99.   Engine.Active := False;
  100.   with aBitmap do
  101.   begin
  102.     if (Width <> W) or (Height <> H) then SetSize(W, H);
  103.     Canvas.Draw(0,0,TmpBitmap);
  104.   end;
  105. end;
  106. end.
  107.  

I checked that the map tiles are being retrieved correctly but the TileImg objects being passed by the drawing engine into the DoDrawTile function are nil resulting in the tiles never being drawn. I hope someone can tell me what code changes are needed to make it work with the latest version of the LazMapViewer package.

alpine

  • Hero Member
  • *****
  • Posts: 1060
Re: LazMapViewer v.0.2.7
« Reply #1 on: February 22, 2024, 10:24:16 pm »
Code: Pascal  [Select][+][-]
  1. Engine.UseThreads := False;
You wait for all the threads to finish anyway.

Or issue an Engine.Redraw once more with the all threads finished.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

lar

  • Newbie
  • Posts: 5
Re: LazMapViewer v.0.2.7
« Reply #2 on: February 23, 2024, 06:35:09 am »
Thanks alpine but setting UseThreads to false had no effect and issuing Engine.Redraw after WaitAllJobTerminated caused an "Invalid type cast" runtime error. Just to clarify, the code I posted worked perfectly fine with v.0.2.5 -- it's getting it to work with v.0.2.7 that is the issue.

alpine

  • Hero Member
  • *****
  • Posts: 1060
Re: LazMapViewer v.0.2.7
« Reply #3 on: February 23, 2024, 08:26:51 am »
Thanks alpine but setting UseThreads to false had no effect and issuing Engine.Redraw after WaitAllJobTerminated caused an "Invalid type cast" runtime error. Just to clarify, the code I posted worked perfectly fine with v.0.2.5 -- it's getting it to work with v.0.2.7 that is the issue.
A lot of changes since 0.2.5. Give me the exact source you have, I'll try to fix it.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

wp

  • Hero Member
  • *****
  • Posts: 11906
Re: LazMapViewer v.0.2.7
« Reply #4 on: February 23, 2024, 09:50:58 am »
Why don't you just use the DoDrawTile code of the current LazMapViewer code?
Code: Pascal  [Select][+][-]
  1. procedure TMapView.DoDrawTile(const TileId: TTileId; X, Y: integer;
  2.   TileImg: TPictureCacheItem);
  3. begin
  4.   if Assigned(TileImg) then
  5.     DrawingEngine.DrawCacheItem(X, Y, TileImg)
  6.   else
  7.     DrawingEngine.FillPixels(X, Y, X + TILE_SIZE, Y + TILE_SIZE, InactiveColor);
  8.   [...]
  9. end;
In the new version drawing on a TLazIntfImage buffer was removed to avoid unnecessary conversions of the image from the DrawingEngine buffers, and the type of the Tileimg argument of the OnDrawTile event had to be changed to the more general TPictureCacheItem.

lar

  • Newbie
  • Posts: 5
Re: LazMapViewer v.0.2.7
« Reply #5 on: February 23, 2024, 02:14:46 pm »
@alpine - I got the 0.2.7 source code from https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/lazmapviewer/ .
 
@wp - In DoDrawTile I am calling DrawingEngine.DrawCacheItem, just as in the LazMapViewer code, with the type of its TileImg argument changed to TPictureCacheItem for 0.2.7. The problem is that the TileImg object that DoDrawTile receives in 0.2.7 is always nil (or unassigned), so the retrieved map winds up being filled with InactiveColor (or in my code clWhite).

wp

  • Hero Member
  • *****
  • Posts: 11906
Re: LazMapViewer v.0.2.7
« Reply #6 on: February 23, 2024, 02:22:34 pm »
Please provide a short demo showing the issue. Create your TMapServer at runtime so that there is no necessity to install a package.

alpine

  • Hero Member
  • *****
  • Posts: 1060
Re: LazMapViewer v.0.2.7
« Reply #7 on: February 23, 2024, 02:51:24 pm »
@alpine - I got the 0.2.7 source code from https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/lazmapviewer/ .
Sorry for the misunderstanding, I've meant:  Give me your source (or a minimal complete example) to fix it.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

lar

  • Newbie
  • Posts: 5
Re: LazMapViewer v.0.2.7
« Reply #8 on: February 23, 2024, 04:22:30 pm »
As requested I've attached a small demo for my MapServer component. Please note that it uses v.0.2.7 of the lazMapViewerPkg as a required package, but I suppose if you don't want to install it you can just copy the v.0.2.7 LazMapViewer source files into the project.

Thanks again for taking the time to look into this.

alpine

  • Hero Member
  • *****
  • Posts: 1060
Re: LazMapViewer v.0.2.7
« Reply #9 on: February 23, 2024, 05:24:25 pm »
As requested I've attached a small demo for my MapServer component. Please note that it uses v.0.2.7 of the lazMapViewerPkg as a required package, but I suppose if you don't want to install it you can just copy the v.0.2.7 LazMapViewer source files into the project.

Thanks again for taking the time to look into this.

At the end of constructor of the map server add the following line:
Code: Pascal  [Select][+][-]
  1. constructor TMapServer.Create(AOwner: TComponent);
  2. begin
  3.   inherited Create(AOwner);
  4.   {...}
  5.   DrawingEngine := BuiltinDrawingEngine;
  6.   Engine.CacheItemClass := BuiltinDrawingEngine.GetCacheItemClass; {<--- add this}
  7. end;
That is needed for the picture cache to create the right TPictureCacheItem descendant.

Into the GetMapImage add the following line:
Code: Pascal  [Select][+][-]
  1. procedure TMapServer.GetMapImage(Lon, Lat: Double; W, H, Z: Integer;
  2.   var aBitmap:TBitmap);
  3. var
  4.   LonLat: TRealPoint;
  5.   TmpBitmap: TBitmap;
  6. begin
  7.   {...}
  8.   Engine.Jobqueue.WaitAllJobTerminated(Engine);
  9.   Engine.Redraw; {<--- add this}
  10.   TmpBitmap := DrawingEngine.SaveToImage(TBitmap) as TBitmap;
  11.   {...}
  12. end;
That is needed because the downloading process was decoupled from the painting. Into the visual component, there are invalidates which trigger another Paint/Redraw on job termination. 

After these changes it should work.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

lar

  • Newbie
  • Posts: 5
Re: LazMapViewer v.0.2.7
« Reply #10 on: February 23, 2024, 06:05:46 pm »
It now works fine with the changes you provided. I appreciate your help.

 

TinyPortal © 2005-2018