図形の上に引かれた線を、3*3などで矩形分割する必要があったため調査メモ。
環境
サンプルコード
#include <iostream> #include <vector> #include <boost/geometry/geometry.hpp> #include <boost/geometry/geometries/linestring.hpp> #include <boost/geometry/geometries/multi_linestring.hpp> #include <boost/geometry/geometries/point_xy.hpp> int main(int argc, const char * argv[]) { namespace bg = boost::geometry; using point_d2 = bg::model::d2::point_xy<double>; using linestring_d2 = bg::model::linestring<point_d2>; linestring_d2 ls; ls.push_back(bg::make<point_d2>(1.1,1.1)); point_d2 lp; bg::assign_values(lp, 2.5, 2.1); bg::append(ls, lp); // print 2 points "((1.1, 1.1), (2.5, 2.1))" std::cout << bg::dsv(ls) << std::endl; // sqrt{(2.5-1.1)^2 + (2.1-1.1)^2} = 1.72… std::cout << "distance " << bg::distance(ls.at(0), ls.at(1)) << std::endl; // boxは境界点を持ちlinestringとの計算に使える using box_d2 = bg::model::box<point_d2>; box_d2 b; bg::envelope(ls, b); std::cout << bg::dsv(b) << std::endl; // distance equal to length std::cout << "length " << bg::length(ls) << std::endl; std::cout << "number of points 1: " << ls.size() << std::endl; std::cout << "number of points 2: " << boost::size(ls) << std::endl; std::cout << "number of points 3: " << bg::num_points(ls) << std::endl; // 点から線への垂線の長さ point_d2 p(1.9, 1.2); // 0.38 std::cout << "distance of " << bg::dsv(p) << " to line: " << bg::distance(p, ls) << std::endl; // linestringはsegmentと見做して計算することもできる double d = bg::distance(p, bg::model::segment<point_d2>(ls.front(), ls.back())); std::cout << "distance " << d << std::endl; // linestringは平滑化できる linestring_d2 ls_redundancied = { {3,3}, {3.8, 4}, {6,6}, {4,9}, {5,8}, {7,7} }; linestring_d2 ls_simplified; bg::simplify(ls_redundancied, ls_simplified, 0.5); std::cout << "not simplified :" << bg::dsv(ls_redundancied) << std::endl; // removed (3.8, 4) and (5,8) std::cout << "simplified :" << bg::dsv(ls_simplified) << std::endl; // // linestringのclipping // box_d2 cb(point_d2(1.2, 1.2), point_d2(4.5, 2.5)); std::vector<linestring_d2> clipped; ls.push_back(point_d2(1.3,1.3)); // 矩形, input, output bg::intersection(cb, ls, clipped); std::cout << "before clipped : " << bg::wkt(ls) << std::endl; for(const auto &v : clipped) { // 複数の線ができるが、multilinestringとしては解釈してもらえないのでfor文で確認 std::cout << bg::wkt(v) << std::endl; } // // multilinestringのclipping // using multilinestring = boost::geometry::model::multi_linestring<linestring_d2>; multilinestring mls; linestring_d2 ls_1 = { {1,9}, {2.8, 7}, {3,6}, {4,5}, {5,4}, {6,2} }; mls.push_back(ls_1); linestring_d2 ls_2 = { {1,2}, {5.8, 3}, {5.9,4}, {6.0,5}, {6.1,6}, {9,11} }; mls.push_back(ls_2); box_d2 cb_2(point_d2(2,3), point_d2(6, 9)); multilinestring mls_clipped; bg::intersection(cb_2, mls, mls_clipped); std::cout << "before mls(A) : " << bg::wkt(mls) << std::endl; std::cout << "clipping box(B) : " << bg::wkt(cb_2) << std::endl; std::cout << "after mls(C) : " << bg::wkt(mls_clipped) << std::endl; // // multi_pointのclipping // using bg_multipoint = boost::geometry::model::multi_point<point_d2>; bg_multipoint mp; mp.push_back(point_d2(1.4, 1.4)); mp.push_back(point_d2(2.0, 2.0)); mp.push_back(point_d2(2.9, 2.9)); mp.push_back(point_d2(3.0, 3.0)); bg_multipoint clipped_mp; box_d2 b2(point_d2(1.5,1.5), point_d2(3.0, 3.0)); for(const auto &p : mp){ // intersectionではなくintersectsで1点ずつ確認する必要があるぽい if(bg::intersects(b2, p)){ clipped_mp.push_back(p); } } // MULTIPOINT((1.4 1.4),(2 2),(2.9 2.9),(3 3)) std::cout << bg::wkt(mp) << std::endl; // MULTIPOINT((2 2),(2.9 2.9),(3 3)) std::cout << bg::wkt(clipped_mp) << std::endl; }
目で見て確認*1
before mls(A)
MULTILINESTRING((1 9,2.8 7,3 6,4 5,5 4,6 2),(1 2,5.8 3,5.9 4,6 5,6.1 6,9 11 ))
clipping box(B)
POLYGON((2 3,2 9,6 9,6 3,2 3))
after mls(C)
MULTILINESTRING((2 7.88889,2.8 7,3 6,4 5,5 4,5.5 3),(5.8 3,5.9 4,6 5))
線と矩形の接点にちゃんと点がある。
なお、矩形から完全に外れたlinestringは無視されるらしい。
その他
今回はC++かつ既存コードがboostを使用していてためBoost::Geometryを使ったが、他にもいろいろあるぽい。