Shapefile projection files - coordinates

I'm working with some open data involving Shapefiles and I've managed to convert the data to GeoJSON and extract the coordinates of the points (along with other information). However the coordinates do not appear to be latitudinal/longitudinal coordinates:
[ 368667.2455000002, 5009510.4067 ]
[ 367885.47140000015, 5019804.3237 ]
[ 395852.80260000005, 5027699.9354 ]
[ 379358.1364000002, 5036798.5747 ]
[ 351968.9621000001, 5017404.8727 ]
[ 375123.64269999973, 5033338.467499999 ]
[ 378133.7736999998, 5032617.237500001 ]
[ 385791.0351, 5010557.9144 ]
[ 349796.77770000044, 5013571.1559999995 ]
[ 367271.0566999996, 5030212.897399999 ]
[ 378808.0292999996, 5013921.017100001 ]
[ 336650.69820000045, 5039983.886399999 ]
[ 364178.05599999987, 5015957.9625 ]
[ 362715.9132000003, 5023112.371200001 ]
[ 351321.0865000002, 5013763.298699999 ]
[ 373254.0789000001, 5026533.7453000005 ]
[ 355235.6211000001, 5016957.0644000005 ]
[ 327797.9938000003, 5036758.195699999 ]
[ 362836.86930000037, 5015895.811000001 ]
[ 375479.41530000046, 5001245.2017 ]
Upon further research, I found that I have to "project" these coordinates with respect to the data in the PRJ file:
PROJCS["City of Ottawa",
GEOGCS["GCS_North_American_1983",
DATUM["D_North_American_1983",
SPHEROID["GRS_1980", 6378137.0, 298.257222101]
],
PRIMEM["Greenwich", 0.0],
UNIT["Degree", 0.0174532925199433]
],
PROJECTION["Transverse_Mercator"],
PARAMETER["False_Easting", 304800.0],
PARAMETER["False_Northing", 0.0],
PARAMETER["Central_Meridian", -76.5],
PARAMETER["Scale_Factor", 0.9999],
PARAMETER["Latitude_Of_Origin", 0.0],
UNIT["Meter", 1.0]
]
I've already read What does an esri projection file represent? and subsequently, https://gis.stackexchange.com/questions/2383/does-re-projecting-an-esri-shapefile-only-update-the-content-of-the-prj-file/2386#2386. Though they describe what projection files do/are, there is no discussion on how the transformation is done.
Unlike Shapefiles, I haven't been able to find a specification on PRJ files. Is there an algorithm that is used to transform the coordinates to lat/long coordinates?
I'm also open to using libraries but they will need to be compatible with either Android (GeoTools did not work for me) or JavaScript (Node).

How the transformation is actually done can be extremely complicated, especially if you're going between datums (such as NAD83 to WGS84, etc.) There are a ton of tools out there that can do this, but I'm not that familiar with mobile stuff but I know some people have gotten GDAL and OGR to build on Android. See http://trac.osgeo.org/gdal/wiki/BuildingForAndroid.
You will need to find the EPSG code for your data. From what you posted, these coordinates are in EPSG:32189 (MTM Zone 9). To find this I used the website http://prj2epsg.org, where you can upload a .prj file and it will find the EPSG code for you. You can view more information about that projection at spatialreference.org. That site has several useful features, such as downloadable prj files for each projection, and a proj4 file for the proj4 library mentioned above.
Hope this helps.

According to the latest GeoJSON spec (RFC7946), the CRS must be WGS84(lat/lng). Tools such as the GDAL suite assume the CRS of your output is in WGS84.
That said, the reprojection step must be done while or before converting from shapefile to GeoJSON.
For example, with ogr2ogr from GDAL, and provided the PRJ companion file is in the same directory as the shapefile (the coordinate system will be read from the PRJ file with no need to specify an input EPSG code),
ogr2ogr -f GeoJSON output.json input.shp
Note that in recent GDAL versions there is no need to force the output coordinate system to be WGS84, as explained in the first paragraph. Previous syntax would be,
ogr2ogr -t_srs EPSG:4326 -f GeoJSON output.json input.shp
You can use a NodeJS wrapper for ogr2ogr
For example,
https://github.com/wavded/ogr2ogr
Corresponding NPM package,
https://www.npmjs.com/package/ogr2ogr
EDIT 1:
Alternatively, SWIG generated NodeJS bindings for GDAL can be used,
https://www.npmjs.com/package/gdal
EDIT 2:
Nevertheless if the OP really wants to convert a GeoJSON still in EPSG:32198 to a GeoJSON in WGS84 this will do the job:
ogr2ogr -t_srs EPSG:4326 -s_srs EPSG:32198 -f GeoJSON output.json input.json
Note that GDAL is distributed with an EPSG Database from where it will be read the following string:
+proj=tmerc +lat_0=0 +lon_0=-76.5 +k=0.9999 +x_0=304800 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
That corresponds to the PRJ file in the question.

