- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要一个函数来计算一对 WGS 84 之间的距离定位到高精度,我计划使用 boost geometry 中的 geographic
函数.
boost geometry Design Rational状态:
There is the Andoyer method, fast and precise, and there is the Vincenty method, slower and more precise..
但是,当使用 Andoyer
和 Vincenty
策略测试 boost::geometry::distance
函数时,我得到了以下结果:
WGS 84 values (metres)
Semimajor axis: 6378137.000000
Flattening: 0.003353
Semiminor axis: 6356752.314245
Semimajor distance: 20037508.342789
Semiminor distance: 19970326.371123
Boost geometry near poles
Andoyer function:
Semimajor distance: 20037508.151445
Semiminor distance: 20003917.164970
Vincenty function:
Semimajor distance: **19970326.180419**
Semiminor distance: 20003931.266635
Boost geometry at poles
Andoyer function:
Semimajor distance: 0.000000
Semiminor distance: 0.000000
Vincenty function:
Semimajor distance: **19970326.371122**
Semiminor distance: 20003931.458623
Vincenty
沿半长轴(即赤道周围)的距离小于南北极之间的半短轴周围的距离。这不可能是正确的。
Semiminor 和 Andoyer
距离看起来很合理。除非点位于地球的另一侧,当 boost
Andoyer
函数返回零时!
问题出在:Vincenty
算法、它的boost geometry
实现,还是我的测试代码?
测试代码:
/// boost geometry WGS84 distance issue
// Note: M_PI is not part of the C or C++ standards, _USE_MATH_DEFINES enables it
#define _USE_MATH_DEFINES
#include <boost/geometry.hpp>
#include <cmath>
#include <iostream>
#include <ios>
// WGS 84 parameters from: Eurocontrol WGS 84 Implementation Manual
// Version 2.4 Chapter 3, page 14
/// The Semimajor axis measured in metres.
/// This is the radius at the equator.
constexpr double a = 6378137.0;
/// Flattening, a ratio.
/// This is the flattening of the ellipse at the poles
constexpr double f = 1.0/298.257223563;
/// The Semiminor axis measured in metres.
/// This is the radius at the poles.
/// Note: this is derived from the Semimajor axis and the flattening.
/// See WGS 84 Implementation Manual equation B-2, page 69.
constexpr double b = a * (1.0 - f);
int main(int /*argc*/, char ** /*argv*/)
{
std::cout.setf(std::ios::fixed);
std::cout << "WGS 84 values (metres)\n";
std::cout << "\tSemimajor axis:\t\t" << a << "\n";
std::cout << "\tFlattening:\t\t" << f << "\n";
std::cout << "\tSemiminor axis:\t\t" << b << "\n\n";
std::cout << "\tSemimajor distance:\t" << M_PI * a << "\n";
std::cout << "\tSemiminor distance:\t" << M_PI * b << "\n";
std::cout << std::endl;
// Min value for delta. 0.000000014 causes Andoyer to fail.
const double DELTA(0.000000015);
// For boost::geometry:
typedef boost::geometry::cs::geographic<boost::geometry::radian> Wgs84Coords;
typedef boost::geometry::model::point<double, 2, Wgs84Coords> GeographicPoint;
// Note boost points are Long & Lat NOT Lat & Long
GeographicPoint near_north_pole (0.0, M_PI_2 - DELTA);
GeographicPoint near_south_pole (0.0, -M_PI_2 + DELTA);
GeographicPoint near_equator_east ( M_PI_2 - DELTA, 0.0);
GeographicPoint near_equator_west (-M_PI_2 + DELTA, 0.0);
// Note: the default boost geometry spheroid is WGS84
// #include <boost/geometry/core/srs.hpp>
typedef boost::geometry::srs::spheroid<double> SpheroidType;
SpheroidType spheriod;
//#include <boost/geometry/strategies/geographic/distance_andoyer.hpp>
typedef boost::geometry::strategy::distance::andoyer<SpheroidType>
AndoyerStrategy;
AndoyerStrategy andoyer(spheriod);
std::cout << "Boost geometry near poles\n";
std::cout << "Andoyer function:\n";
double andoyer_major(boost::geometry::distance(near_equator_east, near_equator_west, andoyer));
std::cout << "\tSemimajor distance:\t" << andoyer_major << "\n";
double andoyer_minor(boost::geometry::distance(near_north_pole, near_south_pole, andoyer));
std::cout << "\tSemiminor distance:\t" << andoyer_minor << "\n";
//#include <boost/geometry/strategies/geographic/distance_vincenty.hpp>
typedef boost::geometry::strategy::distance::vincenty<SpheroidType>
VincentyStrategy;
VincentyStrategy vincenty(spheriod);
std::cout << "Vincenty function:\n";
double vincenty_major(boost::geometry::distance(near_equator_east, near_equator_west, vincenty));
std::cout << "\tSemimajor distance:\t" << vincenty_major << "\n";
double vincenty_minor(boost::geometry::distance(near_north_pole, near_south_pole, vincenty));
std::cout << "\tSemiminor distance:\t" << vincenty_minor << "\n\n";
// Note boost points are Long & Lat NOT Lat & Long
GeographicPoint north_pole (0.0, M_PI_2);
GeographicPoint south_pole (0.0, -M_PI_2);
GeographicPoint equator_east ( M_PI_2, 0.0);
GeographicPoint equator_west (-M_PI_2, 0.0);
std::cout << "Boost geometry at poles\n";
std::cout << "Andoyer function:\n";
andoyer_major = boost::geometry::distance(equator_east, equator_west, andoyer);
std::cout << "\tSemimajor distance:\t" << andoyer_major << "\n";
andoyer_minor = boost::geometry::distance(north_pole, south_pole, andoyer);
std::cout << "\tSemiminor distance:\t" << andoyer_minor << "\n";
std::cout << "Vincenty function:\n";
vincenty_major = boost::geometry::distance(equator_east, equator_west, vincenty);
std::cout << "\tSemimajor distance:\t" << vincenty_major << "\n";
vincenty_minor = boost::geometry::distance(north_pole, south_pole, vincenty);
std::cout << "\tSemiminor distance:\t" << vincenty_minor << "\n";
return 0;
}
最佳答案
我按照@jwd630 的建议查看了geographiclib .
以下是结果:
WGS 84 values (metres)
Semimajor distance: 20037508.342789
Semiminor distance: 19970326.371123
GeographicLib near antipodal
Semimajor distance: 20003931.458625
Semiminor distance: 20003931.455275
GeographicLib antipodal
Semimajor distance: 20003931.458625
Semiminor distance: 20003931.458625
GeographicLib verify
JFK to LHR distance: 5551759.400319
即对于极点之间的半短距离(至 5dp),它提供与 Vincenty 相同的距离,并且它为赤道上的对映点计算相同的距离。
这是正确的,因为赤道对映点之间的最短距离是通过其中一个极点,而不是像默认的 boost Andoyer
算法计算的那样围绕赤道。
所以@jwd630 上面的答案是正确的,在三个算法中,geographiclib是唯一一个计算整个 WGS84 大地水准面的正确距离的方法。
测试代码如下:
/// GeographicLib WGS84 distance
// Note: M_PI is not part of the C or C++ standards, _USE_MATH_DEFINES enables it
#define _USE_MATH_DEFINES
#include <GeographicLib/Geodesic.hpp>
#include <cmath>
#include <iostream>
#include <ios>
// WGS 84 parameters from: Eurocontrol WGS 84 Implementation Manual
// Version 2.4 Chapter 3, page 14
/// The Semimajor axis measured in metres.
/// This is the radius at the equator.
constexpr double a = 6378137.0;
/// Flattening, a ratio.
/// This is the flattening of the ellipse at the poles
constexpr double f = 1.0/298.257223563;
/// The Semiminor axis measured in metres.
/// This is the radius at the poles.
/// Note: this is derived from the Semimajor axis and the flattening.
/// See WGS 84 Implementation Manual equation B-2, page 69.
constexpr double b = a * (1.0 - f);
int main(int /*argc*/, char ** /*argv*/)
{
const GeographicLib::Geodesic& geod(GeographicLib::Geodesic::WGS84());
std::cout.setf(std::ios::fixed);
std::cout << "WGS 84 values (metres)\n";
std::cout << "\tSemimajor axis:\t\t" << a << "\n";
std::cout << "\tFlattening:\t\t" << f << "\n";
std::cout << "\tSemiminor axis:\t\t" << b << "\n\n";
std::cout << "\tSemimajor distance:\t" << M_PI * a << "\n";
std::cout << "\tSemiminor distance:\t" << M_PI * b << "\n";
std::cout << std::endl;
// Min value for delta. 0.000000014 causes boost Andoyer to fail.
const double DELTA(0.000000015);
std::pair<double, double> near_equator_east (0.0, 90.0 - DELTA);
std::pair<double, double> near_equator_west (0.0, -90.0 + DELTA);
std::cout << "GeographicLib near antipodal\n";
double distance_metres(0.0);
geod.Inverse(near_equator_east.first, near_equator_east.second,
near_equator_west.first, near_equator_west.second, distance_metres);
std::cout << "\tSemimajor distance:\t" << distance_metres << "\n";
std::pair<double, double> near_north_pole (90.0 - DELTA, 0.0);
std::pair<double, double> near_south_pole (-90.0 + DELTA, 0.0);
geod.Inverse(near_north_pole.first, near_north_pole.second,
near_south_pole.first, near_south_pole.second, distance_metres);
std::cout << "\tSemiminor distance:\t" << distance_metres << "\n\n";
std::pair<double, double> equator_east (0.0, 90.0);
std::pair<double, double> equator_west (0.0, -90.0);
std::cout << "GeographicLib antipodal\n";
geod.Inverse(equator_east.first, equator_east.second,
equator_west.first, equator_west.second, distance_metres);
std::cout << "\tSemimajor distance:\t" << distance_metres << "\n";
std::pair<double, double> north_pole (90.0, 0.0);
std::pair<double, double> south_pole (-90.0, 0.0);
geod.Inverse(north_pole.first, north_pole.second,
south_pole.first, south_pole.second, distance_metres);
std::cout << "\tSemiminor distance:\t" << distance_metres << "\n\n";
std::pair<double, double> JFK (40.6, -73.8);
std::pair<double, double> LHR (51.6, -0.5);
std::cout << "GeographicLib verify distance\n";
geod.Inverse(JFK.first, JFK.second,
LHR.first, LHR.second, distance_metres);
std::cout << "\tJFK to LHR distance:\t" << distance_metres << std::endl;
return 0;
}
在他的论文中Algorithms for geodesics ,Charles F. F. Karney 指出,“Vincenty 的方法无法收敛于几乎对映的点”。这可能会回答我原来的问题,即 Vincenty
算法不适合对映点。
注意:我提出了 boost
票 #11817描述问题所在Andoyer
算法为对映点返回零,并向 boost
发送了一个拉取请求并修复了它。
然而,对于不正确距离的唯一正确修复是使用正确的算法,即:geographiclib
非常感谢 Charles F. F. Karney (@cffk) 礼貌地指出我的愚蠢错误!
关于c++ - 为什么 boost::geometry 地理 Vincenty 距离在赤道附近不准确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34767736/
我正在尝试使用boost.spirit的qi库解析某些内容,而我遇到了一个问题。根据spirit docs,a >> b应该产生类型为tuple的东西。但这是boost::tuple(又名 fusio
似乎有/正在努力做到这一点,但到目前为止我看到的大多数资源要么已经过时(带有死链接),要么几乎没有信息来实际构建一个小的工作样本(例如,依赖于boost program_options 以构建可执行文
我对 Boost.Log 的状态有点困惑。这是 Boost 的官方部分,还是尚未被接受?当我用谷歌搜索时,我看到一些帖子谈论它在 2010 年是如何被接受的,等等,但是当我查看最后一个 Boost 库
Boost 提供了两种不同的实现 string_view ,这将成为 C++17 的一部分: boost::string_ref在 utility/string_ref.hpp boost::stri
最近,我被一家GIS公司雇用来重写他们的旧地理信息库。所以我目前正在寻找一个好的计算几何库。我看过CGAL,这真是了不起,但是我的老板想要免费的东西。 所以我现在正在检查Boost.Geometry。
假设我有一个无向图 G。假设我添加以下内容 add_edge(1,2,G); add_edge(1,3,G); add_edge(0,2,G); 现在我再说一遍: add_edge(0,2,G); 我
我使用 CMake 来查找 Boost。找到了 Boost,但 CMake 出错了 Imported targets not available for Boost version 请参阅下面的完整错
我是 boost::fusion 和 boost::mpl 库的新手。谁能告诉我这两个库之间的主要区别? 到目前为止,我只使用 fusion::vector 和其他一些简单的东西。现在我想使用 fus
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: What are the benefits of using Boost.Phoenix? 所以我开始阅读 boos
我正在尝试获得一个使用 Boost.Timer 的简单示例,用于一些秒表性能测量,但我不明白为什么我无法成功地将 Boost.Timer 链接到 Boost.Chrono。我使用以下简单脚本从源代码构
我有这样的东西: enum EFood{ eMeat, eFruit }; class Food{ }; class Meat: public Food{ void someM
有人可以告诉我,我如何获得boost::Variant处理无序地图? typedef boost::variant lut_value;unordered_map table; 我认为有一个用于boo
我对 Boost.Geometry 中的环和多边形感到困惑。 在文档中,没有图形显示什么是环,什么是多边形。 谁能画图解释两个概念的区别? 最佳答案 在 Boost.Geometry 中,多边形被定义
我正在使用 boost.pool,但我不知道何时使用 boost::pool<>::malloc和 boost::pool<>::ordered_malloc ? 所以, boost::pool<>:
我正在尝试通过 *boost::fast_pool_allocator* 使用 *boost::container::flat_set*。但是,我收到编译错误。非常感谢您的意见和建议。为了突出这个问题
sau_timer::sau_timer(int secs, timerparam f) : strnd(io), t(io, boost::posix_time::seconds(secs)
我无法理解此功能的文档,我已多次看到以下内容 tie (ei,ei_end) = out_edges(*(vi+a),g); **g**::out_edge_iterator ei, ei_end;
我想在 C++ 中序列化分层数据结构。我正在处理的项目使用 boost,所以我使用 boost::property_tree::ptree 作为我的数据节点结构。 我们有像 Person 这样的高级结
我需要一些帮助来解决这个异常,我正在实现一个 NPAPI 插件,以便能够使用来自浏览器扩展的本地套接字,为此我正在使用 Firebreath 框架。 对于套接字和连接,我使用带有异步调用的 Boost
我尝试将 boost::bind 与 boost::factory 结合使用但没有成功 我有这个类 Zambas 有 4 个参数(2 个字符串和 2 个整数)和 class Zambas { publ
我是一名优秀的程序员,十分优秀!