2017-08-11 87 views
1

我试图使用Boost :: Geometry _union与整数,为性能和数字的准确性。为此,我将输入的坐标乘以10,000。从而创建最多9位数的坐标。我认为,因为我使用64位整数,这应该很好。如何使用Boost :: Geometry _union与整数

不幸的是,当我运行代码时,我得到了奇怪的结果(输出多边形包括一个远离输入中任何多边形的点)。调查升压的代码::几何给我带来了这样的结论:原产地是在文件cart_intersect.hpp一个环绕式的问题:

set<1>(point, get<0, 1>(segment) + boost::numeric_cast 
      < 
       CoordinateType 
      >(numerator * dy_promoted/denominator)); 

当所有三个(分子,dy_promoted和分母)是巨大的,在乘法的结果需要超过64位,因此整个结果是不正确的。

使用Boost :: Geometry与这样的大整数有效吗?在保持正确性和精确度的同时使用Boost :: Geometry的正确方法是什么?


编辑 @sehe,感谢您的答复。这里是一个SSCCE,编译VS2013和Boost 1.63

#include <boost/geometry/geometry.hpp> 
#include <boost/geometry/geometries/polygon.hpp> 
#include <boost/geometry/geometries/point_xy.hpp> 
#include <boost/geometry/multi/geometries/multi_polygon.hpp> 
#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 
namespace bg = boost::geometry; 

typedef bg::model::d2::point_xy<long long, bg::cs::cartesian> TPoint; 
typedef bg::model::ring<TPoint> TRing; 
typedef bg::model::polygon<TPoint> TPolygon; 
typedef bg::model::multi_polygon<TPolygon> TMultiPolygon; 

void PrintRing(const TRing& rng) 
{ 
    for (const auto& ver : rng) 
    { 
    cout << "(" << ver.x() << "," << ver.y() << "),"; 
    } 
} 

void PrintPolygon(const TPolygon& pol) 
{ 
    cout << "Outer: "; 
    PrintRing(pol.outer()); 
    cout << endl; 

    for (const auto& rng : pol.inners()) 
    { 
    cout << "Inner: "; 
    PrintRing(rng); 
    cout << endl; 
    } 
} 

void PrintMultiPolygon(const string name, const TMultiPolygon& mp) 
{ 
    cout << "Multi-Polygon " << name << " : " << endl; 
    for (const auto& pol : mp) 
    { 
    PrintPolygon(pol); 
    } 
    cout << endl; 
} 

int main() 
{ 
    cout << "BOOST_LIB_VERSION: " << BOOST_LIB_VERSION << endl; 
    const vector<TPoint> verticesA{ { -405129, 2010409 }, { 3370580, 2010409 }, { 3370580, 1997709 }, { -405129, 1997709 }, { -405129, 2010409 } }; 
    const TRing rngA(verticesA.cbegin(), verticesA.cend()); 
    TPolygon polA; 
    polA.outer() = rngA; 
    TMultiPolygon mpA; 
    mpA.push_back(polA); 

    const vector<TPoint> verticesB{ { 3364230, -895349 }, { 3364230, 2004060 }, { 3376930, 2004059 }, { 3376930, -895350 }, { 3364230, -895349 } }; 
    const TRing rngB(verticesB.cbegin(), verticesB.cend()); 
    TPolygon polB; 
    polB.outer() = rngB; 
    TMultiPolygon mpB; 
    mpB.push_back(polB); 

    TMultiPolygon output; 

    bg::union_(mpA, mpB, output); 

    PrintMultiPolygon("A", mpA); 
    PrintMultiPolygon("B", mpB); 
    PrintMultiPolygon("output", output); 
} 

程序的输出:

BOOST_LIB_VERSION: 1_63

Multi-Polygon A :
Outer: (-405129,2010409),(3370580,2010409),(3370580,1997709),(-405129,1997709),(-405129,2010409),

Multi-Polygon B :
Outer: (3364230,-895349),(3364230,2004060),(3376930,2004059),(3376930,-895350),(3364230,-895349),

Multi-Polygon output :
Outer: (3370580,2004060),(3376930,2004059),(3376930,-895350),(3364230,-895349),(3364230,-1372382),(-405129,1997709),(-405129,2010409),(3370580,2010409),(3370580,2004060),

注意以粗体显示的坐标,Y值是远超过任何Y坐标在输入中。

+0

您可以使用整数类型来防止boost :: multiprecision的溢出和/或大容量整数。如果您发布SSCCE,我们可以向您展示一个示例。现在我们不能给出更有用的答案,因为所有有用的代码都缺少问题。 – sehe

+0

@sehe,谢谢你的回应。我已经相应地更新了这篇文章。 –

回答

1

事实上,随着-fsanitize=undefined打印

/home/sehe/custom/boost/boost/geometry/strategies/cartesian/intersection.hpp:190:18: runtime error: signed integer overflow: 10923345128122 * 2899409 cannot be represented in type 'long long int' 

运行相反,你可以使用供应商定义的128位扩展,或使用Boost的:

namespace mp = boost::multiprecision; 

typedef mp::checked_int128_t T; 
typedef bg::model::d2::point_xy<T, bg::cs::cartesian> TPoint; 

