lazarus-ccr/components/lazmapviewer/source/mvmapprovider.pas

373 lines
9.1 KiB
ObjectPascal

{ (C) 2014 ti_dic@hotmail.com
License: modified LGPL with linking exception (like RTL, FCL and LCL)
See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution,
for details about the license.
See also: https://wiki.lazarus.freepascal.org/FPC_modified_LGPL
}
unit mvMapProvider;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, laz2_dom;
type
{ TTileId }
TTileId = record
X, Y: int64;
Z: integer;
end;
TGetSvrStr = function (id: integer): string;
TGetValStr = function (const Tile: TTileId): String;
TProjectionType = (ptEPSG3857, ptEPSG3395);
TMapProvider = class;
{TBaseTile}
TBaseTile= class
FID:integer;
FMapProvider:TMapProvider;
Public
constructor Create(aProvider:TMapProvider);
destructor Destroy; override;
Property ID:integer read FID;
end;
{ TMapProvider }
TMapProvider = class
private
FLayer: integer;
idServer: Array of Integer;
FName: String;
FUrl: Array of string;
FProjectionType: Array of TProjectionType;
FNbSvr: Array of integer;
FGetSvrStr: Array of TGetSvrStr;
FGetXStr: Array of TGetValStr;
FGetYStr: Array of TGetValStr;
FGetZStr: Array of TGetValStr;
FMinZoom: Array of integer;
FMaxZoom: Array of integer;
FTiles:array of TBaseTile;
FTileHandling: TRTLCriticalSection;
function GetLayerCount: integer;
function GetProjectionType: TProjectionType;
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;
GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr;
GetZStr: TGetValStr);
procedure GetZoomInfos(out AZoomMin, AZoomMax: integer);
function GetUrlForTile(id: TTileId): String;
procedure ToXML(ADoc: TXMLDocument; AParentNode: TDOMNode);
property Name: String read FName;
property LayerCount: integer read GetLayerCount;
property Layer: integer read FLayer write SetLayer;
property ProjectionType: TProjectionType read GetProjectionType;
end;
function GetSvrLetter(id: integer): String;
function GetSvrBase1(id: integer): String;
function GetStrYahooY(const Tile: TTileId): string;
function GetStrYahooZ(const Tile: TTileId): string;
function GetStrQuadKey(const Tile: TTileId): string;
const
SVR_LETTER = 'Letter';
SVR_BASE1 = 'Base1';
STR_YAHOOY = 'YahooY'; // Idea: Deprecate, as Yahoo Maps are dead
STR_YAHOOZ = 'YahooZ'; // Idea: Deprecate, as Yahoo Maps are dead
STR_QUADKEY = 'QuadKey';
implementation
uses
TypInfo;
function GetSvrLetter(id: integer): String;
begin
Result := Char(Ord('a') + id);
end;
function GetStrQuadKey(const Tile: TTileId): string;
var
i, d, m: Longword;
begin
{ Bing Maps Tile System
http://msdn.microsoft.com/en-us/library/bb259689.aspx }
Result := '';
for i := Tile.Z downto 1 do
begin
d := 0;
m := 1 shl (i - 1);
if (Tile.x and m) <> 0 then
Inc(d, 1);
if (Tile.y and m) <> 0 then
Inc(d, 2);
Result := Result + IntToStr(d);
end;
end;
function GetSvrBase1(id: integer): String;
Begin
Result := IntToStr(id + 1);
end;
function GetStrYahooY(const Tile : TTileId): string;
begin
Result := IntToStr( -(Tile.Y - (1 shl Tile.Z) div 2) - 1);
end;
function GetStrYahooZ(const Tile : TTileId): string;
Begin
result := IntToStr(Tile.Z + 1);
end;
{ TBaseTile }
constructor TBaseTile.Create(aProvider: TMapProvider);
begin
FMapProvider := aProvider;
if assigned(aProvider) then
FID:=aProvider.AppendTile(self);
end;
destructor TBaseTile.Destroy;
begin
If assigned(FMapProvider) then
FMapProvider.RemoveTile(self);
FMapProvider:=nil;
inherited Destroy;
end;
{ TMapProvider }
function TMapProvider.GetLayerCount: integer;
begin
Result := Length(FUrl);
end;
function TMapProvider.GetProjectionType: TProjectionType;
begin
Result := FProjectionType[layer];
end;
procedure TMapProvider.SetLayer(AValue: integer);
begin
if FLayer = AValue then Exit;
if (aValue < Low(FUrl)) and (aValue > High(FUrl)) then
Begin
Raise Exception.Create('bad Layer');
end;
FLayer:=AValue;
end;
constructor TMapProvider.Create(AName: String);
begin
FName := aName;
InitCriticalSection(FTileHandling);
end;
destructor TMapProvider.Destroy;
var
i: Integer;
begin
Finalize(idServer);
Finalize(FName);
Finalize(FProjectionType);
Finalize(FUrl);
Finalize(FNbSvr);
Finalize(FGetSvrStr);
Finalize(FGetXStr);
Finalize(FGetYStr);
Finalize(FGetZStr);
Finalize(FMinZoom);
Finalize(FMaxZoom);
EnterCriticalSection(FTileHandling);
for i := high(FTiles) downto 1 do
try
freeandnil(FTiles[i]);
except
FTiles[i]:=nil;
end;
LeaveCriticalsection(FTileHandling);
DoneCriticalsection(FTileHandling);
inherited;
end;
function TMapProvider.AppendTile(aTile: TBaseTile): integer;
var
lNewID: Integer;
begin
EnterCriticalSection(FTileHandling);
lNewID :=high(FTiles)+1;
setlength(FTiles,lNewID+1);
FTiles[lNewID]:=aTile;
LeaveCriticalsection(FTileHandling);
result := lNewID;
end;
procedure TMapProvider.RemoveTile(aTile: TBaseTile);
var
lID, lMaxTile: Integer;
begin
if (atile.ID <= high(FTiles)) and (atile.ID>0) and (FTiles[aTile.ID]=aTile) then
begin
EnterCriticalSection(FTileHandling);
lID := aTile.ID;
lMaxTile :=High(FTiles);
aTile.FID := -1;
FTiles[lID] := FTiles[lMaxTile];
FTiles[lID].FID := lID;
setlength(FTiles,lMaxTile);
LeaveCriticalsection(FTileHandling);
end;
end;
procedure TMapProvider.AddURL(Url: String; ProjectionType: TProjectionType;
NbSvr, aMinZoom, aMaxZoom: integer; GetSvrStr: TGetSvrStr;
GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr);
var
nb: integer;
begin
nb := Length(FUrl)+1;
SetLength(IdServer, nb);
SetLength(FUrl, nb);
SetLength(FProjectionType, nb);
SetLength(FNbSvr, nb);
SetLength(FGetSvrStr, nb);
SetLength(FGetXStr, nb);
SetLength(FGetYStr, nb);
SetLength(FGetZStr, nb);
SetLength(FMinZoom, nb);
SetLength(FMaxZoom, nb);
nb := High(FUrl);
FUrl[nb] := Url;
FProjectionType[nb] := ProjectionType;
FNbSvr[nb] := NbSvr;
FMinZoom[nb] := aMinZoom;
FMaxZoom[nb] := aMaxZoom;
FGetSvrStr[nb] := GetSvrStr;
FGetXStr[nb] := GetXStr;
FGetYStr[nb] := GetYStr;
FGetZStr[nb] := GetZStr;
FLayer := Low(FUrl);
end;
procedure TMapProvider.GetZoomInfos(out AZoomMin, AZoomMax: integer);
begin
AZoomMin := FMinZoom[layer];
AZoomMax := FMaxZoom[layer];
end;
function TMapProvider.GetUrlForTile(id: TTileId): String;
var
i: integer;
XVal, yVal, zVal, SvrVal: String;
idsvr: integer;
begin
Result := '';
i := layer;
if (i > High(idServer)) or (i < Low(idServer)) or (FNbSvr[i] = 0) then
exit;
idsvr := idServer[i] mod FNbSvr[i];
idServer[i] += 1;
SvrVal := IntToStr(idsvr);
XVal := IntToStr(id.X);
YVal := IntToStr(id.Y);
ZVal := IntToStr(id.Z);
if Assigned(FGetSvrStr[i]) then
SvrVal := FGetSvrStr[i](idsvr);
if Assigned(FGetXStr[i]) then
XVal := FGetXStr[i](id);
if Assigned(FGetYStr[i]) then
YVal := FGetYStr[i](id);
if Assigned(FGetZStr[i]) then
ZVal := FGetZStr[i](id);
Result := StringReplace(FUrl[i], '%serv%', SvrVal, [rfreplaceall]);
Result := StringReplace(Result, '%x%', XVal, [rfreplaceall]);
Result := StringReplace(Result, '%y%', YVal, [rfreplaceall]);
Result := StringReplace(Result, '%z%', ZVal, [rfreplaceall]);
end;
procedure TMapProvider.ToXML(ADoc: TXMLDocument; AParentNode: TDOMNode);
var
i: Integer;
node: TDOMElement;
layerNode: TDOMElement;
s: String;
begin
node := ADoc.CreateElement('map_provider');
node.SetAttribute('name', FName);
AParentNode.AppendChild(node);
for i:=0 to LayerCount-1 do begin
layerNode := ADoc.CreateElement('layer');
node.AppendChild(layernode);
layerNode.SetAttribute('url', FUrl[i]);
layerNode.SetAttribute('minZoom', IntToStr(FMinZoom[i]));
layerNode.SetAttribute('maxZoom', IntToStr(FMaxZoom[i]));
layerNode.SetAttribute('serverCount', IntToStr(FNbSvr[i]));
s := GetEnumName(TypeInfo(TProjectionType), Ord(FProjectionType[i]));
if s.StartsWith('pt') then
s := s.Substring(2);
layerNode.SetAttribute('projection', s);
if FGetSvrStr[i] = @GetSvrLetter then
s := SVR_LETTER
else if FGetSvrStr[i] = @GetSvrBase1 then
s := SVR_BASE1
else
s := '';
if s <> '' then
layerNode.SetAttribute('serverProc', s);
if FGetXStr[i] = @GetStrQuadKey then
s := STR_QUADKEY
else
s := '';
if s <> '' then
layerNode.SetAttribute('xProc', s);
if FGetYStr[i] = @GetStrQuadKey then
s := STR_QUADKEY
else if FGetYStr[i] = @GetStrYahooY then
s := STR_YAHOOY
else
s := '';
if s <> '' then layerNode.SetAttribute('yProc', s);
if FGetZStr[i] = @GetStrQuadKey then
s := STR_QUADKEY
else if FGetZStr[i] = @GetStrYahooZ then
s := STR_YAHOOZ
else
s := '';
if s <> '' then
layerNode.SetAttribute('zProc', s);
end;
end;
end.