Composant Delphi / Google Maps / OpenStreetMap / Leaflet  / Mappilary / Native Maps 100% Delphi 0% WebBrowser 0% Javascript

Roads

you are here :TECNativeMap

API Keys

TECNativeMap uses OpenStreetMap.

If you want to use these services of PTV or TomTom or MapBox you must register on their site to obtain a user key .

Offline mode

If you specify a directory in the LocalCache property, all datas will be cached and can be reused in offline mode.


TECRouting

Managing Routes and turn by turn navigation.

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=nil); overload;

Calculate a route between addresses or points
map.Routing.routeType := rtCar;
// 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]);
Params allows you to pass additional parameters to the routing engine

Attention for OpenStreetMap and OSRM you must make sure to pass valid settings, see the documentation (identical for both because the engine is the same)

1
FutureRoute is an empty line that will be initialized with the data returned by the routing engine, this allows you to attach parameters that can be used when the route is finalized in OnAddRoute;

property routeType: TMQRouteType

Type of route ( rtCar, rtTruck, rtFastest, rtShortest , rtPedestrian, rtBicycle )

Only PTV, TomTom and Valhalla support rtTruck

2

property OptimizeRoute : boolean

Calculation optimization, only MapBox and TomTom engines support this feature

property GroupName : string

Name of the group which will own the new road (TECShapeLine), default empty

function FutureRoute:TECShapeLine;

returns an empty line that you can pass to Request
(*
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

Color of the road

property Weight: integer

Thickness of the road

property StartMarkerFilename: string

Image used to mark the start, default

property EndMarkerFilename: string

Image used to mark the arrival, by default

property RouteDrawingTime: integer

Time (in MS) to display the route, allows to realize an animation for a progressive display.
Default 0, the road appears only once.

property EditRoute: TECShapeLine

To edit the route with the mouse

property EditOnClick : boolean

By default a click on a route makes switch to edit mode, simply click on the points A or B to exit this mode

Routing engine

procedure Engine(value:TRoutingEngine;const ApiKey:string='');

Allows you to choose a routing engine, OpenStreetMap (default choice), PTV, Valhalla, TomTom, OSRM or MapBox

map.routing.Engine(reOpenStreetMap);
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');

Use EngineValidUrl to change the url before is sent to the engine

This is recommended for Valhalla which by default is connected to a demo server.

1
procedure doUrl(sender:TECThreadDataRoute);
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;

Define its own engine

Use EngineUrl and EngineExcute to edit your own engine.

property EngineUrl : TECThreadRoutingUrl

property EngineExecute : TECThreadRoutingExecute

Map.Routing.Engine(reCustom);
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 and EngineExecute are executed in another thread !

1

property EngineName : string

Gives a name to the engine, used for local storage

property EngineKey : string

Key to use the engine, you get yours from TomTom or MapBox

property TurnByTurn: TECTurnByTurn

The turn by turn navigation management

4 events are available

property OnAddRoute : TOnAddRoute
Raised when the road has been created
property OnChangeRoute : TOnChangeRoute
Raised when the road has changed
property OnErrorRoute : TOnErrorRoute
Raised if the road has not been created
property OnDrawRoute : TOnDrawRoute
Raised when the road was fully displayed (useful if RouteDrawingTime > 0)
map.Routing.OnAddRoute := doOnAddRoute;
map.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

This property makes it easier to build and manage the itinerary included in the route..

Fig. 1 Demo Itinerary

procedure ShowInstruction(const index: integer);

Displays an infoWindow containing the index number instruction

procedure ShowSegment(const index: integer);

Zoom in on the index segment

property Count: integer

Total number of segments

property Route: TECShapeLine

Connect the route you want to manage.

property SegmentRoute: TECShapeLine

Contains a line representing the selected segment, which you can access to manage its appearance..

property Segment[const index: integer]: TECItinerarySegment

Table containing all segments

TECItinerarySegment

property Instruction: string
Segment entry instruction
property Manoeuver: string
JSON string returned by the routing engine containing all the data for the maneuver
property DistanceKm: double
Segment distance in km
property PointA : TLatLng
Latitude and longitude of segment start
property PointB : TLatLng
Latitude and longitude of the end of the segment

property SegmentIndex: integer

Selects a segment

property OnSelectedItinerarySegment: TOnSelectedItinerarySegment

Event triggered by a click on the route being managed

property OnChangeRoute : TNotifyEvent

Event triggered by a click on a route other than the one in the itinerary
procedure TItineraryForm.FormCreate(Sender: TObject);
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

The way ahead

function Position(const Lat, Lng: double):boolean

Specify your GPS position

property AlertDistance: integer

By default 300 meters

property ExecutionDistance: integer

Default 100 meters

property ErrorDistance: integer


Default 30 meters

property NextInstruction:string

Next statement to follow

Available in the OnInstruction event

2

property NextManeuver: string ;

List of operations (in the form of a json string containing various parameters depending on the engine used)

Available in the OnInstruction event

3

property NextInstructionInKm: double ;

Distance in KM for the next instruction

Available in the OnInstruction event

4

property NextInstructionPosition: TLatLng ;

Geographical position of the next instruction

Available in the OnInstruction event

5

available events

property OnAlert: TOnTurnByTurnAlert

Triggered when you arrive less than AlertDistance meters from the target

property OnInstruction: TOnTurnByTurnInstruction


Triggered when you arrive less than ExecutionDistance meters from the target

property OnArrival: TNotifyEvent

property OnError: TOnTurnByTurnError

property OnAfterInstruction: TOnTurnByTurnInstruction

property OnConnectRoute: TNotifyEvent

Triggered by a road connection

property OnDeconnectRoute: TNotifyEvent

Triggered by the disconnection of a road

Fig. 2 DemoNativeRoute

The DemoNativeRoute demo has been rewritten to use the new feature.

1

Old methods, use new features available since version 2.7

2

Search for routes

You have at your disposal 4 routines (2 synchronous et 2 asynchronous) to calculate a route.

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 = '' )