事实上,你可以使用任意精度整数:

typedef mp::checked_cpp_int T; 

Note If you want to use unchecked arithmetic with cpp_int you will have to make sure that expression-templates are disabled for boost

typedef mp::number<mp::backends::cpp_int_backend<0, 0, mp::signed_magnitude, mp::unchecked>, mp::et_off> T; 

See e.g. Why does using boost::multiprecision::cpp_int affect tail call optimization here , How to use sqrt and ceil with Boost::multiprecision? , etc.

与所有的输出上面变为:

Live On Wandbox

BOOST_LIB_VERSION: 1_64 
Multi-Polygon A : 
Outer: (-405129,2010409),(3370580,2010409),(3370580,1997709),(-405129,1997709),(-405129,2010409), 

Multi-Polygon B : 
Outer: (3364230,-895349),(3364230,2004060),(3376930,2004059),(3376930,-895350),(3364230,-895349), 

Multi-Polygon output : 
Outer: (3370580,2004060),(3376930,2004059),(3376930,-895350),(3364230,-895349),(3364230,1997709),(-405129,1997709),(-405129,2010409),(3370580,2010409),(3370580,2004060), 

查看更多:Boost Geometry and exact point types

+0

感谢您的详细和专业的答案。我尝试用我的1_63 boost库编译这段代码,并得到了以下编译错误:1> C:\ Workspace \ ThirdParty \ boost \ ver_1_63_0 \ boost/geometry/po licies/robustness/se gment_ratio.hpp(152) :错误C2679:二进制'=':找不到操作符找到类型为'double'的右侧操作数(或者没有可接受的转换)任何想法? –

+0

哦。 [Wandbox以1.63确认。0](https://wandbox.org/permlink/T5Nogw780MS04hGL)。我会建议升级。 – sehe

0

有点风马牛不相及,但没有必要花费这么多的代码初始化或打印数据:

Live On Wandbox

typedef bgm::polygon<bgm::d2::point_xy<mp::checked_int128_t, bg::cs::cartesian>> TPolygon; 
typedef bgm::multi_polygon<TPolygon> TMultiPolygon; 

int main() { 
    std::cout << "BOOST_LIB_VERSION: " << BOOST_LIB_VERSION << "\n"; 
    TMultiPolygon 
     mpA{{{{ { -405129, 2010409 }, { 3370580, 2010409 }, { 3370580, 1997709 }, { -405129, 1997709 }, { -405129, 2010409 } }}}}, 
     mpB{{{{ { 3364230, -895349 }, { 3364230, 2004060 }, { 3376930, 2004059 }, { 3376930, -895350 }, { 3364230, -895349 } }}}}, 
     output; 

    bg::union_(mpA, mpB, output); 

    std::cout << "A : " << bg::wkt(mpA) << "\n"; 
    std::cout << "B : " << bg::wkt(mpB) << "\n"; 
    std::cout << "ouput : " << bg::wkt(output) << "\n"; 
} 

打印

BOOST_LIB_VERSION: 1_64 
A : POLYGON((-405129 2010409,3370580 2010409,3370580 1997709,-405129 1997709,-405129 2010409)) 
B : POLYGON((3364230 -895349,3364230 2004060,3376930 2004059,3376930 -895350,3364230 -895349)) 
ouput : MULTIPOLYGON(((3370580 2004060,3376930 2004059,3376930 -895350,3364230 -895349,3364230 1997709,-405129 1997709,-405129 2010409,3370580 2010409,3370580 2004060))) 

就包括

#include <boost/geometry/io/io.hpp> 

其实,你并不真的需要做MPA/MPB multipolygons,所以您可以:

Live On Wandbox

TPolygon 
    pA{{{ { -405129, 2010409 }, { 3370580, 2010409 }, { 3370580, 1997709 }, { -405129, 1997709 }, { -405129, 2010409 } }}}, 
    pB{{{ { 3364230, -895349 }, { 3364230, 2004060 }, { 3376930, 2004059 }, { 3376930, -895350 }, { 3364230, -895349 } }}}; 

TMultiPolygon output; 
bg::union_(pA, pB, output); 

打印:

BOOST_LIB_VERSION: 1_64 
A : POLYGON((-405129 2010409,3370580 2010409,3370580 1997709,-405129 1997709,-405129 2010409)) 
B : POLYGON((3364230 -895349,3364230 2004060,3376930 2004059,3376930 -895350,3364230 -895349)) 
ouput : MULTIPOLYGON(((3370580 2004060,3376930 2004059,3376930 -895350,3364230 -895349,3364230 1997709,-405129 1997709,-405129 2010409,3370580 2010409,3370580 2004060))) 

当然阅读支持一样的:

Live On Wandbox

TPolygon pA, pB; 
bg::read_wkt("POLYGON((-405129 2010409,3370580 2010409,3370580 1997709,-405129 1997709,-405129 2010409))", pA); 
bg::read_wkt("POLYGON((3364230 -895349,3364230 2004060,3376930 2004059,3376930 -895350,3364230 -895349))", pB); 
+0

看起来更清洁,谢谢! –

相关问题