RGeo: Plotting a Great Circle on a Mercator Projection

132 views Asked by At

I need to trace out multiple shapes on a map, each shape is specified as a type of line between two long/lat coordinates. I have been breaking/interpolating/splitting these lines into a series of points that I've been plotting onto Google Maps (via GeoJSON) which uses a Mercator Projection, and storing it within a postgresql-postgis database.

I have solved this problem for Rhumb Lines, and Clockwise Args, but I'm completely lost on how to trace Great Circles. I have been using RGeo to assist with the other line types, and would've expected things to be much easier than I'm finding it.

How do I plot a Great Circle path between two coordinates, with a definable number of steps?

In a fit of late-night coding delirium, I've ported some code samples from C and JavaScript to Ruby. Specifically from OGR It's a mostly-fine solution, but it's not a reliable solution to say the least, as some of the polygon lines I'm building have begun to overlap, or not leave the expected gaps between converging lines.

I think the answer lines within using a Spherical Factory, but attempting to transform the line string from the spherical factory to a mercator factory only gives me a line with two points.

spherical_factory = RGeo::Geographic.spherical_factory(srid: 4326)
point1 = spherical_factory.point(YOUR_LONGITUDE1, YOUR_LATITUDE1)
point2 = spherical_factory.point(YOUR_LONGITUDE2, YOUR_LATITUDE2)
great_circle = spherical_factory.line(point1, point2)
# TODO: Split the great_circle

I've even tried ChatGPT for advice, it gives me wonderful code that calls an LineString#interpolate function that does not exist. I would really like a solution that works as simply as that.

Failing any advice, I might try recursively generating an increasing circle from the start coordinate, and building the line from the intersecting points.

1

There are 1 answers

0
Ben M On

Following some advice, I used PostGIS and the ST_Segmentize function.

As I had a PostgreSQL/PostGIS database, with RGeo's support of WKT, I was able to combine the two into a simple algorithm.

SRID = 4326 # Used by WGS84 / Google Maps

spherical_factory = RGeo::Geographic.spherical_factory(srid: SRID)
mercator_factory = ... # output factory

# Generate a RGeo Line String for the Great Circle
start_point = spherical_factory.point(point.longitude, point.latitude)
target_point = spherical_factory.point(target.longitude, target.latitude)
great_circle = spherical_factory.line_string([start_point, target_point])

# Segment line using 1km chunks
great_circle_as_wkt = "srid=#{SRID};#{great_circle}"
great_circle_segments = ActiveRecord::Base.connection.execute("SELECT ST_AsText(ST_Segmentize(('#{great_circle_as_wkt}'::geography), 1000)) AS circle;").first['circle']

# Convert the WKT Back into a RGeo Line String
segmented_line = RGeo::WKRep::WKTParser.new(mercator_factory).parse(great_circle_segments)

# Desired Output
segmented_line.points

The Spherical Factory probably isn't needed, but would like any additional solution that would use it instead of hitting the database.

This is probably not the most efficient method, but I don't need it to be.