// Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_TEST_MODULE #define BOOST_TEST_MODULE test_point_iterator #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // At the end because of conflicts with Boost.QVM #include namespace bg = ::boost::geometry; namespace ba = ::boost::assign; typedef bg::model::point point_type; typedef bg::model::point point_type_3d; typedef bg::model::linestring linestring_type; typedef bg::model::polygon polygon_type; //ccw, open // multi geometries typedef bg::model::multi_point multi_point_type; typedef bg::model::multi_point multi_point_type_3d; typedef bg::model::multi_linestring multi_linestring_type; typedef bg::model::multi_polygon multi_polygon_type; typedef boost::tuple tuple_point_type; typedef boost::tuple tuple_point_type_3d; typedef std::vector tuple_multi_point_type; typedef std::vector tuple_multi_point_type_3d; template struct vector_as_multipoint : std::vector {}; template struct vector_as_linestring : std::vector {}; BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type) BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type_3d) BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(vector_as_multipoint) BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(vector_as_linestring) template inline Geometry from_wkt(std::string const& wkt) { Geometry geometry; boost::geometry::read_wkt(wkt, geometry); return geometry; } // this function is implemented because std::max_element() requires ForwardIterator // but bg::point_iterator<> is InputIterator since it returns non-true reference template inline boost::optional::value_type> max_value(InputIt first, InputIt last, Pred pred) { typedef typename std::iterator_traits::value_type value_type; if (first != last) { value_type found = *first++; for (; first != last; ) { value_type current = *first++; if (pred(current, found)) found = current; } return found; } return boost::none; } template inline std::ostream& print_point_range(std::ostream& os, Iterator first, Iterator beyond, std::string const& header) { os << header << "("; for (Iterator it = first; it != beyond; ++it) { os << " " << bg::dsv(*it); } os << " )"; return os; } template < typename Geometry, bool Enable = true, bool IsConst = boost::is_const::value > struct test_iterator_concepts { typedef bg::point_iterator iterator; BOOST_CONCEPT_ASSERT((boost::BidirectionalIteratorConcept)); BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept)); BOOST_CONCEPT_ASSERT((boost_concepts::LvalueIteratorConcept)); BOOST_CONCEPT_ASSERT ((boost_concepts::BidirectionalTraversalConcept)); }; template struct test_iterator_concepts : test_iterator_concepts { typedef bg::point_iterator iterator; BOOST_CONCEPT_ASSERT ((boost::Mutable_BidirectionalIteratorConcept)); BOOST_CONCEPT_ASSERT ((boost_concepts::WritableIteratorConcept)); BOOST_CONCEPT_ASSERT ((boost_concepts::SwappableIteratorConcept)); }; template struct test_iterator_concepts {}; struct equals { template static inline std::size_t number_of_elements(Iterator begin, Iterator end) { std::size_t size = std::distance(begin, end); std::size_t num_elems(0); for (Iterator it = begin; it != end; ++it) { ++num_elems; } BOOST_CHECK(size == num_elems); num_elems = 0; for (Iterator it = end; it != begin; --it) { ++num_elems; } BOOST_CHECK(size == num_elems); return num_elems; } template static inline bool apply(Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2) { std::size_t num_points1 = number_of_elements(begin1, end1); std::size_t num_points2 = number_of_elements(begin2, end2); if (num_points1 != num_points2) { return false; } Iterator1 it1 = begin1; Iterator2 it2 = begin2; for (; it1 != end1; ++it1, ++it2) { if (! bg::equals(*it1, *it2)) { return false; } } return true; } }; template struct test_assignment { template static inline void apply(Iterator it, ConstIterator cit, Value const& value1, Value const& value2) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "== before assignment ==" << std::endl; std::cout << "value1: " << bg::wkt(value1) << std::endl; std::cout << "value2: " << bg::wkt(value2) << std::endl; std::cout << "*it : " << bg::wkt(*it) << std::endl; std::cout << "*cit : " << bg::wkt(*cit) << std::endl; #endif BOOST_CHECK(bg::equals(*it, value1)); BOOST_CHECK(! bg::equals(*it, value2)); BOOST_CHECK(bg::equals(*cit, value1)); BOOST_CHECK(! bg::equals(*cit, value2)); *it = value2; BOOST_CHECK(bg::equals(*it, value2)); BOOST_CHECK(! bg::equals(*it, value1)); BOOST_CHECK(bg::equals(*cit, value2)); BOOST_CHECK(! bg::equals(*cit, value1)); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "== after 1st assignment ==" << std::endl; std::cout << "value1: " << bg::wkt(value1) << std::endl; std::cout << "value2: " << bg::wkt(value2) << std::endl; std::cout << "*it : " << bg::wkt(*it) << std::endl; std::cout << "*cit : " << bg::wkt(*cit) << std::endl; #endif *it = value1; BOOST_CHECK(bg::equals(*it, value1)); BOOST_CHECK(! bg::equals(*it, value2)); BOOST_CHECK(bg::equals(*cit, value1)); BOOST_CHECK(! bg::equals(*cit, value2)); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "== after 2nd assignment ==" << std::endl; std::cout << "value1: " << bg::wkt(value1) << std::endl; std::cout << "value2: " << bg::wkt(value2) << std::endl; std::cout << "*it : " << bg::wkt(*it) << std::endl; std::cout << "*cit : " << bg::wkt(*cit) << std::endl; std::cout << std::endl; #endif } }; template <> struct test_assignment { template static inline void apply(Iterator, ConstIterator, Value const&, Value const&) { } }; template < typename Geometry, typename PointRange, bool EnableConceptChecks = true > struct test_point_iterator_of_geometry { typedef typename bg::point_type::type point_type; template static inline void base_test(G& geometry, PointRange const& point_range, std::string const& header) { typedef bg::point_iterator point_iterator; test_iterator_concepts(); point_iterator begin = bg::points_begin(geometry); point_iterator end = bg::points_end(geometry); BOOST_CHECK(std::size_t(std::distance(begin, end)) == bg::num_points(geometry)); BOOST_CHECK(equals::apply(begin, end, bg::points_begin(point_range), bg::points_end(point_range)) ); boost::ignore_unused(header); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << header << " geometry: " << bg::wkt(geometry) << std::endl; print_point_range(std::cout, begin, end, "point range: "); std::cout << std::endl; typedef bg::point_iterator point_range_iterator; print_point_range(std::cout, bg::points_begin(point_range), bg::points_end(point_range), "expected point range: "); std::cout << std::endl; #endif } template struct test_reverse { template static inline void apply(Iterator first, Iterator last, G const& geometry) { boost::ignore_unused(geometry); std::reverse(first, last); #ifdef BOOST_GEOMETRY_TEST_DEBUG print_point_range(std::cout, first, last, "reversed:\n") << std::endl; std::cout << bg::wkt(geometry) << std::endl; std::cout << std::endl; #endif std::reverse(first, last); #ifdef BOOST_GEOMETRY_TEST_DEBUG print_point_range(std::cout, first, last, "re-reversed:\n") << std::endl; std::cout << bg::wkt(geometry) << std::endl; std::cout << std::endl; std::cout << std::endl; #endif } }; template struct test_reverse { template static inline void apply(Iterator, Iterator, G const&) { } }; static inline void apply(Geometry geometry, PointRange const& point_range, point_type const& zero_point) { base_test(geometry, point_range, "non-const"); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl; #endif base_test(geometry, point_range, "const"); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl; #endif // testing construction of const and non-const iterator typedef bg::point_iterator point_iterator; typedef bg::point_iterator const_point_iterator; point_iterator begin = bg::points_begin(geometry); point_iterator end = bg::points_end(geometry); const_point_iterator const_begin = bg::points_begin(geometry); const_point_iterator const_end = bg::points_end(geometry); // same for reverse iterator typedef bg::point_reverse_iterator point_reverse_iterator; typedef bg::point_reverse_iterator < Geometry const > const_point_reverse_iterator; point_reverse_iterator rbegin = bg::points_rbegin(geometry); point_reverse_iterator rend = bg::points_rend(geometry); const_point_reverse_iterator const_rbegin = bg::points_rbegin(geometry); const_point_reverse_iterator const_rend = bg::points_rend(geometry); // testing assignment of non-const to const iterator const_begin = begin; const_end = end; // testing assignment of non-const to const reverse_iterator const_rbegin = rbegin; const_rend = rend; // testing equality/inequality comparison BOOST_CHECK(begin == const_begin); BOOST_CHECK(end == const_end); if (begin != end) { BOOST_CHECK(begin != const_end); BOOST_CHECK(const_begin != end); } // testing equality/inequality comparison for reverse_iterator BOOST_CHECK(rbegin == const_rbegin); BOOST_CHECK(rend == const_rend); if (rbegin != rend) { BOOST_CHECK(rbegin != const_rend); BOOST_CHECK(const_rbegin != rend); } if (begin != end) { BOOST_CHECK(rbegin != rend); point_reverse_iterator rlast(rend); --rlast; BOOST_CHECK(bg::equals(*begin, *rlast)); point_iterator last(end); --last; BOOST_CHECK(bg::equals(*rbegin, *last)); } // testing dereferencing/assignment bool const is_reference = boost::is_reference < typename std::iterator_traits::reference >::value; if (begin != end) { if (BOOST_GEOMETRY_CONDITION(is_reference)) { point_type p = *begin; point_type q = zero_point; test_assignment::apply(begin, const_begin, p, q); *begin = q; test_assignment::apply(begin, const_begin, q, p); *begin = p; } } // test with algorithms #ifdef BOOST_GEOMETRY_TEST_DEBUG print_point_range(std::cout, begin, end, "original:\n") << std::endl; print_point_range(std::cout, rbegin, rend, "reverse traversal:\n") << std::endl; std::cout << bg::wkt(geometry) << std::endl; std::cout << std::endl; #endif test_reverse::apply(begin, end, geometry); typedef typename std::iterator_traits < point_iterator >::value_type point; if (const_begin != const_end) { boost::optional pt_max = max_value(const_begin, const_end, bg::less()); BOOST_CHECK(bool(pt_max)); // to avoid warnings #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "max point: " << bg::dsv(*pt_max) << std::endl; #endif } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl; std::cout << std::endl; std::cout << std::endl; #endif } static inline void apply(Geometry geometry, PointRange const& point_range) { apply(geometry, point_range, bg::make_zero()); } }; //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_linestring_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** LINESTRING ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef linestring_type L; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt("LINESTRING()"), TMP() ); tester::apply(from_wkt("LINESTRING(3 3,4 4,5 5)"), ba::tuple_list_of(3,3)(4,4)(5,5) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_polygon_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** POLYGON ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef polygon_type P; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt

