Les tuiles sont d'abord recherchées dans le cache mémoire (les tuiles affichées il y a peu), le cache local, l'archive locale puis sur internet si besoin.
Cache local
En attribuant un répertoire à la propriété LocalCache les tuiles téléchargées depuis internet sont enregistrées en local et sont disponibles hors connexion.Sous android vous allez devoir demander la permission pour lire et écrire vos données.
1...
System.Permissions,
{$IFDEF ANDROID}
Androidapi.Jni.Os,
Androidapi.jni.javatypes,
Androidapi.Helpers,
{$ENDIF}
...
{$IFDEF ANDROID}
PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)],
procedure(const APermissions: TArray< string >;
const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 2) and
(AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted)
then map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache')
else
map.LocalCache := '';
end)
{$ELSE}
map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache');
{$ENDIF}
Utilisez la propriété MaxDayInCache pour spécifier la durée de retention dans le cache, 0 pour un cache infini, par défaut 30 jours.
LocalTileCache
Cette propriété de type TCustomTileCache vous permet de prendre en charge le stockage et la lecture des tuiles locales, au lieu de les placer dans un sous-répertoire vous pouvez par exemple les stocker dans une base de donnée.
Vous devez donc vous créer une classe descende de TCustomTileCache et redéfinir certaines méthodes.
Par exemple l'unité TileCacheSQLite.FireDAC contient TTileCacheSQLite qui stocke vos tuiles dans une base SQLite enregistrée dans votre répertoire LocalCache.
...
//Define a local directory in which to store the database
map.LocalCache := ExtractfilePath(ParamStr(0)) + 'cache' ;
// Create TTileCacheSQLite,
// which handles DB creation on server changeover,
// and tile saving and reading on demand
map.LocalTileCache := TTileCacheSQLite.create(map);
private
...
protected
// overload to react to server changes,
// here we'll open a database with the server's name
procedure doChangeTileServer(sender: TObject); override;
// override to save the XYZ tile contained in Stream,
// AHandle must be True if registration is ok
procedure doSaveLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;
// override to load the XYZ tile in Stream,
// AHandle must be True if is ok
procedure doLoadLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;
LocalTileCache est automatiquement libéré à la destruction de la map ou lorsque vous le changez, mettez le à nil pour revenir au stockage classique dans les répertoires.
MBTiles
Un fichier MBTiles est un format de fichier pour stocker des tuiles de carte dans un seul fichier, c'est techniquement une base de données SQLite.
Pour l'utiliser rajoutez le fichier uecMBTiles.FireDAC (FMX.uecMBTiles.FireDAC sous Firemonkey) dans vos uses
FireDAC est utilisé pour accéder à la base SQLite, donc cela n'est compatible qu'avec les versions récentes de Delphi
1... System.Permissions,System.IOUtils,
FMX.uecNativeMapControl,FMX.uecMBTiles.FireDAC;
{$IFDEF ANDROID}
const
PermissionReadExternalStorage = 'android.permission.READ_EXTERNAL_STORAGE';
PermissionWriteExternalStorage = 'android.permission.WRITE_EXTERNAL_STORAGE';
{$ENDIF}
procedure TForm23.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID} // android permissions management
PermissionsService.RequestPermissions
([PermissionReadExternalStorage,
PermissionWriteExternalStorage],
nil);
{$ENDIF}
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
FDataBase := TPath.Combine(TPath.GetSharedDocumentsPath, 'countries-raster.mbtiles');
{$ELSE}
FDataBase := 'H:\#DATA\MBTiles\countries-raster.mbtiles';
{$ENDIF}
// connect the component Map to the MBTiles server
FecMBTiles := TecMBTiles.Create(Map);
// open DataBase, true if ok
if not FecMBTiles.Connect(FDataBase) then
begin
ShowMessage(FecMBTiles.MessageError);
end;
// call FecMBTiles.Disconnect for disconnect
end;
procedure TForm23.FormDestroy(Sender: TObject);
begin
FecMBTiles.Free;
end;
La démo utilise le fichier MBTiles raster que vous pourrez trouver sur //github.com/klokantech/vector-tiles-sample
1Archive Locale
Un fichier MBTiles sera bien plus efficace qu'un simple zip.
2Une archive locale correspond au cache local mis dans un Zip, cela simplifie le déploiement des tuiles et des autres fichiers.
Pour améliorer la vitesse les tuiles sont extraites de l'archive et placées dans le cache locale lors de la première demande, vous devez donc définir un cache local pour utiliser une archive.
map.TileServer := tsOSM;
map.LocalArchive := ExtractfilePath(ParamStr(0))+'ile_de_re.zip';
Si des routes ou des géolocations d'adresses sont enregistrées dans l'archive la récupération est totalement transparente
2// if an archive is connected and contains the route, no internet connection is made to return the way
map.Routing.Request('saint-martin de ré', 'la couarde sur mer');
Vous pouvez y stocker vos images ou des fichiers de données (kml, geojson etc...), pour les charger il suffira de faire débuter le nom du fichier par /
map.Shapes.LoadFromFile('/DATA/tdf.kml');
map.LoadFromFile('/DATA/tarbes.txt');
// load image in marker
marker.filename := '/IMAGE/node.png';
Utilisez MapArchive pour manipuler directement votre archive et extraire vos autres données.
try
map.MapArchive.ReadStream('DATA/mydata.txt',m);
memo1.Lines.LoadFromStream(m);
finally
m.Free;
end;
MapArchiveCreator
Ce petit utilitaire permet de créer vos archives, vous pouvez télécharger des zones de tuiles, enregistrer des routes, ajouter des images et des fichiers.
Vous pouvez interdire toute connexion internet pour les tuiles et le geocodage en utilisant la propriété OnlyLocal
3map.onlyLocal := true;
Téléchager une zone complète
La classe TECDownLoadTiles vous permet de télécharger en arrière-plan une zone complète, la demo EcNativeMapFiremonkeyDemo vous montre comment précharger la zone visible à l'écran.
FECDownLoadTiles:=TECDownLoadTiles.create;
FECDownLoadTiles.OnDownLoad := doDownLoadtiles;
FECDownLoadTiles.OnEndDownLoad :=
doEndDownLoadtiles;
// tiles are saved in
DirectoryTiles
FECDownLoadTiles.DirectoryTiles := map.LocalCache;
FECDownLoadTiles.TileServer := map.TileServer;
FECDownLoadTiles.TileSize := map.TileSize;
// download visible area from
zoom+1 to MaxZoom
FECDownLoadTiles.DownLoadTiles(map.Zoom+1,map.MaxZoom,
map.NorthEastLatitude,map.NorthEastLongitude,
map.SouthWestLatitude,map.SouthWestLongitude);
...
// for abort
FECDownLoadTiles.Cancel;
// for pause
FECDownLoadTiles.Pause := true;
// restart
FECDownLoadTiles.Pause := false;
// see ECNativeMapFiremokeyDemo for
complete use
Assurez-vous que votre fournisseur de tuiles autorise cela !
3Reprendre le téléchargement ultérieument
Vous devez sauvegarder les propriétés suivantes pour pouvoir reprendre le téléchargement à une position spécifique.
property StartY : integer
property StartZoom : byte
property StartCountTiles : integer
property StartDownLoadTiles : integer
property FromZoom : integer
property ToZoom : Integer
property NorthEastLatitude : double
property NorthEastLongitude : double
property SouthWestLatitude : double
property SouthWestLongitude : double
Pour la reprise il faudra appeler cette version de DownLoadTiles
const NorthEastLatitude, NorthEastLongitude,
SouthWestLatitude,SouthWestLongitude: double;
const StartX,StartY:integer;
const StartZoom:byte;
const StartCountTiles,
StartDownLoadtiles:integer);
Remplir le Stream des tuiles
Vous pouvez aussi directement retourner un stream contenant le jpeg ou le png de vos tuiles, utile si vous avez vos tuiles dans une base de données.
// manual
management tiles as stream
map.TileServerInfo.getTileStream := getTileStream;
// the name will be uses as
subdirectory in cache
map.TileServerInfo.Name := 'MyMAP';
// important to specify a manual
management tiles
map.TileServer := tsOwnerDraw;
// asks for a tile
procedure
TForm2.getTileStream(const
ThreadIndex:integer;var
TileStream: TMemoryStream;
const x, y, z:
integer);
begin
// here fill tileStream with
tileXYZ
end;
Vous pouvez aussi vous en servir pour utiliser un serveur de tuiles distant.
1