41 #define M_PI 3.14159265358979323846 44 #define DEG2RAD(x) ((x)*M_PI/180) 50 mEllipsoidalMode =
false;
59 : mCoordTransform( nullptr )
66 delete mCoordTransform;
72 if (
this == & origDA )
84 mEllipsoidalMode = origDA.mEllipsoidalMode;
85 mEllipsoid = origDA.mEllipsoid;
86 mSemiMajor = origDA.mSemiMajor;
87 mSemiMinor = origDA.mSemiMinor;
88 mInvFlattening = origDA.mInvFlattening;
92 delete mCoordTransform;
98 mEllipsoidalMode = flag;
103 return mEllipsoidalMode && mEllipsoid !=
GEO_NONE;
133 sqlite3_stmt *myPreparedStatement;
150 bool semiMajorOk, semiMinorOk;
151 double semiMajor = paramList[1].toDouble( & semiMajorOk );
152 double semiMinor = paramList[2].toDouble( & semiMinorOk );
153 if ( semiMajorOk && semiMinorOk )
175 QString mySql =
"select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid +
'\'';
176 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
178 if ( myResult == SQLITE_OK )
180 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
182 radius =
QString( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
183 parameter2 =
QString( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
187 sqlite3_finalize( myPreparedStatement );
188 sqlite3_close( myDatabase );
193 QgsDebugMsg(
QString(
"setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
198 if ( radius.
left( 2 ) ==
"a=" )
202 QgsDebugMsg(
QString(
"setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
209 if ( parameter2.
left( 2 ) ==
"b=" )
212 mInvFlattening = mSemiMajor / ( mSemiMajor - mSemiMinor );
214 else if ( parameter2.
left( 3 ) ==
"rf=" )
217 mSemiMinor = mSemiMajor - ( mSemiMajor / mInvFlattening );
221 QgsDebugMsg(
QString(
"setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
225 QgsDebugMsg(
QString(
"setEllipsoid: a=%1, b=%2, 1/f=%3" ).arg( mSemiMajor ).arg( mSemiMinor ).arg( mInvFlattening ) );
229 QString proj4 =
"+proj=longlat +ellps=" + ellipsoid +
" +no_defs";
236 if ( destCRS.
srsid() == 0 )
239 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
261 mEllipsoid =
QString(
"PARAMETER:%1:%2" ).
arg( semiMajor ).
arg( semiMinor );
262 mSemiMajor = semiMajor;
263 mSemiMinor = semiMinor;
264 mInvFlattening = mSemiMajor / ( mSemiMajor - mSemiMinor );
279 if ( geomDimension <= 0 )
284 MeasureType measureType = type;
285 if ( measureType == Default )
287 measureType = ( geomDimension == 1 ? Length : Area );
290 if ( !mEllipsoidalMode || mEllipsoid ==
GEO_NONE )
293 if ( measureType == Length )
299 return geomV2->
area();
316 if ( measureType == Length )
367 return measure( geomV2, Area );
376 return measure( geomV2, Length );
385 if ( !geomV2 || geomV2->
dimension() < 2 )
390 if ( !mEllipsoidalMode || mEllipsoid ==
GEO_NONE )
408 surfaces.
append( static_cast<const QgsSurfaceV2*>( multiSurf->
geometryN( i ) ) );
414 for ( ; surfaceIt != surfaces.
constEnd(); ++surfaceIt )
425 length +=
measure( outerRing );
428 for (
int i = 0; i < nInnerRings; ++i )
446 curve->
points( linePointsV2 );
453 if ( points.
size() < 2 )
461 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
462 p1 = mCoordTransform->
transform( points[0] );
468 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
509 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
578 for (
int idx = 0; idx < numRings; idx++ )
585 for (
int jdx = 0; jdx < nPoints; jdx++ )
591 wkbPtr +=
sizeof( double );
596 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
603 if ( points.
size() > 2 )
649 curve->
points( linePointsV2 );
660 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
688 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
696 double dx = p2.
x() - p1.
x();
697 double dy = p2.
y() - p1.
y();
698 bearing = atan2( dx, dy );
710 double* course1,
double* course2 )
const 716 double a = mSemiMajor;
717 double b = mSemiMinor;
718 double f = 1 / mInvFlattening;
723 double L = p2_lon - p1_lon;
724 double U1 = atan(( 1 - f ) * tan( p1_lat ) );
725 double U2 = atan(( 1 - f ) * tan( p2_lat ) );
726 double sinU1 = sin( U1 ), cosU1 = cos( U1 );
727 double sinU2 = sin( U2 ), cosU2 = cos( U2 );
729 double lambdaP = 2 *
M_PI;
731 double sinLambda = 0;
732 double cosLambda = 0;
737 double cosSqAlpha = 0;
738 double cos2SigmaM = 0;
744 while ( qAbs( lambda - lambdaP ) > 1e-12 && --iterLimit > 0 )
746 sinLambda = sin( lambda );
747 cosLambda = cos( lambda );
748 tu1 = ( cosU2 * sinLambda );
749 tu2 = ( cosU1 * sinU2 - sinU1 * cosU2 * cosLambda );
750 sinSigma = sqrt( tu1 * tu1 + tu2 * tu2 );
751 cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
752 sigma = atan2( sinSigma, cosSigma );
753 alpha = asin( cosU1 * cosU2 * sinLambda / sinSigma );
754 cosSqAlpha = cos( alpha ) * cos( alpha );
755 cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
756 C = f / 16 * cosSqAlpha * ( 4 + f * ( 4 - 3 * cosSqAlpha ) );
758 lambda = L + ( 1 - C ) * f * sin( alpha ) *
759 ( sigma + C * sinSigma * ( cos2SigmaM + C * cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) ) );
762 if ( iterLimit == 0 )
765 double uSq = cosSqAlpha * ( a * a - b * b ) / ( b * b );
766 double A = 1 + uSq / 16384 * ( 4096 + uSq * ( -768 + uSq * ( 320 - 175 * uSq ) ) );
767 double B = uSq / 1024 * ( 256 + uSq * ( -128 + uSq * ( 74 - 47 * uSq ) ) );
768 double deltaSigma = B * sinSigma * ( cos2SigmaM + B / 4 * ( cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) -
769 B / 6 * cos2SigmaM * ( -3 + 4 * sinSigma * sinSigma ) * ( -3 + 4 * cos2SigmaM * cos2SigmaM ) ) );
770 double s = b * A * ( sigma - deltaSigma );
774 *course1 = atan2( tu1, tu2 );
779 *course2 = atan2( cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda ) +
M_PI;
787 return sqrt(( p2.
x() - p1.
x() ) * ( p2.
x() - p1.
x() ) + ( p2.
y() - p1.
y() ) * ( p2.
y() - p1.
y() ) );
792 if ( points.
size() < 2 )
805 if ( mEllipsoidalMode && ( mEllipsoid !=
GEO_NONE ) )
834 double QgsDistanceArea::getQ(
double x )
const 841 return sinx *( 1 + sinx2 *( m_QA + sinx2 *( m_QB + sinx2 * m_QC ) ) );
845 double QgsDistanceArea::getQbar(
double x )
const 852 return cosx *( m_QbarA + cosx2 *( m_QbarB + cosx2 *( m_QbarC + cosx2 * m_QbarD ) ) );
864 double a2 = ( mSemiMajor * mSemiMajor );
865 double e2 = 1 - ( a2 / ( mSemiMinor * mSemiMinor ) );
873 m_AE = a2 * ( 1 - e2 );
875 m_QA = ( 2.0 / 3.0 ) * e2;
876 m_QB = ( 3.0 / 5.0 ) * e4;
877 m_QC = ( 4.0 / 7.0 ) * e6;
879 m_QbarA = -1.0 - ( 2.0 / 3.0 ) * e2 - ( 3.0 / 5.0 ) * e4 - ( 4.0 / 7.0 ) * e6;
880 m_QbarB = ( 2.0 / 9.0 ) * e2 + ( 2.0 / 5.0 ) * e4 + ( 4.0 / 7.0 ) * e6;
881 m_QbarC = - ( 3.0 / 25.0 ) * e4 - ( 12.0 / 35.0 ) * e6;
882 m_QbarD = ( 4.0 / 49.0 ) * e6;
884 m_Qp = getQ( M_PI / 2 );
885 m_E = 4 * M_PI * m_Qp * m_AE;
898 double x1, y1, x2, y2, dx, dy;
903 if (( ! mEllipsoidalMode ) || ( mEllipsoid ==
GEO_NONE ) )
907 int n = points.
size();
908 x2 =
DEG2RAD( points[n-1].x() );
909 y2 =
DEG2RAD( points[n-1].y() );
910 Qbar2 = getQbar( y2 );
914 for (
int i = 0; i < n; i++ )
922 Qbar2 = getQbar( y2 );
925 while ( x1 - x2 >
M_PI )
928 while ( x2 - x1 >
M_PI )
932 area += dx * ( m_Qp - getQ( y2 ) );
936 area += dx * getQ( y2 ) - ( dx / dy ) * ( Qbar2 - Qbar1 );
938 if (( area *= m_AE ) < 0.0 )
948 if ( area > m_E / 2 )
960 size = points.
size();
963 for ( i = 0; i < size; i++ )
968 area = area + points[i].x() * points[( i+1 ) % size].y() - points[( i+1 ) % size].x() * points[i].y();
988 else if ( qAbs( value ) > 1000000.0 )
991 value = value / 1000000.0;
993 else if ( qAbs( value ) > 10000.0 )
996 value = value / 10000.0;
1005 if ( keepBaseUnit || qAbs( value ) == 0.0 )
1009 else if ( qAbs( value ) > 1000.0 )
1012 value = value / 1000;
1014 else if ( qAbs( value ) < 0.01 )
1017 value = value * 1000;
1019 else if ( qAbs( value ) < 0.1 )
1022 value = value * 100;
1033 if ( keepBaseUnit || qAbs( value ) <= 0.5*43560.0 )
1038 else if ( qAbs( value ) <= 0.5*5280.0*5280.0 )
1048 value /= 5280.0 * 5280.0;
1053 if ( qAbs( value ) <= 528.0 || keepBaseUnit )
1055 if ( qAbs( value ) == 1.0 )
1088 if ( qAbs( value ) == 1.0 )
1098 QgsDebugMsg(
QString(
"Error: not picked up map units - actual value = %1" ).arg( u ) );
1102 return QString(
"%L1%2" ).
arg( value, 0,
'f', decimals ).
arg( unitLabel );
1237 return QString(
"%L1%2" ).
arg( area, 0,
'f', decimals ).
arg( unitLabel );
1251 QgsDebugMsg(
"We're measuring on an ellipsoid or using projections, the system is returning meters" );
1253 else if ( mEllipsoidalMode && mEllipsoid ==
GEO_NONE )
1257 QgsDebugMsg(
"We're measuing on planimetric distance/area on given CRS, measured value is in CRS units" );
1263 factorUnits *= factorUnits;
1266 measure *= factorUnits;
1268 measureUnits = displayUnits;
1277 double result = length * factorUnits;
1291 double result = area * factorUnits;
const QgsCurveV2 * exteriorRing() const
double convertLengthMeasurement(double length, QGis::UnitType toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
int numGeometries() const
Returns the number of geometries within the collection.
virtual QgsPolygonV2 * surfaceToPolygon() const =0
const QgsCurveV2 * interiorRing(int i) const
~QgsDistanceArea()
Destructor.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
void computeAreaInit()
precalculates some values (must be called always when changing ellipsoid)
QString toProj4() const
Returns a Proj4 string representation of this CRS.
Abstract base class for all geometries.
A geometry is the spatial representation of a feature.
bool setEllipsoid(const QString &ellipsoid)
Sets ellipsoid by its acronym.
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
double toDouble(bool *ok) const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
QString trUtf8(const char *sourceText, const char *disambiguation, int n)
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
double y() const
Get the y value of the point.
bool willUseEllipsoid() const
Returns whether calculations will use the ellipsoid.
static QString toString(QGis::UnitType unit)
Returns a translated string representing a distance unit.
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
QString number(int n, int base)
bool createFromSrsId(const long theSrsId)
Set up this CRS by fetching the appropriate information from the sqlite backend.
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void append(const T &value)
QGis::UnitType lengthUnits() const
Returns the units of distance for length calculations made by this object.
#define QgsDebugMsgLevel(str, level)
Line string geometry type, with support for z-dimension and m-values.
QGis::UnitType mapUnits() const
Returns the units for the projection used by the CRS.
double bearing(const QgsPoint &p1, const QgsPoint &p2) const
compute bearing - in radians
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
const long GEOCRS_ID
Magic number for a geographic coord sys in QGIS srs.db tbl_srs.srs_id.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
Multi surface geometry collection.
double measureLine(const QList< QgsPoint > &points) const
Measures the length of a line with multiple segments.
double computePolygonFlatArea(const QList< QgsPoint > &points) const
double measurePolygon(const QList< QgsPoint > &points) const
measures polygon area
bool saveAsUserCRS(const QString &name)
Save the proj4-string as a custom CRS.
A class to represent a point.
QString toString() const
String representation of the point (x,y)
static double fromUnitToUnitFactor(QGis::UnitType fromUnit, QGis::UnitType toUnit)
Returns the conversion factor between the specified distance units.
double computePolygonArea(const QList< QgsPoint > &points) const
calculates area of polygon on ellipsoid algorithm has been taken from GRASS: gis/area_poly1.c
virtual double perimeter() const
Returns the perimeter of the geometry.
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
QgsDistanceArea & operator=(const QgsDistanceArea &origDA)
Assignment operator.
static QString textUnit(double value, int decimals, QGis::UnitType u, bool isArea, bool keepBaseUnit=false)
Returns a measurement formatted as a friendly string.
double computeDistanceFlat(const QgsPoint &p1, const QgsPoint &p2) const
uses flat / planimetric / Euclidean distance
General purpose distance and area calculator.
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
QgsUnitTypes::AreaUnit areaUnits() const
Returns the units of area for areal calculations made by this object.
virtual QgsLineStringV2 * curveToLine() const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QString ellipsoid() const
Returns ellipsoid's acronym.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QString mid(int position, int n) const
double computeDistanceBearing(const QgsPoint &p1, const QgsPoint &p2, double *course1=nullptr, double *course2=nullptr) const
calculates distance from two points on ellipsoid based on inverse Vincenty's formulae ...
QgsPolygonV2 * surfaceToPolygon() const override
void convertMeasurement(double &measure, QGis::UnitType &measureUnits, QGis::UnitType displayUnits, bool isArea) const
Helper for conversion between physical units.
static AreaUnit distanceToAreaUnit(QGis::UnitType distanceUnit)
Converts a distance unit to its corresponding area unit, eg meters to square meters.
void setSourceAuthId(const QString &authid)
sets source spatial reference system by authid
Class for storing a coordinate reference system (CRS)
virtual int dimension() const =0
Returns the inherent dimension of the geometry.
virtual double length() const
Returns the length of the geometry.
static QString formatArea(double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
UnitType
Map units that qgis supports.
QString left(int n) const
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
static QString srsDbFilePath()
Returns the path to the srs.db file.
Custom exception class for Coordinate Reference System related exceptions.
QgsWKBTypes::Type readHeader() const
Q_DECL_DEPRECATED double measure(const QgsGeometry *geometry) const
General measurement (line distance or polygon area)
const_iterator constEnd() const
const_iterator constBegin() const
long srsid() const
Returns the SrsId, if available.
Abstract base class for curved geometry type.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QgsDistanceArea()
Constructor.
virtual void points(QgsPointSequenceV2 &pt) const =0
Returns a list of points within the curve.
static void convertPointList(const QList< QgsPoint > &input, QgsPointSequenceV2 &output)
Upgrades a point list from QgsPoint to QgsPointV2.
virtual double area() const
Returns the area of the geometry.
double x() const
Get the x value of the point.
void setEllipsoidalMode(bool flag)
Sets whether coordinates must be projected to ellipsoid before measuring.
double computeDistance(const QList< QgsPoint > &points) const
calculate distance with given coordinates (does not do a transform anymore)
bool createFromProj4(const QString &theProjString)
Set up this CRS by passing it a proj4 style formatted string.
int numInteriorRings() const
QByteArray toUtf8() const