projectiontype.diff (40,245 bytes)
Index: source/mvengine.pas
===================================================================
--- source/mvengine.pas (revision 7925)
+++ source/mvengine.pas (working copy)
@@ -20,18 +20,15 @@
interface
uses
- Classes, SysUtils, IntfGraphics, Controls,
+ Classes, SysUtils, IntfGraphics, Controls, Math, TypInfo,
mvTypes, mvJobQueue, mvMapProvider, mvDownloadEngine, mvCache, mvDragObj;
const
- EARTH_RADIUS = 6378137;
- MIN_LATITUDE = -85.05112878;
- MAX_LATITUDE = 85.05112878;
- MIN_LONGITUDE = -180;
- MAX_LONGITUDE = 180;
- SHIFT = 2 * pi * EARTH_RADIUS / 2.0;
+ EARTH_EQUATORIAL_RADIUS = 6378137;
+ EARTH_POLAR_RADIUS = 6356752.3142;
+ EARTH_CIRCUMFERENCE = 2 * pi * EARTH_EQUATORIAL_RADIUS;
+ EARTH_ECCENTRICITY = sqrt(1-( exp(2*ln(EARTH_POLAR_RADIUS)) / exp(2*ln(EARTH_EQUATORIAL_RADIUS)))); // power doesn't work in interface
-
Type
TDrawTileEvent = Procedure (const TileId: TTileId; X,Y: integer;
TileImg: TLazIntfImage) of object;
@@ -89,9 +86,13 @@
procedure SetUseThreads(AValue: Boolean);
procedure SetWidth(AValue: integer);
procedure SetZoom(AValue: integer);
- function LonLatToMapWin(const aWin: TMapWindow; aPt: TRealPoint): TPoint;
- Function MapWinToLonLat(const aWin: TMapWindow; aPt : TPoint) : TRealPoint;
+ function DegreesToMapPixels(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
+ Function MapPixelsToDegrees(var aWin: TMapWindow; APoints: TPoint): TRealPoint;
+ Function PixelsToDegreesEPSG3395(APoints: TPoint; Zoom: Integer): TRealPoint;
+ Function PixelsToDegreesEPSG3857(APoints: TPoint; Zoom: Integer): TRealPoint;
Procedure CalculateWin(var aWin: TMapWindow);
+ function DegreesToPixelsEPSG3395(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
+ function DegreesToPixelsEPSG3857(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
Procedure Redraw(const aWin: TmapWindow);
function CalculateVisibleTiles(const aWin: TMapWindow) : TArea;
function IsCurrentWin(const aWin: TMapWindow) : boolean;
@@ -106,7 +107,7 @@
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
- function AddMapProvider(OpeName: String; Url: String;
+ function AddMapProvider(OpeName: String; ProjectionType: TProjectionType; Url: String;
MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr = nil;
GetXStr: TGetValStr = nil; GetYStr: TGetValStr = nil;
GetZStr: TGetValStr = nil): TMapProvider;
@@ -113,8 +114,8 @@
procedure CancelCurrentDrawing;
procedure ClearMapProviders;
procedure GetMapProviders(AList: TStrings);
- function LonLatToScreen(aPt: TRealPoint): TPoint;
- function LonLatToWorldScreen(aPt: TRealPoint): TPoint;
+ function LonLatToScreen(ALonLat: TRealPoint): TPoint;
+ function LonLatToWorldScreen(ALonLat: TRealPoint): TPoint;
function ReadProvidersFromXML(AFileName: String; out AMsg: String): Boolean;
procedure Redraw;
Procedure RegisterProviders;
@@ -177,7 +178,7 @@
implementation
uses
- Math, Forms, laz2_xmlread, laz2_xmlwrite, laz2_dom,
+ Forms, laz2_xmlread, laz2_xmlwrite, laz2_dom,
mvJobs, mvGpsObj;
type
@@ -354,9 +355,9 @@
inherited Destroy;
end;
-function TMapViewerEngine.AddMapProvider(OpeName: String; Url: String;
- MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr; GetXStr: TGetValStr;
- GetYStr: TGetValStr; GetZStr: TGetValStr): TMapProvider;
+function TMapViewerEngine.AddMapProvider(OpeName: String; ProjectionType: TProjectionType;
+ Url: String; MinZoom, MaxZoom, NbSvr: integer; GetSvrStr: TGetSvrStr;
+ GetXStr: TGetValStr; GetYStr: TGetValStr; GetZStr: TGetValStr): TMapProvider;
var
idx :integer;
Begin
@@ -368,7 +369,7 @@
end
else
Result := TMapProvider(lstProvider.Objects[idx]);
- Result.AddUrl(Url, NbSvr, MinZoom, MaxZoom, GetSvrStr, GetXStr, GetYStr, GetZStr);
+ Result.AddUrl(Url, ProjectionType, NbSvr, MinZoom, MaxZoom, GetSvrStr, GetXStr, GetYStr, GetZStr);
end;
function TMapViewerEngine.CalculateVisibleTiles(const aWin: TMapWindow): TArea;
@@ -387,20 +388,18 @@
procedure TMapViewerEngine.CalculateWin(var aWin: TMapWindow);
var
- mx, my: Extended;
- res: Extended;
- px, py: Int64;
+ PixelLocation: TPoint; // review: coth: Should it use Int64?
begin
- mx := aWin.Center.Lon * SHIFT / 180.0;
- my := ln( tan((90 - aWin.Center.Lat) * pi / 360.0 )) / (pi / 180.0);
- my := my * SHIFT / 180.0;
- res := (2 * pi * EARTH_RADIUS) / (TILE_SIZE * (1 shl aWin.Zoom));
- px := Round((mx + shift) / res);
- py := Round((my + shift) / res);
+ case aWin.MapProvider.ProjectionType of
+ ptEPSG3857: PixelLocation := DegreesToPixelsEPSG3857(aWin, aWin.Center);
+ ptEPSG3395: PixelLocation := DegreesToPixelsEPSG3395(aWin, aWin.Center);
+ else PixelLocation := DegreesToPixelsEPSG3857(aWin, aWin.Center);
+ end;
- aWin.X := aWin.Width div 2 - px;
- aWin.Y := aWin.Height div 2 - py;
+ aWin.X := Int64(aWin.Width div 2) - PixelLocation.x;
+ aWin.Y := Int64(aWin.Height div 2) - PixelLocation.y;
+
end;
procedure TMapViewerEngine.CancelCurrentDrawing;
@@ -572,90 +571,234 @@
(aTile.Y >= 0) and (aTile.Y <= tiles-1);
end;
-function TMapViewerEngine.LonLatToMapWin(const aWin: TMapWindow;
- aPt: TRealPoint): TPoint;
+function TMapViewerEngine.DegreesToMapPixels(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
var
- tiles: Int64;
- circumference: Int64;
- res: Extended;
- tmpX,tmpY : Double;
+ PixelLocaltion: TPoint;
begin
- tiles := 1 shl aWin.Zoom;
- circumference := tiles * TILE_SIZE;
- tmpX := ((aPt.Lon+ 180.0)*circumference)/360.0;
- res := (2 * pi * EARTH_RADIUS) / circumference;
+ case aWin.MapProvider.ProjectionType of
+ ptEPSG3395: PixelLocaltion := DegreesToPixelsEPSG3395(aWin, ALonLat);
+ ptEPSG3857: PixelLocaltion := DegreesToPixelsEPSG3857(aWin, ALonLat);
+ else PixelLocaltion := DegreesToPixelsEPSG3857(aWin, ALonLat);
+ end;
- tmpY := -aPt.Lat;
- tmpY := ln(tan((degToRad(tmpY) + pi / 2.0) / 2)) *180 / pi;
- tmpY:= (((tmpY / 180.0) * SHIFT) + SHIFT) / res;
+ Result.X := PixelLocaltion.x + aWin.X;
+ Result.Y := PixelLocaltion.y + aWin.Y;
- tmpX := tmpX + aWin.X;
- tmpY := tmpY + aWin.Y;
- Result.X := trunc(tmpX);
- Result.Y := trunc(tmpY);
end;
-function TMapViewerEngine.LonLatToScreen(aPt: TRealPoint): TPoint;
+// review: coth: Should it use Int64?
+function TMapViewerEngine.DegreesToPixelsEPSG3857(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
+const
+ MIN_LATITUDE = -85.05112878;
+ MAX_LATITUDE = 85.05112878;
+ MIN_LONGITUDE = -180;
+ MAX_LONGITUDE = 180;
+var
+ px, py: Extended;
+ pt: TRealPoint;
+begin
+
+ //
+ // https://epsg.io/3857
+ // https://pubs.usgs.gov/pp/1395/report.pdf, page 41
+ // https://en.wikipedia.org/wiki/Web_Mercator_projection
+
+ pt.Lat := Math.EnsureRange(ALonLat.Lat, MIN_LATITUDE, MAX_LATITUDE);
+ pt.Lon := Math.EnsureRange(ALonLat.Lon, MIN_LONGITUDE, MAX_LONGITUDE);
+
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // px := ( TILE_SIZE / (2 * pi)) * (2**aWin.Zoom) * (pt.LonRad + pi);
+ // py := ( TILE_SIZE / (2 * pi)) * (2**aWin.Zoom) *
+ px := ( TILE_SIZE / (2 * pi)) * ( Power (2, aWin.Zoom) ) * (pt.LonRad + pi);
+ py := ( TILE_SIZE / (2 * pi)) * ( Power (2, aWin.Zoom) ) *
+ (pi - ln( tan(pi/4 + pt.LatRad/2) ));
+
+ Result.x := Round(px);
+ Result.y := Round(py);
+
+end;
+
+// review: coth: Should it use Int64?
+function TMapViewerEngine.DegreesToPixelsEPSG3395(var aWin: TMapWindow; ALonLat: TRealPoint): TPoint;
+const
+ MIN_LATITUDE = -80;
+ MAX_LATITUDE = 84;
+ MIN_LONGITUDE = -180;
+ MAX_LONGITUDE = 180;
+var
+ px, py, lny, sny: Extended;
+ pt: TRealPoint;
+ cfmpx, cfmpm: Extended;
+ Z: Integer;
+begin
+
+ //
+ // https://epsg.io/3395
+ // https://pubs.usgs.gov/pp/1395/report.pdf, page 44
+
+ pt.Lat := Math.EnsureRange(ALonLat.Lat, MIN_LATITUDE, MAX_LATITUDE);
+ pt.Lon := Math.EnsureRange(ALonLat.Lon, MIN_LONGITUDE, MAX_LONGITUDE);
+
+ Z := 23 - aWin.Zoom;
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // cfmpx := 2**31;
+ cfmpx := Power (2, 31);
+ cfmpm := cfmpx / EARTH_CIRCUMFERENCE;
+
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // px := (EARTH_CIRCUMFERENCE/2 + EARTH_EQUATORIAL_RADIUS * pt.LonRad) * cfmpm / 2**Z;
+ px := (EARTH_CIRCUMFERENCE/2 + EARTH_EQUATORIAL_RADIUS * pt.LonRad) * cfmpm / Power(2, Z);
+
+ sny := EARTH_ECCENTRICITY * sin(pt.LatRad);
+ lny := tan(pi/4 + pt.LatRad/2) * power((1-sny)/(1+sny), EARTH_ECCENTRICITY/2);
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // py := (EARTH_CIRCUMFERENCE/2 - EARTH_EQUATORIAL_RADIUS * ln(lny)) * cfmpm / 2**Z;
+ py := (EARTH_CIRCUMFERENCE/2 - EARTH_EQUATORIAL_RADIUS * ln(lny)) * cfmpm / Power(2, Z);
+
+ Result.x := Round(px);
+ Result.y := Round(py);
+
+end;
+
+function TMapViewerEngine.LonLatToScreen(ALonLat: TRealPoint): TPoint;
Begin
- Result := LonLatToMapWin(MapWin, aPt);
+ Result := DegreesToMapPixels(MapWin, ALonLat);
end;
-function TMapViewerEngine.LonLatToWorldScreen(aPt: TRealPoint): TPoint;
+function TMapViewerEngine.LonLatToWorldScreen(ALonLat: TRealPoint): TPoint;
begin
- Result := LonLatToScreen(aPt);
+ Result := LonLatToScreen(ALonLat);
Result.X := Result.X + MapWin.X;
Result.Y := Result.Y + MapWin.Y;
end;
-function TMapViewerEngine.MapWinToLonLat(const aWin: TMapWindow;
- aPt: TPoint): TRealPoint;
+function TMapViewerEngine.MapPixelsToDegrees(var aWin: TMapWindow; APoints: TPoint): TRealPoint;
var
- tiles: Int64;
- circumference: Int64;
- lat: Extended;
- res: Extended;
+ iMapWidth: Int64;
mPoint : TPoint;
begin
- tiles := 1 shl aWin.Zoom;
- circumference := tiles * TILE_SIZE;
- mPoint.X := aPt.X - aWin.X;
- mPoint.Y := aPt.Y - aWin.Y;
+ // review: coth: respective projection check. move to subfunctions? figure out what did i mean here...
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // iMapWidth := (2**aWin.Zoom) * TILE_SIZE;
+ iMapWidth := Round(Power (2, aWin.Zoom)) * TILE_SIZE;
+ mPoint.X := APoints.X - aWin.X;
+ mPoint.Y := APoints.Y - aWin.Y;
+
if mPoint.X < 0 then
mPoint.X := 0
else
- if mPoint.X > circumference then
- mPoint.X := circumference;
+ if mPoint.X > iMapWidth then
+ mPoint.X := iMapWidth;
if mPoint.Y < 0 then
mPoint.Y := 0
else
- if mPoint.Y > circumference then
- mPoint.Y := circumference;
+ if mPoint.Y > iMapWidth then
+ mPoint.Y := iMapWidth;
- Result.Lon := ((mPoint.X * 360.0) / circumference) - 180.0;
+ case aWin.MapProvider.ProjectionType of
+ ptEPSG3857: Result := PixelsToDegreesEPSG3857(mPoint, aWin.Zoom);
+ ptEPSG3395: Result := PixelsToDegreesEPSG3395(mPoint, aWin.Zoom);
+ else Result := PixelsToDegreesEPSG3857(mPoint, aWin.Zoom);
+ end;
- res := (2 * pi * EARTH_RADIUS) / circumference;
- lat := ((mPoint.Y * res - SHIFT) / SHIFT) * 180.0;
+end;
- lat := radtodeg (2 * arctan( exp( lat * pi / 180.0)) - pi / 2.0);
- Result.Lat := -lat;
+Function TMapViewerEngine.PixelsToDegreesEPSG3857(APoints: TPoint; Zoom: Integer): TRealPoint;
+const
+ MIN_LATITUDE = -85.05112878;
+ MAX_LATITUDE = 85.05112878;
+ MIN_LONGITUDE = -180;
+ MAX_LONGITUDE = 180;
+begin
- if Result.Lat > MAX_LATITUDE then
- Result.Lat := MAX_LATITUDE
- else
- if Result.Lat < MIN_LATITUDE then
- Result.Lat := MIN_LATITUDE;
+ //
+ // https://epsg.io/3857
+ // https://pubs.usgs.gov/pp/1395/report.pdf, page 41
- if Result.Lon > MAX_LONGITUDE then
- Result.Lon := MAX_LONGITUDE
- else
- if Result.Lon < MIN_LONGITUDE then
- Result.Lon := MIN_LONGITUDE;
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // Result.LonRad := ( APoints.X / (( TILE_SIZE / (2*pi)) * 2**Zoom) ) - pi;
+ // Result.LatRad := arctan( sinh(pi - (APoints.Y/TILE_SIZE) / 2**Zoom * pi*2) );
+ Result.LonRad := ( APoints.X / (( TILE_SIZE / (2*pi)) * Power(2, Zoom)) ) - pi;
+ Result.LatRad := arctan( sinh(pi - (APoints.Y/TILE_SIZE) / Power(2, Zoom) * pi*2) );
+
+ Result.Lat := Math.EnsureRange(Result.Lat, MIN_LATITUDE, MAX_LATITUDE);
+ Result.Lon := Math.EnsureRange(Result.Lon, MIN_LONGITUDE, MAX_LONGITUDE);
+
end;
+Function TMapViewerEngine.PixelsToDegreesEPSG3395(APoints: TPoint; Zoom: Integer): TRealPoint;
+
+ function PhiIteration(y, phi: Extended): Extended;
+ var
+ t: Extended;
+ begin
+ t := exp(y/EARTH_EQUATORIAL_RADIUS);
+ phi := pi/2 - 2*arctan( t *
+ Math.power((
+ (1 - EARTH_ECCENTRICITY * sin(phi)) /
+ (1 + EARTH_ECCENTRICITY * sin(phi))),
+ EARTH_ECCENTRICITY/2)
+ );
+ Result := phi;
+ end;
+
+const
+ MIN_LATITUDE = -80;
+ MAX_LATITUDE = 84;
+ MIN_LONGITUDE = -180;
+ MAX_LONGITUDE = 180;
+var
+ LonRad, LatRad: Extended;
+ WorldSize: Int64;
+ Cpm: Extended;
+ Z: Integer;
+ t, phi: Extended;
+ i: Integer;
+begin
+
+ //
+ // https://epsg.io/3395
+ // https://pubs.usgs.gov/pp/1395/report.pdf, page 44
+
+ Z := 23 - Zoom;
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // WorldSize := 2**31;
+ WorldSize := Round(Power(2, 31));
+ Cpm := WorldSize / EARTH_CIRCUMFERENCE;
+
+ // note: coth: ** for better readability, but breaking OmniPascal in VSCode
+ // LonRad := (APoints.x / (Cpm/2**Z) - EARTH_CIRCUMFERENCE/2) / EARTH_EQUATORIAL_RADIUS;
+ // LatRad := (APoints.y / (Cpm/2**Z) - EARTH_CIRCUMFERENCE/2);
+ LonRad := (APoints.x / (Cpm/Power(2, Z)) - EARTH_CIRCUMFERENCE/2) / EARTH_EQUATORIAL_RADIUS;
+ LatRad := (APoints.y / (Cpm/Power(2, Z)) - EARTH_CIRCUMFERENCE/2);
+
+ t := pi/2 - 2*arctan(exp(-LatRad/EARTH_EQUATORIAL_RADIUS));
+
+ i := 0;
+ repeat
+ phi := t;
+ t := PhiIteration(LatRad, phi);
+ inc(i);
+ if i>10 then
+ Break;
+ //raise Exception.Create('Phi iteration takes too long.');
+ until
+ abs(phi - t) < 1e-8;
+
+ LatRad := t;
+
+ Result.LonRad := LonRad;
+ Result.LatRad := LatRad;
+
+ Result.Lat := Math.EnsureRange(Result.Lat, MIN_LATITUDE, MAX_LATITUDE);
+ Result.Lon := Math.EnsureRange(Result.Lon, MIN_LONGITUDE, MAX_LONGITUDE);
+
+end;
+
procedure TMapViewerEngine.MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
@@ -705,7 +848,7 @@
old := TMemObj(Sender.LnkObj);
aPt.X := old.FWin.Width DIV 2-Sender.OfsX;
aPt.Y := old.FWin.Height DIV 2-Sender.OfsY;
- nCenter := MapWinToLonLat(old.FWin,aPt);
+ nCenter := MapPixelsToDegrees(old.FWin,aPt);
SetCenter(nCenter);
end;
@@ -717,11 +860,12 @@
lcName: String;
begin
lcName := LowerCase(AName);
- case lcName of
- 'letter': Result := @GetLetterSvr;
- 'yahoo': Result := @GetYahooSvr;
- else Result := nil;
- end;
+ if lcName = LowerCase(SVR_LETTER) then
+ Result := @GetSvrLetter
+ else if lcName = LowerCase(SVR_BASE1) then
+ Result := @GetSvrBase1
+ else
+ Result := nil;
end;
function GetValStr(AName: String): TGetValStr;
@@ -729,12 +873,14 @@
lcName: String;
begin
lcName := Lowercase(AName);
- case lcName of
- 'quadkey': Result := @GetQuadKey;
- 'yahooy': Result := @GetYahooY;
- 'yahooz': Result := @GetYahooZ;
- else Result := nil;
- end;
+ if lcName = LowerCase(STR_QUADKEY) then
+ Result := @GetStrQuadKey
+ else if lcName = LowerCase(STR_YAHOOY) then
+ Result := @GetStrYahooY
+ else if lcName = LowerCase(STR_YAHOOZ) then
+ Result := @GetStrYahooZ
+ else
+ Result := nil;
end;
function GetAttrValue(ANode: TDOMNode; AttrName: String): String;
@@ -753,6 +899,7 @@
doc: TXMLDocument = nil;
node, layerNode: TDOMNode;
providerName: String;
+ projectionType: TProjectionType;
url: String;
minZoom: Integer;
maxZoom: Integer;
@@ -793,6 +940,8 @@
s := GetAttrValue(layerNode, 'serverCount');
if s = '' then svrCount := 1
else svrCount := StrToInt(s);
+ s := Concat('pt', GetAttrValue(layerNode, 'projection'));
+ projectionType := TProjectionType(GetEnumValue(TypeInfo(TProjectionType), s)); //-1 will default to ptEPSG3857
svrProc := GetAttrValue(layerNode, 'serverProc');
xProc := GetAttrValue(layerNode, 'xProc');
yProc := GetAttrValue(layerNode, 'yProc');
@@ -803,7 +952,7 @@
ClearMapProviders;
first := false;
end;
- AddMapProvider(providerName,
+ AddMapProvider(providerName, projectionType,
url, minZoom, maxZoom, svrCount,
GetSvrStr(svrProc), GetValStr(xProc), GetValStr(yProc), GetValStr(zProc)
);
@@ -852,54 +1001,58 @@
var
HERE1, HERE2: String;
begin
-// AddMapProvider('Aucun','',0,30, 0); ???
- AddMapProvider('Google Normal',
- 'http://mt%serv%.google.com/vt/lyrs=m@145&v=w2.104&x=%x%&y=%y%&z=%z%',
- 0, 19, 4, nil);
- AddMapProvider('Google Hybrid',
- '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',
- 'http://mt%serv%.google.com/vt/lyrs=t@145&v=w2.104&x=%x%&y=%y%&z=%z%',
- 0, 19, 4, nil);
+ // dev links
+ //https://gis-lab.info/forum/viewtopic.php?f=19&t=19763
+ //https://a.tile.openstreetmap.org/16/51693/32520.png
+ //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://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
+ //https://mc.bbbike.org/mc/?lon=37.62178&lat=55.740937&zoom=14&num=1&mt0=opentopomap&mt1=mapnik-german
+ //https://t.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/12031010103311?mkt=ru-RU&it=G,BX,RL&shading=hill&n=z&og=677&c4w=1&cstl=vb&src=h
{
- AddMapProvider('Google Hybrid','http://khm%d.google.com/kh/v=82&x=%x%&y=%y%&z=%z%&s=Ga',4);
- AddMapProvider('Google Hybrid','http://mt%d.google.com/vt/lyrs=h@145&v=w2.104&x=%d&y=%d&z=%z%',4);
- AddMapProvider('Google physical','http://mt%d.google.com/vt/lyrs=t@145&v=w2.104&x=%d&y=%d&z=%z%',4);
- AddMapProvider('Google Physical Hybrid','http://mt%d.google.com/vt/lyrs=t@145&v=w2.104&x=%x%&y=%y%&z=%z%',4);
- AddMapProvider('Google Physical Hybrid','http://mt%d.google.com/vt/lyrs=h@145&v=w2.104&x=%x%&y=%y%&z=%z%',4);
+ // needs 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('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('OpenStreetMap Osmarender','http://%serv%.tah.openstreetmap.org/Tiles/tile/%z%/%x%/%y%.png',0,20,3, @getLetterSvr); // [Char(Ord('a')+Random(3)), Z, X, Y]));
- //AddMapProvider('Yahoo Normal','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&.intl=en&x=%x%&y=%y%d&z=%d&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //(Z+1]));
- //AddMapProvider('Yahoo Satellite','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%d&y=%d&z=%d&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- //AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%x%&y=%y%&z=%z%&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- //AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&t=h&.intl=en&x=%x%&y=%y%&z=%z%&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- // opeName, Url, MinZoom, MaxZoom, NbSvr, GetSvrStr, GetXStr, GetYStr, GetZStr
- MapWin.MapProvider := AddMapProvider('OpenStreetMap Mapnik',
- 'http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png',
- 0, 19, 3, @GetLetterSvr);
- AddMapProvider('Open Cycle Map',
- 'http://%serv%.tile.opencyclemap.org/cycle/%z%/%x%/%y%.png',
- 0, 18, 3, @getLetterSvr);
- AddMapProvider('Open Topo Map',
- 'http://%serv%.tile.opentopomap.org/%z%/%x%/%y%.png',
- 0, 19, 3, @getLetterSvr);
- AddMapProvider('Virtual Earth Bing',
- '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, @GetQuadKey);
- AddMapProvider('Virtual Earth Road',
- 'http://r%serv%.ortho.tiles.virtualearth.net/tiles/r%x%.png?g=72&shading=hill',
- 1, 19, 4, nil, @GetQuadKey);
- AddMapProvider('Virtual Earth Aerial',
- 'http://a%serv%.ortho.tiles.virtualearth.net/tiles/a%x%.jpg?g=72&shading=hill',
- 1, 19, 4, nil, @GetQuadKey);
- AddMapProvider('Virtual Earth Hybrid',
- 'http://h%serv%.ortho.tiles.virtualearth.net/tiles/h%x%.jpg?g=72&shading=hill',
- 1, 19, 4, nil, @GetQuadKey);
+ // 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 Sattelite', ptEPSG3857, 'http://khm%serv%.google.com/kh/v=863?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); // review: doesn't work?
+ // Yandex
+ AddMapProvider('Yandex.Maps', 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 Sattelite', 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 Sattelite', ptEPSG3395, 'https://core-sat.maps.yandex.net/tiles?l=sat&x=%x%&y=%y%&z=%z%', 0, 19, 4, @GetSvrBase1, nil, nil, nil);
+
+ MapWin.MapProvider := // Setting OSM as default map
+
+ // debug: coth: comment out
+ //AddMapProvider('OpenStreetMap Mapnik', ptEPSG3857, 'http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png', 0, 19, 5, @GetSvrLetter);
+
+ // OSM section
+ AddMapProvider('OpenStreetMap Mapnik', ptEPSG3857, 'http://%serv%.tile.openstreetmap.org/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter);
+ AddMapProvider('OpenStreetMap Wikipedia', ptEPSG3857, 'https://maps.wikimedia.org/osm-intl/%z%/%x%/%y%.png', 0, 19, 3, @GetSvrLetter);
+ 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);
+ // todo: requires an optional key
+ 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);
+
+ // 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);
+ // review: remove? fully identical to Bing Maps?
+ //AddMapProvider('Virtual Earth Road', ptEPSG3857, 'http://r%serv%.ortho.tiles.virtualearth.net/tiles/r%x%.png?g=72&shading=hill', 1, 19, 4, 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);
+
if (HERE_AppID <> '') and (HERE_AppCode <> '') then begin
// Registration required to access HERE maps:
// https://developer.here.com/?create=Freemium-Basic&keepState=true&step=account
@@ -908,20 +1061,13 @@
// 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 Maps', HERE1 + 'normal.day' + HERE2,
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here Maps Grey', HERE1 + 'normal.day.grey' + HERE2,
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here Maps Reduced', HERE1 + 'reduced.day' + HERE2,
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here Maps Transit', HERE1 + 'normal.day.transit' + HERE2,
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here POI Maps', HERE1 + 'normal.day' + HERE2 + '&pois',
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here Pedestrian Maps', HERE1 + 'pedestrian.day' + HERE2,
- 1, 19, 4, @GetYahooSvr);
- AddMapProvider('Here DreamWorks Maps', HERE1 + 'normal.day' + HERE2 + '&style=dreamworks',
- 1, 19, 4, @GetYahooSvr);
+ 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);
end;
if (OpenWeatherMap_ApiKey <> '') then begin
@@ -929,50 +1075,18 @@
// 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',
- 'https://tile.openweathermap.org/map/clouds_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey,
- 1, 19, 1, nil);
- AddMapProvider('OpenWeatherMap Precipitation',
- 'https://tile.openweathermap.org/map/precipitation_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey,
- 1, 19, 1, nil);
- AddMapProvider('OpenWeatherMap Pressure',
- 'https://tile.openweathermap.org/map/pressure_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey,
- 1, 19, 1, nil);
- AddMapProvider('OpenWeatherMap Temperature',
- 'https://tile.openweathermap.org/map/temp_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey,
- 1, 19, 1, nil);
- AddMapProvider('OpenWeatherMap Wind',
- 'https://tile.openweathermap.org/map/wind_new/%z%/%x%/%y%.png?appid=' + OpenWeatherMap_ApiKey,
- 1, 19, 1, nil);
+ 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);
end;
- { The Ovi Maps (former Nokia maps) are no longer available.
-
- AddMapProvider('Ovi Normal',
- 'http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/normal.day/%z%/%x%/%y%/256/png8',
- 0, 20, 5, @GetLetterSvr);
- AddMapProvider('Ovi Satellite',
- 'http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/satellite.day/%z%/%x%/%y%/256/png8',
- 0, 20, 5, @GetLetterSvr);
- AddMapProvider('Ovi Hybrid',
- 'http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/hybrid.day/%z%/%x%/%y%/256/png8',
- 0, 20, 5, @GetLetterSvr);
- AddMapProvider('Ovi Physical',
- 'http://%serv%.maptile.maps.svc.ovi.com/maptiler/v2/maptile/newest/terrain.day/%z%/%x%/%y%/256/png8',
- 0, 20, 5, @GetLetterSvr);
- }
-
- {
- AddMapProvider('Yahoo Normal','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&.intl=en&x=%x%&y=%y%d&z=%d&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //(Z+1]));
- AddMapProvider('Yahoo Satellite','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%d&y=%d&z=%d&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/ae/ximg?v=1.9&t=a&s=256&.intl=en&x=%x%&y=%y%&z=%z%&r=1', 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- AddMapProvider('Yahoo Hybrid','http://maps%serv%.yimg.com/hx/tl?b=1&v=4.3&t=h&.intl=en&x=%x%&y=%y%&z=%z%&r=1' , 0,20,3,@GetYahooSvr, nil, @getYahooY, @GetYahooZ); //[Random(3)+1, X, YahooY(Y), Z+1]));
- }
end;
function TMapViewerEngine.ScreenToLonLat(aPt: TPoint): TRealPoint;
begin
- Result := MapWinToLonLat(MapWin, aPt);
+ Result := MapPixelsToDegrees(MapWin, aPt);
end;
procedure TMapViewerEngine.SetActive(AValue: boolean);
@@ -1040,6 +1154,7 @@
begin
MapWin.MapProvider := TMapProvider(lstProvider.Objects[idx]);
ConstraintZoom(MapWin);
+ CalculateWin(MapWin);
end
else
MapWin.MapProvider := nil;
@@ -1099,7 +1214,7 @@
begin
Cache.GetFromCache(EnvTile.Win.MapProvider, EnvTile.Tile, img);
X := EnvTile.Win.X + EnvTile.Tile.X * TILE_SIZE; // begin of X
- Y := EnvTile.Win.Y + EnvTile.Tile.Y * TILE_SIZE; // begin of X
+ Y := EnvTile.Win.Y + EnvTile.Tile.Y * TILE_SIZE; // begin of Y
DrawTile(EnvTile.Tile, X, Y, img);
end;
finally
@@ -1151,8 +1266,8 @@
BottomRight.Y := tmpWin.Height;
Repeat
CalculateWin(tmpWin);
- visArea.TopLeft := MapWinToLonLat(tmpWin, TopLeft);
- visArea.BottomRight := MapWinToLonLat(tmpWin, BottomRight);
+ visArea.TopLeft := MapPixelsToDegrees(tmpWin, TopLeft);
+ visArea.BottomRight := MapPixelsToDegrees(tmpWin, BottomRight);
if AreaInsideArea(aArea, visArea) then
break;
dec(tmpWin.Zoom);
@@ -1221,8 +1336,8 @@
Each part can exhibit a unit identifier, such as °, ', or ". BUT: they are
ignored. This means that an input string 50°30" results in the output value 50.5
- although the second part is marked as seconds, not minutes!
-
+ although the second part is marked as seconds, not minutes!
+
Hemisphere suffixes ('N', 'S', 'E', 'W') are supported at the end of the input string.
}
function TryStrToGps(const AValue: String; out ADeg: Double): Boolean;
@@ -1365,7 +1480,7 @@
d_radians := PI * 2.0
else
d_radians := arccos(arg);
- Result := EARTH_RADIUS * d_radians;
+ Result := EARTH_EQUATORIAL_RADIUS * d_radians;
case AUnits of
duMeters: ;
Index: source/mvmapprovider.pas
===================================================================
--- source/mvmapprovider.pas (revision 7925)
+++ source/mvmapprovider.pas (working copy)
@@ -15,7 +15,7 @@
interface
uses
- Classes, SysUtils, laz2_xmlwrite, laz2_dom;
+ Classes, SysUtils, laz2_xmlwrite, laz2_dom, TypInfo, Math;
type
@@ -28,6 +28,7 @@
TGetSvrStr = function (id: integer): string;
TGetValStr = function (const Tile: TTileId): String;
+ TProjectionType = (ptEPSG3857, ptEPSG3395);
TMapProvider = class;
@@ -49,6 +50,7 @@
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;
@@ -60,12 +62,13 @@
FTileHandling: TRTLCriticalSection;
function GetLayerCount: integer;
procedure SetLayer(AValue: integer);
+ function GetProjectionType: TProjectionType;
public
constructor Create(AName: String);
destructor Destroy; override;
function AppendTile(aTile: TBaseTile): integer;
procedure RemoveTile(aTile: TBaseTile);
- procedure AddURL(Url: String; NbSvr, aMinZoom, aMaxZoom: integer;
+ procedure AddURL(Url: String; ProjectionType: TProjectionType; NbSvr, aMinZoom, aMaxZoom: integer;
GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr;
GetZStr: TGetValStr);
procedure GetZoomInfos(out AZoomMin, AZoomMax: integer);
@@ -72,26 +75,32 @@
function GetUrlForTile(id: TTileId): String;
procedure ToXML(ADoc: TXMLDocument; AParentNode: TDOMNode);
property Name: String read FName;
+ property ProjectionType: TProjectionType read GetProjectionType;
property LayerCount: integer read GetLayerCount;
property Layer: integer read FLayer write SetLayer;
end;
+function GetSvrLetter(id: integer): String;
+function GetSvrBase1(id: integer): String;
+function GetStrYahooY(const Tile: TTileId): string; // Idea: Deprecate, as Yahoo Maps are dead
+function GetStrYahooZ(const Tile: TTileId): string; // Idea: Deprecate, as Yahoo Maps are dead
+function GetStrQuadKey(const Tile: TTileId): string;
-function GetLetterSvr(id: integer): String;
-function GetYahooSvr(id: integer): String;
-function GetYahooY(const Tile: TTileId): string;
-function GetYahooZ(const Tile: TTileId): string;
-function GetQuadKey(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
-function GetLetterSvr(id: integer): String;
+function GetSvrLetter(id: integer): String;
begin
Result := Char(Ord('a') + id);
end;
-function GetQuadKey(const Tile: TTileId): string;
+function GetStrQuadKey(const Tile: TTileId): string;
var
i, d, m: Longword;
begin
@@ -110,17 +119,17 @@
end;
end;
-function GetYahooSvr(id: integer): String;
+function GetSvrBase1(id: integer): String;
Begin
Result := IntToStr(id + 1);
end;
-function GetYahooY(const Tile : TTileId): string;
+function GetStrYahooY(const Tile : TTileId): string;
begin
Result := IntToStr( -(Tile.Y - (1 shl Tile.Z) div 2) - 1);
end;
-function GetYahooZ(const Tile : TTileId): string;
+function GetStrYahooZ(const Tile : TTileId): string;
Begin
result := IntToStr(Tile.Z + 1);
end;
@@ -160,6 +169,11 @@
FLayer:=AValue;
end;
+function TMapProvider.GetProjectionType: TProjectionType;
+begin
+ Result := FProjectionType[layer];
+end;
+
constructor TMapProvider.Create(AName: String);
begin
FName := aName;
@@ -172,6 +186,7 @@
begin
Finalize(idServer);
Finalize(FName);
+ Finalize(FProjectionType);
Finalize(FUrl);
Finalize(FNbSvr);
Finalize(FGetSvrStr);
@@ -221,7 +236,7 @@
end;
end;
-procedure TMapProvider.AddURL(Url: String; NbSvr, aMinZoom, aMaxZoom: integer;
+procedure TMapProvider.AddURL(Url: String; ProjectionType: TProjectionType; NbSvr, aMinZoom, aMaxZoom: integer;
GetSvrStr: TGetSvrStr; GetXStr: TGetValStr; GetYStr: TGetValStr;
GetZStr: TGetValStr);
var
@@ -230,6 +245,7 @@
nb := Length(FUrl)+1;
SetLength(IdServer, nb);
SetLength(FUrl, nb);
+ SetLength(FProjectionType, nb);
SetLength(FNbSvr, nb);
SetLength(FGetSvrStr, nb);
SetLength(FGetXStr, nb);
@@ -239,6 +255,7 @@
SetLength(FMaxZoom, nb);
nb := High(FUrl);
FUrl[nb] := Url;
+ FProjectionType[nb] := ProjectionType;
FNbSvr[nb] := NbSvr;
FMinZoom[nb] := aMinZoom;
FMaxZoom[nb] := aMaxZoom;
@@ -297,7 +314,9 @@
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]);
@@ -304,29 +323,34 @@
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] = @getLetterSvr then s := 'Letter'
- else if FGetSvrStr[i] = @GetYahooSvr then s := 'Yahoo'
- else if FGetSvrstr[i] <> nil then s := 'unknown'
- else s := '';
+ if FGetSvrStr[i] = @GetSvrLetter then s := SVR_LETTER
+ else if FGetSvrStr[i] = @GetSvrBase1 then s := SVR_BASE1
+ // else if FGetSvrstr[i] <> nil then s := 'unknown'
+ else s := '';
if s <> '' then layerNode.SetAttribute('serverProc', s);
- if FGetXStr[i] = @GetQuadKey then s := 'QuadKey'
- else if FGetXStr[i] <> nil then s := '(unknown)'
- else s := '';
+ if FGetXStr[i] = @GetStrQuadKey then s := STR_QUADKEY
+ // else if FGetXStr[i] <> nil then s := '(unknown)'
+ else s := '';
if s <> '' then layerNode.SetAttribute('xProc', s);
- if FGetYStr[i] = @GetQuadKey then s := 'QuadKey'
- else if FGetYStr[i] = @GetYahooY then s := 'YahooY'
- else if FGetYStr[i] <> nil then s := '(unknown)'
- else s := '';
+ if FGetYStr[i] = @GetStrQuadKey then s := STR_QUADKEY
+ else if FGetYStr[i] = @GetStrYahooY then s := STR_YAHOOY
+ // else if FGetYStr[i] <> nil then s := '(unknown)'
+ else s := '';
if s <> '' then layerNode.SetAttribute('yProc', s);
- if FGetZStr[i] = @GetQuadKey then s := 'QuadKey'
- else if FGetZStr[i] = @GetYahooZ then s := 'YahooZ'
- else if FGetZStr[i] <> nil then s := '(unknown)'
- else s := '';
+ if FGetZStr[i] = @GetStrQuadKey then s := STR_QUADKEY
+ else if FGetZStr[i] = @GetStrYahooZ then s := STR_YAHOOZ
+ // else if FGetZStr[i] <> nil then s := '(unknown)'
+ else s := '';
if s <> '' then layerNode.SetAttribute('zProc', s);
+
end;
end;
Index: source/mvtypes.pas
===================================================================
--- source/mvtypes.pas (revision 7925)
+++ source/mvtypes.pas (working copy)
@@ -10,11 +10,12 @@
unit mvTypes;
{$mode objfpc}{$H+}
+{$MODESWITCH ADVANCEDRECORDS}
interface
uses
- Classes, SysUtils;
+ Classes, SysUtils, Math;
const
TILE_SIZE = 256;
@@ -21,7 +22,7 @@
PALETTE_PAGE = 'Misc';
Type
- { TArea }
+ { TArea }
TArea = record
top, left, bottom, right: Int64;
end;
@@ -28,8 +29,17 @@
{ TRealPoint }
TRealPoint = Record
- Lon : Double;
- Lat : Double;
+ public
+ Lon: Double;
+ Lat: Double;
+ private
+ function GetLonRad: Extended;
+ procedure SetLonRad(AValue: Extended);
+ function GetLatRad: Extended;
+ procedure SetLatRad(AValue: Extended);
+ public
+ property LonRad: Extended read GetLonRad write SetLonRad;
+ property LatRad: Extended read GetLatRad write SetLatRad;
end;
{ TRealArea }
@@ -40,5 +50,23 @@
implementation
+function TRealPoint.GetLonRad: Extended;
+begin
+ Result := degtorad(Self.Lon);
+end;
+procedure TRealPoint.SetLonRad(AValue: Extended);
+begin
+ Self.Lon := radtodeg(AValue);
+end;
+
+function TRealPoint.GetLatRad: Extended;
+begin
+ Result := degtorad(Self.Lat);
+end;
+procedure TRealPoint.SetLatRad(AValue: Extended);
+begin
+ Self.Lat := radtodeg(AValue);
+end;
+
end.