39#define DEG2RAD(x)    ((x)*M_PI/180) 
   40#define RAD2DEG(r) (180.0 * (r) / M_PI) 
   41#define POW2(x) ((x)*(x)) 
   48  mInvFlattening = -1.0;
 
 
   57  : mCoordTransform( other.mCoordTransform )
 
   58  , mEllipsoid( other.mEllipsoid )
 
   59  , mSemiMajor( other.mSemiMajor )
 
   60  , mSemiMinor( other.mSemiMinor )
 
   61  , mInvFlattening( other.mInvFlattening )
 
 
   68  mCoordTransform = other.mCoordTransform;
 
   69  mEllipsoid = other.mEllipsoid;
 
   70  mSemiMajor = other.mSemiMajor;
 
   71  mSemiMinor = other.mSemiMinor;
 
   72  mInvFlattening = other.mInvFlattening;
 
 
  107    setFromParams( params );
 
 
  117  mSemiMajor = semiMajor;
 
  118  mSemiMinor = semiMinor;
 
  119  mInvFlattening = mSemiMajor / ( mSemiMajor - mSemiMinor );
 
 
  126double QgsDistanceArea::measure( 
const QgsAbstractGeometry *geomV2, MeasureType type )
 const 
  133  const int geomDimension = geomV2->
dimension();
 
  134  if ( geomDimension <= 0 )
 
  139  MeasureType measureType = type;
 
  140  if ( measureType == Default )
 
  142    measureType = ( geomDimension == 1 ? Length : Area );
 
  148    if ( measureType == Length )
 
  154      return geomV2->
area();
 
  166        sum += measure( collection->
geometryN( i ), measureType );
 
  171    if ( measureType == Length )
 
  173      const QgsCurve *curve = qgsgeometry_cast<const QgsCurve *>( geomV2 );
 
  186      const QgsSurface *surface = qgsgeometry_cast<const QgsSurface *>( geomV2 );
 
  213  return measure( geomV2, Area );
 
 
  222  return measure( geomV2, Length );
 
 
  231  if ( !geomV2 || geomV2->
dimension() < 2 )
 
  242  QVector< const QgsSurface * > surfaces;
 
  243  const QgsSurface *surf = qgsgeometry_cast<const QgsSurface *>( geomV2 );
 
  246    surfaces.append( surf );
 
  248  const QgsMultiSurface *multiSurf = qgsgeometry_cast<const QgsMultiSurface *>( geomV2 );
 
  251    surfaces.reserve( ( surf ? 1 : 0 ) + multiSurf->
numGeometries() );
 
  259  QVector<const QgsSurface *>::const_iterator surfaceIt = surfaces.constBegin();
 
  260  for ( ; surfaceIt != surfaces.constEnd(); ++surfaceIt )
 
  271      length += measure( outerRing );
 
  274    for ( 
int i = 0; i < nInnerRings; ++i )
 
 
  291  QVector<QgsPointXY> linePoints;
 
  292  curve->
points( linePointsV2 );
 
  299  if ( points.size() < 2 )
 
  309    Q_ASSERT_X( 
static_cast<bool>( mGeod ), 
"QgsDistanceArea::measureLine()", 
"Error creating geod_geodesic object" );
 
  317      p1 = mCoordTransform.
