Skip to content
Permalink
Browse files
Cleanup QgsDistanceArea API
- remove methods which accept a QgsGeometry pointer, leave
duplicate methods which accept QgsGeometry reference (caller
should handle null geometry pointers in an acceptable
way instead of just returning 0 measurements)
- make protected members private. This class isn't designed
to be subclassed
- remove some methods not exposed to bindings and not used
anywhere
  • Loading branch information
nyalldawson committed Apr 17, 2017
1 parent 7b202ed commit 4fc49c9613f3c0287aa8d9f6704ee6735ce33dd3
Showing with 35 additions and 244 deletions.
  1. +1 −165 src/core/qgsdistancearea.cpp
  2. +21 −66 src/core/qgsdistancearea.h
  3. +13 −13 tests/src/core/testqgsdistancearea.cpp
@@ -341,15 +341,6 @@ double QgsDistanceArea::measure( const QgsAbstractGeometry *geomV2, MeasureType
}
}

double QgsDistanceArea::measureArea( const QgsGeometry *geometry ) const
{
if ( !geometry )
return 0.0;

const QgsAbstractGeometry *geomV2 = geometry->geometry();
return measure( geomV2, Area );
}

double QgsDistanceArea::measureArea( const QgsGeometry &geometry ) const
{
if ( geometry.isNull() )
@@ -359,15 +350,6 @@ double QgsDistanceArea::measureArea( const QgsGeometry &geometry ) const
return measure( geomV2, Area );
}

double QgsDistanceArea::measureLength( const QgsGeometry *geometry ) const
{
if ( !geometry )
return 0.0;

const QgsAbstractGeometry *geomV2 = geometry->geometry();
return measure( geomV2, Length );
}

double QgsDistanceArea::measureLength( const QgsGeometry &geometry ) const
{
if ( geometry.isNull() )
@@ -377,14 +359,6 @@ double QgsDistanceArea::measureLength( const QgsGeometry &geometry ) const
return measure( geomV2, Length );
}

double QgsDistanceArea::measurePerimeter( const QgsGeometry *geometry ) const
{
if ( !geometry )
return 0.0;

return measurePerimeter( *geometry );
}

double QgsDistanceArea::measurePerimeter( const QgsGeometry &geometry ) const
{
if ( geometry.isNull() )
@@ -529,7 +503,7 @@ double QgsDistanceArea::measureLine( const QgsPoint &p1, const QgsPoint &p2, Qgs
else
{
QgsDebugMsgLevel( "Cartesian calculation on canvas coordinates", 4 );
result = computeDistanceFlat( p1, p2 );
result = p2.distance( p1 );
}
}
catch ( QgsCsException &cse )
@@ -639,100 +613,6 @@ QgsUnitTypes::AreaUnit QgsDistanceArea::areaUnits() const
QgsUnitTypes::distanceToAreaUnit( mCoordTransform.sourceCrs().mapUnits() );
}

QgsConstWkbPtr QgsDistanceArea::measurePolygon( QgsConstWkbPtr wkbPtr, double *area, double *perimeter, bool hasZptr ) const
{
if ( !wkbPtr )
{
QgsDebugMsg( "no feature to measure" );
return wkbPtr;
}

wkbPtr.readHeader();

// get number of rings in the polygon
int numRings;
wkbPtr >> numRings;

if ( numRings == 0 )
{
QgsDebugMsg( "no rings to measure" );
return QgsConstWkbPtr( nullptr, 0 );
}

// Set pointer to the first ring
QList<QgsPoint> points;
QgsPoint pnt;
double x, y;
if ( area )
*area = 0;
if ( perimeter )
*perimeter = 0;

try
{
for ( int idx = 0; idx < numRings; idx++ )
{
int nPoints;
wkbPtr >> nPoints;

// Extract the points from the WKB and store in a pair of
// vectors.
for ( int jdx = 0; jdx < nPoints; jdx++ )
{
wkbPtr >> x >> y;
if ( hasZptr )
{
// totally ignore Z value
wkbPtr += sizeof( double );
}

pnt = QgsPoint( x, y );

if ( mEllipsoidalMode && ( mEllipsoid != GEO_NONE ) )
{
pnt = mCoordTransform.transform( pnt );
}
points.append( pnt );
}

if ( points.size() > 2 )
{
if ( area )
{
double areaTmp = computePolygonArea( points );
if ( idx == 0 )
{
// exterior ring
*area += areaTmp;
}
else
{
*area -= areaTmp; // interior rings
}
}

if ( perimeter )
{
if ( idx == 0 )
{
// exterior ring
*perimeter += computeDistance( points );
}
}
}

points.clear();
}
}
catch ( QgsCsException &cse )
{
Q_UNUSED( cse );
QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate polygon area or perimeter." ) );
}

return wkbPtr;
}