("POLYGON()"), TMP() ); tester::apply(from_wkt

("POLYGON(())"), TMP() ); tester::apply(from_wkt

("POLYGON((1 1,9 1,9 9,1 9),(5 5,6 5,6 6,5 6))"), ba::tuple_list_of(1,1)(9,1)(9,9)(1,9)(5,5)(6,5)(6,6)(5,6) ); tester::apply(from_wkt

("POLYGON((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),())"), ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9) ); tester::apply(from_wkt

("POLYGON((),(3 3,4 4,5 5),(),(),(6 6,7 7,8 8),(),(),(9 9),())"), ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multipoint_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTIPOINT ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef multi_point_type MP; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt("MULTIPOINT()"), TMP() ); tester::apply(from_wkt("MULTIPOINT(3 3,4 4,5 5)"), ba::tuple_list_of(3,3)(4,4)(5,5) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multipoint_3d_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTIPOINT 3D ***" << std::endl; #endif typedef tuple_multi_point_type_3d TMP; typedef multi_point_type_3d MP; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt("MULTIPOINT()"), TMP() ); tester::apply(from_wkt("MULTIPOINT(3 3 3,4 4 4,5 5 5)"), ba::tuple_list_of(3,3,3)(4,4,4)(5,5,5) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multilinestring_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTILINESTRING ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef multi_linestring_type ML; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt("MULTILINESTRING()"), TMP() ); tester::apply(from_wkt("MULTILINESTRING(())"), TMP() ); tester::apply(from_wkt("MULTILINESTRING((),(),())"), TMP() ); tester::apply(from_wkt("MULTILINESTRING((1 1,2 2,3 3),(3 3,4 4,5 5),(6 6))"), ba::tuple_list_of(1,1)(2,2)(3,3)(3,3)(4,4)(5,5)(6,6) ); tester::apply(from_wkt("MULTILINESTRING((),(),(1 1,2 2,3 3),(),(),(3 3,4 4,5 5),(),(6 6),(),(),())"), ba::tuple_list_of(1,1)(2,2)(3,3)(3,3)(4,4)(5,5)(6,6) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multipolygon_point_iterator ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTIPOLYGON ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef multi_polygon_type MPL; typedef test_point_iterator_of_geometry tester; tester::apply(from_wkt("MULTIPOLYGON()"), TMP() ); tester::apply(from_wkt("MULTIPOLYGON( () )"), TMP() ); tester::apply(from_wkt("MULTIPOLYGON( (()) )"), TMP() ); tester::apply(from_wkt("MULTIPOLYGON( ((),()) )"), TMP() ); tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(6 6,7 7,8 8),(9 9)),((1 1,2 2,10 10),(11 11,12 12)))"), ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ (1,1)(2,2)(10,10)(11,11)(12,12) ); tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),()),((),(1 1,2 2,10 10),(),(),(),(11 11,12 12),(),(),(13 13),()))"), ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ (1,1)(2,2)(10,10)(11,11)(12,12)(13,13) ); tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),()),((),(1 1,2 2,10 10),(),(),(),(11 11,12 12),(),(),(13 13),()),((),(),()))"), ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ (1,1)(2,2)(10,10)(11,11)(12,12)(13,13) ); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl; #endif } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multipoint_of_point_pointers ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTIPOINT OF POINT POINTERS ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef vector_as_multipoint MP; MP multipoint; for (int i = 1; i < 10; i++) { test::test_point_xy* p = new test::test_point_xy; p->x = i; p->y = -i; multipoint.push_back(p); } test::test_point_xy* zero = new test::test_point_xy; zero->x = 0; zero->y = 0; typedef test_point_iterator_of_geometry tester; tester::apply(multipoint, ba::tuple_list_of(1,-1)(2,-2)(3,-3)(4,-4)(5,-5)(6,-6)\ (7,-7)(8,-8)(9,-9), zero ); for (unsigned int i = 0; i < multipoint.size(); i++) { delete multipoint[i]; } delete zero; } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_linestring_of_point_pointers ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** LINESTRING OF POINT POINTERS ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef vector_as_linestring L; L linestring; for (int i = 1; i < 10; i++) { test::test_point_xy* p = new test::test_point_xy; p->x = i; p->y = -i; linestring.push_back(p); } test::test_point_xy* zero = new test::test_point_xy; zero->x = 0; zero->y = 0; typedef test_point_iterator_of_geometry tester; tester::apply(linestring, ba::tuple_list_of(1,-1)(2,-2)(3,-3)(4,-4)(5,-5)(6,-6)\ (7,-7)(8,-8)(9,-9), zero ); for (unsigned int i = 0; i < linestring.size(); i++) { delete linestring[i]; } delete zero; } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_multipoint_copy_on_dereference ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** MULTIPOINT WITH COPY-ON-DEREFERENCE ITERATOR ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef multipoint_copy_on_dereference MP; typedef test_point_iterator_of_geometry < MP, TMP, false // no concept checks > tester; // bg::read_wkt does not work for this multipoint type so we have // to initialize the multipoint manually MP multipoint; for (int i = 1; i < 10; ++i) { multipoint.push_back(point_type(i, -i)); } tester::apply(multipoint, // from_wkt("MULTIPOINT(1 -1,2 -2,3 -3,4 -4,5 -5,6 -6, 7 -7,8 -8,9 -9)"), ba::tuple_list_of(1,-1)(2,-2)(3,-3)(4,-4)(5,-5)(6,-6)\ (7,-7)(8,-8)(9,-9) ); } //====================================================================== //====================================================================== BOOST_AUTO_TEST_CASE( test_linestring_copy_on_dereference ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "*** LINESTRING WITH COPY-ON-DEREFERENCE ITERATOR ***" << std::endl; #endif typedef tuple_multi_point_type TMP; typedef linestring_copy_on_dereference L; typedef test_point_iterator_of_geometry < L, TMP, false // no concept checks > tester; tester::apply(from_wkt("LINESTRING(1 -1,2 -2,3 -3,4 -4,5 -5,6 -6, 7 -7,8 -8,9 -9)"), ba::tuple_list_of(1,-1)(2,-2)(3,-3)(4,-4)(5,-5)(6,-6)\ (7,-7)(8,-8)(9,-9) ); }