Using Javascript, the best solution I found and which I implemented (and it's working) resides on using the library proj4. But I know this library exists also for Python.
In Javascript it would be:
var firstProjection = 'PROJCS["NAD83 / Massachusetts Mainland",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",42.68333333333333],PARAMETER["standard_parallel_2",41.71666666666667],PARAMETER["latitude_of_origin",41],PARAMETER["central_meridian",-71.5],PARAMETER["false_easting",200000],PARAMETER["false_northing",750000],AUTHORITY["EPSG","26986"],AXIS["X",EAST],AXIS["Y",NORTH]]';
var secondProjection = "+proj=gnom +lat_0=90 +lon_0=0 +x_0=6300000 +y_0=6300000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
//I'm not going to redefine those two in latter examples.
proj4(firstProjection,secondProjection,[2,5]);
// [-2690666.2977344505, 3662659.885459918]
If only 1 projection is given then it is assumed that it is being projected from WGS84 (standard of GPS).
proj4(firstProjection,[-71,41]);
// [242075.00535055372, 750123.32090043]

Related

Mapbox opengl line with different colors based on metadata like speed and other information (eg leaning angle, acceleration)

I'm working on a map on whitch I want to draw the path I drove with my motorcycle. For this I want to use mapbox opengl because of the wonderful graphical features. I have dificulties to understand the different kind of sources that Mapbox offers (https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/). I collect the data with my self developed logger (lat, lng, speed, acc, gyro, leaning angle, alt) and can export them in any kind of file or format. But as far as I understood, geo.json files are not able to support metadata. So I looked up the "Tiled Sources" but here I getting into trouble. Do I need a mapper from Mapbox from my file and then consume the data to mapbox or do i have a direct options to import my CSV and define the data columns.
But as far as I understood, geo.json files are not able to support metadata.
Incorrect. You can store any metadata you like either on the properties attribute of a Feature, or at the top level of a FeatureCollection.
So I looked up the "Tiled Sources" but here I getting into trouble.
You don't want a tiled source.
Do I need a mapper from Mapbox from my file and then consume the data to mapbox or do i have a direct options to import my CSV and define the data columns.
Probably what you want is to convert the CSV to GeoJSON. You can even do it dynamically in your code front end.
After loading the CSV (using something like D3's csv method), you can do something like this:
const geojson = {
type: 'FeatureCollection',
features: rows.map((row, id) => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [+row.longitude], +row.latitude],
},
properties: {
id,
...row
}
}))
}
map.addSource('mysource', { type: 'geojson', data: geojson });

Can I use Azure Maps tiles as a data source for Mapbox style JSON files?

As far as I can tell, I have used the correct format for the URL, but on replacing the Mapbox style JSON file in Mapbox Studio, I get an 'Invalid source URL" error
I've looked at all the relevant Mapbox and Azure Maps examples, eg:
1) https://learn.microsoft.com/en-au/rest/api/maps/render/getmapimagerytile
2) https://learn.microsoft.com/en-au/rest/api/maps/render/getmaptile
...
"sources": {
"azure": {
"type": "raster",
"url": "https://atlas.microsoft.com/map/imagery/png",
"subscription-key" : "<my-key>",
"api-version" : "1.0",
"tileSize": 256
},
"composite": {
"url": "mapbox://mapbox.mapbox-streets-v8",
"type": "vector"
}
},...
When replacing a style in Mapbox Studio with one that contains the above source, I get an 'Invalid source URL' error. I expected Mapbox to be able to use that source.
Try maybe that way:
"Imagery tiles": {
"type": "raster",
"tiles": [
"https://atlas.microsoft.com/map/imagery/png?subscription-key=yourkey&api-version=1.0&style=satellite&zoom={z}&x={x}&y={y}"
],
"maxzoom": 18,
"tileSize": 256
}
You can use the Azure Maps vector tiles with Mapbox style JSON files. However, the data schema of the vector tiles is different for Azure Maps than the Mapbox street tiles, so you would need to adjust your style to use different source layers. TomTom is the primary data provider and the source layers of the vector tiles are documented here: https://developer.tomtom.com/maps-api/maps-api-documentation-vector/tile
Note, the Azure Maps Web SDK uses the same rendering engine as Mapbox GL JS and is able to render data just as well. It has an easier to use API interface that is also less error prone, so you might want to consider taking a look at that. It doesn't support custom styles yet, but this is planned. Here is a bunch of code samples using this SDK: https://azuremapscodesamples.azurewebsites.net

Mapbox : GeoJson Source in Runtime Styling

Do Mapbox Supports, GeoJson source support in Runtime Styling.
I tried same Style (file with two Source 1. Vector, 2. GeoJson) file with mapbox-gl-native and mapbox-gl-js.
It was working as expected in Native SDK but it seems mapbox-gl-js is ignoring if source type is GeoJson.
I tried version 0.52
This is definitely possible. You just need to call .addSource on your map object before you use that source to generate the style layers. This example shows how the general flow for adding a GeoJson source: https://docs.mapbox.com/mapbox-gl-js/example/multiple-geometries/
If you're trying to reference a geojson file, you'll just need to specify that file's URL via the data field of your source object. If you're going that route, the GeoJson file needs to be on the same domain or accessible using CORS.
Here's a quick and dirty code snippet to illustrate what I mean:
map.on("load", function() {
map.addSource("my-geojson-source", {
"type": "geojson",
"data": "path/to/data.geojson"
});
map.addLayer({
"id": "styled-geojson-layer",
"type": "circle", // this depends on your data & goals
"source": "my-geojson-source",
... // add style things here
});
});
If you get stuck, the library documentation should have everything you need:
https://docs.mapbox.com/mapbox-gl-js/examples/
https://docs.mapbox.com/mapbox-gl-js/style-spec/#sources
https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers

Reading OSM Map (or other format) files to determine shortest distance from coordinate to path

My App uses openstreetmap files to show waypoint (or coordinates) on a map.
Based on an Openstreet map file: how can I determine the shortest distance from a GPS coordinate to the (walking) path.
Can I read an OSM (map) or .osm file ... to access the paths?
There are some misconceptions. First, the OSM file is not the map file. The OSM file can be used to create a format to make map rendering fast e.g. mapsforge format does this.
With e.g. GraphHopper you import the OSM file like .pbf or .osm which then creates a graph which can be used for problems you described. Not exactly sure what problem you have though ;)
The following solution works:
Get the graphhopper project in your IDE.
Get the raw Openstreetmap data (.pbf) via this very nice provider.
Run this command in your (git) bash shell: ./graphhopper.sh -a import -i gelderland-latest.osm.pbf
Make a new (maven) project with this pom.xml file:
nl.xyz
graphhopper
1.0
system
${project.basedir}/libs/graphhopper-web-1.0-SNAPSHOT.jar
Copy generated graphhopper-web-1.0-SNAPSHOT.jar from the graphhopper project to the libs folder of your new project so it will be included in your path.
Copy the generated graphhopper data to a folder within your small project.
Create this simple demo:
public static void main(String[] args) {
private static String mapsFolder = "graphhopper-data/yourlocation-latest.osm-gh";
GraphHopper graphHopper = new GraphHopper().forMobile();
graphHopper.load(mapsFolder);
System.out.println("Found graph " + graphHopper.getGraphHopperStorage().toString() + ", nodes:" + graphHopper.getGraphHopperStorage().getNodes());
QueryResult queryResult = graphHopper.getLocationIndex().findClosest( 52.11111, 6.111111, EdgeFilter.ALL_EDGES);
double distance = queryResult.getQueryDistance();
System.out.println( "Shortest distance is: " + distance);
}
UPDATE: Using the JAR on Android may give a lot of compiler errors due to library version mismatchers. A better solution for getting this example run at Android, is using this dependency in your build.gradle:
implementation 'com.graphhopper:graphhopper-core:1.0-pre33'
Consequence is that you have to set the default routing profile. You can achieve via this change:
graphHopper = new GraphHopper().forMobile();
// Next line:
graphHopper.setProfiles( Collections.singletonList(new ProfileConfig("my_car").setVehicle("car").setWeighting("fastest")));
graphHopper.load(routingDataFolder);
I hope you enjoy this wonderful 'graphhopper' software!

Dojo layer don't includes all essentials

I have a sample script which uses
dojo.require("dojo.parser");
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.layout.TabContainer");
dojo.require("dojox.grid.DataGrid");
dojo.require("dijit.Tree");
dojo.require("dojo.data.ItemFileReadStore");
I want to create a minified build of dojo, so I use this profile
dependencies = {
stripConsole : "normal",
selectorEngine : "acme",
optimize : "closure",
layerOptimize : "closure",
cssOptimize : "comments.keepLines",
mini : true,
internStrings : true,
localeList : "en-us",
releaseName : "dojo.custom",
action : "release",
optimize : "shrinksafe",
layerOptimize : "shrinksafe",
layers : [
{
name : "dojo.js",
dependencies : [
"dojo.parser",
"dojo.data.ItemFileReadStore",
"dojox.grid.DataGrid",
"dijit.layout.BorderContainer",
"dijit.layout.ContentPane",
"dijit.layout.TabContainer",
"dijit.Tree"
]
}
],
prefixes: [ [ "dijit", "../dijit" ], [ "dojox", "../dojox" ] ]
}
Yes, builder compile huge dojo.js file which I include in my html page, but still there is MANY xhr requests. System loads scripts which I don't use explicitly. Here's a screenshot
Interesting.
Are you sure the browser is successfully finding and loading the compressed version?
The browser is looking for _base.js which should definitely already be baked into that file.
Update
Tommi - dojo.js layer is always built by the build system, you don't have to explicitly declare it. I'm not sure what the effect will be of you explicitly declaring it along with dependencies. This might work, but it might not. Maybe the dependencies are overridding the normal dojo.js contents.
What I normally do is just let the system build dojo.js and then create a layer that has all the dijit/dojox stuff that I may want, and deploy that. I also usually create a 3rd separate file with my custom stuff in it.
I would try that. The key I think is to make a separate layer from dojo.js. (But still include the normal dojo.js in your page).