double QgsDistanceArea::measurePolygon( const QgsCurve *curve ) const
{
if ( !curve )
@@ -877,50 +757,6 @@ double QgsDistanceArea::computeDistanceBearing(
return s;
}

double QgsDistanceArea::computeDistanceFlat( const QgsPoint &p1, const QgsPoint &p2 ) const
{
return sqrt( ( p2.x() - p1.x() ) * ( p2.x() - p1.x() ) + ( p2.y() - p1.y() ) * ( p2.y() - p1.y() ) );
}

double QgsDistanceArea::computeDistance( const QList<QgsPoint> &points ) const
{
if ( points.size() < 2 )
return 0;

double total = 0;
QgsPoint p1, p2;

try
{
p1 = points[0];

for ( QList<QgsPoint>::const_iterator i = points.begin(); i != points.end(); ++i )
{
p2 = *i;
if ( mEllipsoidalMode && ( mEllipsoid != GEO_NONE ) )
{
total += computeDistanceBearing( p1, p2 );
}
else
{
total += computeDistanceFlat( p1, p2 );
}

p1 = p2;
}

return total;
}
catch ( QgsCsException &cse )
{
Q_UNUSED( cse );
QgsMessageLog::logMessage( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate line length." ) );
return 0.0;
}
}



///////////////////////////////////////////////////////////
// stuff for measuring areas - copied from GRASS
// don't know how does it work, but it's working .)
@@ -24,7 +24,6 @@
class QgsGeometry;
class QgsAbstractGeometry;
class QgsCurve;
class QgsConstWkbPtr;

/** \ingroup core
General purpose distance and area calculator.
@@ -132,17 +131,6 @@ class CORE_EXPORT QgsDistanceArea
//! returns ellipsoid's inverse flattening
double ellipsoidInverseFlattening() const { return mInvFlattening; }

/** Measures the area of a geometry.
* \param geometry geometry to measure
* \returns area of geometry. For geometry collections, non surface geometries will be ignored. The units for the
* returned area can be retrieved by calling areaUnits().
* \since QGIS 2.12
* \see measureLength()
* \see measurePerimeter()
* \see areaUnits()
*/
double measureArea( const QgsGeometry *geometry ) const;

/** Measures the area of a geometry.
* \param geometry geometry to measure
* \returns area of geometry. For geometry collections, non surface geometries will be ignored. The units for the
@@ -154,17 +142,6 @@ class CORE_EXPORT QgsDistanceArea
*/
double measureArea( const QgsGeometry &geometry ) const;

/** Measures the length of a geometry.
* \param geometry geometry to measure
* \returns length of geometry. For geometry collections, non curve geometries will be ignored. The units for the
* returned distance can be retrieved by calling lengthUnits().
* \since QGIS 2.12
* \see lengthUnits()
* \see measureArea()
* \see measurePerimeter()
*/
double measureLength( const QgsGeometry *geometry ) const;

/** Measures the length of a geometry.
* \param geometry geometry to measure
* \returns length of geometry. For geometry collections, non curve geometries will be ignored. The units for the
@@ -176,17 +153,6 @@ class CORE_EXPORT QgsDistanceArea
*/
double measureLength( const QgsGeometry &geometry ) const;

/** Measures the perimeter of a polygon geometry.
* \param geometry geometry to measure
* \returns perimeter of geometry. For geometry collections, any non-polygon geometries will be ignored. The units for the
* returned perimeter can be retrieved by calling lengthUnits().
* \since QGIS 2.12
* \see lengthUnits()
* \see measureArea()
* \see measurePerimeter()
*/
double measurePerimeter( const QgsGeometry *geometry ) const;

/** Measures the perimeter of a polygon geometry.
* \param geometry geometry to measure
* \returns perimeter of geometry. For geometry collections, any non-polygon geometries will be ignored. The units for the
@@ -224,14 +190,14 @@ class CORE_EXPORT QgsDistanceArea

/**
* Calculates distance from one point with distance in meters and azimuth (direction)
* When the sourceCrs is Geographic, computeSpheroidProject will be called
* When the sourceCrs() is geographic, computeSpheroidProject() will be called
* otherwise QgsPoint.project() will be called after QgsUnitTypes::fromUnitToUnitFactor() has been applied to the distance
* \note:
* The input Point must be in the CoordinateReferenceSystem being used
* The input Point must be in the coordinate reference system being used
* \since QGIS 3.0
* \param p1 start point [can be Cartesian or Geographic]
* \param distance must be in meters
* \param azimuth - azimuth in radians. [default M_PI/2 - East of p1]
* \param azimuth - azimuth in radians, clockwise from North
* \param projectedPoint calculated projected point
* \return distance in mapUnits
* \see sourceCrs()
@@ -303,24 +269,6 @@ class CORE_EXPORT QgsDistanceArea
*/
double convertAreaMeasurement( double area, QgsUnitTypes::AreaUnit toUnits ) const;

protected:
//! measures polygon area and perimeter, vertices are extracted from WKB
// \note not available in Python bindings
QgsConstWkbPtr measurePolygon( QgsConstWkbPtr feature, double *area, double *perimeter, bool hasZptr = false ) const;

/**
* calculates distance from two points on ellipsoid
* based on inverse Vincenty's formulae
*
* Points p1 and p2 are expected to be in degrees and in currently used ellipsoid
*
* \note if course1 is not NULL, bearing (in radians) from first point is calculated
* (the same for course2)
* \returns distance in meters
*/
double computeDistanceBearing( const QgsPoint &p1, const QgsPoint &p2,
double *course1 = nullptr, double *course2 = nullptr ) const;

/**
* Given a location, an azimuth and a distance, computes the
* location of the projected point. Based on Vincenty's formula
@@ -330,9 +278,9 @@ class CORE_EXPORT QgsDistanceArea
* https://git.osgeo.org/gogs/rttopo/librttopo
* - spheroid_project.spheroid_project(...)
* \since QGIS 3.0
* \param p1 - location of first Geographic (lat,long) point as degrees.
* \param distance - distance in meters. [default 1 meter]
* \param azimuth - azimuth in radians. [default M_PI/2 - East of p1]
* \param p1 - location of first geographic (latitude/longitude) point as degrees.
* \param distance - distance in meters.
* \param azimuth - azimuth in radians, clockwise from North
* \return p2 - location of projected point as degrees.
*/

@@ -345,28 +293,35 @@ class CORE_EXPORT QgsDistanceArea
*/
QgsPoint computeSpheroidProject( const QgsPoint &p1, double distance = 1, double azimuth = M_PI / 2 ) const;

//! uses flat / planimetric / Euclidean distance
double computeDistanceFlat( const QgsPoint &p1, const QgsPoint &p2 ) const;
private:

//! calculate distance with given coordinates (does not do a transform anymore)
double computeDistance( const QList<QgsPoint> &points ) const;
/**
* Calculates distance from two points on ellipsoid
* based on inverse Vincenty's formulae
*
* Points p1 and p2 are expected to be in degrees and in currently used ellipsoid
*
* \note if course1 is not NULL, bearing (in radians) from first point is calculated
* (the same for course2)
* \returns distance in meters
*/
double computeDistanceBearing( const QgsPoint &p1, const QgsPoint &p2,
double *course1 = nullptr, double *course2 = nullptr ) const;

/**
* calculates area of polygon on ellipsoid
* Calculates area of polygon on ellipsoid
* algorithm has been taken from GRASS: gis/area_poly1.c
*/
double computePolygonArea( const QList<QgsPoint> &points ) const;

double computePolygonFlatArea( const QList<QgsPoint> &points ) const;

/**
* precalculates some values
* Precalculates some values
* (must be called always when changing ellipsoid)
*/
void computeAreaInit();

private:

enum MeasureType
{
Default,
Loading

0 comments on commit 4fc49c9

Please sign in to comment.