transform( points[0] );
 
  321    for ( QVector<QgsPointXY>::const_iterator i = points.constBegin(); i != points.constEnd(); ++i )
 
  330        geod_inverse( mGeod.get(), p1.
y(), p1.
x(), p2.
y(), p2.
x(), &distance, &azimuth1, &azimuth2 );
 
  347    QgsMessageLog::logMessage( QObject::tr( 
"Caught a coordinate system exception while trying to transform a point. Unable to calculate line length." ) );
 
 
  361    Q_ASSERT_X( 
static_cast<bool>( mGeod ), 
"QgsDistanceArea::measureLine()", 
"Error creating geod_geodesic object" );
 
  373      QgsDebugMsgLevel( QStringLiteral( 
"Ellipsoidal calculations is enabled, using ellipsoid %1" ).arg( mEllipsoid ), 4 );
 
  378      QgsDebugMsgLevel( QStringLiteral( 
"New points are %1 and %2, calculating..." ).arg( pp1.
toString( 4 ), pp2.toString( 4 ) ), 4 );
 
  382      geod_inverse( mGeod.get(), pp1.
y(), pp1.
x(), pp2.y(), pp2.x(), &result, &azimuth1, &azimuth2 );
 
  386      QgsDebugMsgLevel( QStringLiteral( 
"Cartesian calculation on canvas coordinates" ), 4 );
 
  393    QgsMessageLog::logMessage( QObject::tr( 
"Caught a coordinate system exception while trying to transform a point. Unable to calculate line length." ) );
 
 
  417    p2 = p1.
project( distance, azimuth );
 
  419  QgsDebugMsgLevel( QStringLiteral( 
"Converted distance of %1 %2 to %3 distance %4 %5, using azimuth[%6] from point[%7] to point[%8] sourceCrs[%9] mEllipsoid[%10] isGeographic[%11] [%12]" )
 
  420                    .arg( QString::number( distance, 
'f', 7 ),
 
  422                          QString::number( result, 
'f', 7 ),
 
  423                          mCoordTransform.
sourceCrs().
isGeographic() ? QStringLiteral( 
"Geographic" ) : QStringLiteral( 
"Cartesian" ),
 
  431                    .arg( QStringLiteral( 
"SemiMajor[%1] SemiMinor[%2] InvFlattening[%3] " ).arg( QString::number( mSemiMajor, 
'f', 7 ), QString::number( mSemiMinor, 
'f', 7 ), QString::number( mInvFlattening, 
'f', 7 ) ) ), 4 );
 
  432  if ( projectedPoint )
 
 
  440  const QgsPointXY &p1, 
double distance, 
double azimuth )
 const 
  450  geod_direct( mGeod.get(), p1.
y(), p1.
x(), 
RAD2DEG( azimuth ), distance, &lat2, &lon2, &azimuth2 );
 
 
  460    p1.
setX( p1.
x() + 360 );
 
  462    p2.
setX( p2.
x() + 360 );
 
  465  double p1x = p1.
x() < 180 ? p1.
x() : p2.
x();
 
  466  double p1y = p1.
x() < 180 ? p1.
y() : p2.
y();
 
  467  double p2x = p1.
x() < 180 ? p2.
x() : p1.
x();
 
  468  double p2y = p1.
