Real-time Data Visualization using any Earth API - visualization

How to create something like on this video (1-2 minutes http://www.ted.com/index.php/talks/sergey_brin_and_larry_page_on_google.html) using "Google Earth API" or some other?
Especially: I have an online game and want to show dynamical data on some "virtual earth". 3 types of objects changing their state in real-time. It's enough to update each 5 seconds. I already have open api for it.
The problem is i do not know if it's possible to draw something like colored lines from a sphere's center and change them dynamically.
Sorry for an abstract question, but the goal is the same.

Well, if you're using the Google Earth API (requires that the Google Earth Plugin be installed), you can just create a bunch of extruded polygons. For example, if you go to the Earth API Interactive Sampler and paste/run this:
var lookAt = ge.getView().copyAsLookAt(ge.ALTITUDE_RELATIVE_TO_GROUND);
var lat = lookAt.getLatitude();
var lng = lookAt.getLongitude();
// first create inner and outer boundaries
// outer boundary is a square
var outerBoundary = ge.createLinearRing('');
var coords = outerBoundary.getCoordinates();
coords.pushLatLngAlt(lat - 0.5, lng - 0.5, 1000000);
coords.pushLatLngAlt(lat - 0.5, lng + 0.5, 1000000);
coords.pushLatLngAlt(lat + 0.5, lng + 0.5, 1000000);
coords.pushLatLngAlt(lat + 0.5, lng - 0.5, 1000000);
// create the polygon and set its boundaries
var polygon = ge.createPolygon('');
polygon.setExtrude(true);
polygon.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
polygon.setOuterBoundary(outerBoundary);
// create the polygon placemark and add it to Earth
var polygonPlacemark = ge.createPlacemark('');
polygonPlacemark.setGeometry(polygon);
ge.getFeatures().appendChild(polygonPlacemark);
// persist the placemark for other interactive samples
window.placemark = polygonPlacemark;
window.polygonPlacemark = polygonPlacemark;
You'll see a 3D polygon extruded out of the globe.
There's much more you can do with this; I suggest playing with the Earth API and KML (foundation for geometry primitives in the Earth API) by visiting code.google.com/apis/earth and code.google.com/apis/kml.

Related

How to get the edge of a polygon drawn on map within Leaflet

I am working with Leaflet and Leaflet-Draw in Angular to draw some polygons on the Google Map. How can I implement a listener when the user clicks exactly on the edge of the drawn polygons and get the lat and lng of that edge. I know a similar situation can be implemented with Google Map API like the code below, but I can not find any source to help me implement the same thing in Leaflet.
google.maps.event.addListener(polygon, 'click', function (event) { console.log(event.edge) }
Google Map Documentation: https://developers.google.com/maps/documentation/javascript/reference/polygon#PolyMouseEvent
For those who come across this question: I found a solution myself!
I didn't find anything directly from Leaflet draw library that I could use, so I defined the problem for myself as a trigonometry problem and solve it that way.
I defined a function in which on polygon click, it converts the event.latlng and loops over polygon.getLatLngs()[0] taking a pair of A and B points. A is the first coordinates, B is the next and if it reaches to the end of array, B will be the first point. Then using Collinear Function of 3 points with x, y, I checked if the clicked x, y has a same slope as point A and B.(has to be rounded it up), if so, I would save that A and B point pair with their latLng information and further used it in my project.
Although this method works, I would appreciate if anybody would know a better solution or library built-in function that can be used instead. Thanks!
When the user clicks on the polygon you can loop through all corners and check if he clicked in the near of the corner.
poly.on('click', function(e){
var latlng = e.latlng;
var corners = poly.getLatLngs();
if(!L.LineUtil.isFlat(corners)){ //Convert to a flat array
corners = corners[0];
}
//Convert the point to pixels
var point = mymap.latLngToContainerPoint(latlng);
//Loop through each corner
corners.forEach(function(ll){
//Convert the point to pixels
var point1 = mymap.latLngToContainerPoint(ll);
var distance = Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point.y - point1.y, 2));
//Check if distance between pixels is smaller then 10
if(distance < 10){
console.log('corner clicked');
}
});
});
This is plain JS you have to convert it self to angular.
A alternativ is to place on each corner a DivMarker or a CircleMarker and fire a event if the marker is clicked.
Looks like: https://geoman.io/leaflet-geoman

