static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, const QGeoCoordinate ¢er, qreal distance, int steps) { // Calculate points based on great-circle distance // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function // but tweaked here for computing multiple points // pre-calculate qreal latRad = qgeocoordinate_degToRad(center.latitude()); qreal lonRad = qgeocoordinate_degToRad(center.longitude()); qreal cosLatRad = std::cos(latRad); qreal sinLatRad = std::sin(latRad); qreal ratio = (distance / (qgeocoordinate_EARTH_MEAN_RADIUS * 1000.0)); qreal cosRatio = std::cos(ratio); qreal sinRatio = std::sin(ratio); qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio; qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio; for (int i = 0; i < steps; ++i) { qreal azimuthRad = 2 * M_PI * i / steps; qreal resultLatRad = std::asin(sinLatRad_x_cosRatio + cosLatRad_x_sinRatio * std::cos(azimuthRad)); qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio, cosRatio - sinLatRad * std::sin(resultLatRad)); qreal lat2 = qgeocoordinate_radToDeg(resultLatRad); qreal lon2 = qgeocoordinate_radToDeg(resultLonRad); if (lon2 < -180.0) { lon2 += 360.0; } else if (lon2 > 180.0) { lon2 -= 360.0; } path << QGeoCoordinate(lat2, lon2, center.altitude()); } }
/*! Returns the distance (in meters) from this coordinate to the coordinate specified by \a other. Altitude is not used in the calculation. This calculation returns the great-circle distance between the two coordinates, with an assumption that the Earth is spherical for the purpose of this calculation. Returns 0 if the type of this coordinate or the type of \a other is QGeoCoordinate::InvalidCoordinate. */ qreal QGeoCoordinate::distanceTo(const QGeoCoordinate &other) const { if (type() == QGeoCoordinate::InvalidCoordinate || other.type() == QGeoCoordinate::InvalidCoordinate) { return 0; } // Haversine formula double dlat = qgeocoordinate_degToRad(other.d->lat - d->lat); double dlon = qgeocoordinate_degToRad(other.d->lng - d->lng); double y = sin(dlat / 2.0) * sin(dlat / 2.0) + cos(qgeocoordinate_degToRad(d->lat)) * cos(qgeocoordinate_degToRad(other.d->lat)) * sin(dlon / 2.0) * sin(dlon / 2.0); double x = 2 * atan2(sqrt(y), sqrt(1 - y)); return qreal(x * qgeocoordinate_EARTH_MEAN_RADIUS * 1000); }
/*! Returns the azimuth (or bearing) in degrees from this coordinate to the coordinate specified by \a other. Altitude is not used in the calculation. There is an assumption that the Earth is spherical for the purpose of this calculation. Returns 0 if the type of this coordinate or the type of \a other is QGeoCoordinate::InvalidCoordinate. */ qreal QGeoCoordinate::azimuthTo(const QGeoCoordinate &other) const { if (type() == QGeoCoordinate::InvalidCoordinate || other.type() == QGeoCoordinate::InvalidCoordinate) { return 0; } double dlon = qgeocoordinate_degToRad(other.d->lng - d->lng); double lat1Rad = qgeocoordinate_degToRad(d->lat); double lat2Rad = qgeocoordinate_degToRad(other.d->lat); double y = sin(dlon) * cos(lat2Rad); double x = cos(lat1Rad) * sin(lat2Rad) - sin(lat1Rad) * cos(lat2Rad) * cos(dlon); double whole; double fraction = modf(qgeocoordinate_radToDeg(atan2(y, x)), &whole); return qreal((int(whole + 360) % 360) + fraction); }
void QGeoCoordinatePrivate::atDistanceAndAzimuth(const QGeoCoordinate &coord, qreal distance, qreal azimuth, double *lon, double *lat) { double latRad = qgeocoordinate_degToRad(coord.d->lat); double lonRad = qgeocoordinate_degToRad(coord.d->lng); double cosLatRad = cos(latRad); double sinLatRad = sin(latRad); double azimuthRad = qgeocoordinate_degToRad(azimuth); double ratio = (distance / (qgeocoordinate_EARTH_MEAN_RADIUS * 1000.0)); double cosRatio = cos(ratio); double sinRatio = sin(ratio); double resultLatRad = asin(sinLatRad * cosRatio + cosLatRad * sinRatio * cos(azimuthRad)); double resultLonRad = lonRad + atan2(sin(azimuthRad) * sinRatio * cosLatRad, cosRatio - sinLatRad * sin(resultLatRad)); *lat = qgeocoordinate_radToDeg(resultLatRad); *lon = qgeocoordinate_radToDeg(resultLonRad); }