diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index ee3686568..10572ec12 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -39,241 +39,243 @@ namespace mapnik { namespace util { - std::string to_hex(const char* blob, unsigned size) +std::string to_hex(const char* blob, unsigned size) +{ + std::string buf; + buf.reserve(size*2); + std::ostringstream s(buf); + s.seekp(0); + char hex[3]; + std::memset(hex,0,3); + for ( unsigned pos=0; pos < size; ++pos) { - std::string buf; - buf.reserve(size*2); - std::ostringstream s(buf); - s.seekp(0); - char hex[3]; - std::memset(hex,0,3); - for ( unsigned pos=0; pos < size; ++pos) - { - std::sprintf (hex, "%02x", int(blob[pos]) & 0xff); - s << hex; - } - return s.str(); + std::sprintf (hex, "%02x", int(blob[pos]) & 0xff); + s << hex; } + return s.str(); +} - enum wkbByteOrder { - wkbXDR=0, - wkbNDR=1 - }; +enum wkbByteOrder { + wkbXDR=0, + wkbNDR=1 +}; - inline void reverse_bytes(char size, char *address) +inline void reverse_bytes(char size, char *address) +{ + char * first = address; + char * last = first + size - 1; + for(;first < last;++first, --last) { - char * first = address; - char * last = first + size - 1; - for(;first < last;++first, --last) - { - char x = *last; - *last = *first; - *first = x; - } + char x = *last; + *last = *first; + *first = x; } +} - template - inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order) - { +template +inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order) +{ #ifdef MAPNIK_BIG_ENDIAN - bool need_swap = byte_order ? wkbNDR : wkbXDR; + bool need_swap = byte_order ? wkbNDR : wkbXDR; #else - bool need_swap = byte_order ? wkbXDR : wkbNDR; + bool need_swap = byte_order ? wkbXDR : wkbNDR; #endif - char* buf = reinterpret_cast(&val); - if (need_swap) - { - reverse_bytes(size,buf); - } - stream.write(buf,size); + char* buf = reinterpret_cast(&val); + if (need_swap) + { + reverse_bytes(size,buf); + } + stream.write(buf,size); +} + +struct wkb_buffer +{ + wkb_buffer(std::size_t size) + : size_(size), + data_( (size_!=0) ? static_cast(::operator new (size_)):0) + {} + + ~wkb_buffer() + { + ::operator delete(data_); } - struct wkb_buffer + inline std::size_t size() const { - wkb_buffer(std::size_t size) - : size_(size), - data_( (size_!=0) ? static_cast(::operator new (size_)):0) - {} + return size_; + } - ~wkb_buffer() - { - ::operator delete(data_); - } - - inline std::size_t size() const - { - return size_; - } - - inline char* buffer() - { - return data_; - } - - std::size_t size_; - char * data_; - }; - - typedef boost::shared_ptr wkb_buffer_ptr; - - wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order) + inline char* buffer() { - assert(g.size() == 1); - std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point - wkb_buffer_ptr wkb = boost::make_shared(size); - boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); - int type = static_cast(mapnik::Point); - write(ss,type,4,byte_order); - double x = 0; - double y = 0; - g.vertex(0,&x,&y); + return data_; + } + + std::size_t size_; + char * data_; +}; + +typedef boost::shared_ptr wkb_buffer_ptr; + +template +wkb_buffer_ptr to_point_wkb( GeometryType const& g, wkbByteOrder byte_order) +{ + assert(g.size() == 1); + std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point + wkb_buffer_ptr wkb = boost::make_shared(size); + boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); + ss.write(reinterpret_cast(&byte_order),1); + int type = static_cast(mapnik::Point); + write(ss,type,4,byte_order); + double x = 0; + double y = 0; + g.vertex(0,&x,&y); + write(ss,x,8,byte_order); + write(ss,y,8,byte_order); + assert(ss.good()); + return wkb; +} + +template +wkb_buffer_ptr to_line_string_wkb( GeometryType const& g, wkbByteOrder byte_order) +{ + unsigned num_points = g.size(); + assert(num_points > 1); + std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints + wkb_buffer_ptr wkb = boost::make_shared(size); + boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); + ss.write(reinterpret_cast(&byte_order),1); + int type = static_cast(mapnik::LineString); + write(ss,type,4,byte_order); + write(ss,num_points,4,byte_order); + double x = 0; + double y = 0; + for (unsigned i=0; i< num_points; ++i) + { + g.vertex(i,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); - assert(ss.good()); - return wkb; } + assert(ss.good()); + return wkb; +} - wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order) +template +wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order) +{ + unsigned num_points = g.size(); + assert(num_points > 1); + + typedef std::pair point_type; + typedef std::vector linear_ring; + boost::ptr_vector rings; + + double x = 0; + double y = 0; + std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings + for (unsigned i=0; i< num_points; ++i) { - unsigned num_points = g.size(); - assert(num_points > 1); - std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints - wkb_buffer_ptr wkb = boost::make_shared(size); - boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); - int type = static_cast(mapnik::LineString); - write(ss,type,4,byte_order); - write(ss,num_points,4,byte_order); - double x = 0; - double y = 0; - for (unsigned i=0; i< num_points; ++i) + unsigned command = g.vertex(i,&x,&y); + if (command == SEG_MOVETO) { - g.vertex(i,&x,&y); + rings.push_back(new linear_ring); // start new loop + size += 4; // num_points + } + rings.back().push_back(std::make_pair(x,y)); + size += 2 * 8; // point + } + unsigned num_rings = rings.size(); + wkb_buffer_ptr wkb = boost::make_shared(size); + boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); + + ss.write(reinterpret_cast(&byte_order),1); + int type = static_cast(mapnik::Polygon); + write(ss,type,4,byte_order); + write(ss,num_rings,4,byte_order); + + BOOST_FOREACH ( linear_ring const& ring, rings) + { + unsigned num_points = ring.size(); + write(ss,num_points,4,byte_order); + BOOST_FOREACH ( point_type const& pt, ring) + { + double x = pt.first; + double y = pt.second; write(ss,x,8,byte_order); write(ss,y,8,byte_order); } - assert(ss.good()); - return wkb; } - wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) + assert(ss.good()); + return wkb; +} + +template +wkb_buffer_ptr to_wkb(GeometryType const& g, wkbByteOrder byte_order ) +{ + wkb_buffer_ptr wkb; + + switch (g.type()) { - unsigned num_points = g.size(); - assert(num_points > 1); + case mapnik::Point: + wkb = to_point_wkb(g, byte_order); + break; + case mapnik::LineString: + wkb = to_line_string_wkb(g, byte_order); + break; + case mapnik::Polygon: + wkb = to_polygon_wkb(g, byte_order); + break; + default: + break; + } + return wkb; +} - typedef std::pair point_type; - typedef std::vector linear_ring; - boost::ptr_vector rings; +wkb_buffer_ptr to_wkb(geometry_container const& paths, wkbByteOrder byte_order ) +{ + if (paths.size() == 1) + { + // single geometry + return to_wkb(paths.front(), byte_order); + } - double x = 0; - double y = 0; - std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings - for (unsigned i=0; i< num_points; ++i) + if (paths.size() > 1) + { + // multi geometry or geometry collection + std::vector wkb_cont; + bool collection = false; + int multi_type = 0; + size_t multi_size = 1 + 4 + 4; + geometry_container::const_iterator itr = paths.begin(); + geometry_container::const_iterator end = paths.end(); + for ( ; itr!=end; ++itr) { - unsigned command = g.vertex(i,&x,&y); - if (command == SEG_MOVETO) - { - rings.push_back(new linear_ring); // start new loop - size += 4; // num_points - } - rings.back().push_back(std::make_pair(x,y)); - size += 2 * 8; // point + wkb_buffer_ptr wkb = to_wkb(*itr,byte_order); + multi_size += wkb->size(); + int type = static_cast(itr->type()); + if (multi_type > 0 && multi_type != itr->type()) + collection = true; + multi_type = type; + wkb_cont.push_back(wkb); } - unsigned num_rings = rings.size(); - wkb_buffer_ptr wkb = boost::make_shared(size); - boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); + wkb_buffer_ptr multi_wkb = boost::make_shared(multi_size); + boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary); ss.write(reinterpret_cast(&byte_order),1); - int type = static_cast(mapnik::Polygon); - write(ss,type,4,byte_order); - write(ss,num_rings,4,byte_order); + multi_type = collection ? 7 : multi_type + 3; + write(ss,multi_type, 4, byte_order); + write(ss,paths.size(),4,byte_order); - BOOST_FOREACH ( linear_ring const& ring, rings) + BOOST_FOREACH ( wkb_buffer_ptr const& wkb, wkb_cont) { - unsigned num_points = ring.size(); - write(ss,num_points,4,byte_order); - BOOST_FOREACH ( point_type const& pt, ring) - { - double x = pt.first; - double y = pt.second; - write(ss,x,8,byte_order); - write(ss,y,8,byte_order); - } + ss.write(wkb->buffer(),wkb->size()); } - - assert(ss.good()); - return wkb; + return multi_wkb; } - wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order ) - { - wkb_buffer_ptr wkb; - - switch (g.type()) - { - case mapnik::Point: - wkb = to_point_wkb(g, byte_order); - break; - case mapnik::LineString: - wkb = to_line_string_wkb(g, byte_order); - break; - case mapnik::Polygon: - wkb = to_polygon_wkb(g, byte_order); - break; - default: - break; - } - return wkb; - } - - wkb_buffer_ptr to_wkb(geometry_container const& paths, wkbByteOrder byte_order ) - { - if (paths.size() == 1) - { - // single geometry - return to_wkb(paths.front(), byte_order); - } - - if (paths.size() > 1) - { - // multi geometry or geometry collection - std::vector wkb_cont; - bool collection = false; - int multi_type = 0; - size_t multi_size = 1 + 4 + 4; - geometry_container::const_iterator itr = paths.begin(); - geometry_container::const_iterator end = paths.end(); - for ( ; itr!=end; ++itr) - { - wkb_buffer_ptr wkb = to_wkb(*itr,byte_order); - multi_size += wkb->size(); - int type = static_cast(itr->type()); - if (multi_type > 0 && multi_type != itr->type()) - collection = true; - multi_type = type; - wkb_cont.push_back(wkb); - } - - wkb_buffer_ptr multi_wkb = boost::make_shared(multi_size); - boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary); - ss.write(reinterpret_cast(&byte_order),1); - multi_type = collection ? 7 : multi_type + 3; - write(ss,multi_type, 4, byte_order); - write(ss,paths.size(),4,byte_order); - - BOOST_FOREACH ( wkb_buffer_ptr const& wkb, wkb_cont) - { - ss.write(wkb->buffer(),wkb->size()); - } - return multi_wkb; - } - - return wkb_buffer_ptr(); - } - - }} - + return wkb_buffer_ptr(); +} +}} #endif // MAPNIK_GEOMETRY_TO_WKB_HPP