TECNativeMap allows to save and reload all of its data in a simple text file, this includes not only the component settings and views but also the map data
Alternatively, you can import/export your data in formats GPX , GeoJSON and KML
Backup/restore
Saves the map to a text file.
Use extensions .gpx, .json, .kml to specify a format, otherwise it is the internal format of ECNativeMap that will be used
Charge la carte avec un fichier texte
Use extensions .osm, .olt, .gpx, .json , .kml or .csv to specify a format, otherwise it is the internal format of ECNativeMap that will be used
LoadFromFile can download files on internet
1
Property read/write which gives access to the data of the card in GPX format.
Property read/write which gives access to the data of the card in a text format.
Property in reading / writing which returns the geographical elements of the map in Kml format
Property read/write which gives access to the data of the card in the GeoJson format.
You access to the "properties" with TECShape.Properties field data, see chapter on the vector tiles to learn how to styling your items.
This property is used by SaveToFile, LoadFromFile.
Events
When the loading of a file (.csv, .kml, .geojson, .gpx or .txt) is finished the event OnLoad(sender: TObject; const GroupName: string; const FinishLoading: Boolean); is fired.
...
// fired when load ready
procedure TForm.mapLoad(sender: TObject; const GroupName: string;
const FinishLoading: Boolean);
begin
// show all éléments
map.group[groupname].fitbounds;
end;
During loading the map the event OnLoadShapes(sender: TObject; const ShapeType:string; const index, max: integer; var cancel: boolean) fires for each item added.
ShapeType can have the values 'TECShapePOI', 'TECShapeMarker', 'TECShapeLine' , 'TECShapePolygone' and 'TECShapeInfoWindow'.
Index indicates the number of the currently loaded element and Max the total number of items to be loaded.
You can cancel the load switching cancel to true
When the file was loaded event OnLoad(sender: TObject;const GroupName:string;const FinishLoading : boolean) is triggered
GroupName contains the name of the Group that has been loaded, empty for direct loading of the map (default group)
FinishLoading true if the file has been loaded in totality and false if it was abandoned by switching cancel to true
OSM XML
You can directly load a file to the OSM XML format
or olt with LoadFromFile.
The groups also have the functions
LoadFromOSMStream and
LoadFromOSMString.
TOSMFile (uecOSM unit) allows you to work with files in the OSM XML format (base format of OpenStreetMap)
You can download parts of the world in this format on geofabrik.de, take .osm.bz2 and unzip them
But you can also get these data directly from TECNativeMap using OverPass API
OverPassApi
The OverPassApi property allows you to use the Overpass API to get data from OpenStreetMap.
A layer is available to simplify the use
1By default the server used is https://overpass-api.de/api/interpreter, use the Url property to change it
Queries are nonblocking, plug on the event onData to recover data when available.
Use Query to run your request.
// get highway
map.OverPassApi.Query('way({{bbox}})[highway][name];(._;>;);out;)');
// the event is triggered when data is available
procedure TForm.doOverPass(const value:TECOverPassData);
begin
// load OSM data in your map
map.Shapes.LoadFromOSMString(value.Data);
end;
You can use {{bbox}} to limit the search to the visible area of your map, and {{center}} to indicate the focal point of your map.
2See for more information on the scripting language of OverPassAPI :
wiki.openstreetmap.org/wiki/Overpass_API/Language_Guidewiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
Some queries are available as standard
StreetNames returns just a list containing the name of the streets
procedure StreetNames(const bbox:string='';const OnDataEvent:TECOnOverPass=nil); overload;
Use this version to set a different search in the current view box
procedure StreetNames(const SWLatitude,SWLongitude,NELatitude,NELongitude:double;const OnDataEvent:TECOnOverPass=nil); overload;
Streets Returns the OSM data for the chosen area streets (it is equivalent to the example above)
procedure Streets(const SWLatitude,SWLongitude,NELatitude,NELongitude:double;const OnDataEvent:TECOnOverPass=nil); overload;
Amenity to find specific points
const data:TSetOSMData=[odNode,odWay];
const bbox: string = '';
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Amenity(const SWLatitude, SWLongitude, NELatitude,NELongitude: double;
const amenity_value: string = '';
const data:TSetOSMData=[odNode,odWay];
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Amenity( const amenity_values: array of string;
const data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const bbox: string = '';
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Amenity( const SWLatitude, SWLongitude, NELatitude,NELongitude: double;
const amenity_values: array of string;
const data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const OnDataEvent: TECOnOverPass = nil); overload;
// find all 'restaurant' (Node and Way) in visible area
map.OverPassApi.Amenity('restaurant');
// find all 'restaurant' (only Node) in visible area
map.OverPassApi.Amenity('restaurant',[odNode]);
// the event is triggered when data is available
// Set OnDataEvent to connect to a specific procedure
procedure TForm.doOverPass(const value:TECOverPassData);
begin
// load OSM data in your map
map.Shapes.LoadFromOSMString(value.Data);
end;
map.OverPassApi.Amenity('restaurant',[odNode],'',myEvent);
...
procedure TForm.myEvent(const value:TECOverPassData);
begin
// load OSM data in your map
map.Shapes.LoadFromOSMString(value.Data);
end;
Tag is the generic procedure to search through all the keys, not just Amenity
const Data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const bbox: string = '';
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Tag(const tag_name:string;
const tag_values: array of string;
const data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const bbox: string = '';
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Tag(const tag_name: string = '';
const tag_value: string = '';
const data:TSetOSMData=[odNode,odWay];
const bbox: string = '';
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Tag(const SWLatitude, SWLongitude, NELatitude,NELongitude: double;
const tag_name: string = '';
const tag_value: string = '';
const data:TSetOSMData=[odNode,odWay];
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Tag(const SWLatitude, SWLongitude, NELatitude,NELongitude: double;
const tags: array of string;
const Data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const OnDataEvent: TECOnOverPass = nil); overload;
procedure Tag(const SWLatitude, SWLongitude, NELatitude,NELongitude: double;
const tag_name:string;
const tag_values: array of string;
const data:TSetOSMData=[odNode,odWay];
const Op: TBinaryFilterOSM = bfAnd;
const OnDataEvent: TECOnOverPass = nil); overload;
// search Way 'highway'='residential
map.OverPass.Tag('highway','residential',[odWay]);
// search Way 'highway'='residential' OR 'highway'='primary'
map.OverPass.Tag('highway',['residential','primary'],[odWay],bfOr);
//search Way width highway=residential AND name='Park Avenue'
map.OverPass.Tag(['highway','residential','name','Park Avenue'],[odWay],bfAnd);
Data Returns the set of OSM data for the specified area
procedure Data(const SWLatitude,SWLongitude,NELatitude,NELongitude:double;const OnDataEvent:TECOnOverPass=nil); overload;
map.OverPassApi.data;
FilterPolygone allows you to use a polygon to limit the search area
For example, you can use a isoChrone
3// within 10 minutes walking distance
map.routing.IsoChrone.Time(map.latitude,map.longitude,map[ 'isochrone'].polygones,[10]) ;
if map['isochrone'].polygones.Count> 0 then
map.OverPassApi.FilterPolygone := map['isochrone'].polygones[0];
DemoNativeOverPassFiremonkey shows you how to extract data from OpenStreetMap.
OSM XML is large, some files are several Giga, TOSMFile can use an internal format (.olt) up to 19 times lighter, 10 times faster to process.
To convert a .osm file in .olt use the procedure OSMFileToOLT(const OSMFilename:string;const Notify:TNOtifyEvent=nil);
The conversion is performed in a thread and Notify is called when the work is complete.
begin
// doEndSaveToOLT is call when file is saved
OSMFileToOLT(FOSMFile.filename, doEndSaveToOLT);
end;
procedure TForm2.doEndSaveToOLT(Sender : TObject);
begin
// here your osm file is savec in .olt
end;
Use TOSMFile to convert portions of OSM files
2TOMSFile
function LoadFromFile(const sFilename
: string) : boolean;
function LoadFromStream(const OSMStream
: TStream) : boolean;
function LoadFromString(const OSMData :
string) : boolean;
property FilterPrimitive : TSetPrimitiveOSM ;
There are nodes, ways and relations.
FOSMFile.FilterPrimitive := [poNode,poWay,poRelation];
If you want to know simply the area geographical covered by the file without loading the data, filter all !
4property FilterBounds : TFilterBounds;
Determines the geographical areas that interest us, data outside are ignored.
FOSMFile.FilterBounds.Add(Area1_NorthEastLat, Area1_NorthEastLng, Area1_SouthWestLat, Area1_SouthWestLng);
FOSMFile.FilterBounds.Add(Area2_NorthEastLat, Area2_NorthEastLng, Area2_SouthWestLat, Area2_SouthWestLng);
property FilterNode : TListFilterOSM;
property FilterWay : TListFilterOSM;
property FilterRelation : TListFilterOSM;
Filters items based on their keys and values, filters down from the class TFilterOSM
ExcludeKeyValue(const Key, Value : string), OnlyKeyValue(const Key, Value : string), ExcludeIfKeyExist(const Key:string) and OnlyIfKeyExist(const Key:string) simplifies the creation of filters.
3FOSMFile.FilterWay.ExcludeIfKeyExist('building');
FOSMFile.FilterWay.ExcludeKeyValue('leisure','park');
FOSMFile.FilterWay.ExcludeKeyValue('natural','coastline');
Reload a file after changing the filters, the keys and values are not recharged allows to earn a few seconds.
procedure saveToFile(const Filename : string; NotifyEvent : TNotifyEvent = nil);
FOSMFile.SaveToFile('path_myfile.geojson');
// save in olt
FOSMFile.SaveToFile('path_myfile.olt');
To save in a thread add a NotifyEvent
4begin
// doEndSaveToOLT is call when file is saved
FOSMFile.SaveToFile('path_myfile.olt',doEndSaveToOLT);
end;
procedure TForm2.doEndSaveToOLT(Sender : TObject);
begin
// here your osm file is savec in .olt
end;
property Ways : TWayList read FWayList;
property Relations : TRelationList read FRelationList;
Lists of the elements contained in the file after filtering.
Each list has functions for performing research on these items.
Find(idElement) Returns an item based on its id
The various Search functions fill the SearchResult list with the elements eligible
function Search(const Lat, Lng, radiusKM : double) : integer; overload;Find all items located in an area centered around the point Lat, Lng and radius radiusKM
function Search(const SWLat, SWLng, NELat, NELng : double) : integer; overload;
Finds all elements in the area.
function Search(const SWLat, SWLng, NELat, NELng : double; const Key, Values : string) : integer; overload;
Finds all elements in the area with Key containing the specified values.
function Search(const Key, Values : string) : integer; overload;
Find all items whose key contains values.
FOSMFile.Nodes.Search('amenity','cafe|bar|restaurant');
// search all ways with highway=residential or highway=secondary
FOSMFile.Ways.Search('highway','residential|secondary');
function Search(const Key : string) : integer; overload;
Find all items with this key, regardless of the value.
procedure Clear;
procedure Abort;
Abandons a loading
procedure ToShapes(Shapes:TECShapes;NotifyEvent:TNotifyEvent=nil);
Loads data into a group.
FOSMFile.ToShapes(map.Shapes);
Loads the search data in a group.
FOSMFile.Nodes.Search('amenity','cafe|bar|restaurant');
// search all ways with highway=residential or highway=secondary
FOSMFile.Ways.Search('highway','residential|secondary');
// load in default group
FOSMFile.FindToShapes(map.Shapes);
function CountKey(Node: TBaseOSM):integer;
Returns the number of tag for an element
function getKey(Node:TBaseOSM;const index:integer):string;
Returns the key which is the index
function ReadKey(Node : TBaseOSM; const KeyName : string) : string; overload;
Returns the value of the Key
function ReadKey(Node : TBaseOSM) : string; overload;
Returns the set of key/value pairs in the form: Key1=value1#13#10Key2=value2#13#10Keyx=ValueX
function ReadValuesForKey(const KeyName : string; valuesList : TStringList): integer;
ValuesList filled with all of the values for a Key
property Aborted : boolean;
Indicates if loading has been interrupted by Abort
property Bounds : TBoundsLatLng ;
Contains the geographical area covered by the file
property FileFormat: TFileTypeOSM;
Returns the file type (ftOSM ou ftOLT)
property Filename : string ;
property FileSize : int64;
property Keys : TUniqueStringList;
List of all of the Key from the file
property Values : TUniqueStringList;
List of all the Value of the file
property Role[Member : TMemberOSM]:string;
property Timestamp : string ;
Returns the date of the last update of the file
property OnRead : TOnOSMBlockRead;
To be able to process files of several Giga reading is made by block, this event is raised every time a block is read.
property OnLoaded : TNotifyEvent;
Raised when the entire file has been processed.
Check out DemoOSMViewer to see how to use TOSMFile
2OSMViewer
Convert OSM in OLT
Open the osm file in OSMviewer, the area covered is displayed on the map
Check the primitives that you want to export (nodes, ways and relations), and then click Save OLT to start the conversion
Depending on the size of the OSM file work may take several minutes.
5To export the ways all the nodes are kept in memory
, you need 1 MB of memory per Giga of file.
If you convert only the nodes you can work with 100
Giga files even if you have only 8 MB of
memory.
Once the loaded zone you will have the choice between displayed data on the map or save them in .olt
By loading data you can search according to key/value pairs
You can download an apk for android to a mini demo that displays a small area OSM data.
Image capture
You can save the viewable area of the screen with the ScreenShot property that is an TBitmap
// Delphi
map component TECNativeMap
// save map to bmp
file
map.Screenshot.SaveTofile('c:\mymap.bmp');
Alternatively, you can capture any geographic area, even off screen, with the property ScreenShots
5// procedure
call when bitmap ready
map.ScreenShots.OnScreenShot := doScreenShot ;
// you can change the size of the
bitmap between each capture (default
800x600)
map.ScreenShots.Width := 2000;
map.ScreenShots.Height:= 2000;
// you can change
tileserver
map.ScreenShots.TileServer := tsOsmFr;
// capture area centered on a point
with a specified zoom
map.ScreenShots.ScreenShot(latitude,longiture,
16,'optional_name_of_capture');
// you can take screenshots even if
the previous is not over yet
// Take the best zoom to a specific
area
map.ScreenShots.ScreenShot(NorthEastLat, NorthEastELng,
SouthWestWLat, SouthWestLng,'optional_name_of_capture');
// Take the best zoom to an area
defined by its center and radius in km
// CAUTION use double for the
radius, here 1.0 km, otherwise it will be mistaken for a
simple zoom
map.ScreenShots.ScreenShot(Latitude, Longitude,
1.0 ,'optional_name_of_capture');
// when capture is ready, you go
here
procedure
TForm.doScreenShot(const
name:string;const Screenshot:TBitmap);
begin
// don't free ScreenShot
!
screenshot.SaveToFile(YourPath+name+'.bmp');
end;
The Photographer demo for Firemonkey shows you an example of using, you run 8 "drones" to photograph the ground every x meters.