Finding coordinates from heading and distance in R - distance

I want to get the coordinates of new points, preferably using the sf package, when the inital positions and the distance and heading traveled is known.
Consider this; we have three points (pts), with a heading and a distance in km attached. How to find the coordinates for the new positions?
library(data.table, dplyr, sf)
dat <- data.table(lon = c(10,10.1,10.4), lat = c(58.4,57.4,57.8),
heading = c(45,10,235), distance_km = c(1,5.3,3))
pts <- dat %>%
sf::st_as_sf(coords = c("lon","lat")) %>%
sf::st_set_crs(4326)
Simple feature collection with 3 features and 2 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 10 ymin: 57.4 xmax: 10.4 ymax: 58.4
Geodetic CRS: WGS 84
heading distance_km geometry
1 45 1.0 POINT (10 58.4)
2 10 5.3 POINT (10.1 57.4)
3 235 3.0 POINT (10.4 57.8)
Was considering making circles around the points, but dont know how to connect the point to the circle with the correct heading.
buf <- st_buffer(pts, dist = pts$distance_km*1000)
circ <- st_cast(buf, "LINESTRING")

Found the answer here: Calculate coordinate from starting point, having distance and an angle for all quadrants and here:
Convert radians to degree / degree to radians
Will post my R solution for completeness. If anyone has a better or more smooth solution, feel free to post it.
library(data.table, sf, mapview)
dat <- data.table(lon = c(10,10.1,10.4), lat = c(58.4,57.4,57.8),
heading = c(45,10,235), distance_km = c(1,5.3,3))
pts <- dat %>%
sf::st_as_sf(coords = c("lon","lat")) %>%
sf::st_set_crs(4326)
pts <- st_transform(pts, 32632)
pts$utm_n <- st_coordinates(pts)[,1]
pts$utm_e <- st_coordinates(pts)[,2]
buf <- st_buffer(pts, dist = pts$distance_km*1000)
circ <- st_cast(buf, "LINESTRING")
rad2deg <- function(rad) {(rad * 180) / (pi)}
deg2rad <- function(deg) {(deg * pi) / (180)}
pts$newp_e <- pts$utm_e + (pts$distance_km*1000* cos(deg2rad(pts$heading)))
pts$newp_n <- pts$utm_n + (pts$distance_km*1000* sin(deg2rad(pts$heading)))
dt <- data.table(pts)
pts2 <- dt %>%
sf::st_as_sf(coords = c("newp_n", "newp_e")) %>%
sf::st_set_crs(32632)
mapview(pts2) + mapview(pts, zcol = "heading") + mapview(circ)

Related

Compute coordinates position with projection

Given 2 coordinates (point 1 and 2 in red) in WGS84 I need to find the coordinates of the point perpendicular (point 3) to the line at a given distance.
I could manage to make the math to compute this perpendicular point, but when displayed on the map, the point seems to be at a wrong place, probably because of the projection.
What I want on a map:
And what I have instead on the map:
How can I take into account the projection so that the point on the map appears perpendicular to the line? The algorithm below to compute the point comes from here: https://math.stackexchange.com/questions/93424/calculate-rectangle-coordinates-from-line-and-height
public static Coords ComputePerpendicularPoint(Coords first, Coords last, double distance)
{
double slope = -(last.Lon.Value - first.Lon.Value) / (last.Lat.Value - first.Lat.Value);
// number of km per degree = ~111km (111.32 in google maps, but range varies between 110.567km at the equator and 111.699km at the poles)
// 1km in degree = 1 / 111.32km = 0.0089
// 1m in degree = 0.0089 / 1000 = 0.0000089
distance = distance * 0.0000089 / 100; //0.0000089 => represents around 1m in wgs84. /100 because distance is in cm
double t = distance / Math.Sqrt(1 + (slope * slope));
Coords perp_coord = new Coords();
perp_coord.Lon = first.Lon + t;
perp_coord.Lat = first.Lat + (t * slope);
return perp_coord;
}
Thank you in advance!

Find pixel coordinate of world/geographic coordinate in tile

