Продолжаю свой "микроблог".
Немного причесал свой скрипт и готов представить его публике.
Цель: общедоступные карты глубин
Garmin QuickDraw(
https://connect.garmin.com/modern/quick ... fullScreen )
Простейший скрипт
GetUrlScript.txt для него состоит всего из нескольких строк:
- Код: Выделить всё
Var G,mask:integer;
i:byte;
GRMN:string;
Begin
GRMN:='';
for i:=1 to GetZ-1 do
begin
G:=0;
mask:=1 shl (i-1);
if ((GetX and mask)<>0) then G:=G+1;
if ((GetY and mask)<>0) then G:=G+2;
GRMN:=intToStr(G)+GRMN;
end;
ResultURL:=GetUrlBase+GRMN+'.png?units=m';
End.
Но беда в том, что 90% скачиваемых тайлов будут пустыми. Ну нет на нашей территории такого количества рек и озёр, а те , что есть, отрисованы не полностью. Даже если пользоваться полигональным выделением, процент всё же будет достаточно большим.
Т.е. необходима доработка.
Была замечена интересная особенность гарминовской системы: если на каком то уровне попадается пустой тайл, то на площади, покрываемой этим тайлом, на всех последующих уровнях тайлы будут пустыми и скачивать их нет смысла !!!
Например, если на уровне 10 присутствует пустой тайл, то на уровне 11 под этим тайлом будут находиться 4 пустых тайла, на уровне 12 - уже 16 пустых тайлов, на 13 -- 64 тайла и т.д.. И ведь скачивать их нет никакого смысла! Это будет просто пустая нагрузка на сервер и значительная потеря времени. Если на второе можно и наплевать, то излишняя нагрузка на сервер впоследствии может обернуться серьёзным усложнением (со стороны хостера) доступа.
Тут ещё один момент возникает. Если мы в вышеприведённом примере начинаем скачивание с 13 зума и натыкаемся на пустой тайл, то имеет смысл проверить на пустоту все тайлы "над" этим тайлом. В нашем случае все тайлы до 11 уровня пустые. И сделав 3 контрольных скачивания до первого непустого зума (тайлы 12, 11 и 10 уровней) мы понимаем, что скачивать остальные 63 пустых тайла на 13-м зуме смысла нет!
Собственно, этот подход и был реализован в доработанном скрипте, который я и предоставляю вашему вниманию:
- Код: Выделить всё
Const DefUrlBase ='https://downloadqdc.garmin.com/GCSProxyServlet/MarineImages/';
NameInCache='С:cache\GarminQD'; //необходимо изменить букву диска под свои условия
DLoaderMode =false;
SaveScriptBuf=false;
//---------------------------------------------------------
// получение ссылки на тайл
Function GetGrmnCoord:string;
var G,mask:integer;
i:byte;
GRMN:string;
Begin
GRMN:='';
for i:=1 to GetZ-1 do
begin
G:=0;
mask:=1 shl (i-1);
if ((GetX and mask)<>0) then G:=G+1;
if ((GetY and mask)<>0) then G:=G+2;
GRMN:=intToStr(G)+GRMN;
end;
Result:=GRMN;
//ResultURL:=DefUrlBase+GRMN+'.png?units=m';
End;
//---------------------------------------------------------
//проверка вышележащих тайлов на пустоту; если скачивание идёт с 1-го зума, то эта проверка не особо и нужна
Function FindUpperEmptyTile(Coord:string):string;
Var VResponseCode : Cardinal ;
VResponseHeader, VResponseData: AnsiString;
VRequestUrl, VRequestHeader : AnsiString;
NewCoord,LastEmpty:string;
i:byte;
Begin
Result :=Coord;
NewCoord :=Coord;
LastEmpty:='';
if Coord<>'' then
if Assigned(Downloader) then
begin
for i:=length(Coord) downto 3 do
begin
LastEmpty:=NewCoord;
delete(NewCoord,length(NewCoord),1);
VRequestUrl := DefUrlBase+NewCoord+'.png?units=m';
VRequestHeader := '';
VResponseHeader := '';
VResponseData := '';
VResponseCode := Downloader.DoHttpRequest(VRequestUrl, VRequestHeader, '', VResponseHeader, VResponseData);
if VResponseCode = 200 then
begin
if ((Pos('Content-Length: 749'+#13,VResponseHeader)=0)
and (Pos('Content-Length: 355'+#13,VResponseHeader)=0)) then // размер пустых тайлов =749 и =355 байт
begin
Result:=LastEmpty;
break;
end;
end
else
begin
Result:=LastEmpty;
break;
end;
end;
end;
End;
//---------------------------------------------------------
VAR
VResponseCode : Cardinal ;
VResponseHeader, VResponseData: AnsiString;
VRequestUrl, VRequestHeader : AnsiString;
i :byte;
isEmpty :boolean;
GrmnCoord,
tmpGrmnCoord:string;
GrmnFullFName:string;
//---------------------------------------------------------
BEGIN
ResultURL:='';
// Переменная ScriptBuffer служит для хранения и переноса списка пустых тайлов.
// Тайлы хранятся в гарминоском формате.
if ScriptBuffer='' then ScriptBuffer:=';';
if ScriptBuffer[length(ScriptBuffer)]<>';' then ScriptBuffer:=ScriptBuffer+';';
GrmnCoord:=GetGrmnCoord;
isEmpty:=false;
tmpGrmnCoord:=GrmnCoord;
for i:=length(GrmnCoord) downto 3 do
begin
if Pos(';'+tmpGrmnCoord+';',ScriptBuffer)<>0 then
begin
isEmpty:=true;
break;
end;
delete(tmpGrmnCoord,length(tmpGrmnCoord),1);
end;
if not isEmpty then
if Assigned(Downloader) then
begin
VRequestUrl := DefUrlBase+GrmnCoord+'.png?units=m';
VRequestHeader := '';
VResponseHeader := '';
VResponseData := '';
VResponseCode := Downloader.DoHttpRequest(VRequestUrl, VRequestHeader, '', VResponseHeader, VResponseData);
if VResponseCode = 200 then
begin
if ((Pos('Content-Length: 749'+#13,VResponseHeader)<>0)
or (Pos('Content-Length: 355'+#13,VResponseHeader)<>0)) then
begin
ScriptBuffer:=ScriptBuffer+FindUpperEmptyTile(GrmnCoord)+';'; //все пустые тайлы с наименьшим Z записываются в ScriptBuffer
// ScriptBuffer:=ScriptBuffer+ (GrmnCoord)+';'; //DEBUG
if SaveScriptBuf then SaveToLocalFile(NameInCache+'\ScriptBuffer', ScriptBuffer); //DEBUG
ResultURL:='';
end
else
begin
// SaveToLocalFile(NameInCache+'\GRMN\'+GrmnCoord+'.png', VResponseData); //DEBUG
if DLoaderMode then //режим качалки или просмотрщика ? у второго нагрузка на сервер в 2 раза больше, но он более универсален
begin
GrmnFullFName:='\z'+IntToStr(GetZ)+'\'+IntToStr(GetX div 1024)+'\x'+IntToStr(GetX)+'\'+IntToStr(GetY div 1024)+'\y'+IntToStr(GetY)+'.png'; //CacheType=2
SaveToLocalFile(NameInCache+GrmnFullFName, VResponseData);
ResultURL:='';
end
else ResultURL:=DefUrlBase+GrmnCoord+'.png?units=m'; //viewer mode with double tile download
end;
end;
end;
END.
Скрипт работает, но и его можно и нужно усовершенствовать. Недостатки я описывал в предыдущем сообщении.
Например, в нём нужно руками исправить путь до папки с кэшем в в переменной
NameInCache.
Итоговый файл PARAMS.TXT
- Код: Выделить всё
[PARAMS]
GUID={CBA03063-23D9-FAAF-CDDC-9182B98644B1}
asLayer=1
name_ru=GarminQD
name =GarminQD
name_uk=GarminQD
CacheType=2
DefURLBase=
projection=1
sradiusa=6378137
sradiusb=6378137
NameInCache=GarminQD
Ext=.png
ContentType=image/png
UseDwn=1
IsUseDownloaderInScript=1
MaxConnectToServerCount=1
По поводу многопоточности (MaxConnectToServerCount). Можно выставить значение отличное от 1 (по умолчанию =4). Как мне объяснили в ЛС, для каждого потока будет создан свой экземпляр ScriptBuffer. Так что ничего особо страшного произойти не должно, кроме того, что каждый поток будет самостоятельно составлять список пустых тайлов.
PS: 2021-03-13 Перезалил архив с ZMP: в скрипте исправил баг, внесённый случайно непосредственно перед первой публикацией; из
params.txt убрал ограничение на количество потоков.
PPS: 2021-03-20 Перезалил: Добавил приведение
ResponseHeader к нижнему регистру.