2017-08-11 119 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

看起來更清潔,謝謝! –

相關問題