I'm trying to use Mapbox Terrain RGB to get elevation for specific points in space. I used mercantile.tile to get the coordinates of the tile containing my point at zoom level 15, which for -43º, -22º (for simplicity sake) is 12454, 18527, then mercantile.xy to get the corresponding world coordinates: -4806237.7150042495, -2621281.2257876047.
Shouldn't the integer part of -4806237.7150042495 / 256 (tile size) equal the x coordinate of the tile containing the point, that is, 12454? If this calculation checked out I'd figure that I'm looking for the pixel column (x axis) corresponding to the decimal part of the result, like column 127(256 * 0,5) for 12454,5. However, the division results in -18774.366, (which is curiously close to the tile y coordinate, but it looks like a coincidence). What am I missing here?
As an alternative, I thought of using mercantile.bounds, assigning the first and last pixel columns to the westmost and eastmost longitudes, and finding my position with interpolation, but I wanted to check if I'm doing this the right/recommended way. I'm interested in point elevations, so everything said here goes for the Y axis as well.
Here's what I got so far:
def correct_altitude_mode(kml):
with open(kml, "r+") as f:
txt = f.read()
if re.search("(?<=<altitudeMode>)relative(?=<\/altitudeMode>)", txt):
lat = round(float(find_with_re("latitude", txt)), 5)
lng = round(float(find_with_re("longitude", txt)), 5)
alt = round(float(find_with_re("altitude", txt)), 5)
z = 15
tile = mercantile.tile(lng, lat, z)
westmost, southmost, eastmost, northmost = mercantile.bounds(tile)
pixel_column = np.interp(lng, [westmost, eastmost], [0,256])
pixel_row = np.interp(lat, [southmost, northmost], [256, 0])
response = requests.get(f"https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{tile.x}/{tile.y}.pngraw?access_token=pk.eyJ1IjoibWFydGltcGFzc29zIiwiYSI6ImNra3pmN2QxajBiYWUycW55N3E1dG1tcTEifQ.JFKSI85oP7M2gbeUTaUfQQ")
buffer = BytesIO(response.content)
tile_img = png.read_png_int(buffer)
_,R,G,B = (tile_img[int(pixel_row), int(pixel_column)])
print(tile_img[int(pixel_row), int(pixel_column)])
height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
print(f"R:{R},G:{G},B:{B}\n{height}")
plt.hlines(pixel_row, 0.0, 256.0, colors="r")
plt.vlines(pixel_column, 0.0, 256.0, colors="r")
plt.imshow(tile_img)

Leaflet LatLng coordinates to xy map

How leaflet does to calculate the x y coordinates of the tiles from zoom z, latitude and longitude coordinates ?
what is the formula please?
Thank you
You can use map.latlngtoContainerPoint(latlng) but when you want the formular you can look into the src
Leafet/Map.js#L1071 --> Leafet/Map.js#L1014
In case you are referring to computation of tile z x y "coordinates" / names, then there is a very simple algorithm, as described on OpenStreetMap wiki about slippy maps: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
Lon./lat. to tile numbers
n = 2 ^ zoom
xtile = n * ((lon_deg + 180) / 360)
ytile = n * (1 - arsinh(tan(lat_rad)) / π)) / 2
With arsinh being the Inverse hyperbolic sine
Some background explanation:
X goes from 0 (left edge is 180 °W) to 2zoom − 1 (right edge is 180 °E)
Y goes from 0 (top edge is 85.0511 °N) to 2zoom − 1 (bottom edge is 85.0511 °S) in a Mercator projection
See the wiki page for further explanation and details, as well as some code in different programming languages.

Manually building Hexagonal Torus

I am interested in building a hexagonal Torus using a mesh of points?
I think I can start with a 2-d polygon, and then iterate 360 times (1 deg resolution) to build a complete solid.
Is this the best way to do this? What I'm really after is building wing profiles with variable cross section geometry over it's span.
In Your way You can do this with polyhedron(). Add an appropriate number of points per profile in defined order to a vector „points“, define faces by the indices of the points in a second vector „faces“ and set both vectors as parameter in polyhedron(), see documentation. You can control the quality of the surface by the number of points per profile and the distance between the profiles (sectors in torus).
Here an example code:
// parameter:
r1 = 20; // radius of torus
r2 = 4; // radius of polygon/ thickness of torus
s = 360; // sections per 360 deg
p = 6; // points on polygon
a = 30; // angle of the first point on Polygon
// points on cross-section
// angle = 360*i/p + startangle, x = r2*cos(angle), y = 0, z = r2*sin(angle)
function cs_point(i) = [r1 + r2*cos(360*i/p + a), 0, r2*sin(360*i/p + a)];
// returns to the index in the points - vector the section number and the number of the point on this section
function point_index(i) = [floor(i/p), i - p*floor(i/p)];
// returns the points x-, y-, z-coordinates by rotatating the corresponding point from crossection around the z-axis
function iterate_cs(i) = [cs[point_index(i)[1]][0]*cos(360*floor(i/p)/s), cs[point_index(i)[1]][0]*sin(360*floor(i/p)/s), cs[point_index(i)[1]][2]];
// for every point find neighbour points to build faces, ( + p: point on the next cross-section), points ordered clockwise
// to connect point on last section to corresponding points on first section
function item_add1(i) = i >= (s - 1)*p ? -(s)*p : 0;
// to connect last point on section to first points on the same and the next section
function item_add2(i) = i - p*floor(i/p) >= p-1 ? -p : 0;
// build faces
function find_neighbours1(i) = [i, i + 1 + item_add2(i), i + 1 + item_add2(i) + p + item_add1(i)];
function find_neighbours2(i) = [i, i + 1 + + item_add2(i) + p + item_add1(i), i + p + item_add1(i)];
cs = [for (i = [0:p-1]) cs_point(i)];
points = [for (i = [0:s*p - 1]) iterate_cs(i)];
faces1 = [for (i = [0:s*p - 1]) find_neighbours1(i)];
faces2 = [for (i = [0:s*p - 1]) find_neighbours2(i)];
faces = concat(faces1, faces2);
polyhedron(points = points, faces = faces);
here the result:
Since openscad 2015-03 faces can have more than 3 points, if all points of the face are on the same plane. So in this case faces could be build in one step too.
Are you building smth. like NACA airfoils? https://en.wikipedia.org/wiki/NACA_airfoil
There are a few OpenSCAD designs for those floating around, see e.g. https://www.thingiverse.com/thing:898554

