|
34 | 34 | #include "qgsunittypes.h"
|
35 | 35 | #include "qgsexception.h"
|
36 | 36 |
|
| 37 | +#include <GeographicLib/Geodesic.hpp> |
| 38 | +#include <GeographicLib/GeodesicLine.hpp> |
| 39 | + |
37 | 40 | #define DEG2RAD(x) ((x)*M_PI/180)
|
38 | 41 | #define RAD2DEG(r) (180.0 * (r) / M_PI)
|
39 | 42 | #define POW2(x) ((x)*(x))
|
@@ -454,6 +457,66 @@ QgsPointXY QgsDistanceArea::computeSpheroidProject(
|
454 | 457 | return QgsPointXY( RAD2DEG( lambda2 ), RAD2DEG( lat2 ) );
|
455 | 458 | }
|
456 | 459 |
|
| 460 | +QList< QList<QgsPointXY> > QgsDistanceArea::geodesicLine( const QgsPointXY &p1, const QgsPointXY &p2, const double interval, const bool breakLine ) const |
| 461 | +{ |
| 462 | + if ( !willUseEllipsoid() ) |
| 463 | + { |
| 464 | + return QList< QList< QgsPointXY > >() << ( QList< QgsPointXY >() << p1 << p2 ); |
| 465 | + } |
| 466 | + |
| 467 | + GeographicLib::Geodesic geod( mSemiMajor, 1 / mInvFlattening ); |
| 468 | + |
| 469 | + QgsPointXY pp1, pp2; |
| 470 | + try |
| 471 | + { |
| 472 | + pp1 = mCoordTransform.transform( p1 ); |
| 473 | + pp2 = mCoordTransform.transform( p2 ); |
| 474 | + } |
| 475 | + catch ( QgsCsException & ) |
| 476 | + { |
| 477 | + QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate geodesic line." ) ); |
| 478 | + return QList< QList< QgsPointXY > >(); |
| 479 | + } |
| 480 | + |
| 481 | + GeographicLib::GeodesicLine line = geod.InverseLine( pp1.y(), pp1.x(), pp2.y(), pp2.x() ); |
| 482 | + const double totalDist = line.Distance(); |
| 483 | + |
| 484 | + QList< QList< QgsPointXY > > res; |
| 485 | + QList< QgsPointXY > currentPart; |
| 486 | + currentPart << p1; |
| 487 | + double d = interval; |
| 488 | + double prevLon = p1.x(); |
| 489 | + while ( d < totalDist ) |
| 490 | + { |
| 491 | + double lat, lon; |
| 492 | + ( void )line.Position( d, lat, lon ); |
| 493 | + |
| 494 | + if ( breakLine && ( ( prevLon < -120 && lon > 120 ) || ( prevLon > 120 && lon < -120 ) ) ) |
| 495 | + { |
| 496 | + // TODO -- when breaking the geodesic at the date line, we need to calculate the latitude |
| 497 | + // at which the geodesic intersects the date line, and add points to both line segments at this latitude |
| 498 | + // on the date line. See Baselga & Martinez-Llario 2017 for an algorithm to calculate geodesic-geodesic intersections on ellipsoids. |
| 499 | + |
| 500 | + res << currentPart; |
| 501 | + currentPart.clear(); |
| 502 | + } |
| 503 | + |
| 504 | + prevLon = lon; |
| 505 | + |
| 506 | + try |
| 507 | + { |
| 508 | + currentPart << mCoordTransform.transform( QgsPointXY( lon, lat ), QgsCoordinateTransform::ReverseTransform ); |
| 509 | + } |
| 510 | + catch ( QgsCsException & ) |
| 511 | + { |
| 512 | + QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point." ) ); |
| 513 | + } |
| 514 | + d += interval; |
| 515 | + } |
| 516 | + res << currentPart; |
| 517 | + return res; |
| 518 | +} |
| 519 | + |
457 | 520 | QgsUnitTypes::DistanceUnit QgsDistanceArea::lengthUnits() const
|
458 | 521 | {
|
459 | 522 | return willUseEllipsoid() ? QgsUnitTypes::DistanceMeters : mCoordTransform.sourceCrs().mapUnits();
|
|
0 commit comments