Index: extensions/test/gis/io/wkb/read_wkb.cpp =================================================================== --- extensions/test/gis/io/wkb/read_wkb.cpp +++ extensions/test/gis/io/wkb/read_wkb.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include #include @@ -24,7 +26,7 @@ #include #include -#include +#include #include @@ -43,6 +45,15 @@ void test_geometry_wrong_wkb(std::string const& wkbhex, std::string const& wkt) std::cout << bg::read_wkb(wkb.begin(), wkb.end(), g_wkb) << std::endl; } +template +void test_geometry_parse_failure(std::string const& wkbhex, std::string const& wkt) +{ + byte_vector wkb; + BOOST_CHECK( bg::hex2wkb(wkbhex, std::back_inserter(wkb)) ); + Geometry g_wkb; + BOOST_CHECK( bg::read_wkb(wkb.begin(), wkb.end(), g_wkb) == false ); +} + template void test_geometry_equals(std::string const& wkbhex, std::string const& wkt) { @@ -53,6 +64,31 @@ void test_geometry_equals(std::string const& wkbhex, std::string const& wkt) Geometry g_expected; bg::read_wkt(wkt, g_expected); + + bool eq = bg::equals(g_wkb, g_expected); + + if(eq != IsEqual) + { + std::cout << "WKT EXPECTED:"<< bg::wkt(g_expected) << std::endl; + std::cout << "WKT ACTUAL:"<< bg::wkt(g_wkb) << std::endl; + } + + BOOST_CHECK( eq == IsEqual ); +} + +template +void test_geometry_print(std::string const& wkbhex, std::string const& wkt) +{ + byte_vector wkb; + BOOST_CHECK( bg::hex2wkb(wkbhex, std::back_inserter(wkb)) ); + Geometry g_wkb; + BOOST_CHECK( bg::read_wkb(wkb.begin(), wkb.end(), g_wkb) ); + + Geometry g_expected; + bg::read_wkt(wkt, g_expected); + + std::cout << "WKT OUT:"<< bg::wkt(g_wkb) << std::endl; + BOOST_CHECK( bg::equals(g_wkb, g_expected) == IsEqual ); } @@ -72,6 +108,11 @@ int test_main(int, char* []) { typedef bg::model::point point_type; typedef bg::model::linestring linestring_type; + typedef bg::model::polygon polygon_type; + + typedef bg::model::point point_3d_type; + typedef bg::model::linestring linestring_3d_type; + typedef bg::model::polygon polygon_3d_type; // // POINT @@ -110,26 +151,102 @@ int test_main(int, char* []) "01010000E0E61000005839B4C876BEF33F83C0CAA145B616400000000000002E400000000000C05340", "POINT (1.234 5.678)"); +// //// 3D - needs to implement geometry_type handling +// +// // POINT(1.234 5.678 99) +// test_geometry_equals( +// "01e90300005839b4c876bef33f83c0caa145b616400000000000c05840", "POINT Z (1.234 5.678 99)"); + // // LineString // - //test_geometry_equals( - // "0102000000030000005839B4C876BEF33F83C0CAA145B616404F401361C333224062A1D634EF3824409CC420B072482A40EB73B515FB2B3040", - // "LINESTRING (1.234 5.678, 9.1011 10.1112, 13.1415 16.1718)"); + test_geometry_equals( + "0102000000030000005839B4C876BEF33F83C0CAA145B616404F401361C333224062A1D634EF3824409CC420B072482A40EB73B515FB2B3040", + "LINESTRING (1.234 5.678, 9.1011 10.1112, 13.1415 16.1718)"); + // LINESTRING (1.234 5.678 99, 9.1011 10.1112 99, 13.1415 16.1718 99) - Z coordinate in a two-dimensional linestring + // Result is LINESTRING (1.234 5.678, 99 9.1011, 10.1112 99) + test_geometry_equals( +"0102000080030000005839B4C876BEF33F83C0CAA145B616400000000000C058404F401361C333224062A1D634EF3824400000000000C058409CC420B072482A40EB73B515FB2B30400000000000C05840", + "LINESTRING (1.234 5.678, 9.1011 10.1112, 13.1415 16.1718)"); // - // MultiPoint + // Polygon + // + + test_geometry_equals( +"010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940", + "POLYGON((100 200, 200 200, 200 400, 100 400, 100 200))" + ); + + // POLYGON((100 200 99, 200 200 99, 200 400 99, 100 400 99, 100 200 99)) - Z coordinate in a two-dimensional polygon + // Result is POLYGON((100 200,99 200,200 99,200 400,99 100)) + test_geometry_equals( +"01030000800100000005000000000000000000594000000000000069400000000000C05840000000000000694000000000000069400000000000C05840000000000000694000000000000079400000000000C05840000000000000594000000000000079400000000000C05840000000000000594000000000000069400000000000C05840", + "POLYGON((100 200, 200 200, 200 400, 100 400, 100 200))" + ); + + test_geometry_equals( +"0103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002E40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003E40000000000080414000000000008041400000000000003E40000000000000344000000000000034400000000000003E40", + "POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))" + ); + + // POLYGON ((35 10 99, 10 20 99, 15 40 99, 45 45 99, 35 10 99),(20 30 99, 35 35 99, 30 20 99, 20 30 99)) - Z coordinate in a two-dimensional polygon + // Result is POLYGON((35 10,99 10,20 99,15 40,99 45),()) + test_geometry_equals( +"01030000800200000005000000000000000080414000000000000024400000000000C05840000000000000244000000000000034400000000000C058400000000000002E4000000000000044400000000000C05840000000000080464000000000008046400000000000C05840000000000080414000000000000024400000000000C058400400000000000000000034400000000000003E400000000000C05840000000000080414000000000008041400000000000C058400000000000003E4000000000000034400000000000C0584000000000000034400000000000003E400000000000C05840", + "POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))" + ); + + + // + // Multi Geometries // typedef bg::model::multi_point multipoint_type; + typedef bg::model::multi_linestring multilinestring_type; + typedef bg::model::multi_polygon multipolygon_type; + + // + // MultiPoint + // test_geometry_equals( - "0104000000020000000101000000000000000000F03F0000000000000040010100000000000000000008400000000000001040", "MULTIPOINT (1 2, 3 4)"); + "01040000000100000001010000005839b4c876bef33f83c0caa145b61640", + "MULTIPOINT (1.234 5.678)" + ); test_geometry_equals( - "01040000000200000001010000005839B4C876BEF33F83C0CAA145B61640010100000062A1D634EF3824409CC420B072482A40", "MULTIPOINT (1.234 5.678, 10.1112 13.1415)"); + "01040000000200000001010000005839B4C876BEF33F83C0CAA145B61640010100000062A1D634EF3824409CC420B072482A40", + "MULTIPOINT (1.234 5.678, 10.1112 13.1415)" + ); + + // + // MultiLineString + // + + test_geometry_equals( + "0105000000010000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b3040", + "MULTILINESTRING((1.234 5.678,9.1011 10.1112,13.1415 16.1718))"); + test_geometry_equals( + "0105000000020000000102000000030000005839b4c876bef33f83c0caa145b616404f401361c333224062a1d634ef3824409cc420b072482a40eb73b515fb2b30400102000000020000003333333333333340b81e85eb513835403d0ad7a3703d3740c3f5285c8f423940", + "MULTILINESTRING((1.234 5.678,9.1011 10.1112,13.1415 16.1718),(19.2 21.22,23.24 25.26))"); + + + // + // MultiPolygon + // + + test_geometry_equals( +"010600000001000000010300000001000000050000000000000000005940000000000000694000000000000069400000000000006940000000000000694000000000000079400000000000005940000000000000794000000000000059400000000000006940", + "MULTIPOLYGON(((100 200,200 200,200 400,100 400,100 200)))" + ); + + test_geometry_equals( +"0106000000010000000103000000020000000500000000000000008041400000000000002440000000000000244000000000000034400000000000002e40000000000000444000000000008046400000000000804640000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40", + "MULTIPOLYGON(((35 10,10 20,15 40,45 45,35 10),(20 30,35 35,30 20,20 30)))" + ); return 0; } Index: include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp =================================================================== --- include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp +++ include/boost/geometry/extensions/gis/io/wkb/detail/ogc.hpp @@ -69,11 +69,9 @@ struct geometry_type point = 1, linestring = 2, polygon = 3, - - // TODO: Not implemented multipoint = 4, - //multilinestring = 5, - //multipolygon = 6, + multilinestring = 5, + multipolygon = 6, //collection = 7 }; }; Index: include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp =================================================================== --- include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp +++ include/boost/geometry/extensions/gis/io/wkb/detail/parser.hpp @@ -107,19 +107,15 @@ struct geometry_type_parser byte_order_type::enum_t order) { boost::uint32_t value; - if (value_parser::parse(it, end, value, order)) + if (!value_parser::parse(it, end, value, order)) { - // TODO: Refine the test when multi* geometries are supported + return false; + } - boost::uint32_t id = value & 0xff; + boost::uint32_t id = value & 0xff; + type = geometry_type::enum_t(id); - if (geometry_type::multipoint >= id) - { - type = geometry_type::enum_t(id); - return true; - } - } - return false; + return true; } }; @@ -164,24 +160,37 @@ struct parsing_assigner } }; -template +template struct point_parser { template - static bool parse(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order) + static bool parse(Iterator& it, Iterator end, Point& point, byte_order_type::enum_t order) { - // TODO: mloskot - Add assert on point dimension, 2d only - geometry_type::enum_t type; - if (geometry_type_parser::parse(it, end, type, order)) + + if (!geometry_type_parser::parse(it, end, type, order)) { - if (geometry_type::point == type && it != end) - { - parsing_assigner::value>::run(it, end, point, order); - } - return true; + return false; } - return false; + + if (geometry_type::point != type) + { + return false; + } + + // Check that the number of double values in the stream is equal + // or greater than the number of expected values in the point + + typedef typename std::iterator_traits::difference_type size_type; + + size_type const container_byte_size = dimension::value * sizeof(double); + size_type const stream_byte_size = std::distance(it,end); + + assert(stream_byte_size >= container_byte_size); + + parsing_assigner::value>::run(it, end, point, order); + + return true; } }; @@ -189,41 +198,26 @@ template struct point_container_parser { template - static bool parse(Iterator& it, Iterator end, C& container, byte_order_type::enum_t order) + static bool parse(Iterator& it, Iterator end, C& container, byte_order_type::enum_t order, boost::uint32_t num_points) { typedef typename point_type::type point_type; - boost::uint32_t num_points(0); - if (!value_parser::parse(it, end, num_points, order)) - { - return false; - } - typedef typename std::iterator_traits::difference_type size_type; assert(num_points <= boost::uint32_t( (std::numeric_limits::max)() ) ); size_type const container_size = static_cast(num_points); - size_type const point_size = dimension::value * sizeof(double); - if (std::distance(it, end) >= (container_size * point_size)) - { - point_type point_buffer; - std::back_insert_iterator output(std::back_inserter(container)); - - // Read coordinates into point and append point to line (ring) - size_type points_parsed = 0; - while (points_parsed < container_size && it != end) - { - parsing_assigner::value>::run(it, end, point_buffer, order); - output = point_buffer; - ++output; - ++points_parsed; - } + point_type point_buffer; + std::back_insert_iterator output(std::back_inserter(container)); - if (container_size != points_parsed) - { - return false; - } + // Read coordinates into point and append point to container + size_type points_parsed = 0; + while (points_parsed < container_size && it != end) + { + parsing_assigner::value>::run(it, end, point_buffer, order); + output = point_buffer; + ++output; + ++points_parsed; } return true; @@ -249,8 +243,23 @@ struct linestring_parser return false; } - assert(it != end); - return point_container_parser::parse(it, end, linestring, order); + boost::uint32_t num_points(0); + if (!value_parser::parse(it, end, num_points, order)) + { + return false; + } + + // Check that the number of double values in the stream is equal + // or greater than the number of expected values in the linestring + + typedef typename std::iterator_traits::difference_type size_type; + + size_type const container_byte_size = dimension::value * num_points * sizeof(double); + size_type const stream_byte_size = std::distance(it,end); + + assert(stream_byte_size >= container_byte_size); + + return point_container_parser::parse(it, end, linestring, order, num_points); } }; @@ -276,12 +285,21 @@ struct polygon_parser typedef typename ring_type::type ring_type; std::size_t rings_parsed = 0; - while (rings_parsed < num_rings && it != end) //while (rings_parsed < num_rings && it != end) + + while (rings_parsed < num_rings && it != end) { + + boost::uint32_t num_points(0); + if (!value_parser::parse(it, end, num_points, order)) + { + return false; + } + if (0 == rings_parsed) { ring_type& ring0 = exterior_ring(polygon); - if (!point_container_parser::parse(it, end, ring0, order)) + + if (!point_container_parser::parse(it, end, ring0, order, num_points)) { return false; } @@ -290,17 +308,14 @@ struct polygon_parser { interior_rings(polygon).resize(rings_parsed); ring_type& ringN = interior_rings(polygon).back(); - if (!point_container_parser::parse(it, end, ringN, order)) + + if (!point_container_parser::parse(it, end, ringN, order, num_points)) { return false; } } - ++rings_parsed; - } - if (num_rings != rings_parsed) - { - return false; + ++rings_parsed; } return true; Index: include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp =================================================================== --- include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp +++ include/boost/geometry/extensions/multi/gis/io/wkb/detail/parser.hpp @@ -19,6 +19,9 @@ #include #include +#include + +#include namespace boost { namespace geometry { @@ -52,6 +55,19 @@ struct multipoint_parser return false; } + // Check that the number of double values in the stream is equal + // or greater than the number of expected values in the multipoint + + typedef typename std::iterator_traits::difference_type size_type; + + size_type const container_byte_size = dimension::value * num_points * sizeof(double) + + num_points * sizeof(boost::uint8_t) + + num_points * sizeof(boost::uint32_t); + + size_type const stream_byte_size = std::distance(it,end); + + assert(stream_byte_size >= container_byte_size); + point_type point_buffer; std::back_insert_iterator output(std::back_inserter(multipoint)); @@ -67,7 +83,13 @@ struct multipoint_parser return false; } - point_parser::parse(it, end, point_buffer, point_byte_order); + geometry_type::enum_t point_type_type; + if (!geometry_type_parser::parse(it, end, point_type_type, point_byte_order)) + { + return false; + } + + parsing_assigner::value>::run(it, end, point_buffer, point_byte_order); output = point_buffer; @@ -78,6 +100,180 @@ struct multipoint_parser } }; +template +struct multilinestring_parser +{ + template + static bool parse(Iterator& it, Iterator end, MultiLinestring& multilinestring, byte_order_type::enum_t order) + { + typedef typename MultiLinestring::value_type linestring_type; + typedef typename point_type::type point_type; + + geometry_type::enum_t type; + if (!geometry_type_parser::parse(it, end, type, order)) + { + return false; + } + + if (geometry_type::multilinestring != type) + { + return false; + } + + boost::uint32_t num_linestrings(0); + if (!value_parser::parse(it, end, num_linestrings, order)) + { + return false; + } + + linestring_type linestring_buffer; + std::back_insert_iterator output(std::back_inserter(multilinestring)); + + typedef typename std::iterator_traits::difference_type size_type; + assert(num_linestrings <= boost::uint32_t( (std::numeric_limits::max)() ) ); + + size_type linestrings_parsed = 0; + while (linestrings_parsed < num_linestrings && it != end) + { + detail::wkb::byte_order_type::enum_t linestring_byte_order; + if (!detail::wkb::byte_order_parser::parse(it, end, linestring_byte_order)) + { + return false; + } + + geometry_type::enum_t type; + if (!geometry_type_parser::parse(it, end, type, linestring_byte_order)) + { + return false; + } + + if (geometry_type::linestring != type) + { + return false; + } + + boost::uint32_t num_points(0); + if (!value_parser::parse(it, end, num_points, linestring_byte_order)) + { + return false; + } + + // Check that the number of double values in the stream is equal + // or greater than the number of expected values in the linestring + + typedef typename std::iterator_traits::difference_type size_type; + + size_type const container_byte_size = dimension::value * num_points * sizeof(double); + size_type const stream_byte_size = std::distance(it,end); + + assert(stream_byte_size >= container_byte_size); + + return point_container_parser::parse(it, end, linestring_buffer, linestring_byte_order, num_points); + + output = linestring_buffer; + + ++output; + ++linestrings_parsed; + } + return true; + } +}; + +template +struct multipolygon_parser +{ + template + static bool parse(Iterator& it, Iterator end, MultiPolygon& multipolygon, byte_order_type::enum_t order) + { + typedef typename MultiPolygon::value_type polygon_type; + typedef typename ring_type::type ring_type; + + geometry_type::enum_t multipolygontype; + if (!geometry_type_parser::parse(it, end, multipolygontype, order)) + { + return false; + } + + if (geometry_type::multipolygon != multipolygontype) + { + return false; + } + + boost::uint32_t num_polygons(0); + if (!value_parser::parse(it, end, num_polygons, order)) + { + return false; + } + + polygon_type polygon_buffer; + std::back_insert_iterator output(std::back_inserter(multipolygon)); + + std::size_t polygons_parsed = 0; + while(polygons_parsed < num_polygons && it != end) + { + detail::wkb::byte_order_type::enum_t polygon_byte_order; + if (!detail::wkb::byte_order_parser::parse(it, end, polygon_byte_order)) + { + return false; + } + + geometry_type::enum_t type; + if (!geometry_type_parser::parse(it, end, type, polygon_byte_order)) + { + return false; + } + + if (geometry_type::polygon != type) + { + return false; + } + + boost::uint32_t num_rings(0); + if (geometry_type::polygon != type || + !value_parser::parse(it, end, num_rings, polygon_byte_order)) + { + return false; + } + + std::size_t rings_parsed = 0; + + while (rings_parsed < num_rings && it != end) + { + boost::uint32_t num_points(0); + if (!value_parser::parse(it, end, num_points, polygon_byte_order)) + { + return false; + } + + if (0 == rings_parsed) + { + ring_type& ring0 = exterior_ring(polygon_buffer); + + if (!point_container_parser::parse(it, end, ring0, polygon_byte_order, num_points)) + { + return false; + } + } + else + { + interior_rings(polygon_buffer).resize(rings_parsed); + ring_type& ringN = interior_rings(polygon_buffer).back(); + + if (!point_container_parser::parse(it, end, ringN, polygon_byte_order, num_points)) + { + return false; + } + } + ++rings_parsed; + } + output = polygon_buffer; + ++output; + } + + return true; + } +}; + }} // namespace detail::wkb #endif // DOXYGEN_NO_IMPL Index: include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp =================================================================== --- include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp +++ include/boost/geometry/extensions/multi/gis/io/wkb/read_wkb.hpp @@ -32,6 +32,28 @@ struct read_wkb } }; +template +struct read_wkb +{ + template + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, + detail::wkb::byte_order_type::enum_t order) + { + return detail::wkb::multilinestring_parser::parse(it, end, geometry, order); + } +}; + +template +struct read_wkb +{ + template + static inline bool parse(Iterator& it, Iterator end, Geometry& geometry, + detail::wkb::byte_order_type::enum_t order) + { + return detail::wkb::multipolygon_parser::parse(it, end, geometry, order); + } +}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH Index: include/boost/geometry/multi/algorithms/equals.hpp =================================================================== --- include/boost/geometry/multi/algorithms/equals.hpp +++ include/boost/geometry/multi/algorithms/equals.hpp @@ -41,6 +41,17 @@ struct equals : detail::equals::equals_by_collection {}; +template +struct equals + < + MultiLinestring1, MultiLinestring2, + multi_linestring_tag, multi_linestring_tag, + 2, + Reverse + > + : detail::equals::equals_by_collection +{}; + template struct equals <