x() < 180 ? p2.
y() : p1.
y();
 
  476    fractionAlongLine = ( 180 - p1x ) / ( p2x - p1x );
 
  478      fractionAlongLine = 1 - fractionAlongLine;
 
  479    return p1y + ( 180 - p1x ) / ( p2x - p1x ) * ( p2y - p1y );
 
  484  Q_ASSERT_X( 
static_cast<bool>( mGeod ), 
"QgsDistanceArea::latitudeGeodesicCrossesAntimeridian()", 
"Error creating geod_geodesic object" );
 
  488  geod_geodesicline line;
 
  489  geod_inverseline( &line, mGeod.get(), p1y, p1x, p2y, p2x, GEOD_ALL );
 
  491  const double totalDist = line.s13;
 
  492  double intersectionDist = line.s13;
 
  497  while ( std::fabs( lon - 180.0 ) > 0.00000001 && iterations < 100 )
 
  499    if ( iterations > 0 && std::fabs( p2x - p1x ) > 5 )
 
  512      QgsDebugMsgLevel( QStringLiteral( 
"Narrowed window to %1, %2 - %3, %4" ).arg( p1x ).arg( p1y ).arg( p2x ).arg( p2y ), 4 );
 
  514      geod_inverseline( &line, mGeod.get(), p1y, p1x, p2y, p2x, GEOD_ALL );
 
  515      intersectionDist = line.s13 * 0.5;
 
  522      intersectionDist *= ( 180.0 - p1x ) / ( lon - p1x );
 
  527    geod_position( &line, intersectionDist, &lat, &lon, &t );
 
  533    QgsDebugMsgLevel( QStringLiteral( 
"After %1 iterations lon is %2, lat is %3, dist from p1: %4" ).arg( iterations ).arg( lon ).arg( lat ).arg( intersectionDist ), 4 );
 
  536  fractionAlongLine = intersectionDist / totalDist;
 
  538    fractionAlongLine = 1 - fractionAlongLine;
 
 
  554  std::unique_ptr< QgsMultiLineString > res = std::make_unique< QgsMultiLineString >();
 
  557    const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( *part );
 
  565    const std::unique_ptr< QgsLineString > l = std::make_unique< QgsLineString >();
 
  572      QVector< QgsPoint > newPoints;
 
  580      for ( 
int i = 0; i < line->
numPoints(); i++ )
 
  586          x = std::fmod( x, 360.0 );
 
  597        if ( i > 0 && ( ( prevLon < -120 && lon > 120 ) || ( prevLon > 120 && lon  < -120 ) ) )
 
  606            z = prevZ + ( p.
z() - prevZ ) * fract;
 
  610            m = prevM + ( p.
m() - prevM ) * fract;
 
  614          if ( prevLon < -120 )
 
  619          QgsPoint newPoint( antiMeridianPoint );
 
  625          if ( std::isfinite( newPoint.
x() ) && std::isfinite( newPoint.
y() ) )
 
  627            newPoints << newPoint;
 
  632          newPoints.reserve( line->
numPoints() - i + 1 );
 
  639          if ( std::isfinite( antiMeridianPoint.
x() ) && std::isfinite( antiMeridianPoint.
y() ) )
 
  643            newPoint.
setX( antiMeridianPoint.
x() );
 
  644            newPoint.
setY( antiMeridianPoint.
y() );
 
  645            newPoints << newPoint;
 
  661      QgsMessageLog::logMessage( QObject::tr( 
"Caught a coordinate system exception while trying to transform linestring. Unable to calculate break point." ) );
 
  662      res->addGeometry( line->
clone() );
 
 
  675    return QVector< QVector< QgsPointXY > >() << ( QVector< QgsPointXY >() << p1 << p2 );
 
  681    return QVector< QVector< QgsPointXY > >();
 
  691    QgsMessageLog::logMessage( QObject::tr( 
"Caught a coordinate system exception while trying to transform a point. Unable to calculate geodesic line." ) );
 
  692    return QVector< QVector< QgsPointXY > >();
 
  695  geod_geodesicline line;
 
  696  geod_inverseline( &line, mGeod.get(), pp1.y(), pp1.x(), pp2.y(), pp2.x(), GEOD_ALL );
 
  697  const double totalDist = line.s13;
 
  699  QVector< QVector< QgsPointXY > > res;
 
  700  QVector< QgsPointXY > currentPart;
 
  703  double prevLon = pp1.
x();
 
  704  double prevLat = pp1.y();
 
  705  bool lastRun = 
false;
 
  719      geod_position( &line, d, &lat, &lon, &t );
 
  722    if ( breakLine && ( ( prevLon < -120 && lon > 120 ) || ( prevLon > 120 && lon < -120 ) ) )
 
  733        if ( prevLon < -120 )
 
  738        if ( std::isfinite( p.
x() ) && std::isfinite( p.
y() ) )
 
  756        if ( std::isfinite( p.
x() ) && std::isfinite( p.
y() ) )
 
  782    if ( d >= totalDist )
 
 
  808  curve->