How to calculate location’s long/lat based on its bbox coordinates

please could anyone help?
I need to use a map.toFly() method to interpolate between 2 locations.
According to the Mapbox documentation, I need to pass in an object describing the destination I want to fly to. The object has to have a center property holding an array with centre Long/lat coordinates of the destination I need to be taken to.
https://docs.mapbox.com/mapbox-gl-js/example/flyto/
My problem with implementing the method is that I only have bounding box coordinates of the 2 locations between which I need to interpolate . I can’t do something like this:
map.flyTo(bbox)
Does anyone know how to obtain
centre Long/lat coordinates of each location based on their bbox coordinates?
Assuming you have 2 LngLatBounds objects you can call the getCenter() method.
var point1 = bounds1.getCenter();
var point2 = bounds2.getCenter();
where both bounds1 and bounds2 are objects of the type LngLatBounds.
Check:
https://docs.mapbox.com/mapbox-gl-js/api/#lnglatbounds#getcenter
Edit: for the values you gave in your comment it would be for the first bounds:
var sw1 = new mapboxgl.LngLat(110.2672863, -7.1144639);
var ne1 = new mapboxgl.LngLat(110.5088836, -6.9319917);
var bounds1 = new mapboxgl.LngLatBounds(sw1, ne1);
Note: Mapbox GL uses longitude, latitude coordinate order (as opposed to latitude, longitude).

Calculate altitude using Leaflet

I want to calculate altitude of a marker but I didn't find any solution in Leaflet. I found the elevation plugin which allow to draw elevation profil on map, but I don't need that. Do you have idea how to calculate altitude? Thank you.
Edit: A nice option
Adding this for anyone who might want it: since having written this answer, I wrote the plugin leaflet-topography to make doing this very fast and easy.
Original answer:
Not sure if anyone has answered yet but I cracked my head over this for a week and found a nice solution. First, you need to get the leaflet plugin leaflet-tileLayer-colorPicker:
https://github.com/frogcat/leaflet-tilelayer-colorpicker
This plugin enables you to get the color of a certain pixel on the map, given the latitude and longitude. Then, you need a dataset. One that's designed for this is the mapbox Terrain-RGB tiles:
https://docs.mapbox.com/help/troubleshooting/access-elevation-data/
These tiles have elevation data encoded in RGB format. The description on mapbox's site was not step-by-step enough for a beginner like me, so here's how you can do it:
Add the Terrain-RGB tilelayer
var colorPicker = L.tileLayer.colorPicker('https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.outdoors',
accessToken: 'your mapbox accesstoken'
}).addTo(yourMap)
.setOpacity(0); // optional
Create a function which takes in latlng and outputs RGB as an array
function getElevation(location){
var color = colorPicker.getColor(location)
// location is an array [lat, lng]
Pick apart the RGB values of the array and put into mapbox's elevation equation
let R = color[0];
let G = color[1];
let B = color[2];
let height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
let heightRounded = Math.round( height * 10) / 10 + ' meters';
return heightRounded;
}
That last bit is just to give a nice number rounded to the first decimal, output as a string like "182 meters", but you can write it however you like.
I had a similar problem working on a Shiny app with leaflet and found a workaround using Google Elevation API and google_elevation() function of googleway package
The latter (R part) is probably not in your interest but the Google Elevation API implementation should work for you.

getting GKObstacleGraph to work with SKTileMapNode

