QString QgsCoordinateUtils::formatCoordinateForProject( const QgsPoint& point, const QgsCoordinateReferenceSystem& destCrs, int precision ) { QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "MU" ); QgsPoint geo = point; if ( format == "DM" || format == "DMS" || format == "D" ) { // degrees if ( destCrs.isValid() && !destCrs.geographicFlag() ) { // need to transform to geographic coordinates QgsCoordinateTransform ct( destCrs, QgsCoordinateReferenceSystem( GEOSRID ) ); try { geo = ct.transform( point ); } catch ( QgsCsException& ) { return QString(); } } if ( format == "DM" ) return geo.toDegreesMinutes( precision, true, true ); else if ( format == "DMS" ) return geo.toDegreesMinutesSeconds( precision, true, true ); else return geo.toString( precision ); } else { // coordinates in map units return point.toString( precision ); } }
int QgsCoordinateUtils::calculateCoordinatePrecision( double mapUnitsPerPixel, const QgsCoordinateReferenceSystem& mapCrs ) { // Get the display precision from the project settings bool automatic = QgsProject::instance()->readBoolEntry( "PositionPrecision", "/Automatic" ); int dp = 0; if ( automatic ) { QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "MU" ); bool formatGeographic = ( format == "DM" || format == "DMS" || format == "D" ); // we can only calculate an automatic precision if both map CRS and format are geographic or both not geographic if ( mapCrs.geographicFlag() == formatGeographic ) { // Work out a suitable number of decimal places for the coordinates with the aim of always // having enough decimal places to show the difference in position between adjacent pixels. // Also avoid taking the log of 0. if ( !qgsDoubleNear( mapUnitsPerPixel, 0.0 ) ) dp = static_cast<int>( ceil( -1.0 * log10( mapUnitsPerPixel ) ) ); } else { dp = format == "D" ? 4 : 2; //guess sensible fallback } } else dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" ); // Keep dp sensible if ( dp < 0 ) dp = 0; return dp; }
bool QgsNorthArrowPlugin::calculateNorthDirection() { QgsMapCanvas& mapCanvas = *( qGisInterface->mapCanvas() ); bool goodDirn = false; if ( mapCanvas.layerCount() > 0 ) { QgsCoordinateReferenceSystem outputCRS = mapCanvas.mapRenderer()->destinationCrs(); if ( outputCRS.isValid() && !outputCRS.geographicFlag() ) { // Use a geographic CRS to get lat/long to work out direction QgsCoordinateReferenceSystem ourCRS; ourCRS.createFromOgcWmsCrs( GEO_EPSG_CRS_AUTHID ); assert( ourCRS.isValid() ); QgsCoordinateTransform transform( outputCRS, ourCRS ); QgsRectangle extent = mapCanvas.extent(); QgsPoint p1( extent.center() ); // A point a bit above p1. XXX assumes that y increases up!! // May need to involve the maptopixel transform if this proves // to be a problem. QgsPoint p2( p1.x(), p1.y() + extent.height() * 0.25 ); // project p1 and p2 to geographic coords try { p1 = transform.transform( p1 ); p2 = transform.transform( p2 ); } catch ( QgsCsException &e ) { Q_UNUSED( e ); // just give up QgsDebugMsg( "North Arrow: Transformation error, quitting" ); return false; } // Work out the value of the initial heading one takes to go // from point p1 to point p2. The north direction is then that // many degrees anti-clockwise or vertical. // Take some care to not divide by zero, etc, and ensure that we // get sensible results for all possible values for p1 and p2. goodDirn = true; double angle = 0.0; // convert to radians for the equations below p1.multiply( PI / 180.0 ); p2.multiply( PI / 180.0 ); double y = sin( p2.x() - p1.x() ) * cos( p2.y() ); double x = cos( p1.y() ) * sin( p2.y() ) - sin( p1.y() ) * cos( p2.y() ) * cos( p2.x() - p1.x() ); if ( y > 0.0 ) { if ( x > TOL ) angle = atan( y / x ); else if ( x < -TOL ) angle = PI - atan( -y / x ); else angle = 0.5 * PI; } else if ( y < 0.0 ) { if ( x > TOL ) angle = -atan( -y / x ); else if ( x < -TOL ) angle = atan( y / x ) - PI; else angle = 1.5 * PI; } else { if ( x > TOL ) angle = 0.0; else if ( x < -TOL ) angle = PI; else { angle = 0.0; // p1 = p2 goodDirn = false; } } // And set the angle of the north arrow. Perhaps do something // different if goodDirn = false. mRotationInt = static_cast<int>( round( fmod( 360.0 - angle * 180.0 / PI, 360.0 ) ) ); } else { // For geographic CRS and for when there are no layers, set the // direction back to the default mRotationInt = 0; } } return goodDirn; }
bool QgsDecorationNorthArrow::calculateNorthDirection() { QgsMapCanvas* mapCanvas = QgisApp::instance()->mapCanvas(); bool goodDirn = false; // Get the shown extent... QgsRectangle canvasExtent = mapCanvas->extent(); // ... and all layers extent, ... QgsRectangle fullExtent = mapCanvas->fullExtent(); // ... and combine QgsRectangle extent = canvasExtent.intersect( & fullExtent ); // If no layers are added or shown, we can't get any direction if ( mapCanvas->layerCount() > 0 && ! extent.isEmpty() ) { QgsCoordinateReferenceSystem outputCRS = mapCanvas->mapRenderer()->destinationCrs(); if ( outputCRS.isValid() && !outputCRS.geographicFlag() ) { // Use a geographic CRS to get lat/long to work out direction QgsCoordinateReferenceSystem ourCRS; ourCRS.createFromOgcWmsCrs( GEO_EPSG_CRS_AUTHID ); assert( ourCRS.isValid() ); QgsCoordinateTransform transform( outputCRS, ourCRS ); QgsPoint p1( extent.center() ); // A point a bit above p1. XXX assumes that y increases up!! // May need to involve the maptopixel transform if this proves // to be a problem. QgsPoint p2( p1.x(), p1.y() + extent.height() * 0.25 ); // project p1 and p2 to geographic coords try { p1 = transform.transform( p1 ); p2 = transform.transform( p2 ); } catch ( QgsCsException &e ) { Q_UNUSED( e ); // just give up QgsDebugMsg( "North Arrow: Transformation error, quitting" ); return false; } // Work out the value of the initial heading one takes to go // from point p1 to point p2. The north direction is then that // many degrees anti-clockwise or vertical. // Take some care to not divide by zero, etc, and ensure that we // get sensible results for all possible values for p1 and p2. goodDirn = true; double angle = 0.0; // convert to radians for the equations below p1.multiply( PI / 180.0 ); p2.multiply( PI / 180.0 ); double y = sin( p2.x() - p1.x() ) * cos( p2.y() ); double x = cos( p1.y() ) * sin( p2.y() ) - sin( p1.y() ) * cos( p2.y() ) * cos( p2.x() - p1.x() ); // Use TOL to decide if the quotient is big enough. // Both x and y can be very small, if heavily zoomed // For small y/x, we set directly angle 0. Not sure // if this is needed. if ( y > 0.0 ) { if ( x > 0.0 && ( y / x ) > TOL ) angle = atan( y / x ); else if ( x < 0.0 && ( y / x ) < -TOL ) angle = PI - atan( -y / x ); else angle = 0.5 * PI; } else if ( y < 0.0 ) { if ( x > 0.0 && ( y / x ) < -TOL ) angle = -atan( -y / x ); else if ( x < 0.0 && ( y / x ) > TOL ) angle = atan( y / x ) - PI; else angle = 1.5 * PI; } else { if ( x > TOL ) angle = 0.0; else if ( x < -TOL ) angle = PI; else { angle = 0.0; // p1 = p2 goodDirn = false; } } // And set the angle of the north arrow. Perhaps do something // different if goodDirn = false. mRotationInt = qRound( fmod( 360.0 - angle * 180.0 / PI, 360.0 ) ); } else { // For geographic CRS and for when there are no layers, set the // direction back to the default mRotationInt = 0; } } return goodDirn; }