points( linePointsV2 );
 
  809  QVector<QgsPointXY> linePoints;
 
  821      QVector<QgsPointXY> pts;
 
  822      for ( QVector<QgsPointXY>::const_iterator i = points.constBegin(); i != points.constEnd(); ++i )
 
  824        pts.append( mCoordTransform.
transform( *i ) );
 
  826      return computePolygonArea( pts );
 
  830      return computePolygonArea( points );
 
  836    QgsMessageLog::logMessage( QObject::tr( 
"Caught a coordinate system exception while trying to transform a point. Unable to calculate polygon area." ) );
 
 
  854    Q_ASSERT_X( 
static_cast<bool>( mGeod ), 
"QgsDistanceArea::bearing()", 
"Error creating geod_geodesic object" );
 
  861    geod_inverse( mGeod.get(), pp1.
y(), pp1.
x(), pp2.y(), pp2.x(), &distance, &azimuth1, &azimuth2 );
 
  867    const double dx = p2.
x() - p1.
x();
 
  868    const double dy = p2.
y() - p1.
y();
 
  873    bearing = std::atan2( dx, dy );
 
 
  879void QgsDistanceArea::computeAreaInit()
 const 
  888  mGeod.reset( 
new geod_geodesic() );
 
  889  geod_init( mGeod.get(), mSemiMajor, 1 / mInvFlattening );
 
  908double QgsDistanceArea::computePolygonArea( 
const QVector<QgsPointXY> &points )
 const 
  910  if ( points.isEmpty() )
 
  918    return computePolygonFlatArea( points );
 
  923  Q_ASSERT_X( 
static_cast<bool>( mGeod ), 
"QgsDistanceArea::computePolygonArea()", 
"Error creating geod_geodesic object" );
 
  927  struct geod_polygon p;
 
  928  geod_polygon_init( &p, 0 );
 
  930  const bool isClosed = points.constFirst() == points.constLast();
 
  935  int i = points.size();
 
  936  while ( ( isClosed && --i ) || ( !isClosed && --i >= 0 ) )
 
  937    geod_polygon_addpoint( mGeod.get(), &p, points.at( i ).y(), points.at( i ).x() );
 
  940  double perimeter = 0;
 
  941  geod_polygon_compute( mGeod.get(), &p, 0, 1, &area, &perimeter );
 
  943  return std::fabs( area );
 
  946double QgsDistanceArea::computePolygonFlatArea( 
const QVector<QgsPointXY> &points )
 const 
  952  size = points.size();
 
  955  for ( i = 0; i < size; i++ )
 
  960    area = area + points[i].x() * points[( i + 1 ) % size].y() - points[( i + 1 ) % size].x() * points[i].y();
 
  964  return std::fabs( area ); 
 
  983  const double result = length * factorUnits;
 
  984  QgsDebugMsgLevel( QStringLiteral( 
"Converted length of %1 %2 to %3 %4" ).arg( length )
 
 
  997  const double result = area * factorUnits;
 
  998  QgsDebugMsgLevel( QStringLiteral( 
"Converted area of %1 %2 to %3 %4" ).arg( area )
 
 
DistanceUnit
Units of distance.
@ SquareMeters
Square meters.
@ Reverse
Reverse/inverse transform (from destination to source)
Abstract base class for all geometries.
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual double area() const
Returns the planar, 2-dimensional area of the geometry.
This class represents a coordinate reference system (CRS).
QString toProj() const
Returns a Proj string representation of this CRS.
Qgis::DistanceUnit mapUnits
Contains information about the context in which a coordinate transform is executed.
Custom exception class for Coordinate Reference System related exceptions.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
virtual void points(QgsPointSequence &pt) const =0
Returns a list of points within the curve.
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
QgsDistanceArea & operator=(const QgsDistanceArea &other)
double latitudeGeodesicCrossesAntimeridian(const QgsPointXY &p1, const QgsPointXY &p2, double &fractionAlongLine) const
Calculates the latitude at which the geodesic line joining p1 and p2 crosses the antimeridian (longit...
static QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source spatial reference system.
double measureArea(const QgsGeometry &geometry) const
Measures the area of a geometry.
double convertLengthMeasurement(double length, Qgis::DistanceUnit toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
QVector< QVector< QgsPointXY > > geodesicLine(const QgsPointXY &p1, const QgsPointXY &p2, double interval, bool breakLine=false) const
Calculates the geodesic line between p1 and p2, which represents the shortest path on the ellipsoid b...
double measurePerimeter(const QgsGeometry &geometry) const
Measures the perimeter of a polygon geometry.
double measureLength(const QgsGeometry &geometry) const
Measures the length of a geometry.
double bearing(const QgsPointXY &p1, const QgsPointXY &p2) const
Computes the bearing (in radians) between two points.
QString ellipsoid() const
Returns ellipsoid's acronym.
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
QgsGeometry splitGeometryAtAntimeridian(const QgsGeometry &geometry) const
Splits a (Multi)LineString geometry at the antimeridian (longitude +/- 180 degrees).
Qgis::DistanceUnit lengthUnits() const
Returns the units of distance for length calculations made by this object.
double measurePolygon(const QVector< QgsPointXY > &points) const
Measures the area of the polygon described by a set of points.
double measureLineProjected(const QgsPointXY &p1, double distance=1, double azimuth=M_PI_2, QgsPointXY *projectedPoint=nullptr) const
Calculates the distance from one point with distance in meters and azimuth (direction) When the sourc...
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
QgsDistanceArea()
Constructor.
QgsPointXY computeSpheroidProject(const QgsPointXY &p1, double distance=1, double azimuth=M_PI_2) const
Given a location, an azimuth and a distance, computes the location of the projected point.
bool willUseEllipsoid() const
Returns whether calculations will use the ellipsoid.
double convertAreaMeasurement(double area, Qgis::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
static QString formatArea(double area, int decimals, Qgis::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
Qgis::AreaUnit areaUnits() const
Returns the units of area for areal calculations made by this object.
static EllipsoidParameters ellipsoidParameters(const QString &ellipsoid)
Returns the parameters for the specified ellipsoid.
int numGeometries() const
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
void convertToStraightSegment(double tolerance=M_PI/180., QgsAbstractGeometry::SegmentationToleranceType toleranceType=QgsAbstractGeometry::MaximumAngle)
Converts the geometry to straight line segments, if it is a curved geometry type.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
static void convertPointList(const QVector< QgsPointXY > &input, QgsPointSequence &output)
Upgrades a point list from QgsPointXY to QgsPoint.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Line string geometry type, with support for z-dimension and m-values.
bool isEmpty() const override
Returns true if the geometry is empty.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Multi surface geometry collection.
A class to represent a 2D point.
QgsPointXY project(double distance, double bearing) const
Returns a new point which corresponds to this point projected by a specified distance in a specified ...
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
QString asWkt() const
Returns the well known text representation for the point (e.g.
void setX(double x)
Sets the x value of the point.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
void setX(double x)
Sets the point's x-coordinate.
QgsPolygon * surfaceToPolygon() const override
Gets a polygon representation of this surface.
virtual QgsPolygon * surfaceToPolygon() const =0
Gets a polygon representation of this surface.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE QString formatArea(double area, int decimals, Qgis::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
static Q_INVOKABLE Qgis::AreaUnit distanceToAreaUnit(Qgis::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static bool isCurvedType(Qgis::WkbType type)
Returns true if the WKB type is a curved type or can contain curved geometries.
CONSTLATIN1STRING geoNone()
Constant that holds the string representation for "No ellips/No CRS".
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QVector< QgsPoint > QgsPointSequence
#define QgsDebugMsgLevel(str, level)
Contains parameters for an ellipsoid.
double semiMajor
Semi-major axis.
bool valid
Whether ellipsoid parameters are valid.
double semiMinor
Semi-minor axis.
QgsCoordinateReferenceSystem crs
Associated coordinate reference system.
double inverseFlattening
Inverse flattening.
bool useCustomParameters
Whether custom parameters alone should be used (semiMajor/semiMinor only)