1
// Generic Geometry Library
3
// Copyright Mateusz Loskot <mateusz@loskot.net> 2009
4
// Use, modification and distribution is subject to the Boost Software License,
5
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6
// http://www.boost.org/LICENSE_1_0.txt)
8
#ifndef GGL_IO_WKB_DETAIL_PARSER_HPP
9
#define GGL_IO_WKB_DETAIL_PARSER_HPP
17
#include <boost/cstdint.hpp>
18
#include <boost/type_traits/is_integral.hpp>
19
#include <boost/type_traits/is_same.hpp>
20
#include <boost/static_assert.hpp>
21
#include <boost/concept/requires.hpp>
23
#include <ggl/core/access.hpp>
24
#include <ggl/core/coordinate_dimension.hpp>
25
#include <ggl/core/coordinate_type.hpp>
26
#include <ggl/core/concepts/point_concept.hpp>
27
#include <ggl/core/exterior_ring.hpp>
28
#include <ggl/core/interior_rings.hpp>
29
#include <ggl/extensions/gis/io/wkb/detail/endian.hpp>
30
#include <ggl/extensions/gis/io/wkb/detail/ogc.hpp>
35
#ifndef DOXYGEN_NO_IMPL
36
namespace detail { namespace wkb {
43
template <typename Iterator>
44
static bool parse(Iterator& it, Iterator end, T& value, byte_order_type::enum_t order)
46
// Very basic pre-conditions check on stream of bytes passed in
48
boost::is_integral<typename std::iterator_traits<Iterator>::value_type>::value
50
BOOST_STATIC_ASSERT((sizeof(boost::uint8_t) ==
51
sizeof(typename std::iterator_traits<Iterator>::value_type)
54
typedef typename std::iterator_traits<Iterator>::difference_type diff_type;
55
diff_type const required_size = sizeof(T);
56
if (it != end && std::distance(it, end) >= required_size)
58
typedef endian::endian_value<T> parsed_value_type;
59
parsed_value_type parsed_value;
61
// Decide on direcion of endianness translation, detault to native
62
if (byte_order_type::xdr == order)
64
parsed_value.template load<endian::big_endian_tag>(it);
66
else if (byte_order_type::ndr == order)
68
parsed_value.template load<endian::little_endian_tag>(it);
72
parsed_value.template load<endian::native_endian_tag>(it);
76
std::advance(it, required_size);
84
struct byte_order_parser
86
template <typename Iterator>
87
static bool parse(Iterator& it, Iterator end, byte_order_type::enum_t& order)
90
if (value_parser<boost::uint8_t>::parse(it, end, value, byte_order_type::unknown))
92
if (byte_order_type::unknown > value)
94
order = byte_order_type::enum_t(value);
102
struct geometry_type_parser
104
template <typename Iterator>
105
static bool parse(Iterator& it, Iterator end, geometry_type::enum_t& type,
106
byte_order_type::enum_t order)
108
boost::uint32_t value;
109
if (value_parser<boost::uint32_t>::parse(it, end, value, order))
111
// TODO: Refine the test when multi* geometries are supported
113
boost::uint32_t id = value & 0xff;
114
if (geometry_type::polygon >= id)
116
type = geometry_type::enum_t(id);
124
template <typename P, int I, int N>
125
struct parsing_assigner
127
template <typename Iterator>
128
static void run(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
130
typedef typename coordinate_type<P>::type coordinate_type;
132
// coordinate type in WKB is always double
134
if (value_parser<double>::parse(it, end, value, order))
136
// actual coordinate type of point may be different
137
set<I>(point, static_cast<coordinate_type>(value));
141
// TODO: mloskot - Report premature termination at coordinate level
142
//throw failed to read coordinate value
144
// default initialized value as fallback
145
set<I>(point, coordinate_type());
147
parsing_assigner<P, I+1, N>::run(it, end, point, order);
151
template <typename P, int N>
152
struct parsing_assigner<P, N, N>
154
template <typename Iterator>
155
static void run(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
161
template <typename P>
164
template <typename Iterator>
165
static bool parse(Iterator& it, Iterator end, P& point, byte_order_type::enum_t order)
167
// TODO: mloskot - Add assert on point dimension, 2d only
169
geometry_type::enum_t type;
170
if (geometry_type_parser::parse(it, end, type, order))
172
if (geometry_type::point == type && it != end)
174
parsing_assigner<P, 0, dimension<P>::value>::run(it, end, point, order);
182
BOOST_CONCEPT_ASSERT((concept::Point<P>));
185
template <typename C>
186
struct point_container_parser
188
template <typename Iterator>
189
static bool parse(Iterator& it, Iterator end, C& container, byte_order_type::enum_t order)
191
typedef typename point_type<C>::type point_type;
193
boost::uint32_t num_points(0);
194
if (!value_parser<boost::uint32_t>::parse(it, end, num_points, order))
199
typedef typename std::iterator_traits<Iterator>::difference_type size_type;
200
assert(num_points <= boost::uint32_t( (std::numeric_limits<size_type>::max)() ) );
202
size_type const container_size = static_cast<size_type>(num_points);
203
size_type const point_size = dimension<point_type>::value * sizeof(double);
205
if (std::distance(it, end) >= (container_size * point_size))
207
point_type point_buffer;
208
std::back_insert_iterator<C> output(std::back_inserter(container));
210
// Read coordinates into point and append point to line (ring)
211
size_type points_parsed = 0;
212
while (points_parsed < container_size && it != end)
214
parsing_assigner<point_type, 0, dimension<point_type>::value>::run(it, end, point_buffer, order);
215
output = point_buffer;
220
if (container_size != points_parsed)
230
template <typename L>
231
struct linestring_parser
233
template <typename Iterator>
234
static bool parse(Iterator& it, Iterator end, L& linestring, byte_order_type::enum_t order)
236
typedef typename point_type<L>::type point_type;
238
geometry_type::enum_t type;
239
if (!geometry_type_parser::parse(it, end, type, order))
244
if (geometry_type::linestring != type)
250
return point_container_parser<L>::parse(it, end, linestring, order);
254
template <typename Polygon>
255
struct polygon_parser
257
template <typename Iterator>
258
static bool parse(Iterator& it, Iterator end, Polygon& polygon, byte_order_type::enum_t order)
260
geometry_type::enum_t type;
261
if (!geometry_type_parser::parse(it, end, type, order))
266
boost::uint32_t num_rings(0);
267
if (geometry_type::polygon != type ||
268
!value_parser<boost::uint32_t>::parse(it, end, num_rings, order))
273
typedef typename ring_type<Polygon>::type ring_type;
275
std::size_t rings_parsed = 0;
276
while (rings_parsed < num_rings && it != end) //while (rings_parsed < num_rings && it != end)
278
if (0 == rings_parsed)
280
ring_type& ring0 = exterior_ring(polygon);
281
if (!point_container_parser<ring_type>::parse(it, end, ring0, order))
288
interior_rings(polygon).resize(rings_parsed);
289
ring_type& ringN = interior_rings(polygon).back();
290
if (!point_container_parser<ring_type>::parse(it, end, ringN, order))
298
if (num_rings != rings_parsed)
307
}}} // namespace ggl::detail::wkb
308
#endif // DOXYGEN_NO_IMPL
310
#endif // GGL_IO_WKB_DETAIL_PARSER_HPP