diff --git a/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpi b/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpi index 75c7c061d..8d0e10a5f 100644 --- a/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpi +++ b/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpi @@ -43,6 +43,7 @@ + diff --git a/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpr b/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpr index 8fe82fa19..6c0063141 100644 --- a/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpr +++ b/components/lazmapviewer/examples/fulldemo/mapviewer_demo.lpr @@ -12,8 +12,8 @@ uses begin RequireDerivedFormResource:=True; - Application.Title:='MapViewer_Demo'; - Application.Scaled:=True; + Application.Title := 'MapViewer_Demo'; + Application.Scaled := True; Application.Initialize; Application.CreateForm(TMainForm, MainForm); Application.CreateForm(TGPSListViewer, GPSListViewer); diff --git a/components/lazmapviewer/source/mvcache.pas b/components/lazmapviewer/source/mvcache.pas index 4ead49df4..6b7adedde 100644 --- a/components/lazmapviewer/source/mvcache.pas +++ b/components/lazmapviewer/source/mvcache.pas @@ -17,19 +17,22 @@ unit mvCache; interface uses - Classes, SysUtils, IntfGraphics, syncObjs, - mvMapProvider, mvTypes, FPImage; + Classes, SysUtils, Types, FPImage, IntfGraphics, syncObjs, + mvMapProvider, mvTypes; Type { TPictureCacheItem } TPictureCacheItem = class(TObject) + private + FTileSize: TSize; protected function GetImageObject: TObject; virtual; class function GetImageReader({%H-}AStream: TStream): TFPCustomImageReader; public constructor Create({%H-}AStream: TStream); virtual; destructor Destroy; override; + property TileSize: TSize read FTileSize write FTileSize; end; TPictureCacheItemClass = class of TPictureCacheItem; @@ -46,6 +49,7 @@ Type FBasePath: String; FUseDisk: Boolean; FUseThreads: Boolean; + FTileSize: TSize; procedure SetCacheItemClass(AValue: TPictureCacheItemClass); procedure SetUseThreads(AValue: Boolean); Procedure EnterCrit; @@ -71,6 +75,7 @@ Type property UseThreads: Boolean read FUseThreads write SetUseThreads; property CacheItemClass: TPictureCacheItemClass read FCacheItemClass write SetCacheItemClass; property MaxAge: Integer read FMaxAge write FMaxAge; // in days + property TileSize: TSize read FTileSize; end; @@ -341,6 +346,7 @@ var idx: integer; begin FileName := GetFileName(MapProvider, TileId); + FTileSize := MapProvider.TileSize; EnterCrit; try idx := Cache.IndexOf(FileName); @@ -352,6 +358,7 @@ begin idx := 0; end; item:= FCacheItemClass.Create(Stream); //GetNewImgFor(Stream); + item.TileSize := FTileSize; Cache.Objects[idx]:=item; finally LeaveCrit; @@ -439,7 +446,8 @@ begin // e.g 0.5 = right or lower half of the tile, when divided by 2 ltid := TileId; lDeltaZoom := 1; - w := TILE_SIZE; + FTileSize := MapProvider.TileSize; + w := tileSize.CX; repeat w := w shr 1; dec(ltid.Z); @@ -452,8 +460,8 @@ begin begin // We found a tile in the cache that contains the preview xfrac := xfrac - ltid.X; //xfrac and yfrac calculated for the position in the tile from the cache yfrac := yfrac - ltid.Y; - px := Trunc(xfrac * TILE_SIZE); //x and y are the percentage of the tile width - py := Trunc(yfrac * TILE_SIZE); + px := Trunc(xfrac * FTileSize.CX); //x and y are the percentage of the tile width + py := Trunc(yfrac * FTileSize.CY); ARect := Rect(px, py, px+w, py+w); TileID := ltid; Result := true; diff --git a/components/lazmapviewer/source/mvde_intfgraphics.pas b/components/lazmapviewer/source/mvde_intfgraphics.pas index 1d2b61c17..3096edfa6 100644 --- a/components/lazmapviewer/source/mvde_intfgraphics.pas +++ b/components/lazmapviewer/source/mvde_intfgraphics.pas @@ -195,7 +195,7 @@ begin raise EInvalidGraphic.Create('PNG/JPG expected.'); try rawImg.Init; - rawImg.Description.Init_BPP32_B8G8R8A8_BIO_TTB(TILE_SIZE, TILE_SIZE); + rawImg.Description.Init_BPP32_B8G8R8A8_BIO_TTB(TileSize.CX, TileSize.CY); FImage := TLazIntfImage.Create(rawImg, True); try FImage.LoadFromStream(AStream, Reader); diff --git a/components/lazmapviewer/source/mvengine.pas b/components/lazmapviewer/source/mvengine.pas index e19d04b3f..8041ed7fc 100644 --- a/components/lazmapviewer/source/mvengine.pas +++ b/components/lazmapviewer/source/mvengine.pas @@ -20,7 +20,7 @@ unit mvEngine; interface uses - Classes, SysUtils, IntfGraphics, Controls, Math, GraphType, FPImage, + Classes, SysUtils, Types, IntfGraphics, Controls, Math, GraphType, FPImage, mvTypes, mvGeoMath, mvJobQueue, mvMapProvider, mvDownloadEngine, mvCache, mvDragObj; type @@ -125,6 +125,7 @@ type procedure AdjustZoomCenter(var AWin: TMapWindow); procedure ConstraintZoom(var aWin: TMapWindow); function GetTileName(const Id: TTileId): String; + function GetTileSize: TSize; procedure evDownload(Data: TObject; Job: TJob); procedure TileDownloaded(Data: PtrInt); procedure EraseBackground(const R: TRect); @@ -140,9 +141,9 @@ type constructor Create(aOwner: TComponent); override; destructor Destroy; override; - function AddMapProvider(OpeName: String; ProjectionType: TProjectionType; Url: String; - MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr = nil; - GetXStr: TGetValStr = nil; GetYStr: TGetValStr = nil; + function AddMapProvider(OpeName: String; ProjectionType: TProjectionType; + ATileSize: TSize; Url: String; MinZoom, MaxZoom, NbSvr: integer; + GetSvrStr: TGetSvrStr = nil; GetXStr: TGetValStr = nil; GetYStr: TGetValStr = nil; GetZStr: TGetValStr = nil): TMapProvider; procedure CancelCurrentDrawing; procedure ClearMapProviders; @@ -187,6 +188,7 @@ type property CacheMaxAge: Integer read GetCacheMaxAge write SetCacheMaxAge; property ZoomMin: Integer read FZoomMax write FZoomMin; property ZoomMax: Integer read FZoomMax write FZoomMax; + property TileSize: TSize read GetTileSize; published property Active: Boolean read FActive write SetActive default false; @@ -319,7 +321,7 @@ begin end; function TMapViewerEngine.AddMapProvider(OpeName: String; ProjectionType: TProjectionType; - Url: String; MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr; + ATileSize: TSize; Url: String; MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr): TMapProvider; var idx :integer; @@ -332,7 +334,7 @@ Begin end else Result := TMapProvider(lstProvider.Objects[idx]); - Result.AddUrl(Url, ProjectionType, NbSvr, MinZoom, MaxZoom, GetSvrStr, GetXStr, GetYStr, GetZStr); + Result.AddUrl(Url, ProjectionType, ATileSize, NbSvr, MinZoom, MaxZoom, GetSvrStr, GetXStr, GetYStr, GetZStr); end; procedure TMapViewerEngine.AdjustZoomCenter(var AWin: TMapWindow); @@ -352,20 +354,22 @@ function TMapViewerEngine.CalculateVisibleTiles(const aWin: TMapWindow; out var MaxX, MaxY, startX, startY: int64; WorldMax: Int64; + tileSz: TSize; begin Area := Default(TArea); Result := (aWin.X <= 0) and (aWin.Y <= 0); WorldMax := Int64(1) shl AWin.Zoom - 1; - MaxX := Int64(aWin.Width) div TILE_SIZE + 1; - MaxY := Int64(aWin.Height) div TILE_SIZE + 1; + tileSz := TileSize; + MaxX := Int64(aWin.Width) div tileSz.CX + 1; + MaxY := Int64(aWin.Height) div tileSz.CY + 1; if (MaxX > WorldMax) or (MaxY > WorldMax) then begin Result := False; MaxX := Min(WorldMax, MaxX); MaxY := Min(WorldMax, MaxY); end; - startX := -aWin.X div TILE_SIZE; - startY := -aWin.Y div TILE_SIZE; + startX := -aWin.X div tileSz.CX; + startY := -aWin.Y div tileSz.CY; if (startX < 0) or (startY < 0) then begin startX := Max(0, startX); @@ -437,7 +441,7 @@ begin exit(false); // Catch the case, that the screen is wider than the whole world - mapWidth := mvGeoMath.ZoomFactor(MapWin.Zoom) * TILE_SIZE; + mapWidth := mvGeoMath.ZoomFactor(MapWin.Zoom) * TileSize.CX; Result := (MapWin.Width > mapWidth); if not Result then begin @@ -619,6 +623,14 @@ begin Result := IntToStr(Id.X) + '.' + IntToStr(Id.Y) + '.' + IntToStr(Id.Z); end; +function TMapViewerEngine.GetTileSize: TSize; +begin + if Assigned(MapWin.MapProvider) then + Result := MapWin.MapProvider.TileSize + else + Result := TILE_SIZE_256; +end; + function TMapViewerEngine.GetUseThreads: Boolean; begin Result := Queue.UseThreads; @@ -669,7 +681,7 @@ begin Result.X := pixelLocation.x + AWin.X; if FCyclic and CrossesDateline then begin - mapWidth := ZoomFactor(AWin.Zoom) * TILE_SIZE; + mapWidth := ZoomFactor(AWin.Zoom) * TileSize.CX; while (Result.X < 0) do Result.X := Result.X + mapWidth; while (Result.X > AWin.Width) do @@ -688,8 +700,9 @@ const MAX_LONGITUDE = 180; TWO_PI = 2.0 * pi; var - factor, px, py: Extended; + factorX, factorY, px, py: Extended; pt: TRealPoint; + tileSz: TSize; begin // https://epsg.io/3857 // https://pubs.usgs.gov/pp/1395/report.pdf, page 41 @@ -697,9 +710,11 @@ begin pt.Lat := Math.EnsureRange(APt.Lat, MIN_LATITUDE, MAX_LATITUDE); pt.Lon := Math.EnsureRange(APt.Lon, MIN_LONGITUDE, MAX_LONGITUDE); - factor := TILE_SIZE / TWO_PI * ZoomFactor(AWin.Zoom); - px := factor * (pt.LonRad + pi); - py := factor * (pi - ln( tan(pi/4 + pt.LatRad/2) )); + tileSz := TileSize; + factorX := tileSz.CX / TWO_PI * ZoomFactor(AWin.Zoom); + factorY := tileSz.CY / TWO_PI * ZoomFactor(AWin.Zoom); + px := factorX * (pt.LonRad + pi); + py := factorY * (pi - ln( tan(pi/4 + pt.LatRad/2) )); Result.x := Round(px); Result.y := Round(py); @@ -768,7 +783,7 @@ var mPoint : TPoint; PType: TProjectionType; begin - mapWidth := round(mvGeoMath.ZoomFactor(AWin.Zoom)) * TILE_SIZE; + mapWidth := round(mvGeoMath.ZoomFactor(AWin.Zoom)) * TileSize.CX; if FCyclic then begin @@ -797,6 +812,7 @@ const MAX_LONGITUDE = 180; var zoomfac: Int64; + tileSz: TSize; begin // https://epsg.io/3857 // https://pubs.usgs.gov/pp/1395/report.pdf, page 41 @@ -805,8 +821,9 @@ begin // Result.LonRad := ( APoints.X / (( TILE_SIZE / (2*pi)) * 2**Zoom) ) - pi; // Result.LatRad := arctan( sinh(pi - (APoints.Y/TILE_SIZE) / 2**Zoom * pi*2) ); zoomFac := mvGeoMath.ZoomFactor(Zoom); - Result.LonRad := ( APoint.X / (( TILE_SIZE / (2*pi)) * zoomFac) ) - pi; - Result.LatRad := arctan( sinh(pi - (APoint.Y/TILE_SIZE) / zoomFac * pi*2) ); + tileSz := TileSize; + Result.LonRad := ( APoint.X / (( tileSz.CX / (2*pi)) * zoomFac) ) - pi; + Result.LatRad := arctan( sinh(pi - (APoint.Y/tileSz.CY) / zoomFac * pi*2) ); Result.Lat := Math.EnsureRange(Result.Lat, MIN_LATITUDE, MAX_LATITUDE); Result.Lon := Math.EnsureRange(Result.Lon, MIN_LONGITUDE, MAX_LONGITUDE); @@ -977,6 +994,22 @@ function TMapViewerEngine.ReadProvidersFromXML(AFileName: String; end; end; + function CalcTileSize(s: String): TSize; + var + x: Integer; + w, h: Integer; + begin + Result := TILE_SIZE_256; + if s <> '' then + begin + x := pos('x', s); + if TryStrToInt(Trim(copy(s, 1, x-1)), w) and TryStrToInt(Trim(copy(s, x+1, Length(s))), h) then + Result := Size(w, h) + else + raise Exception.CreateFmt('Invalid tile size value %s', [s]); + end; + end; + var stream: TFileStream; doc: TXMLDocument = nil; @@ -993,6 +1026,7 @@ var yProc: String; zProc: String; first: Boolean; + tileSz: TSize; begin Result := false; AMsg := ''; @@ -1025,6 +1059,7 @@ begin else svrCount := StrToInt(s); s := Concat('pt', GetAttrValue(layerNode, 'projection')); projectionType := TProjectionType(GetEnumValue(TypeInfo(TProjectionType), s)); //-1 will default to ptEPSG3857 + tileSz := CalcTileSize(GetAttrValue(layerNode, 'tileSize')); svrProc := GetAttrValue(layerNode, 'serverProc'); xProc := GetAttrValue(layerNode, 'xProc'); yProc := GetAttrValue(layerNode, 'yProc'); @@ -1035,7 +1070,7 @@ begin ClearMapProviders; first := false; end; - AddMapProvider(providerName, projectionType, + AddMapProvider(providerName, projectionType, tileSz, url, minZoom, maxZoom, svrCount, GetSvrStr(svrProc), GetValStr(xProc), GetValStr(yProc), GetValStr(zProc) ); @@ -1064,6 +1099,7 @@ var previewDrawn: Boolean; previewImg: TPictureCacheItem; R: TRect; + tileSz: TSize; procedure AddJob; var @@ -1084,22 +1120,22 @@ var var T, L, B, R: Integer; begin - T := -AWin.Y div TILE_SIZE - Max(0, Sign(AWin.Y)); - B := T + AWin.Height div TILE_SIZE + 1; - L := -AWin.X div TILE_SIZE - Max(0, Sign(AWin.X)); - R := L + AWin.Width div TILE_SIZE + 1; + T := -AWin.Y div tileSz.CY - Max(0, Sign(AWin.Y)); + B := T + AWin.Height div tileSz.CY + 1; + L := -AWin.X div tileSz.CX - Max(0, Sign(AWin.X)); + R := L + AWin.Width div tileSz.CX + 1; if T < TilesVis.top then // Erase above top - EraseBackground(Rect(0, 0, AWin.Width, AWin.Y + TilesVis.top * TILE_SIZE)); + EraseBackground(Rect(0, 0, AWin.Width, AWin.Y + TilesVis.top * tileSz.CY)); if L < TilesVis.left then // Erase on the left - EraseBackground(Rect(0, AWin.Y + TilesVis.top * TILE_SIZE, - AWin.X + TilesVis.left * TILE_SIZE, - AWin.Y + (TilesVis.bottom + 1) * TILE_SIZE)); + EraseBackground(Rect(0, AWin.Y + TilesVis.top * tileSz.CY, + AWin.X + TilesVis.left * tileSz.CX, + AWin.Y + (TilesVis.bottom + 1) * tileSz.CY)); if R > TilesVis.right then // Erase on the right - EraseBackground(Rect(AWin.X + (TilesVis.right + 1) * TILE_SIZE, - AWin.Y + TilesVis.top * TILE_SIZE, AWin.Width, - AWin.Y + (TilesVis.bottom + 1) * TILE_SIZE)); + EraseBackground(Rect(AWin.X + (TilesVis.right + 1) * tileSz.CX, + AWin.Y + TilesVis.top * tileSz.CY, AWin.Width, + AWin.Y + (TilesVis.bottom + 1) * tileSz.CY)); if B > TilesVis.bottom then // Erase below - EraseBackground(Rect(0, AWin.Y + (TilesVis.bottom + 1) * TILE_SIZE, + EraseBackground(Rect(0, AWin.Y + (TilesVis.bottom + 1) * tileSz.CY, AWin.Width, AWin.Height)); end; @@ -1112,12 +1148,14 @@ begin Exit; end; + tileSz := TileSize; + 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 TILE_SIZE - 1, 0); + XShift := IfThen(aWin.X > 0, numTiles - aWin.X div tileSz.CX - 1, 0); for y := TilesVis.Top to TilesVis.Bottom do for X := TilesVis.Left to TilesVis.Right do begin @@ -1139,8 +1177,8 @@ begin // is not valid begin previewdrawn := False; - py := AWin.Y + Y * TILE_SIZE; - px := AWin.X + X * TILE_SIZE; + py := AWin.Y + Y * tileSz.CY; + px := AWin.X + X * tileSz.CX; if FDrawPreviewTiles then begin if IsValidTile(AWin, Tiles[iTile]) then // Invalid tiles probably will not be found in the cache @@ -1372,33 +1410,35 @@ var worldWidth : Integer; numTiles : Integer; baseX : Integer; + tileSz: TSize; begin if IsCurrentWin(AWin)then begin Cache.GetFromCache(AWin.MapProvider, ATile, img); - Y := AWin.Y + ATile.Y * TILE_SIZE; // begin of Y + tileSz := TileSize; + Y := AWin.Y + ATile.Y * tileSz.CY; // begin of Y if Cyclic then begin - baseX := AWin.X + ATile.X * TILE_SIZE; // begin of X + baseX := AWin.X + ATile.X * tileSz.CX; // begin of X numTiles := 1 shl AWin.Zoom; - worldWidth := numTiles * TILE_SIZE; + worldWidth := numTiles * tileSz.CX; // From the center to the left (western) hemisphere X := baseX; - while (X+TILE_SIZE >= 0) do + while (X+tileSz.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-TILE_SIZE) <= AWin.Width) do + while ((X-tileSz.CX) <= AWin.Width) do begin DrawTile(ATile, X, Y, img); X := X + worldWidth; end; end else begin - X := AWin.X + ATile.X * TILE_SIZE; // begin of X + X := AWin.X + ATile.X * tileSz.CX; // begin of X DrawTile(ATile, X, Y, img); end; end; diff --git a/components/lazmapviewer/source/mvengine_mapreg.inc b/components/lazmapviewer/source/mvengine_mapreg.inc index 065a76ad9..fad540f3a 100644 --- a/components/lazmapviewer/source/mvengine_mapreg.inc +++ b/components/lazmapviewer/source/mvengine_mapreg.inc @@ -8,6 +8,7 @@ - https://vec01.maps.yandex.net/tiles?l=map&x=51693+570&y=32520&z=16&scale=1&lang=ru_RU - https://www.linux.org.ru/forum/development/9038716 - https://wiki.openstreetmap.org/wiki/Tiles +- (https://wiki.openstreetmap.org/wiki/OpenRailwayMap/API) - https://pubs.usgs.gov/pp/1395/report.pdf - https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_numbers_to_lon..2Flat. - https://mc.bbbike.org/mc/?num=2 @@ -22,15 +23,18 @@ Some providers submitted by } // OpenStreetMap section - MapWin.MapProvider := AddMapProvider('OpenStreetMap Mapnik', ptEPSG3857, 'http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); + MapWin.MapProvider := AddMapProvider('OpenStreetMap Mapnik', ptEPSG3857, TILE_SIZE_256, 'http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); // OSM Wikipedia no longer available for services outside Wikimedia projects. // AddMapProvider('OpenStreetMap Wikipedia', ptEPSG3857, 'https://maps.wikimedia.org/osm-intl/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); // OSM Sputnik is no longer available. Keeping it here for reference only... // AddMapProvider('OpenStreetMap Sputnik', ptEPSG3857, 'https://%serv%.tilessputnik.ru/tiles/kmt2/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); - AddMapProvider('OpenStreetMap.fr Hot', ptEPSG3857, 'https://%serv%.tile.openstreetmap.fr/hot/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); - AddMapProvider('Open Topo Map', ptEPSG3857, 'http://%serv%.tile.opentopomap.org/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); - AddMapProvider('OpenStreetMap.fr Cycle Map', ptEPSG3857, 'https://dev.%serv%.tile.openstreetmap.fr/cyclosm/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); - AddMapProvider('OSM Refuges', ptEPSG3857, 'https://maps.refuges.info/hiking/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('OpenStreetMap.fr Hot', ptEPSG3857, TILE_SIZE_256, 'https://%serv%.tile.openstreetmap.fr/hot/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); + AddMapProvider('Open Topo Map', ptEPSG3857, TILE_SIZE_256, 'http://%serv%.tile.opentopomap.org/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter); + AddMapProvider('OpenStreetMap.fr Cycle Map', ptEPSG3857, TILE_SIZE_256, 'https://dev.%serv%.tile.openstreetmap.fr/cyclosm/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); + AddMapProvider('OSM Refuges', ptEPSG3857, TILE_SIZE_256, 'https://maps.refuges.info/hiking/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('OpenRailwayMap Standard', ptEPSG3857, TILE_SIZE_512, 'https://%serv%.tiles.openrailwaymap.org/standard/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); // Creative-Commons license Attribution-ShareAlike 2.0 (CC-BY-SA 2.0) (https://wiki.openstreetmap.org/wiki/OpenRailwayMap/API) + AddMapProvider('OpenRailwayMap Signals', ptEPSG3857, TILE_SIZE_512, 'https://%serv%.tiles.openrailwaymap.org/signals/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); // Creative-Commons license Attribution-ShareAlike 2.0 (CC-BY-SA 2.0) (https://wiki.openstreetmap.org/wiki/OpenRailwayMap/API) + AddMapProvider('OpenRailwayMap MaxSpeed', ptEPSG3857, TILE_SIZE_512, 'https://%serv%.tiles.openrailwaymap.org/maxspeed/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); // Creative-Commons license Attribution-ShareAlike 2.0 (CC-BY-SA 2.0) (https://wiki.openstreetmap.org/wiki/OpenRailwayMap/API) // API Key required if (ThunderForest_ApiKey <> '') then @@ -39,48 +43,48 @@ Some providers submitted by // https://www.thunderforest.com/docs/apikeys/ // The API key is found on their website after registration and logging in. // Store the API key in the ini file under key [ThunderForest] as item API_Key - AddMapProvider('ThunderForest Open Cycle Map', ptEPSG3857, 'https://tile.thunderforest.com/cycle/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 3, nil, nil, nil, nil); - AddMapProvider('ThunderForest OpenStreetMap Transport', ptEPSG3857, 'https://tile.thunderforest.com/transport/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 3, nil, nil, nil, nil); + AddMapProvider('ThunderForest Open Cycle Map', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/cycle/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 3, nil, nil, nil, nil); + AddMapProvider('ThunderForest OpenStreetMap Transport', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/transport/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 3, nil, nil, nil, nil); - AddMapProvider('ThunderForest Neighbourhood', ptEPSG3857, 'https://tile.thunderforest.com/neighbourhood/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Atlas', ptEPSG3857, 'https://tile.thunderforest.com/atlas/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Pioneer', ptEPSG3857, 'https://tile.thunderforest.com/pioneer/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Outdoors', ptEPSG3857, 'https://tile.thunderforest.com/outdoors/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Landscape', ptEPSG3857, 'https://tile.thunderforest.com/outdoors/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Mobile-Atlas', ptEPSG3857, 'https://tile.thunderforest.com/mobile-atlas/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Transport-Dark', ptEPSG3857, 'https://tile.thunderforest.com/transport-dark/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); - AddMapProvider('ThunderForest Spinal-Map', ptEPSG3857, 'https://tile.thunderforest.com/spinal-map/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Neighbourhood', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/neighbourhood/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Atlas', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/atlas/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Pioneer', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/pioneer/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Outdoors', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/outdoors/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Landscape', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/outdoors/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Mobile-Atlas', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/mobile-atlas/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Transport-Dark', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/transport-dark/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); + AddMapProvider('ThunderForest Spinal-Map', ptEPSG3857, TILE_SIZE_256, 'https://tile.thunderforest.com/spinal-map/%z%/%x%/%y%.png?apikey=' + ThunderForest_ApiKey, 0, 19, 4, nil); // The following providers could be used alternatively. No API key required, // but has a gray "API Key required" watermark and maybe other restrictions! - // AddMapProvider('Open Cycle Map', ptEPSG3857, 'http://%serv%.tile.opencyclemap.org/cycle/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); - // AddMapProvider('OpenStreetMap Transport', ptEPSG3857, 'https://%serv%.tile.thunderforest.com/transport/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); + // AddMapProvider('Open Cycle Map', ptEPSG3857, TILE_SIZE_256, 'http://%serv%.tile.opencyclemap.org/cycle/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); + // AddMapProvider('OpenStreetMap Transport', ptEPSG3857, TILE_SIZE_256, 'https://%serv%.tile.thunderforest.com/transport/%z%/%x%/%y%.png', 0, 18, 3, @GetSvrLetter); end; // Google - AddMapProvider('Google Maps', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=m@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); - AddMapProvider('Google Satellite', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=y&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); + AddMapProvider('Google Maps', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=m@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); + AddMapProvider('Google Satellite', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=y&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); // not working any more (June 2023), replaced by above: - //AddMapProvider('Google Satellite', ptEPSG3857, 'http://khm%serv%.google.com/kh/v=863?x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); - AddMapProvider('Google Terrain', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=p&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); - AddMapProvider('Google Satellite Only', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=s&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); - AddMapProvider('Google Altered Roadmap', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=r&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); - AddMapProvider('Google Roadmap', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=m&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); + //AddMapProvider('Google Satellite', ptEPSG3857, TILE_SIZE_256, 'http://khm%serv%.google.com/kh/v=863?x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); + AddMapProvider('Google Terrain', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=p&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); + AddMapProvider('Google Satellite Only', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=s&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); + AddMapProvider('Google Altered Roadmap', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=r&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); + AddMapProvider('Google Roadmap', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=m&hl=en&x=%x%&y=%y%&z=%z%' , 0, 19, 4, nil); // Yandex - AddMapProvider('Yandex.Maps', ptEPSG3395, 'https://core-renderer-tiles.maps.yandex.net/tiles?l=map&x=%x%&y=%y%&z=%z%&scale=1', 0, 19, 4, nil, nil, nil, nil); // Russion labels - AddMapProvider('Yandex.Maps Satellite', ptEPSG3395, 'https://core-sat.maps.yandex.net/tiles?l=sat&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil, nil, nil, nil); - AddMapProvider('Yandex.Maps Satellite-old', ptEPSG3395, 'https://sat0%serv%.maps.yandex.net/tiles?l=sat&x=%x%&y=%y%&z=%z%', 0, 19, 4, @GetSvrBase1, nil, nil, nil); + AddMapProvider('Yandex.Maps', ptEPSG3395, TILE_SIZE_256, 'https://core-renderer-tiles.maps.yandex.net/tiles?l=map&x=%x%&y=%y%&z=%z%&scale=1', 0, 19, 4, nil, nil, nil, nil); // Russion labels + AddMapProvider('Yandex.Maps Satellite', ptEPSG3395, TILE_SIZE_256, 'https://core-sat.maps.yandex.net/tiles?l=sat&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil, nil, nil, nil); + AddMapProvider('Yandex.Maps Satellite-old', ptEPSG3395, TILE_SIZE_256, 'https://sat0%serv%.maps.yandex.net/tiles?l=sat&x=%x%&y=%y%&z=%z%', 0, 19, 4, @GetSvrBase1, nil, nil, nil); // The next ones are no longer valid. Keeping them here just in case ... - //AddMapProvider('Yandex.Maps-old', ptEPSG3395, 'https://vec0%serv%.maps.yandex.net/tiles?l=map&x=%x%&y=%y%&z=%z%&scale=1&lang=ru_RU', 0, 19, 4, @GetSvrBase1, nil, nil, nil); + //AddMapProvider('Yandex.Maps-old', ptEPSG3395, TILE_SIZE_256, 'https://vec0%serv%.maps.yandex.net/tiles?l=map&x=%x%&y=%y%&z=%z%&scale=1&lang=ru_RU', 0, 19, 4, @GetSvrBase1, nil, nil, nil); // Bing - AddMapProvider('Virtual Earth Bing', ptEPSG3857, 'http://ecn.t%serv%.tiles.virtualearth.net/tiles/r%x%?g=671&mkt=en-us&lbl=l1&stl=h&shading=hill', 1, 19, 8, nil, @GetStrQuadKey); - AddMapProvider('Virtual Earth Aerial', ptEPSG3857, 'http://a%serv%.ortho.tiles.virtualearth.net/tiles/a%x%.jpg?g=72&shading=hill', 1, 19, 4, nil, @GetStrQuadKey); - AddMapProvider('Virtual Earth Hybrid', ptEPSG3857, 'http://h%serv%.ortho.tiles.virtualearth.net/tiles/h%x%.jpg?g=72&shading=hill', 1, 19, 4, nil, @GetStrQuadKey); + AddMapProvider('Virtual Earth Bing', ptEPSG3857, TILE_SIZE_256, 'http://ecn.t%serv%.tiles.virtualearth.net/tiles/r%x%?g=671&mkt=en-us&lbl=l1&stl=h&shading=hill', 1, 19, 8, nil, @GetStrQuadKey); + AddMapProvider('Virtual Earth Aerial', ptEPSG3857, TILE_SIZE_256, 'http://a%serv%.ortho.tiles.virtualearth.net/tiles/a%x%.jpg?g=72&shading=hill', 1, 19, 4, nil, @GetStrQuadKey); + AddMapProvider('Virtual Earth Hybrid', ptEPSG3857, TILE_SIZE_256, 'http://h%serv%.ortho.tiles.virtualearth.net/tiles/h%x%.jpg?g=72&shading=hill', 1, 19, 4, nil, @GetStrQuadKey); // 2GIS (Russian labels, limited zoom range) - AddMapProvider('2GIS', ptEPSG3857, 'http://tile%serv%.maps.2gis.com/tiles?x=%x%&y=%y%&z=%z%', 2, 18, 4, nil); // Reduced zoom levels tested... + AddMapProvider('2GIS', ptEPSG3857, TILE_SIZE_256, 'http://tile%serv%.maps.2gis.com/tiles?x=%x%&y=%y%&z=%z%', 2, 18, 4, nil); // Reduced zoom levels tested... if (HERE_AppID <> '') and (HERE_AppCode <> '') then begin // Registration required to access HERE maps: @@ -90,74 +94,74 @@ Some providers submitted by // restart the demo. HERE1 := 'http://%serv%.base.maps.api.here.com/maptile/2.1/maptile/newest/'; HERE2 := '/%z%/%x%/%y%/256/png8?app_id=' + HERE_AppID + '&app_code=' + HERE_AppCode; - AddMapProvider('Here WeGo Map', ptEPSG3857, HERE1 + 'normal.day' + HERE2, 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo Grey Map', ptEPSG3857, HERE1 + 'normal.day.grey' + HERE2, 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo Reduced Map', ptEPSG3857, HERE1 + 'reduced.day' + HERE2, 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo Transit Map', ptEPSG3857, HERE1 + 'normal.day.transit' + HERE2, 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo POI Map', ptEPSG3857, HERE1 + 'normal.day' + HERE2 + '&pois', 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo Pedestrian Map', ptEPSG3857, HERE1 + 'pedestrian.day' + HERE2, 1, 19, 4, @GetSvrBase1); - AddMapProvider('Here WeGo DreamWorks Map', ptEPSG3857, HERE1 + 'normal.day' + HERE2 + '&style=dreamworks', 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'normal.day' + HERE2, 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo Grey Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'normal.day.grey' + HERE2, 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo Reduced Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'reduced.day' + HERE2, 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo Transit Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'normal.day.transit' + HERE2, 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo POI Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'normal.day' + HERE2 + '&pois', 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo Pedestrian Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'pedestrian.day' + HERE2, 1, 19, 4, @GetSvrBase1); + AddMapProvider('Here WeGo DreamWorks Map', ptEPSG3857, TILE_SIZE_256, HERE1 + 'normal.day' + HERE2 + '&style=dreamworks', 1, 19, 4, @GetSvrBase1); end; if (OpenWeatherMap_ApiKey <> '') then begin // Registration required to access OpenWeatherMaps // https://home.openweathermap.org/users/sign_up // Store the API key found on the website in the ini file of the demo under key [OpenWeatherMap] and API_Key and restart the demo - AddMapProvider('OpenWeatherMap Clouds', ptEPSG3857, 'https://tile.openweathermap.org/map/clouds_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); - AddMapProvider('OpenWeatherMap Precipitation', ptEPSG3857, 'https://tile.openweathermap.org/map/precipitation_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); - AddMapProvider('OpenWeatherMap Pressure', ptEPSG3857, 'https://tile.openweathermap.org/map/pressure_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); - AddMapProvider('OpenWeatherMap Temperature', ptEPSG3857, 'https://tile.openweathermap.org/map/temp_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); - AddMapProvider('OpenWeatherMap Wind', ptEPSG3857, 'https://tile.openweathermap.org/map/wind_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); + AddMapProvider('OpenWeatherMap Clouds', ptEPSG3857, TILE_SIZE_256, 'https://tile.openweathermap.org/map/clouds_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); + AddMapProvider('OpenWeatherMap Precipitation', ptEPSG3857, TILE_SIZE_256, 'https://tile.openweathermap.org/map/precipitation_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); + AddMapProvider('OpenWeatherMap Pressure', ptEPSG3857, TILE_SIZE_256, 'https://tile.openweathermap.org/map/pressure_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); + AddMapProvider('OpenWeatherMap Temperature', ptEPSG3857, TILE_SIZE_256, 'https://tile.openweathermap.org/map/temp_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); + AddMapProvider('OpenWeatherMap Wind', ptEPSG3857, TILE_SIZE_256, 'https://tile.openweathermap.org/map/wind_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey, 1, 19, 1, nil); end; { // The following maps need hybrid overlays - AddMapProvider('Google Hybrid', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=h@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); - AddMapProvider('Google Physical', ptEPSG3857, 'http://mt%serv%.google.com/vt/lyrs=t@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); - AddMapProvider('Yandex.Maps Hybrid', ptEPSG3395, 'https://vec0%serv%.maps.yandex.net/tiles?l=skl&x=%x%&y=%y%&z=%z%', 0, 19, 4, @GetSvrBase1, nil, nil, nil); + AddMapProvider('Google Hybrid', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=h@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); + AddMapProvider('Google Physical', ptEPSG3857, TILE_SIZE_256, 'http://mt%serv%.google.com/vt/lyrs=t@145&v=w2.104&x=%x%&y=%y%&z=%z%', 0, 19, 4, nil); + AddMapProvider('Yandex.Maps Hybrid', ptEPSG3395, TILE_SIZE_256, 'https://vec0%serv%.maps.yandex.net/tiles?l=skl&x=%x%&y=%y%&z=%z%', 0, 19, 4, @GetSvrBase1, nil, nil, nil); } // ArcGIS - AddMapProvider('ArcGIS World Street Map', ptEPSG3857, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); - AddMapProvider('ArcGIS World Shaded Relief', ptEPSG3857, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); -// AddMapProvider('ArcGIS World Physical Map', ptEPSG3857, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); --- not yet available - AddMapProvider('ArcGIS NatGeo World Map', ptEPSG3857, 'http://services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/%z%/%y%/%x%', 0, 19, 4, nil); -// AddMapProvider('ArcGIS Ocean Base', ptEPSG3857, 'http://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); // --- not yet available -// AddMapProvider('ArcGIS Imagery', ptEPSG3857, 'http://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); // not available - AddMapProvider('ArcGIS Clarity', ptEPSG3857, 'https://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/%z%/%y%/%x%?blankTile=false', 0, 19, 4, nil); + AddMapProvider('ArcGIS World Street Map', ptEPSG3857, TILE_SIZE_256, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); + AddMapProvider('ArcGIS World Shaded Relief', ptEPSG3857, TILE_SIZE_256, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); +// AddMapProvider('ArcGIS World Physical Map', ptEPSG3857, TILE_SIZE_256, 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); --- not yet available + AddMapProvider('ArcGIS NatGeo World Map', ptEPSG3857, TILE_SIZE_256, 'http://services.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/%z%/%y%/%x%', 0, 19, 4, nil); +// AddMapProvider('ArcGIS Ocean Base', ptEPSG3857, TILE_SIZE_256, 'http://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); // --- not yet available +// AddMapProvider('ArcGIS Imagery', ptEPSG3857, TILE_SIZE_256, 'http://services.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/%z%/%y%/%x%.jpg', 0, 19, 4, nil); // not available + AddMapProvider('ArcGIS Clarity', ptEPSG3857, TILE_SIZE_256, 'https://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/%z%/%y%/%x%?blankTile=false', 0, 19, 4, nil); // Apple - // AddMapProvider('GSP2 Apple', ptEPSG3857, 'http://gsp2.apple.com/tile?api=1&style=slideshow&layers=default&lang=de_DE&z=%z%&x=%x%&y=%y%&v=9', 0, 19, 4, nil); + // AddMapProvider('GSP2 Apple', ptEPSG3857, TILE_SIZE_256, 'http://gsp2.apple.com/tile?api=1&style=slideshow&layers=default&lang=de_DE&z=%z%&x=%x%&y=%y%&v=9', 0, 19, 4, nil); // CartoDB - AddMapProvider('CartoDB Light All', ptEPSG3857, 'https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/%z%/%x%/%y%.png', 0, 19, 4, nil); - AddMapProvider('CartoDB Voyager', ptEPSG3857, 'https://cartodb-basemaps-a.global.ssl.fastly.net/rastertiles/voyager/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('CartoDB Light All', ptEPSG3857, TILE_SIZE_256, 'https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('CartoDB Voyager', ptEPSG3857, TILE_SIZE_256, 'https://cartodb-basemaps-a.global.ssl.fastly.net/rastertiles/voyager/%z%/%x%/%y%.png', 0, 19, 4, nil); // "Maps for free" - AddMapProvider('Maps For Free', ptEPSG3857, 'http://maps-for-free.com/layer/relief/z%z%/row%y%/%z%_%x%-%y%.jpg', 0, 19, 4, nil); + AddMapProvider('Maps For Free', ptEPSG3857, TILE_SIZE_256, 'http://maps-for-free.com/layer/relief/z%z%/row%y%/%z%_%x%-%y%.jpg', 0, 19, 4, nil); // MemoMaps - AddMapProvider('Memo Maps', ptEPSG3857,'http://tile.memomaps.de/tilegen/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('Memo Maps', ptEPSG3857, TILE_SIZE_256, 'http://tile.memomaps.de/tilegen/%z%/%x%/%y%.png', 0, 19, 4, nil); // Sigma DC Control - //AddMapProvider('Sigma DC Control', ptEPSG3857,'http://tiles1.sigma-dc-control.com/layer5/%z%/%x%/%y%.png', 0, 19, 4, nil); // -- not working + //AddMapProvider('Sigma DC Control', ptEPSG3857, TILE_SIZE_256, 'http://tiles1.sigma-dc-control.com/layer5/%z%/%x%/%y%.png', 0, 19, 4, nil); // -- not working // Stamen - AddMapProvider('Stamen Terrain', ptEPSG3857, 'http://tile.stamen.com/terrain/%z%/%x%/%y%.jpg', 0, 19, 4, nil); - AddMapProvider('Stamen Watercolor', ptEPSG3857, 'https://stamen-tiles.a.ssl.fastly.net/watercolor/%z%/%x%/%y%.jpg' , 0, 19, 4, nil); + AddMapProvider('Stamen Terrain', ptEPSG3857, TILE_SIZE_256, 'http://tile.stamen.com/terrain/%z%/%x%/%y%.jpg', 0, 19, 4, nil); + AddMapProvider('Stamen Watercolor', ptEPSG3857, TILE_SIZE_256, 'https://stamen-tiles.a.ssl.fastly.net/watercolor/%z%/%x%/%y%.jpg' , 0, 19, 4, nil); // Via Michelin - AddMapProvider('ViaMichelin', ptEPSG3857, 'http://map1.viamichelin.com/map/mapdirect?map=light&z=%z%&x=%x%&y=%y%&format=png&version=201503191157&layer=background', 0, 19, 4, nil); + AddMapProvider('ViaMichelin', ptEPSG3857, TILE_SIZE_256, 'http://map1.viamichelin.com/map/mapdirect?map=light&z=%z%&x=%x%&y=%y%&format=png&version=201503191157&layer=background', 0, 19, 4, nil); // GeoApify - //AddMapProvider('Geoapify Map Tiles', ptEPSG3857, 'https://maps.geoapify.com/v1/tile/osm-bright-smooth/%z%/%x%/%y%.png' , 0, 19, 4, nil); // -- not working + //AddMapProvider('Geoapify Map Tiles', ptEPSG3857, TILE_SIZE_256, 'https://maps.geoapify.com/v1/tile/osm-bright-smooth/%z%/%x%/%y%.png' , 0, 19, 4, nil); // -- not working // Stadia outdoors - // AddMapProvider('Stadia Outdoors', ptEPSG3857, 'https://tiles.stadiamaps.com/tiles/outdoors/%z%/%x%/%y%.png', 0, 19, 4, nil); -- subscription required + // AddMapProvider('Stadia Outdoors', ptEPSG3857, TILE_SIZE_256, 'https://tiles.stadiamaps.com/tiles/outdoors/%z%/%x%/%y%.png', 0, 19, 4, nil); -- subscription required // Tracestrack - //AddMapProvider('Tracestrack Carto', ptEPSG3857, 'https://tile.tracestrack.com/en/%z%/%x%/%y%.png,' , 0, 19, 4, nil); // -- not working + //AddMapProvider('Tracestrack Carto', ptEPSG3857, TILE_SIZE_256, 'https://tile.tracestrack.com/en/%z%/%x%/%y%.png,' , 0, 19, 4, nil); // -- not working // Waze - AddMapProvider('Waze Background', ptEPSG3857, 'https://worldtiles1.waze.com/tiles/%z%/%x%/%y%.png', 0, 19, 4, nil); + AddMapProvider('Waze Background', ptEPSG3857, TILE_SIZE_256, 'https://worldtiles1.waze.com/tiles/%z%/%x%/%y%.png', 0, 19, 4, nil); diff --git a/components/lazmapviewer/source/mvmapprovider.pas b/components/lazmapviewer/source/mvmapprovider.pas index 481d9b1ee..1354ddad4 100644 --- a/components/lazmapviewer/source/mvmapprovider.pas +++ b/components/lazmapviewer/source/mvmapprovider.pas @@ -15,7 +15,7 @@ unit mvMapProvider; interface uses - Classes, SysUtils, laz2_dom; + Classes, SysUtils, Types, laz2_dom; type @@ -58,17 +58,20 @@ type FGetZStr: Array of TGetValStr; FMinZoom: Array of integer; FMaxZoom: Array of integer; - FTiles:array of TBaseTile; + FTiles: Array of TBaseTile; FTileHandling: TRTLCriticalSection; + FTileSize: Array of TSize; function GetLayerCount: integer; function GetProjectionType: TProjectionType; + function GetTileSize: TSize; procedure SetLayer(AValue: integer); public constructor Create(AName: String); destructor Destroy; override; function AppendTile(aTile: TBaseTile): integer; procedure RemoveTile(aTile: TBaseTile); - procedure AddURL(Url: String; ProjectionType: TProjectionType; NbSvr, aMinZoom, aMaxZoom: integer; + procedure AddURL(Url: String; ProjectionType: TProjectionType; + ATileSize: TSize; NbSvr, aMinZoom, aMaxZoom: integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr); procedure GetZoomInfos(out AZoomMin, AZoomMax: integer); @@ -78,6 +81,7 @@ type property LayerCount: integer read GetLayerCount; property Layer: integer read FLayer write SetLayer; property ProjectionType: TProjectionType read GetProjectionType; + property TileSize: TSize read GetTileSize; end; @@ -98,7 +102,7 @@ const implementation uses - TypInfo; + TypInfo, mvTypes; function GetSvrLetter(id: integer): String; begin @@ -169,6 +173,14 @@ begin Result := FProjectionType[layer]; end; +function TMapProvider.GetTileSize: TSize; +begin + if Length(FTileSize) = 0 then + Result := TILE_SIZE_256 + else + Result := FTileSize[layer]; +end; + procedure TMapProvider.SetLayer(AValue: integer); begin if FLayer = AValue then Exit; @@ -192,6 +204,7 @@ begin Finalize(idServer); Finalize(FName); Finalize(FProjectionType); + Finalize(FTileSize); Finalize(FUrl); Finalize(FNbSvr); Finalize(FGetSvrStr); @@ -284,7 +297,7 @@ begin end; procedure TMapProvider.AddURL(Url: String; ProjectionType: TProjectionType; - NbSvr, aMinZoom, aMaxZoom: integer; GetSvrStr: TGetSvrStr; + ATileSize: TSize; NbSvr, aMinZoom, aMaxZoom: integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr); var nb: integer; @@ -293,6 +306,7 @@ begin SetLength(IdServer, nb); SetLength(FUrl, nb); SetLength(FProjectionType, nb); + SetLength(FTileSize, nb); SetLength(FNbSvr, nb); SetLength(FGetSvrStr, nb); SetLength(FGetXStr, nb); @@ -303,6 +317,7 @@ begin nb := High(FUrl); FUrl[nb] := Url; FProjectionType[nb] := ProjectionType; + FTileSize[nb] := ATileSize; FNbSvr[nb] := NbSvr; FMinZoom[nb] := aMinZoom; FMaxZoom[nb] := aMaxZoom; @@ -407,6 +422,9 @@ begin s := ''; if s <> '' then layerNode.SetAttribute('zProc', s); + + s := Format('%d x %d', [FTileSize[i].CX, FTileSize[i].CY]); + layerNode.SetAttribute('tileSize', s); end; end; diff --git a/components/lazmapviewer/source/mvmapviewer.pas b/components/lazmapviewer/source/mvmapviewer.pas index 7dd5478cd..185cfafbf 100644 --- a/components/lazmapviewer/source/mvmapviewer.pas +++ b/components/lazmapviewer/source/mvmapviewer.pas @@ -2606,7 +2606,7 @@ const Engine.Redraw; W := Canvas.Width; if Cyclic then - W := Min(1 shl Zoom * TILE_SIZE, W); + W := Min(1 shl Zoom * Engine.TileSize.CX, W); if Assigned(FBeforeDrawObjectsEvent) then FBeforeDrawObjectsEvent(Self); @@ -2768,7 +2768,7 @@ begin begin L := Max(0, Engine.MapLeft); T := Max(0, Engine.MapTop); - WS := ZoomFactor(Zoom) * TILE_SIZE; + WS := ZoomFactor(Zoom) * Engine.TileSize.CX; ClipRect := Rect(L, T, Min(Engine.MapLeft + WS, ClientWidth), Min(Engine.MapTop + WS, ClientHeight)); end; @@ -2836,7 +2836,7 @@ begin if Cyclic then begin - WS := ZoomFactor(Zoom) * TILE_SIZE; + WS := ZoomFactor(Zoom) * Engine.TileSize.CX; // To do: Fix case when tiles are not square if (WS < ClientWidth) then begin {TODO Draw multiple copies of the area} @@ -3070,11 +3070,14 @@ end; procedure TMapView.DoDrawStretchedTile(const TileId: TTileID; X, Y: Integer; TileImg: TPictureCacheItem; const R: TRect); +var + tileSize: TSize; begin + tileSize := Engine.TileSize; if Assigned(TileImg) then - DrawingEngine.DrawScaledCacheItem(Rect(X, Y, X + TILE_SIZE, Y + TILE_SIZE), R, TileImg) + DrawingEngine.DrawScaledCacheItem(Rect(X, Y, X + tileSize.CX, Y + tileSize.CY), R, TileImg) else - DrawingEngine.FillPixels(X, Y, X + TILE_SIZE, Y + TILE_SIZE, InactiveColor); + DrawingEngine.FillPixels(X, Y, X + tileSize.CY, Y + tileSize.CY, InactiveColor); if FDebugTiles then DoDrawTileInfo(TileID, X, Y); @@ -3083,25 +3086,32 @@ end; procedure TMapView.DoDrawTile(const TileId: TTileId; X, Y: integer; TileImg: TPictureCacheItem); +var + tileSize: TSize; begin if Assigned(TileImg) then DrawingEngine.DrawCacheItem(X, Y, TileImg) else - DrawingEngine.FillPixels(X, Y, X + TILE_SIZE, Y + TILE_SIZE, InactiveColor); + begin + tileSize := Engine.TileSize; + DrawingEngine.FillPixels(X, Y, X + tileSize.CX, Y + tileSize.CY, InactiveColor); + end; if FDebugTiles then DoDrawTileInfo(TileID, X, Y); - end; procedure TMapView.DoDrawTileInfo(const TileID: TTileID; X, Y: Integer); +var + tileSize: TSize; begin + tileSize := Engine.TileSize; DrawingEngine.PenColor := clGray; DrawingEngine.PenWidth := 1; - DrawingEngine.Line(X, Y, X, Y + TILE_SIZE); - DrawingEngine.Line(X, Y, X + TILE_SIZE, Y); - DrawingEngine.Line(X + TILE_SIZE, Y, X + TILE_SIZE, Y + TILE_SIZE); - DrawingEngine.Line(X, Y + TILE_SIZE, X + TILE_SIZE, Y + TILE_SIZE); + DrawingEngine.Line(X, Y, X, Y + tileSize.CY); + DrawingEngine.Line(X, Y, X + tileSize.CX, Y); + DrawingEngine.Line(X + tileSize.CX, Y, X + tileSize.CX, Y + tileSize.CY); + DrawingEngine.Line(X, Y + tileSize.CY, X + tileSize.CX, Y + tileSize.CY); end; procedure TMapView.DoEraseBackground(const R: TRect); @@ -3248,7 +3258,7 @@ var WorldSize: Int64; begin Result := APoint; - WorldSize := ZoomFactor(Zoom) * TILE_SIZE; + WorldSize := ZoomFactor(Zoom) * Engine.TileSize.CX; if Eastwards then begin while Result.X < ARefX do @@ -3277,7 +3287,7 @@ begin end else begin - WorldSize := ZoomFactor(Zoom) * TILE_SIZE; + WorldSize := ZoomFactor(Zoom) * Engine.TileSize.CX; CanvasWidth := Canvas.Width; SetLength(Result, 1{APoint} + (1{Round} + CanvasWidth div WorldSize)); Result[0] := APoint; @@ -3447,7 +3457,7 @@ begin Result.BottomRight := Engine.ScreenToLatLon(Point(Width, Height)); if Cyclic then begin - mapWidth := ZoomFactor(Engine.Zoom) * TILE_SIZE; + mapWidth := ZoomFactor(Engine.Zoom) * Engine.TileSize.CX; if Width >= mapWidth then begin Result.TopLeft.Lon := -180; @@ -3727,21 +3737,23 @@ var X, Y, Z, W, H: Integer; S: String; extent: TSize; + tileSize: TSize; begin inherited Draw(AView, Area); V := FParentView; PtTL := V.Engine.LatLonToWorldScreen(Area.TopLeft); PtBR := V.Engine.LatLonToWorldScreen(Area.BottomRight); - X := -PtTL.X div TILE_SIZE; - Y := -PtTL.Y div TILE_SIZE; - Pt0 := Point(V.Engine.MapLeft + X * TILE_SIZE, - V.Engine.MapTop + Y * TILE_SIZE); + tileSize := V.Engine.TileSize; + X := -PtTL.X div tileSize.CX; + Y := -PtTL.Y div tileSize.CY; + Pt0 := Point(V.Engine.MapLeft + X * tileSize.CX, + V.Engine.MapTop + Y * tileSize.CY); Pt := Pt0; - H := Y + (PtBR.Y - PtTL.Y) div TILE_SIZE; + H := Y + (PtBR.Y - PtTL.Y) div tileSize.CY; while Y <= H do begin - X := -PtTL.X div TILE_SIZE; - W := X + (PtBR.X - PtTL.X) div TILE_SIZE; + X := -PtTL.X div tileSize.CX; + W := X + (PtBR.X - PtTL.X) div tileSize.CX; while X <= W do begin Z := V.Zoom; @@ -3749,13 +3761,13 @@ begin V.DrawingEngine.BrushColor := clCream; S := Format(' %d-%d-%d ', [X, Y, Z]); extent := V.DrawingEngine.TextExtent(S); - V.DrawingEngine.TextOut(Pt.X + (TILE_SIZE - extent.CX) div 2, - Pt.Y + (TILE_SIZE - extent.CY) div 2, S); - Inc(Pt.X, TILE_SIZE); + V.DrawingEngine.TextOut(Pt.X + (tileSize.CX - extent.CX) div 2, + Pt.Y + (tileSize.CY - extent.CY) div 2, S); + Inc(Pt.X, tileSize.CX); Inc(X); end; Pt.X := Pt0.X; - Inc(Pt.Y, TILE_SIZE); + Inc(Pt.Y, tileSize.CY); Inc(Y); end; end; diff --git a/components/lazmapviewer/source/mvtypes.pas b/components/lazmapviewer/source/mvtypes.pas index a6a598ca3..8c7bb45df 100644 --- a/components/lazmapviewer/source/mvtypes.pas +++ b/components/lazmapviewer/source/mvtypes.pas @@ -15,12 +15,13 @@ unit mvTypes; interface uses - Classes, SysUtils, Math; + Classes, SysUtils, Math, Types; const - TILE_SIZE = 256; PALETTE_PAGE = 'Misc'; DEFAULT_POI_TEXT_WIDTH = 300; + TILE_SIZE_256: TSize = (CX: 256; CY: 256); + TILE_SIZE_512: TSize = (CX: 512; CY: 512); Type { TArea }