Run a geospatial query in memory using Scala

Is there a way to run in Scala a geospatial query, given a set of lat/lon coordinates, to find nearest by distance? The query needs to run in memory possibly.
The set of values is roughly 1 million lon/lat coordinates. I am trying to do that in Spark but the only solution I have found is Magellan but I cannot make it even work for Spark 1.6 and Scala 2.11 so I am trying customized solution.
Example of query: Given one point in wgs84 coordinates and the 1 million set of wsg84 coords, I want the nearest 15 coords in a radius of one mile.
Here is a library with RTree implemetation that can be used for indexing of geo data in Scala: https://github.com/davidmoten/rtree
Just select by bounding box rectangle(s) for your point which will be center of a circle with given radius (distance in your case) and then filter points by the distance to cut out false positives in corners of bounding boxes and then sort results by already calculated distance to take required the nearest 15.
You can use the ‘haversine’ formula to check distance condition between points (see description here http://www.movable-type.co.uk/scripts/latlong.html):
import java.lang.Math._
import com.github.davidmoten.rtree.geometry.{Point, Rectangle}
import com.github.davidmoten.rtree.geometry.Geometries._
def distance(p1: Point, p2: Point): Double = {
val radLon1 = toRadians(p1.x)
val radLat1 = toRadians(p1.y)
val radLon2 = toRadians(p2.x)
val radLat2 = toRadians(p2.y)
val x = sin((radLon2 - radLon1) * 0.5)
val y = sin((radLat2 - radLat1) * 0.5)
val a = y * y + cos(radLat1) * cos(radLat2) * x * x
atan2(sqrt(a), sqrt(1 - a)) * 12756274 // The Earth diameter in meters
}
For calculation of bounding boxes use following function:
def boundingRectangles(c: Point, r: Double): List[Rectangle] = {
val radLon = toRadians(c.x)
val radLat = toRadians(c.y)
val radDist = r / 6378137 // The Earth radius in meters
val lat1 = toDegrees(radLat - radDist)
val lat2 = toDegrees(radLat + radDist)
if (lat1 > -90 && lat2 < 90) {
val deltaLon = asin(sin(radDist) / cos(radLat))
val lon1 = toDegrees(radLon - deltaLon)
val lon2 = toDegrees(radLon + deltaLon)
if (lon1 < -180) rectangle(-180, lat1, lon2, lat2) :: rectangle(lon1 + 360, lat1, 180, lat2) :: Nil
else if (lon2 > 180) rectangle(-180, lat1, lon2 - 360, lat2) :: rectangle(lon1, lat1, 180, lat2) :: Nil
else rectangle(lon1, lat1, lon2, lat2) :: Nil
} else rectangle(-180, max(lat1, -90), 180, min(lat2, 90)) :: Nil
}
List of rectangles required for case when a circle is crossed by the date change meridian, because the RTree doesn't support wrapping of geo-coordinates over the Earth, so we split that rectangles on two by the date change meridian.
Formula and description are here http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#Longitude
EDIT: Finally we ended up to have our own version of the immutable RTree with STR packing that is tuned for efficient window and knn queries on both plane and spherical geometries:
https://github.com/plokhotnyuk/rtree2d
if you want arbitrary datums then you probably need a library but if it is just distance in wgs84 it is a straight forward formula see for example the response to Calculate distance in meters when you know longitude and latitude in java