I am trying to create a GeoJSON path containing lines of hyperbola, in order to recreate Decca Navigator charts in QGIS, something like this:
The chart has nine lines of hyperbola plotted between each master-slave pair of radio beacons labelled B to J, where the beacons are the focus points.
I've written a C++ program which parses the location of the radio beacons, and attempts to construct the lines of hyperbola as a series of GeoJSON lines, but my maths is wrong and the lines are drawn in the wrong place:
(The red line labelled J should be between the Master and Red beacons, not beyond Red.)
My approach to construct the lines is to plot a series of triangles, where two corners are the radio beacons, and the sides are a ratio of the baseline distance plus an offset. For instance the line labelled G crosses the baseline at 60% of the distance from the master to the slave.
for (auto line = 0; line < 10; line++) {
std::vector<coord> pts;
for (auto pt = -150; pt < 150; pt++) {
if (pt != 0)
pts.emplace_back(
findHyperbolaPoint(masterCoords, slaveCoords, line * 0.1, abs(pt) * pt * -0.00005));
}
deccaLines.emplace_back(linestring(pts));
}
The findHyperbolaPoint
performs these steps using handrolled spherical geometry functions:
- Find arclength between Master and Slave
- Calculate bearing from Master to Slave
- Define the arclength of Projected from Master and from Slave
- Calculate angle between Slave-Master-Projected and hence, the bearing from Master to Projected
- Find the coordinates of Projected by travelling the Master-Projected arclength along that bearing
Evidently something is going wrong at step 5 as the projected point is drawn too far from Master:
coord ptFromBearingArc(coord origin, double bearing_rad, double dist_rad) {
double lat, lon;
lat = asin(sin(origin.lat) * cos(dist_rad) +
cos(origin.lat) * sin(dist_rad) * cos(bearing_rad));
lon = origin.lon + atan2(sin(bearing_rad) * sin(dist_rad) * cos(origin.lat),
cos(dist_rad) - sin(origin.lat) * sin(lat));
return {lat, lon};
}
The formulas appear to be correct but evidently I've gone wrong somewhere. Update: this was due to a simple typo in a function. Which wouldn't have occurred if I'd used a library.
Does my approach look sensible? Are better approaches available for plotting hyperbolae in QGIS?
Are there straightforward lightweight C++ library for spherical geometry calculations and/or WGS84 calculations?