I'm currently working in Xcode 8, using Swift 3 and the new SKTileMapNode from SpritKit to make a 2D dungeon crawler type of game.
I'm have trouble getting GKObstacleGraph to work with the tilemap. Please help!
I tried to loop through all the tiles within the obstacle layer of the tilemap and create a polygon for each tile and store it in the GKObstacleGraph. Each tile in obstacle layer is a wall tile. The map looks like some type of dungeon crawler, so the wall is all over the places.
I have something like below:
for row in 0..<tileMapNode.numberOfRows {
for column in 0..<tileMapNode.numberOfColumns {
let tile = tileMapNode.tileDefinition(atColumn: column, row: row)
let tileCenter = tileMapName.centerOfTile(atColumn: column, row: row)
//find 4 corners of each tile from its center
let bottomLeft = float2(CGPointMake(tileCenter.x - tile.size.width/2, tileCenter.y - tile.size.height/2))
let bottomRight = float2(CGPointMake((tileCenter.x - tile.size.width/2, tileCenter.y + tile.size.height/2))
let topRight = float2(CGPointMake((tileCenter.x + tile.size.width/2, tileCenter.y + tile.size.height/2))
let topLeft = float2(CGPointMake((tileCenter.x - tile.size.width/2, tileCenter.y + tile.size.height/2))
var vertices = [topLeft , bottomLeft , bottomRight , topRight ]
let obstacle = GKPolygonObstacle(points: &vertices, count: 4)
obstacleGraph.add(obstacle)
}
}
However, when i run the app it shows that there are over 80000 nodes, way too many pathfinding pathes.
Any help would be appreciated.
I'm not certain that GKObstacleGraph is the right choice of graph here. According to the GameplayKit documentation:
For example, you can design a level with the SpriteKit Scene Editor in Xcode and use physics bodies to mark regions that the player (or other game entities) cannot pass through, then use the obstaclesFromNodePhysicsBodies: method to generate GKPolygonObstacle objects marking impassable regions.
The function obstaclesFromNodePhysicsBodies is used like this to extract obstacles and create the graph;
let obstacles = SKNode.obstaclesFromNodePhysicsBodies(self.children)
graph = GKObstacleGraph(obstacles: obstacles, bufferRadius: 0.0)
For a SKTilemapNode representing a cartesian grid, the GKGridGraph seems the likely choice.

How to draw real world coordinates rotated relative to the device around a center coordinate?

I'm working on a simple location-aware game where the current location of the user is shown on a game map, as well as the locations of other players around him. It's not using MKMapView but a custom game map with no streets.
How can I translate the other lat/long coordinates of other players into CGPoint values to represent them in the world scale game map with a fixed scale like 50 meters = 50 points in screen, and orient all the points such that the user can see in which direction he would have to go to reach another player?
The key goal is to generate CGPoint values for lat/long coordinates for a flat top-down view, but orient the points around the users current location similar to the orient map feature (the arrow) of Google Maps so you know where is what.
Are there frameworks which do the calculations?
first you have to transform lon/lat to cartesian x,y in meters.
next is the direction in degrees to your other players. the direction is dy/dx where dy = player2.y to me.y, same for dx. normalize dy and dx by this value by dividing by distance between playerv2 and me.
you receive
ny = dy / sqrt(dx*dx + dy*dy)
nx = dx / sqrt(dx*dx + dy*dy)
multipl with 50. now you have a point 50 m in direction of the player2:
comp2x = 50 * nx;
comp2y = 50 * ny;
now center the map on me.x/me.y. and apply the screen to meter scale
You want MKMapPointForCoordinate from MapKit. This converts from latitude-longitude pairs to a flat surface defined by an x and y. Take a look at the documentation for MKMapPoint which describes the projection. You can then scale and rotate those x,y pairs into CGPoints as needed for your display. (You'll have to experiment to see what scaling factors work for your game.)
To center the points around your user, just subtract the value of their x and y position (in MKMapPoints) from the points of all other objects. Something like:
MKMapPoint userPoint = MKMapPointForCoordinate(userCoordinate);
MKMapPoint otherObjectPoint = MKMapPointForCoordinate(otherCoordinate);
otherObjectPoint.x -= userPoint.x; // center around your user
otherObjectPoint.y -= userPoint.y;
CGPoint otherObjectCenter = CGPointMake(otherObjectPoint.x * 0.001, otherObjectPoint.y * 0.001);
// Using (50, 50) as an example for where your user view is placed.
userView.center = CGPointMake(50, 50);
otherView.center = CGPointMake(50 + otherObjectCenter.x, 50 + otherObjectCenter.y);