// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Linestring Example #include // for reverse, unique #include #include #include #include #include #include #include #include // Optional includes and defines to handle c-arrays as points, std::vectors as linestrings #include #include BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian) BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(std::vector) BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(std::deque) template inline void translate_function(P& p) { p.x(p.x() + 100.0); } template struct scale_functor { inline void operator()(P& p) { p.x(p.x() * 1000.0); p.y(p.y() * 1000.0); } }; template struct round_coordinates { typedef typename boost::geometry::coordinate_type::type coordinate_type; coordinate_type m_factor; inline round_coordinates(coordinate_type const& factor) : m_factor(factor) {} template inline void round(Point& p) { coordinate_type c = boost::geometry::get(p) / m_factor; int rounded = c; boost::geometry::set(p, coordinate_type(rounded) * m_factor); } inline void operator()(Point& p) { round<0>(p); round<1>(p); } }; int main(void) { using namespace boost::geometry; // Define a linestring, which is a vector of points, and add some points // (we add them deliberately in different ways) typedef model::d2::point_xy point_2d; typedef model::linestring linestring_2d; linestring_2d ls; // points can be created using "make" and added to a linestring using the std:: "push_back" ls.push_back(make(1.1, 1.1)); // points can also be assigned using "assign_values" and added to a linestring using "append" point_2d lp; assign_values(lp, 2.5, 2.1); append(ls, lp); // Lines can be streamed using DSV (delimiter separated values) std::cout << dsv(ls) << std::endl; // The bounding box of linestrings can be calculated typedef model::box box_2d; box_2d b; envelope(ls, b); std::cout << dsv(b) << std::endl; // The length of the line can be calulated std::cout << "length: " << length(ls) << std::endl; // All things from std::vector can be called, because a linestring is a vector std::cout << "number of points 1: " << ls.size() << std::endl; // All things from boost ranges can be called because a linestring is considered as a range std::cout << "number of points 2: " << boost::size(ls) << std::endl; // Generic function from geometry/OGC delivers the same value std::cout << "number of points 3: " << num_points(ls) << std::endl; // The distance from a point to a linestring can be calculated point_2d p(1.9, 1.2); std::cout << "distance of " << dsv(p) << " to line: " << distance(p, ls) << std::endl; // A linestring is a vector. However, some algorithms consider "segments", // which are the line pieces between two points of a linestring. double d = distance(p, model::segment(ls.front(), ls.back())); std::cout << "distance: " << d << std::endl; // Add some three points more, let's do it using a classic array. // (See documentation for picture of this linestring) const double c[][2] = { {3.1, 3.1}, {4.9, 1.1}, {3.1, 1.9} }; append(ls, c); std::cout << "appended: " << dsv(ls) << std::endl; // Output as iterator-pair on a vector { std::vector v; std::copy(ls.begin(), ls.end(), std::back_inserter(v)); std::cout << "as vector: " << dsv(v) << std::endl; } // All algorithms from std can be used: a linestring is a vector std::reverse(ls.begin(), ls.end()); std::cout << "reversed: " << dsv(ls) << std::endl; std::reverse(boost::begin(ls), boost::end(ls)); // The other way, using a vector instead of a linestring, is also possible std::vector pv(ls.begin(), ls.end()); std::cout << "length: " << length(pv) << std::endl; // If there are double points in the line, you can use unique to remove them // So we add the last point, print, make a unique copy and print { // (sidenote, we have to make copies, because // ls.push_back(ls.back()) often succeeds but // IS dangerous and erroneous! point_2d last = ls.back(), first = ls.front(); ls.push_back(last); ls.insert(ls.begin(), first); } std::cout << "extra duplicate points: " << dsv(ls) << std::endl; { linestring_2d ls_copy; std::unique_copy(ls.begin(), ls.end(), std::back_inserter(ls_copy), boost::geometry::equal_to()); ls = ls_copy; std::cout << "uniquecopy: " << dsv(ls) << std::endl; } // Lines can be simplified. This removes points, but preserves the shape linestring_2d ls_simplified; simplify(ls, ls_simplified, 0.5); std::cout << "simplified: " << dsv(ls_simplified) << std::endl; // for_each: // 1) Lines can be visited with std::for_each // 2) for_each_point is also defined for all geometries // 3) for_each_segment is defined for all geometries to all segments // 4) loop is defined for geometries to visit segments // with state apart, and to be able to break out (not shown here) { linestring_2d lscopy = ls; std::for_each(lscopy.begin(), lscopy.end(), translate_function); for_each_point(lscopy, scale_functor()); for_each_point(lscopy, translate_function); std::cout << "modified line: " << dsv(lscopy) << std::endl; } // Lines can be clipped using a clipping box. Clipped lines are added to the output iterator box_2d cb(point_2d(1.5, 1.5), point_2d(4.5, 2.5)); std::vector clipped; intersection(cb, ls, clipped); // Also possible: clip-output to a vector of vectors std::vector > vector_out; intersection(cb, ls, vector_out); std::cout << "clipped output as vector:" << std::endl; for (std::vector >::const_iterator it = vector_out.begin(); it != vector_out.end(); ++it) { std::cout << dsv(*it) << std::endl; } // Calculate the convex hull of the linestring model::polygon hull; convex_hull(ls, hull); std::cout << "Convex hull:" << dsv(hull) << std::endl; // All the above assumed 2D Cartesian linestrings. 3D is possible as well // Let's define a 3D point ourselves, this time using 'float' typedef model::point point_3d; model::linestring line3; line3.push_back(make(1,2,3)); line3.push_back(make(4,5,6)); line3.push_back(make(7,8,9)); // Not all algorithms work on 3d lines. For example convex hull does NOT. // But, for example, length, distance, simplify, envelope and stream do. std::cout << "3D: length: " << length(line3) << " line: " << dsv(line3) << std::endl; // With DSV you can also use other delimiters, e.g. JSON style std::cout << "JSON: " << dsv(ls, ", ", "[", "]", ", ", "[ ", " ]") << std::endl; return 0; }