问题
As for my knowledge, there is no built-in feature in OpenLayers to project the straight line of two points into curved line following the curvature of the Earth.
This was a problem when I got a route that was going straight through Madagascar:
Is there any solution on the frontend for this problem, any feature that I missed in OpenLayers, or is there any third-party solution to calculate this.
I know that this kind of calculation is hard on the frontend, and it also depends on the resolution of the dots between two points.
回答1:
I do not believe that openlayers has a packaged solution for this problem. There are options for dealing with this however, one is to use javascript to take two points and return geoJson routes that represent great circle paths.
Using a library such as arc.js, we can plot great circle arcs between two points:
var generator = new arc.GreatCircle({x: -90, y: -70},{x: 89, y: 70}); // points to connect
var n = 50; // n of points
var coords = generator.Arc(n).geometries[0].coords;
var geojson = {"type":"Feature","geometry":{"type":"LineString","coordinates": coords},"properties":null } ;
Then you can pass the geojson on to openlayers. See this gist.
However, as most renderers don't use spherical geometry (instead treating lat,long as cartesian, which explains the straight lines you are trying to avoid), this suggested approach can still lead to long line segments that hit near the north pole, as each segment is still a straight line and the pole itself occupies the entire top/bottom line in what is often the default projection. One solution would be to sample many more points along the line using arc.js, see this gist (better view here, it'll save you the panning up). Though if long line segments persist, this might be fixed by clipping the northern edge of the map, or restricting its visibility.
The alternative is to use a library such as d3, which can be paired with openlayers, and which uses spherical geometry by default ( and consequently is the only library, tool, or program I know of that will make winding order of polygons matter (when using geographic coordinate space, since it doesn't treat geographic coordinates as planar - while technically geojsonlint and other geojson validators will complain if it is wound "wrong", these validators aren't considering that you might be selecting the space on the other side of a polygon's edges)). This is a lower level library, but will offer some more ability to customize the map at the expense of out of the box solutions.
A basic line connecting two points might look like (depending on setup):
var geojson = {"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,50],[-89,50]]},"properties":null };
var feature = svg.append("path")
.datum(geojson)
.attr("d",path);
var width = 600, height = 300;
var svg = d3.select("svg")
.attr("width",width)
.attr("height",height);
var projection = d3.geoMercator() // projection type
.translate([width/2,height/2])
.scale(width/Math.PI/2*0.7)
var path = d3.geoPath().projection(projection) // path generator
var geojson = [
{"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,50],[-89,50]]},"properties":null },
{"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,-50],[-89,50]]},"properties":null }];
var feature = svg.selectAll("path")
.data(geojson)
.enter().append("path")
.attr("d",path)
.attr("stroke","steelblue")
.attr("stroke-width",3)
// Add the world to reference the lines:
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
if (error) throw error;
svg.append("path")
.datum(topojson.mesh(world))
.attr("d",path)
.attr("stroke","#ccc")
.lower();
});
path {
fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.js"></script>
<svg></svg>
来源:https://stackoverflow.com/questions/47053595/how-to-project-two-point-line-on-the-map-into-a-curved-line-openlayers