35 #define M_PI 3.14159265358979323846
38 #define DEG2RAD(x) ((x)*M_PI/180)
65 if (
this == & origDA )
110 QString radius, parameter2;
116 sqlite3_stmt *myPreparedStatement;
130 if ( ellipsoid.startsWith(
"PARAMETER" ) )
132 QStringList paramList = ellipsoid.split(
":" );
133 bool semiMajorOk, semiMinorOk;
134 double semiMajor = paramList[1].toDouble( & semiMajorOk );
135 double semiMinor = paramList[2].toDouble( & semiMinorOk );
136 if ( semiMajorOk && semiMinorOk )
158 QString mySql =
"select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid +
"'";
159 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
161 if ( myResult == SQLITE_OK )
163 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
165 radius = QString((
char * )sqlite3_column_text( myPreparedStatement, 0 ) );
166 parameter2 = QString((
char * )sqlite3_column_text( myPreparedStatement, 1 ) );
170 sqlite3_finalize( myPreparedStatement );
171 sqlite3_close( myDatabase );
174 if ( radius.isEmpty() || parameter2.isEmpty() )
176 QgsDebugMsg( QString(
"setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
181 if ( radius.left( 2 ) ==
"a=" )
185 QgsDebugMsg( QString(
"setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
192 if ( parameter2.left( 2 ) ==
"b=" )
197 else if ( parameter2.left( 3 ) ==
"rf=" )
204 QgsDebugMsg( QString(
"setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
212 QString proj4 =
"+proj=longlat +ellps=" + ellipsoid +
" +no_defs";
219 if ( destCRS.
srsid() == 0 )
221 QString myName = QString(
" * %1 (%2)" )
222 .arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ) )
243 mEllipsoid = QString(
"PARAMETER:%1:%2" ).arg( semiMajor ).arg( semiMinor );
260 const unsigned char* wkb = geometry->
asWkb();
264 const unsigned char* ptr;
265 unsigned int wkbType;
266 double res, resTotal = 0;
269 memcpy( &wkbType, ( wkb + 1 ),
sizeof( wkbType ) );
272 bool hasZptr =
false;
280 QgsDebugMsg(
"returning " + QString::number( res ) );
286 count = *((
int* )( wkb + 5 ) );
288 for ( i = 0; i < count; i++ )
293 QgsDebugMsg(
"returning " + QString::number( resTotal ) );
300 QgsDebugMsg(
"returning " + QString::number( res ) );
306 count = *((
int* )( wkb + 5 ) );
308 for ( i = 0; i < count; i++ )
318 QgsDebugMsg(
"returning " + QString::number( resTotal ) );
322 QgsDebugMsg( QString(
"measure: unexpected geometry type: %1" ).arg( wkbType ) );
332 const unsigned char* wkb = geometry->
asWkb();
336 const unsigned char* ptr;
337 unsigned int wkbType;
338 double res = 0.0, resTotal = 0.0;
341 memcpy( &wkbType, ( wkb + 1 ),
sizeof( wkbType ) );
344 bool hasZptr =
false;
358 QgsDebugMsg(
"returning " + QString::number( res ) );
364 count = *((
int* )( wkb + 5 ) );
366 for ( i = 0; i < count; i++ )
376 QgsDebugMsg(
"returning " + QString::number( resTotal ) );
380 QgsDebugMsg( QString(
"measure: unexpected geometry type: %1" ).arg( wkbType ) );
388 const unsigned char *ptr = feature + 5;
389 unsigned int nPoints = *((
int* )ptr );
392 QList<QgsPoint> points;
395 QgsDebugMsg(
"This feature WKB has " + QString::number( nPoints ) +
" points" );
397 for (
unsigned int i = 0; i < nPoints; ++i )
399 x = *((
double * ) ptr );
400 ptr +=
sizeof( double );
401 y = *((
double * ) ptr );
402 ptr +=
sizeof( double );
406 ptr +=
sizeof( double );
418 if ( points.size() < 2 )
431 for ( QList<QgsPoint>::const_iterator i = points.begin(); i != points.end(); ++i )
474 QgsDebugMsgLevel( QString(
"New points are %1 and %2, calculating..." ).arg( pp1.
toString( 4 ) ).arg( pp2.toString( 4 ) ), 4 );
480 result = sqrt(( p2.
x() - p1.
x() ) * ( p2.
x() - p1.
x() ) + ( p2.
y() - p1.
y() ) * ( p2.
y() - p1.
y() ) );
503 unsigned int numRings = *((
int* )( feature + 1 +
sizeof(
int ) ) );
512 const unsigned char* ptr = feature + 1 + 2 *
sizeof( int );
514 QList<QgsPoint> points;
524 for (
unsigned int idx = 0; idx < numRings; idx++ )
526 int nPoints = *((
int* )ptr );
531 for (
int jdx = 0; jdx < nPoints; jdx++ )
533 x = *((
double * ) ptr );
534 ptr +=
sizeof( double );
535 y = *((
double * ) ptr );
536 ptr +=
sizeof( double );
540 ptr +=
sizeof( double );
549 points.append( pnt );
552 if ( points.size() > 2 )
598 for ( QList<QgsPoint>::const_iterator i = points.begin(); i != points.end(); ++i )
631 double dx = p2.
x() - p1.
x();
632 double dy = p2.
y() - p1.
y();
633 bearing = atan2( dx, dy );
645 double* course1,
double* course2 )
647 if ( p1.
x() == p2.
x() && p1.
y() == p2.
y() )
658 double L = p2_lon - p1_lon;
659 double U1 = atan(( 1 - f ) * tan( p1_lat ) );
660 double U2 = atan(( 1 - f ) * tan( p2_lat ) );
661 double sinU1 = sin( U1 ), cosU1 = cos( U1 );
662 double sinU2 = sin( U2 ), cosU2 = cos( U2 );
664 double lambdaP = 2 *
M_PI;
666 double sinLambda = 0;
667 double cosLambda = 0;
672 double cosSqAlpha = 0;
673 double cos2SigmaM = 0;
679 while ( qAbs( lambda - lambdaP ) > 1e-12 && --iterLimit > 0 )
681 sinLambda = sin( lambda );
682 cosLambda = cos( lambda );
683 tu1 = ( cosU2 * sinLambda );
684 tu2 = ( cosU1 * sinU2 - sinU1 * cosU2 * cosLambda );
685 sinSigma = sqrt( tu1 * tu1 + tu2 * tu2 );
686 cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
687 sigma = atan2( sinSigma, cosSigma );
688 alpha = asin( cosU1 * cosU2 * sinLambda / sinSigma );
689 cosSqAlpha = cos( alpha ) * cos( alpha );
690 cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
691 C = f / 16 * cosSqAlpha * ( 4 + f * ( 4 - 3 * cosSqAlpha ) );
693 lambda = L + ( 1 - C ) * f * sin( alpha ) *
694 ( sigma + C * sinSigma * ( cos2SigmaM + C * cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) ) );
697 if ( iterLimit == 0 )
700 double uSq = cosSqAlpha * ( a * a - b * b ) / ( b * b );
701 double A = 1 + uSq / 16384 * ( 4096 + uSq * ( -768 + uSq * ( 320 - 175 * uSq ) ) );
702 double B = uSq / 1024 * ( 256 + uSq * ( -128 + uSq * ( 74 - 47 * uSq ) ) );
703 double deltaSigma = B * sinSigma * ( cos2SigmaM + B / 4 * ( cosSigma * ( -1 + 2 * cos2SigmaM * cos2SigmaM ) -
704 B / 6 * cos2SigmaM * ( -3 + 4 * sinSigma * sinSigma ) * ( -3 + 4 * cos2SigmaM * cos2SigmaM ) ) );
705 double s = b * A * ( sigma - deltaSigma );
709 *course1 = atan2( tu1, tu2 );
714 *course2 = atan2( cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda ) +
M_PI;
734 return sinx *( 1 + sinx2 *(
m_QA + sinx2 *(
m_QB + sinx2 *
m_QC ) ) );
760 m_AE = a2 * ( 1 - e2 );
762 m_QA = ( 2.0 / 3.0 ) * e2;
763 m_QB = ( 3.0 / 5.0 ) * e4;
764 m_QC = ( 4.0 / 7.0 ) * e6;
766 m_QbarA = -1.0 - ( 2.0 / 3.0 ) * e2 - ( 3.0 / 5.0 ) * e4 - ( 4.0 / 7.0 ) * e6;
767 m_QbarB = ( 2.0 / 9.0 ) * e2 + ( 2.0 / 5.0 ) * e4 + ( 4.0 / 7.0 ) * e6;
768 m_QbarC = - ( 3.0 / 25.0 ) * e4 - ( 12.0 / 35.0 ) * e6;
780 double x1, y1, x2, y2, dx, dy;
789 int n = points.size();
790 x2 =
DEG2RAD( points[n-1].x() );
791 y2 =
DEG2RAD( points[n-1].y() );
796 for (
int i = 0; i < n; i++ )
807 while ( x1 - x2 >
M_PI )
810 while ( x2 - x1 >
M_PI )
816 if (( dy = y2 - y1 ) != 0.0 )
817 area += dx *
getQ( y2 ) - ( dx / dy ) * ( Qbar2 - Qbar1 );
819 if (( area *=
m_AE ) < 0.0 )
829 if ( area >
m_E / 2 )
841 size = points.size();
844 for ( i = 0; i <
size; i++ )
849 area = area + points[i].x() * points[( i+1 ) % size].y() - points[( i+1 ) % size].x() * points[i].y();
867 unitLabel = QObject::trUtf8(
" m²" );
869 else if ( qAbs( value ) > 1000000.0 )
871 unitLabel = QObject::trUtf8(
" km²" );
872 value = value / 1000000.0;
874 else if ( qAbs( value ) > 10000.0 )
877 value = value / 10000.0;
881 unitLabel = QObject::trUtf8(
" m²" );
886 if ( keepBaseUnit || qAbs( value ) == 0.0 )
890 else if ( qAbs( value ) > 1000.0 )
893 value = value / 1000;
895 else if ( qAbs( value ) < 0.01 )
898 value = value * 1000;
900 else if ( qAbs( value ) < 0.1 )
914 if ( keepBaseUnit || qAbs( value ) <= 0.5*43560.0 )
919 else if ( qAbs( value ) <= 0.5*5280.0*5280.0 )
929 value /= 5280.0 * 5280.0;
934 if ( qAbs( value ) <= 528.0 || keepBaseUnit )
936 if ( qAbs( value ) == 1.0 )
959 if ( qAbs( value ) == 1.0 )
968 QgsDebugMsg( QString(
"Error: not picked up map units - actual value = %1" ).arg( u ) );
972 return QLocale::system().toString( value,
'f', decimals ) + unitLabel;
986 QgsDebugMsg(
"We're measuring on an ellipsoid or using projections, the system is returning meters" );
992 QgsDebugMsg( QString(
"Converting %1 meters" ).arg( QString::number( measure ) ) );
998 QgsDebugMsg( QString(
"to %1 feet" ).arg( QString::number( measure ) ) );
1003 QgsDebugMsg( QString(
"Converting %1 feet" ).arg( QString::number( measure ) ) );
1009 QgsDebugMsg( QString(
"to %1 meters" ).arg( QString::number( measure ) ) );
double computePolygonFlatArea(const QList< QgsPoint > &points)
~QgsDistanceArea()
Destructor.
bool saveAsUserCRS(QString name)
Copied from QgsCustomProjectionDialog /// Please refactor into SQL handler !!! ///.
QgsCoordinateTransform * mCoordTransform
used for transforming coordinates from source CRS to ellipsoid's coordinates
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
void computeAreaInit()
precalculates some values (must be called always when changing ellipsoid)
A geometry is the spatial representation of a feature.
bool setEllipsoid(const QString &ellipsoid)
sets ellipsoid by its acronym
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void _copy(const QgsDistanceArea &origDA)
Copy helper.
const QString & ellipsoid()
returns ellipsoid's acronym
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
bool createFromSrsId(const long theSrsId)
double measurePerimeter(QgsGeometry *geometry)
measures perimeter of polygon
double measurePolygon(const QList< QgsPoint > &points)
measures polygon area
#define QgsDebugMsgLevel(str, level)
double measure(QgsGeometry *geometry)
general measurement (line distance or polygon area)
double computePolygonArea(const QList< QgsPoint > &points)
calculates area of polygon on ellipsoid algorithm has been taken from GRASS: gis/area_poly1.c
double bearing(const QgsPoint &p1, const QgsPoint &p2)
compute bearing - in radians
const long GEOCRS_ID
Magic number for a geographic coord sys in QGIS srs.db tbl_srs.srs_id.
QString toString() const
String representation of the point (x,y)
bool createFromProj4(const QString theProjString)
A class to represent a point geometry.
QgsDistanceArea & operator=(const QgsDistanceArea &origDA)
Assignment operator.
static QString textUnit(double value, int decimals, QGis::UnitType u, bool isArea, bool keepBaseUnit=false)
General purpose distance and area calculator.
double mSemiMajor
ellipsoid parameters
Class for storing a coordinate reference system (CRS)
static const QString srsDbFilePath()
Returns the path to the srs.db file.
double measureLine(const QList< QgsPoint > &points)
measures line
const CORE_EXPORT QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
UnitType
Map units that qgis supports.
void convertMeasurement(double &measure, QGis::UnitType &measureUnits, QGis::UnitType displayUnits, bool isArea)
Helper for conversion between physical units.
Custom exception class for Coordinate Reference System related exceptions.
bool mEllipsoidalMode
indicates whether we will transform coordinates
long mSourceRefSys
id of the source spatial reference system
QString mEllipsoid
ellipsoid acronym (from table tbl_ellipsoids)
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
QgsDistanceArea()
Constructor.
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
QString toProj4() const
Get the Proj Proj4 string representation of this srs.
double computeDistanceBearing(const QgsPoint &p1, const QgsPoint &p2, double *course1=NULL, double *course2=NULL)
calculates distance from two points on ellipsoid based on inverse Vincenty's formulae ...
void setSourceAuthId(QString authid)
sets source spatial reference system by authid