mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Add method to calculate the geodesic line joining two points to QgsDistanceArea
Using geographiclib to calculate the line
This commit is contained in:
parent
148505d47f
commit
fdea61a97c
@ -353,6 +353,27 @@ Datum of Australia Technical Manual", Chapter 4.
|
||||
--> latitudes outside these bounds cause the calculations to become unstable and can return invalid results
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QList< QList< QgsPointXY > > geodesicLine( const QgsPointXY &p1, const QgsPointXY &p2, double interval, bool breakLine = false ) const;
|
||||
%Docstring
|
||||
Calculates the geodesic line between ``p1`` and ``p2``, which represents the shortest path on the
|
||||
ellipsoid between these two points.
|
||||
|
||||
The ellipsoid settings defined on this QgsDistanceArea object will be used during the calculations.
|
||||
|
||||
``p1`` and ``p2`` must be in the sourceCrs() of this QgsDistanceArea object. The returned line
|
||||
will also be in this same CRS.
|
||||
|
||||
The ``interval`` parameter gives the maximum distance between points on the computed line.
|
||||
This argument is always specified in meters. A shorter distance results in a denser line,
|
||||
at the cost of extra computing time.
|
||||
|
||||
If the geodesic line crosses the international date line and ``breakLine`` is true, then
|
||||
the line will be split into two parts, broken at the date line. In this case the function
|
||||
will return two lines, corresponding to the portions at either side of the date line.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -34,6 +34,9 @@
|
||||
#include "qgsunittypes.h"
|
||||
#include "qgsexception.h"
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
#include <GeographicLib/GeodesicLine.hpp>
|
||||
|
||||
#define DEG2RAD(x) ((x)*M_PI/180)
|
||||
#define RAD2DEG(r) (180.0 * (r) / M_PI)
|
||||
#define POW2(x) ((x)*(x))
|
||||
@ -454,6 +457,66 @@ QgsPointXY QgsDistanceArea::computeSpheroidProject(
|
||||
return QgsPointXY( RAD2DEG( lambda2 ), RAD2DEG( lat2 ) );
|
||||
}
|
||||
|
||||
QList< QList<QgsPointXY> > QgsDistanceArea::geodesicLine( const QgsPointXY &p1, const QgsPointXY &p2, const double interval, const bool breakLine ) const
|
||||
{
|
||||
if ( !willUseEllipsoid() )
|
||||
{
|
||||
return QList< QList< QgsPointXY > >() << ( QList< QgsPointXY >() << p1 << p2 );
|
||||
}
|
||||
|
||||
GeographicLib::Geodesic geod( mSemiMajor, 1 / mInvFlattening );
|
||||
|
||||
QgsPointXY pp1, pp2;
|
||||
try
|
||||
{
|
||||
pp1 = mCoordTransform.transform( p1 );
|
||||
pp2 = mCoordTransform.transform( p2 );
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate geodesic line." ) );
|
||||
return QList< QList< QgsPointXY > >();
|
||||
}
|
||||
|
||||
GeographicLib::GeodesicLine line = geod.InverseLine( pp1.y(), pp1.x(), pp2.y(), pp2.x() );
|
||||
const double totalDist = line.Distance();
|
||||
|
||||
QList< QList< QgsPointXY > > res;
|
||||
QList< QgsPointXY > currentPart;
|
||||
currentPart << p1;
|
||||
double d = interval;
|
||||
double prevLon = p1.x();
|
||||
while ( d < totalDist )
|
||||
{
|
||||
double lat, lon;
|
||||
( void )line.Position( d, lat, lon );
|
||||
|
||||
if ( breakLine && ( ( prevLon < -120 && lon > 120 ) || ( prevLon > 120 && lon < -120 ) ) )
|
||||
{
|
||||
// TODO -- when breaking the geodesic at the date line, we need to calculate the latitude
|
||||
// at which the geodesic intersects the date line, and add points to both line segments at this latitude
|
||||
// on the date line. See Baselga & Martinez-Llario 2017 for an algorithm to calculate geodesic-geodesic intersections on ellipsoids.
|
||||
|
||||
res << currentPart;
|
||||
currentPart.clear();
|
||||
}
|
||||
|
||||
prevLon = lon;
|
||||
|
||||
try
|
||||
{
|
||||
currentPart << mCoordTransform.transform( QgsPointXY( lon, lat ), QgsCoordinateTransform::ReverseTransform );
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point." ) );
|
||||
}
|
||||
d += interval;
|
||||
}
|
||||
res << currentPart;
|
||||
return res;
|
||||
}
|
||||
|
||||
QgsUnitTypes::DistanceUnit QgsDistanceArea::lengthUnits() const
|
||||
{
|
||||
return willUseEllipsoid() ? QgsUnitTypes::DistanceMeters : mCoordTransform.sourceCrs().mapUnits();
|
||||
|
@ -288,6 +288,27 @@ class CORE_EXPORT QgsDistanceArea
|
||||
*/
|
||||
QgsPointXY computeSpheroidProject( const QgsPointXY &p1, double distance = 1, double azimuth = M_PI_2 ) const;
|
||||
|
||||
/**
|
||||
* Calculates the geodesic line between \a p1 and \a p2, which represents the shortest path on the
|
||||
* ellipsoid between these two points.
|
||||
*
|
||||
* The ellipsoid settings defined on this QgsDistanceArea object will be used during the calculations.
|
||||
*
|
||||
* \a p1 and \a p2 must be in the sourceCrs() of this QgsDistanceArea object. The returned line
|
||||
* will also be in this same CRS.
|
||||
*
|
||||
* The \a interval parameter gives the maximum distance between points on the computed line.
|
||||
* This argument is always specified in meters. A shorter distance results in a denser line,
|
||||
* at the cost of extra computing time.
|
||||
*
|
||||
* If the geodesic line crosses the international date line and \a breakLine is true, then
|
||||
* the line will be split into two parts, broken at the date line. In this case the function
|
||||
* will return two lines, corresponding to the portions at either side of the date line.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
QList< QList< QgsPointXY > > geodesicLine( const QgsPointXY &p1, const QgsPointXY &p2, double interval, bool breakLine = false ) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user