Visualising spatial information and performing geographical analyses are basic functions for the most of the PTV xServer use cases. This page contains several geographical and map topics.
The PTV xServer currently support the following coordinate formats:
Coordinate Format | Description | Notation Examples [Y, X] |
---|---|---|
OG_GEODECIMAL | Geographic Coordinates in decimal degree notation (WGS84, EPSG:4326) | 49.013106, 8.427825 |
PTV_MERCATOR | PTV variant of Mercator projection: cylindrical map projection | 6270051, 937090 |
PTV_GEOMINSEC | PTV variant of Geographic Coordinate in degree notation (WGS84) | 49°0'47.182'', 8°25'40.17'' |
PTV_GEODECIMAL | PTV c type variant of Geographic Coordinates in decimal degree notation (WGS84) | 4901310.6, 842782.5 |
PTV_SMARTUNITS | PTV internal coordinate format of the Smart Data format (do not use it!) | 5465209, 4356385 |
This section aims at providing information on how to convert coordinates from one format to another. In the table below, you can see the coordinates of some locations in different formats.
Place | Mercator | GeoMinSec | ||||
---|---|---|---|---|---|---|
|
|
|||||
Karlsruhe |
|
|
||||
Berlin |
|
|
Place | GeoDecimal | ||
---|---|---|---|
|
|||
Karlsruhe |
|
||
Berlin |
|
As you can imagine, each of these conversions is proceeded by using specific formula in background. Let us take a look at some of them.
Case: Mercator to Geodecimal | Case: Geodecimal to Mercator |
---|---|
Input: ( XM, YM ) coordinates of the given point in Mercator
format.
Output: ( XGD, YGD ) coordinates in Geodecimal format.
We have:
( XGD, YGD ) = ( λ , φ ) x 100000, where
|
Input: ( XGD, YGD ) coordinates in Geodecimal format. Output: ( XM, YM ) coordinates in Mercator format. We have: ( XM, YM ) = ( XRes, YRes ), where XRes = 6371000 x (π/180) x λ, and YRes = 6371000 x ln(tan(π/4 + π/180 * φ/2)) , with ( λ,φ) = ( XGD, YGD ) / 100000 |
A typical conversion in the program would look like this where the invoked method Mercator_2_GeoMinSec(arg1,arg2,arg3,arg4) will compute the coordinates in the new format.
long xOut, yOut; // Calling the actual conversion method which // returns the rounded integer values of the // transformed coordinates in (xOut, yOut) int result = Mercator_2_GeoMinSec((long)1110032, (long)7076381, out xOut, out yOut); Console.WriteLine("Mercator: 1110032, 7076381"); // Hamburg Mercator coordinates Console.WriteLine("To GeoMinSec: " + xOut.ToString() + ", " + yOut.ToString()); // 958579 , 5332392
A typical conversion in the program would look like this where the invoked method Mercator_2_GeoMinSec(arg1,arg2) will compute the coordinates in the new format.
long[] result = Mercator_2_GeoMinSec((long)1110032, (long)7076381); System.out.println("Mercator: 1110032, 7076381"); System.out.println("To GeoMinSec: " + result[0] + "; " + result[1] + "\n");
If you want to use PTV xMap Server to display points of interest (POI) on a PTV map (e.g. European City Map Premium, North America City Map, World Map, etc.) you usually store the POIs in a database and provide PTV xMap Server only with those points which are in the currently displayed map segment or in an otherwise defined region of interest (ROI).
The examples below show you how to use standard SQL to select POIs from a database table which lie in a given rectangle or within an airline distance from a given point.
If you have a region specified by bounds you can use the BETWEEN statement as shown below in order to retrieve the POIs within that region. As shown in the first mapping example, PTV xMap Server provides you with the map's bounding rectangle, which can be used to obtain the values for the SQL statement below (e.g. left-top [960000,6280000] and right-bottom [970000,6260000]).
SELECT * FROM points WHERE x BETWEEN (950000) AND (970000) AND y BETWEEN (6260000) AND (6280000);
In case you have the region is given by a center coordinate (e.g. [960000, 6270000]) and a region size (e.g. 40000x30000) you can also use the the following query:
SELECT * FROM points WHERE ABS(x-960000) < 20000 AND ABS(y-6270000) < 15000;
If you have a region specified by centre coordinates and a given radius (all points in a radius of 10,000 Mercator units) you can use the below defined formular.
SELECT * FROM points WHERE (x-960000)*(x-960000)+(y-6270000)*(y-6270000) < (10000*10000)
In the SQL statements above all values are Mercator values, but often you want to use values in meters to specify or calculate distances. Below, we show you how to calculate the airline distance between two Mercator coordinates.
The function below uses a formula which gives an approximation of the distance in meters. Hence, the result is not exact, but for distances up to 600 km and 80° latitude the error is sufficiently small.
public static double distanceFromMercator(double x1, double y1, double x2, double y2) { double dx = x2 - x1; double dy = y2 - y1; double Y, B, distance; Y = 0.5 * (y2 + y1); B = 2.0 * Math.atan(Math.exp(Y / 6371000.0)) - (0.5 * Math.PI); distance = Math.cos(B) * Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); return distance; }
We simply showed how to use the calculateReachableObjects function in order to find out which locations are reachable within a certain time or distance domain considering the given routing options. But if you have thousands of POIs it would be impractical to load all points in the database. But you are able to decrease the number of points using the SQL-statements as mentioned above.
For example, if you want to find out which objects are reachable within a 10 minute drive you will receive all points from the database which are within 25 km radius. This airline distance is calculated provided that your speed is 150 km/h. Afterwards you would fill the input list with the selection of points instead of all points in the database.
A PTV xServer installation is always configured to use one distinct map. But sometimes you want to handle requests where each request targets a region in a different map. For example, you provide a store locator for your customers and you have stores all over the world. In this case you would have multiple PTV xServer installations each handling requests using a different map (e.g.: Europe City Map Premium, North America City Map, Australia City Map, etc.).
In this example we show you how to get the right server for a given point or rectangle (which is the server having the most detailed map for the region that contains the point or rectangle).
When geocoding addresses you usually know the country the address is located in. So this case is easy to handle with an associative array which maps countries to servers. Hence, we do not describe this scenario below.
A region directory returns the ServerRegion for a given point (or rectangle) which contains the point. If the point is contained in multiple regions, the supplied IServerRegionComparer is used to determine which region has a higher rank and should come first. In our case we use the detail level of the map that covers a region to determine which region to return.
IRegionDirectory<StandardServerInfo directory> = new SimpleRegionDirectory<StandardServerInfo>( delegate(ServerRegion<StandardServerInfo> a, ServerRegion<StandardServerInfo> b) { return a.ServerInformation.MapDetail - b.ServerInformation.MapDetail; });
IRegionDirectory<StandardServerInfo> directory = new SimpleRegionDirectory<StandardServerInfo>( new IServerRegionComparer<StandardServerInfo>(){ @Override public int compare(ServerRegion<StandardServerInfo> a, ServerRegion<StandardServerInfo> b) { return a.getServerInformation().getMapDetail() - b.getServerInformation().getMapDetail(); } });
In order to add a region to the directory you have to create a new ServerRegion<StandardServerInfo> by specifying the left, right, bottom and top bounds. Afterwards you add information about which server to use for the region, and add the region to the directory.
// create a new region ServerRegion<StandardServerInfo> regionGermany = new ServerRegion<StandardServerInfo>(663234, 1665183, 6028293, 7316753); // add information to the region regionGermany.ServerInformation = new StandardServerInfo(); regionGermany.ServerInformation.MapDetail = 3; regionGermany.ServerInformation.XmapUrl = "http://localhost:50010/xmap/ws/XMap"; // add the region to the directory directory.addRegion(regionGermany);
// create a new region ServerRegion<StandardServerInfo> serverGermany = new ServerRegion<StandardServerInfo>(663234,1665183,6028293,7316753); // add information to the region StandardServerInfo serverInfoGermany = new StandardServerInfo(); serverInfoGermany.setMapDetail(3); serverInfoGermany.setXmapUrl("http://localhost:50010/xmap/ws/XMap"); serverGermany.setServerInformation(serverInfoGermany); // add the region to the directory directory.addRegion(serverGermany);
Once your region directory is set up, you can use it to determine the right server for a request. In the example below, we use the bounding box to request the region from the directory. The returned region contains the information we entered earlier. In this case we use the xmapUrl from the server information to initialise the SOAP client class.
ServerRegion<StandardServerInfo> region = directory.getRegion(boundingBox); if (region != null) { XMapWSService xmapClient = new XMapWSService(); xmapClient.Url = region.ServerInformation.XmapUrl; // ... }
ServerRegion<StandardServerInfo> region = directory.getRegion(boundingBox); if (region != null) { XMapWS xmapClient = new XMapWSProxy( region.getServerInformation().getXmapUrl() ); // ... Map map = xmapClient.renderMapBoundingBox(boundingBox, mapParams, imageInfo, null, false, null); }
Information about coordinate formats and the definition of bounding boxes are also available in this documentation. The bounding box is defined by the map corners "left top" and "right bottom".
These and other samples are also available as stand-alone java and C# programs.
Copyright © 2024 PTV Logistics GmbH All rights reserved. | Imprint