Sommaire
- Clefs pour les API
- Mode hors-ligne
- TECRouting
- Moteur de routage
- Définir son propre moteur
- _4 événements sont disponibles
- Itinerary
- TECTurnByTurn
- événements disponibles
- Recherche de routes
- Afficher la route
- Modifier la route à la souris
- Exemple d'utilisation
- DemoNativeRoute
- Tracer un chemin à la souris ou au doigt
- IsoChrone
Clefs pour les API
Par défaut TECNativeMap utilise les services d'OpenStreetMap.
Si vous souhaitez utiliser PTV, TomTom ou MapBox vous devez vous enregistrer sur leur site pour obtenir une clef.
Mode hors-ligne
Si vous indiquez un répertoire dans la propriété LocalCache, toutes les données des routes seront mise en cache et pourront être réutilisées en mode hors-ligne.
TECRouting
Cette classe gère les routes ainsi que la navigation tour par tour.
procedure Request(const StartAdress, EndAdress: string;const params: string = '';const futureRoute:TECShapeLine=nil); overload;
procedure Request(const dLatLngs: array of double;const params: string = '';const FutureRoute:TECShapeLine); overload;
// get data road between Tarbes and Paris
map.Routing.Request('Tarbes','Paris');
// get data road between Tarbes and Lourdes via Aureilhan
map.Routing.Request('Tarbes','Aureilhan|Lourdes');
// you can also pass a array of coordinate pairs
map.Routing.Request([43.232858,0.0781021,43.2426749,0.0965226]);
Attention pour OpenStreetMap et OSRM vous devez vous assurez de passer des paramètres valides, voir la documentation (identique pour les deux car le moteur est le même)
1property routeType: TMQRouteType
Seul PTV, TomTom et Valhalla supportent rtTruck
2property OptimizeRoute : boolean
property GroupName : string
function FutureRoute:TECShapeLine;
We will directly pass a line to the routing engine
so that we can attach parameters to it
that will be used when the route is calculated,
here we store the speed of our mobile according to the type of route desired
*)
RouteLine := map.routing.futureRoute; // return a empty line
// fired when route is ready
map.Routing.OnAddRoute := doOnAddRoute;
if rbWalking.ischecked then
begin
map.Routing.RouteType := rtPedestrian ;
RouteLine.propertyValue['speed']:='6';
end
else if rbBicycling.ischecked then
begin
map.Routing.RouteType := rtBicycle ;
RouteLine.propertyValue['speed']:='20';
end
else
begin
map.Routing.RouteType := rtCar;
RouteLine.propertyValue['speed']:='50';
end;
// then empty string is for optionnal params, here none
map.Routing.Request(RouteStart.Text, RouteEnd.Text,'',RouteLine);
(* attention by default the request is asynchronous,
so your route is not yet ready just after the request,
connect to OnAddRoute to react when it is ready *)
procedure TForm.doOnAddRoute(sender: TECShapeLine;const params:string);
begin
// sender is the route (TECShapeLine)
// params this is the URL sent to the routing engine
end;
property Color : TColor
property Weight: integer
property StartMarkerFilename: string
property EndMarkerFilename: string
property RouteDrawingTime: integer
Par défaut 0, la route s'affiche en une seule fois.
property EditRoute: TECShapeLine
property EditOnClick : boolean
Moteur de routage
procedure Engine(value:TRoutingEngine;const ApiKey:string='');
Permet de choisir un moteur de routage, au choix, OpenStreetMap, PTV, Valhalla, TomTom, OSRM ou MapBox
map.routing.Engine(reValhalla);
map.routing.Engine(reTomTom,'your_key');
map.routing.Engine(reOSRM);
map.routing.Engine(reMapBox,'your_token');
map.routing.Engine(rePTV,'your_key');
Utilisez EngineValidUrl pour modifier l'url avant quelle ne soit envoyée au moteur
begin
// Here you can change the url
// ! your are not in main thread
sender.Url := ...;
end;
procedure TFDemoNativeRoute.FormCreate(Sender: TObject);
begin
// setup routing
map.routing.Engine(reOSRM);
// intercept url before engine
map.Routing.EngineValidUrl := doUrl;
end;
Définir son propre moteur
Utilisez EngineUrl, EngineExcute pour utiliser votre propre moteur.
property EngineUrl : TECThreadRoutingUrl
property EngineExecute : TECThreadRoutingExecute
Map.Routing.EngineName := yourRouting_Name;
Map.Routing.EngineUrl := yourRouting_URL;
Map.Routing.EngineExecute := yourRouting_Execute;
...
procedure yourRouting_URL(sender: TECThreadDataRoute);
begin
//
end;
procedure yourRouting_Execute(sender: TECThreadDataRoute; var Valid: boolean);
begin
//
end;
EngineUrl et EngineExecute sont exécutés dans un autre thread !
1property EngineName : string
Donne un nom au moteur, utilisé pour le stockage local
property EngineKey : string
Clef pour utiliser le moteur, vous devez obtenir les votres auprès de TomTom ou MapBox
property TurnByTurn: TECTurnByTurn
4 événements sont disponibles
property OnAddRoute : TOnAddRoutemap.routing.OnErrorRoute := doOnErrorRoute ;
map.Routing.OnChangeRoute:= doOnChangeRoute;
procedure TFDemoNativeRoute.doOnAddRoute(sender: TECShapeLine;const params:string);
var i:integer;
PLine : TECPointLine;
begin
// sender is the route (TECShapeLine)
// params this is the URL sent to the routing engine
for i := 0 to sender.Count-1 do
begin
// roadside information points
PLine := sender[i];
PLine.Latitude;
PLine.Longitude;
PLine.Distance; // meters
PLine.Tex;
PLine.Time; // TDateTime
PLine.Maneuver;
end;
end;
procedure TFDemoNativeRoute.doOnErrorRoute(sender: TObject;const params:string);
begin
// sender is a TECThreadDataRoute
ShowMessage('Route not found !');
end;
procedure TFDemoNativeRoute.doOnChangeRoute(sender: TECShapeLine;const params:string);
begin
if not assigned(sender) then exit;
showMessage ( doubleToStrDigit(sender.Distance, 2) + 'km - ' +
doubleToStrDigit(sender.Duration / 3600, 2)+'h' ) ;
end;
Itinerary
Cette propriétée permet de construire et gérer plus simplement l'itinéraire inclus dans la route.
procedure ShowInstruction(const index: integer);
procedure ShowSegment(const index: integer);
property Count: integer
property Route: TECShapeLine
property SegmentRoute: TECShapeLine
property Segment[const index: integer]: TECItinerarySegment
TECItinerarySegment
property Instruction: stringproperty SegmentIndex: integer
property OnSelectedItinerarySegment: TOnSelectedItinerarySegment
property OnChangeRoute : TNotifyEvent
begin
Map.Routing.OnAddRoute := doOnAddRoute;
Map.Routing.itinerary.OnSelectedItinerarySegment :=
doOnSelectedItinerarySegment;
Map.Routing.Itinerary.OnChangeRoute := doChangeRoute;
end;
// request new route
procedure TItineraryForm.AddRouteClick(Sender: TObject);
begin
// select engine routing
case engine.ItemIndex of
0 : map.Routing.Engine(reOpenStreetMap);
1 : map.Routing.Engine(reValhalla);
end;
// select route type
case vehicle.ItemIndex of
0:
Map.Routing.routeType := rtPedestrian;
1:
Map.Routing.routeType := rtBicycle;
2:
Map.Routing.routeType := rtCar;
3:
Map.Routing.routeType := rtTruck;
end;
Map.Routing.Request(StartRoute.Text, EndRoute.Text);
end;
// event triggered when the route has been calculated and is available
procedure TItineraryForm.doOnAddRoute(Sender: TECShapeLine; const params: string);
begin
Sender.Focusable := false;
Sender.Color := GetRandomColor;
// show all road
Sender.fitBounds;
BuildItinerary(Sender);
end;
// build route planner
procedure TItineraryForm.BuildItinerary(const route: TECShapeLine);
var
i: integer;
d: double;
distance: string;
begin
// connect route
Map.Routing.itinerary.route := route;
itinerary.Items.Clear;
itinerary.Items.BeginUpdate;
for i := 0 to Map.Routing.itinerary.Count - 1 do
begin
// calculate distance
d := Map.Routing.itinerary[i].Distancekm;
if d < 1 then
distance := inttostr(round(d * 1000)) + 'm'
else
distance := DoubleToStrDigit(d, 2) + 'km' ;
itinerary.Items.Add(Map.Routing.itinerary[i].Instruction + ' (' +
distance + ')');
end;
itinerary.Items.EndUpdate;
itinerary.ItemIndex := Map.Routing.itinerary.SegmentIndex;
end;
// click on route planner
procedure TItineraryForm.itineraryClick(Sender: TObject);
begin
SelectSegment(itinerary.ItemIndex);
end;
// Triggered by Click on Map.Routing.itinerary.route
procedure TItineraryForm.doOnSelectedItinerarySegment(Sender: TECItinerary);
begin
SelectSegment(Sender.SegmentIndex);
end;
// Triggered by Click of a route <> Map.Routing.itinerary.route
procedure TItineraryForm.doChangeRoute(Sender: TObject);
begin
BuildItinerary(Sender as TECShapeLine)
end;
procedure TItineraryForm.SelectSegment(const index: integer);
var selected_segment: TECShapeLine;
begin
if index < 0 then
exit;
itinerary.ItemIndex := Index;
Map.Routing.itinerary.SegmentIndex := index;
selected_segment := Map.Routing.itinerary.SegmentRoute;
if not assigned(Map.Routing.itinerary.SegmentRoute) then
exit;
// move map for show segment
Map.Routing.itinerary.ShowSegment(index);
// you can also change color of selected_segment here
// Flash the segment 20 times per 250 ms period
// the animation will be automatically released when required
selected_segment.animation := TECAnimationShapeColor.create(20);
selected_segment.animation.Timing := 250;
// show infowindow with segment instruction
Map.Routing.itinerary.ShowInstruction(index);
end;
TECTurnByTurn
property line: TECShapeLine
function Position(const Lat, Lng: double):boolean
property AlertDistance: integer
property ExecutionDistance: integer
property ErrorDistance: integer
property NextInstruction:string
property NextManeuver: string ;
Disponible dans l'événement OnInstruction
3property NextInstructionInKm: double ;
property NextInstructionPosition: TLatLng ;
événements disponibles
property OnAlert: TOnTurnByTurnAlert
property OnInstruction: TOnTurnByTurnInstruction
property OnArrival: TNotifyEvent
property OnError: TOnTurnByTurnError
property OnAfterInstruction: TOnTurnByTurnInstruction
property OnConnectRoute: TNotifyEvent
property OnDeconnectRoute: TNotifyEvent
La demo DemoNativeRoute a été réécrite pour utiliser ces nouvelles fonctionnalité.
1Anciennes méthodes, privilégiez les nouvelles fonctionnalités disponible depuis la version 2.7
1Recherche de routes
Vous avez à votre disposition 4 routines (2 synchrones et 2 asynchrones) pour calculer un itinéraire.
function GetRoutePathByAddress(const StartAdress, EndAdress: string;const routeType:TMQRouteType = rtFastest const params: string = '' ): TECRoutePath
function GetRoutePathFrom(const dLatLngs: array of double;const routeType:TMQRouteType = rtFastest ;const params: string = '' ): TECRoutePath
procedure GetASyncRoutePathByAddress(const StartAdress, EndAdress: string;const routeType:TMQRouteType = rtFastest ;const params: string = '' )
procedure GetASyncRoutePathFrom(const dLatLngs: array of double;const routeType:TMQRouteType = rtFastest ;const params: string = '' )
Ces fonctions permettent d'obtenir les informations d'une route sans effectuer de tracé, les procedures asynchrones vont s'exécuter en arrière-plan et déclencher l'évenement OnRoutePath lorsque les données sont disponibles.
Voir open.mapquestapi.com/directions/ pour le paramètre Params
6Si vous ne libérez pas le TECMapRoutePath obtenu, il le sera automatiquement lors de la destruction de TECNativeMap
7Afficher la route
Vous pouvez créer une TECShapeLine à partir d'un TECMapRoutePath avec la fonction AddRoute
var line : TECShapeLine;
...
// ge data road between Tarbes and Lourdes via Aureilhan
routePath := map.GetRoutePathByAddress('Tarbes','Aureilhan|Lourdes');
// draw polyline from routePath
if routePath<>nil then
begin
// change line 0 with new data
if map.shapes.lines.count>0 then
map.shapes.lines[0].setRoutePath(routePath);
// see the entire route
map.fitBounds(line.NorthEastLatitude,line.NorthEastLongitude,line.SouthWestLatitude,line.SouthWestLongitude);
routePath.free;
end;
Vous pouvez aussi directement modifier une TECShapeLine avec la procedure setRoutePath
var line : TECShapeLine;
...
// ge data road between Tarbes and Lourdes via Aureilhan
routePath := map.GetRoutePathByAddress('Tarbes','Aureilhan|Lourdes');
// draw polyline from routePath
if routePath<>nil then
begin
// change line 0 with new data
if map.shapes.lines.count>0 then
map.shapes.lines[0].setRoutePath(routePath);
// see the entire route
map.fitBounds(line.NorthEastLatitude,line.NorthEastLongitude,line.SouthWestLatitude,line.SouthWestLongitude);
routePath.free;
end;
Modifier la route à la souris
Pour cela vous allez devoir rajouter l'unité uecEditNativeLine ( FMX.uecEditNativeLine sous FireMonkey)
Vous pourrez alors utiliser la classe TecNativeLineToRoute pour pouvoir modifier dynamiquement le trajet.
property Line : TECShapeLineExemple d'utilisation
var ecNativeLineToRoute : TecNativeLineToRoute;
...
ecNativeLineToRoute := TecNativeLineToRoute.create;
// edit route
ecNativeLineToRoute.Line := map.shapes.Lines[0];
// end edit route
ecNativeLineToRoute.Line := nil;
...
ecNativeLineToRoute.free;
DemoNativeRoute
Une démonstration est disponible pour bien comprendre la gestion des routes.
Tracer un chemin à la souris ou au doigt
TECNativeMap dispose d'un assistant qui vous permet de tracer vos chemins en quelques clics, le parcours suivra automatiquent la route entre vos points.
property Activate: booleanEn cliquant directement au centre de l'écran sur la cible vous déclenchez aussi cette action.
2property AddPointOnClick : boolean
map.DrawPath.AddPoint;
map.DrawPath.AddPointOnClick := true;
map.DrawPath.Undo;
var line : TECShapeLine;
line := map.shapes.AddLine;
map.DrawPath.GetPath(Line) ;
property PathType: TECDrawPathType
map.DrawPath.PathType := dptPedestrian;
map.DrawPath.PathType := dptBicycle;
map.DrawPath.PathType := dptCar;
property CursorData : string
Disponible uniquement sous Firemonkey.
3property Name: string
// here we will change the color
// add unit uecMapUtil for use ColorToHTML
Map.Styles.addRule('#' + map.DrawPath.Name + '.line {color:'+ColorToHTML(ColorPathLine.Color)+ '}');
property isReady: boolean
property OnPaintCursor: TECDrawPathPaintCursor
...
// We draw a simple cross in the center of the map,
// the same as in VCL mode
// add unit uecGraphics for TECCanvas
procedure TForm7.doPaintCursor(const canvas:TECCanvas);
var X, Y: integer;
begin
// convert center position to local X,Y
Map.FromLatLngToXY(Map.Center, X, Y);
canvas.PenWidth(2);
canvas.Polyline([Point(X, Y - 10), Point(X, Y + 10)]);
canvas.Polyline([Point(X - 10, Y), Point(X + 10, Y)]);
end;
property OnActivate : TECDrawPathActivate
property OnReady: TECDrawPathReady
map.DrawPath.OnReady := doOnReady;
// This event occurs before and after the calculation
// of the route in a thread,
// while the segment is being calculated
// you can neither validate the route
// nor cancel the last segment
procedure TForm7.doOnReady(const Ready:boolean);
begin
Validate.Enabled := Ready and map.DrawPath.activate;
Undo.Enabled := Ready and map.DrawPath.isUndo;
end;
// Activation / deactivation of route tracing
procedure TForm7.doOnActivate(const Activate:boolean);
begin
AddPoint.Enabled := Activate;
Guidance.Enabled := Activate;
if Activate then
begin
Active_deactive.Text := 'Deactivate' ;
Guidance.ItemIndex := integer(map.DrawPath.PathType);
end
else
Active_deactive.Text := 'Activate'
end;
property OnError : TNotifyEvent ;
IsoChrone
Le service isochrone calcule les zones qui sont accessibles dans des intervalles de temps ou de distances spécifiés à partir d'un emplacement, et renvoie les régions accessibles sous forme de contours de polygones ou de lignes.
Seul Valhalla et MapBox disposent de ce service, à noter que MapBox utilise Valhalla et comme c'est un logiciel opensource vous pouvez vous aussi vous monter votre propre serveur.
8Vous pouvez demander jusqu'a 4 isochrones par appel, et la distance maximale est de 100km.
// To use your own Valhalla server set ServerURL
map.Routing.IsoChrone.ServerURL := 'xxx';
map.Routing.engine(reMapBox,map.MapBoxToken);
// 5, 10, 15 and 20 minutes by bicycle
map.routing.IsoChrone.Time(map.latitude,map.longitude,map.shapes.Polygones,[ 5,10,15,20],rtbicycle) ;
// delineate the 2 and 4.5 km walkable areas
map.routing.IsoChrone.Distance(map.latitude,map.longitude,map[ 'isoGroup'].lines,[2,4.5],rtPedestrian) ;
// other syntax by passing directly the polygons and lines
var P,P1:TECShapePolygone;
L:TECShapeLine;
...
P := map.addPolygone;
P1:= map.addPolygones;
map.routing.IsoChrone.Time(map.latitude,map.longitude,[P,P1],[ 5,10],rtCar) ;
L := map.addLine('your_group');
map.routing.IsoChrone.Distance(map.latitude,map.longitude,[L],[ 80],rtPedestrian) ;
Les polygones et lignes retournées ont des propriétés isoTime et isoDistance qui contiennent les valeurs demandées, vous pouvez vous en servir pour styler vos éléments.
map.styles.addRule('.polygone{if:isotime>0;color:dark(grey)}');
map.styles.addRule('.polygone{if:isotime<21;fcolor:red}');
map.styles.addRule('.polygone{if:isotime<16;fcolor:#d97200}');
map.styles.addRule('.polygone{if:isotime<11;fcolor:yellow}');
map.styles.addRule('.polygone{if:isotime<6;fcolor:green}');