These functions allow to obtain information from a route without trace, asynchronous procedures will run in background and raise the OnRoutePath event when the data are available.

See open.mapquestapi.com/directions/ for the parameter Params

6

If you do not release the TECMapRoutePath obtained, it will be automatically during the destruction of TECNativeMap

7

Display the route

You can create a TECShapeLine from one TECMapRoutePath with the function AddRoute

// Delphi map component ECMap

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;

You can also directly edit a TECShapeLine with the procedure setRoutePath

// Delphi map component ECMap

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;

Edit the road with the mouse

For this you will need to add the unit uecEditNativeLine (FMX.uecEditNativeLine under FireMonkey)

You can then use the TecNativeLineToRoute class to be able to dynamically change the route.

property Line : TECShapeLine
TECShapeLine to modify
property RouteType : TMQRouteType
type of road ( rtFastest, rtShortest, rtPedestrian, rtBicycle )
property Modified : boolean
Indicates if the road was amended
property OnClick : TOnShapeMousePoint
To respond to the click on the road
property OnMouseOver : TOnShapeMousePoint
Can respond to the overview of the road
property OnChange : TNotifyEvent
Triggered event has each modification of the road

Example of use

// Delphi map component ECMap

var ecNativeLineToRoute : TecNativeLineToRoute;
...
ecNativeLineToRoute := TecNativeLineToRoute.create;

// edit route
ecNativeLineToRoute.Line := map.shapes.Lines[0];

// end edit route
ecNativeLineToRoute.Line := nil;
...
ecNativeLineToRoute.free;

DemoNativeRoute

A demonstration is available to understand the management of roads.

Fig. 3 DemoNativeRoute - Turn by turn

Draw a path with the mouse or finger

TECNativeMap has a wizard that allows you to draw your paths in a few clicks, the route will automatically follow the road between your points.

Fig. 4 DrawPath

property Activate: boolean
Activate / Deactivate the tracing assistant.
procedure AddPoint;
Add the central point, the trace will be calculated between this one and the previous point
procedure AddPoint(const latitude,longitude);
Add the point of your choice, the trace will be calculated between this one and the previous point

By clicking directly in the center of the screen on the target you also trigger this action.

2

property AddPointOnClick : boolean

Allows you to choose a point simply by clicking on the map and not just in the center.
function GetPath(const Line: TECShapeLine): boolean;
Retrieves the plot in a TECShapeLine and exits the wizard.
procedure Undo;
Cancels the last segment, you can cancel all the segments one after the other.
map.DrawPath.Activate := true;
map.DrawPath.AddPoint;
map.DrawPath.AddPointOnClick := true;
map.DrawPath.Undo;

var line : TECShapeLine;
line := map.shapes.AddLine;
map.DrawPath.GetPath(Line) ;

property PathType: TECDrawPathType

You can either directly draw line segments between your points, or have them follow a pedestrian, bicycle or car route.
map.DrawPath.PathType := dptStraight;
map.DrawPath.PathType := dptPedestrian;
map.DrawPath.PathType := dptBicycle;
map.DrawPath.PathType := dptCar;

property CursorData : string

Allows to define the central target through a string containing graphic instructions, it is the equivalent of TPathData.Data

Available only under Firemonkey.

3

property Name: string

Name of the group containing the trace, you can use it to define its style.
// You can redefine all the properties of the lines,
// 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

Indicates if the wizard has finished calculating a route, you cannot quit or delete a segment while a trace is pending in a secondary thread.
property isUndo: boolean
Indicates if you can cancel the last segment

property OnPaintCursor: TECDrawPathPaintCursor

You can take over the entire design of the central target.
map.DrawPath.OnPaintCursor := doPaintCursor;
...
// 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

The event is triggered when the assistant is activated or deactivated

property OnReady: TECDrawPathReady

Triggered before the road calculation request and once it is completed
map.DrawPath.OnActivate := doOnActivate;
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 ;

Triggered if the calculation of the route could not take place.

IsoChrone

The isochrone service calculates the areas that are reachable within specified time or distance intervals from a location, and returns the reachable regions as polygon or line contours.

Fig. 5 zones accessibles à 5, 10, 15 et 20 minutes à bicyclette

Only Valhalla and MapBox have this service, note that MapBox uses Valhalla and as it is an opensource software you can also build your own server.

8

You can request up to 4 isochrones per call, and the maximum distance is 100km.

map.Routing.Engine(reValhalla);
// 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) ;


The returned polygons and lines have isoTime and isoDistance properties that contain the requested values, you can use them to style your elements.

// styles used in the image above
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}');
go to page
Réalisé avec la version gratuite pour les particuliers d'Help&Web