mapnik-geometry based to_wkb() implementation

This commit is contained in:
artemp 2015-03-16 16:14:17 +01:00
parent 58d07338e9
commit 5f073ee299

View file

@ -2,7 +2,7 @@
* *
* This file is part of Mapnik (c++ mapping toolkit) * This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -26,9 +26,9 @@
// mapnik // mapnik
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/make_unique.hpp> #include <mapnik/make_unique.hpp>
#include <mapnik/geometry.hpp> #include <mapnik/wkb.hpp>
#include <mapnik/geometry_impl.hpp>
#include <mapnik/vertex.hpp> #include <mapnik/geometry_type.hpp>
// stl // stl
#include <sstream> #include <sstream>
@ -38,17 +38,17 @@
#include <memory> #include <memory>
#include <cassert> #include <cassert>
namespace mapnik { namespace util { namespace mapnik { namespace util { namespace detail {
std::string to_hex(const char* blob, unsigned size) std::string to_hex(const char* blob, unsigned size)
{ {
std::string buf; std::string buf;
buf.reserve(size*2); buf.reserve(size * 2);
std::ostringstream s(buf); std::ostringstream s(buf);
s.seekp(0); s.seekp(0);
char hex[3]; char hex[3];
std::memset(hex,0,3); std::memset(hex, 0, 3);
for ( unsigned pos=0; pos < size; ++pos) for ( unsigned pos = 0; pos < size; ++pos)
{ {
std::sprintf (hex, "%02x", int(blob[pos]) & 0xff); std::sprintf (hex, "%02x", int(blob[pos]) & 0xff);
s << hex; s << hex;
@ -107,7 +107,7 @@ struct wkb_buffer
{ {
wkb_buffer(std::size_t size) wkb_buffer(std::size_t size)
: size_(size), : size_(size),
data_( (size_!=0) ? static_cast<char*>(::operator new (size_)):0) data_( (size_ != 0) ? static_cast<char*>(::operator new (size_)) : 0)
{} {}
~wkb_buffer() ~wkb_buffer()
@ -131,96 +131,70 @@ struct wkb_buffer
using wkb_buffer_ptr = std::unique_ptr<wkb_buffer>; using wkb_buffer_ptr = std::unique_ptr<wkb_buffer>;
template<typename GeometryType> wkb_buffer_ptr point_wkb( new_geometry::point const& pt, wkbByteOrder byte_order)
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
std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size); wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
wkb_stream ss(wkb->buffer(), wkb->size()); wkb_stream ss(wkb->buffer(), wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1); ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(mapnik::new_geometry::geometry_types::Point); write(ss, static_cast<int>(new_geometry::geometry_types::Point), 4 , byte_order);
write(ss,type,4,byte_order); write(ss, pt.x, 8, byte_order);
double x = 0; write(ss, pt.y, 8, byte_order);
double y = 0;
g.vertex(0,&x,&y);
write(ss,x,8,byte_order);
write(ss,y,8,byte_order);
assert(ss.good()); assert(ss.good());
return std::move(wkb); return std::move(wkb);
} }
template<typename GeometryType> wkb_buffer_ptr line_string_wkb(new_geometry::line_string const& line, wkbByteOrder byte_order)
wkb_buffer_ptr to_line_string_wkb( GeometryType const& g, wkbByteOrder byte_order)
{ {
unsigned num_points = g.size(); unsigned num_points = line.size();
assert(num_points > 1); assert(num_points > 1);
std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints std::size_t size = 1 + 4 + 4 + 8 * 2 * num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size); wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
wkb_stream ss(wkb->buffer(), wkb->size()); wkb_stream ss(wkb->buffer(), wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1); ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(mapnik::new_geometry::geometry_types::LineString); write(ss, static_cast<int>(mapnik::new_geometry::geometry_types::LineString) , 4, byte_order);
write(ss,type,4,byte_order); write(ss, num_points, 4, byte_order);
write(ss,num_points,4,byte_order);
double x = 0;
double y = 0;
for (unsigned i=0; i< num_points; ++i) for (unsigned i=0; i< num_points; ++i)
{ {
g.vertex(i,&x,&y); new_geometry::point const& pt = line[i];
write(ss,x,8,byte_order); write(ss, pt.x, 8, byte_order);
write(ss,y,8,byte_order); write(ss, pt.y, 8, byte_order);
} }
assert(ss.good()); assert(ss.good());
return std::move(wkb); return std::move(wkb);
} }
template<typename GeometryType> wkb_buffer_ptr polygon_wkb( new_geometry::polygon const& poly, wkbByteOrder byte_order)
wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
{ {
unsigned num_points = g.size();
assert(num_points > 1);
using point_type = std::pair<double,double>;
using linear_ring = std::vector<point_type>;
std::vector<linear_ring> rings;
double x = 0;
double y = 0;
std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
for (unsigned i=0; i< num_points; ++i) size += 4 + 2 * 8 * poly.exterior_ring.size();
for ( auto const& ring : poly.interior_rings)
{ {
unsigned command = g.vertex(i,&x,&y);
if (command == SEG_MOVETO) size += 4 + 2 * 8 * ring.size();
{
linear_ring ring;
ring.reserve(1);
ring.emplace_back(x,y);
rings.push_back(std::move(ring)); // start new loop
size += 4; // num_points
size += 2 * 8; // point
}
else if (command == SEG_LINETO)
{
rings.back().emplace_back(x,y);
size += 2 * 8; // point
}
} }
unsigned num_rings = rings.size();
wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size); wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
wkb_stream ss(wkb->buffer(), wkb->size()); wkb_stream ss(wkb->buffer(), wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1); ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(mapnik::new_geometry::geometry_types::Polygon); write(ss, static_cast<int>(mapnik::new_geometry::geometry_types::Polygon), 4, byte_order);
write(ss,type,4,byte_order); write(ss, poly.num_rings(), 4, byte_order);
write(ss,num_rings,4,byte_order);
for ( linear_ring const& ring : rings) // exterior
write(ss, poly.exterior_ring.size(), 4, byte_order);
for (auto const& pt : poly.exterior_ring)
{ {
unsigned num_ring_points = ring.size(); write(ss, pt.x, 8, byte_order);
write(ss,num_ring_points,4,byte_order); write(ss, pt.y, 8, byte_order);
for ( point_type const& pt : ring) }
// interiors
for (auto const& ring : poly.interior_rings)
{
write(ss, ring.size(), 4, byte_order);
for ( auto const& pt : ring)
{ {
write(ss,pt.first,8,byte_order); write(ss, pt.x, 8, byte_order);
write(ss,pt.second,8,byte_order); write(ss, pt.y, 8, byte_order);
} }
} }
@ -228,71 +202,106 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
return std::move(wkb); return std::move(wkb);
} }
template<typename GeometryType> wkb_buffer_ptr multi_point_wkb( new_geometry::multi_point const& multi_pt, wkbByteOrder byte_order)
wkb_buffer_ptr to_wkb(GeometryType const& g, wkbByteOrder byte_order )
{ {
wkb_buffer_ptr wkb; std::size_t size = 1 + 4 + (1 + 4 + 8 * 2) * multi_pt.size() ; // byteOrder + wkbType + Point.size * num_points
vertex_adapter va(g); wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
switch (va.type()) wkb_stream ss(wkb->buffer(), wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1);
write(ss, static_cast<int>(new_geometry::geometry_types::MultiPoint), 4, byte_order);
write(ss, multi_pt.size(), 4 ,byte_order);
for (auto const& pt : multi_pt)
{ {
case mapnik::new_geometry::geometry_types::Point:
wkb = to_point_wkb(va, byte_order);
break;
case mapnik::new_geometry::geometry_types::LineString:
wkb = to_line_string_wkb(va, byte_order);
break;
case mapnik::new_geometry::geometry_types::Polygon:
wkb = to_polygon_wkb(va, 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_buffer_ptr> wkb_cont;
bool collection = false;
int multi_type = 0;
size_t multi_size = 1 + 4 + 4;
for (auto const& geom : paths)
{
wkb_buffer_ptr wkb = to_wkb(geom,byte_order);
multi_size += wkb->size();
int type = static_cast<int>(geom.type());
if (multi_type > 0 && multi_type != geom.type())
collection = true;
multi_type = type;
wkb_cont.push_back(std::move(wkb));
}
wkb_buffer_ptr multi_wkb = std::make_unique<wkb_buffer>(multi_size);
wkb_stream ss(multi_wkb->buffer(), multi_wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1); ss.write(reinterpret_cast<char*>(&byte_order),1);
multi_type = collection ? 7 : multi_type + 3; write(ss, static_cast<int>(new_geometry::geometry_types::Point), 4, byte_order);
write(ss,multi_type, 4, byte_order); write(ss, pt.x, 8, byte_order);
write(ss,paths.size(),4,byte_order); write(ss, pt.y, 8, byte_order);
}
assert(ss.good());
return std::move(wkb);
}
for ( wkb_buffer_ptr const& wkb : wkb_cont)
{ template <typename MultiGeometry>
ss.write(wkb->buffer(),wkb->size()); wkb_buffer_ptr multi_geom_wkb(MultiGeometry const& multi_geom, wkbByteOrder byte_order);
}
return std::move(multi_wkb); struct geometry_to_wkb
{
using result_type = wkb_buffer_ptr;
geometry_to_wkb(wkbByteOrder byte_order)
: byte_order_(byte_order) {}
result_type operator() (new_geometry::geometry const& geom) const
{
return util::apply_visitor(*this, geom);
} }
return wkb_buffer_ptr(); result_type operator() (new_geometry::point const& pt) const
{
return point_wkb(pt, byte_order_);
}
result_type operator() (new_geometry::line_string const& line) const
{
return line_string_wkb(line, byte_order_);
}
result_type operator() (new_geometry::polygon const& poly) const
{
return polygon_wkb(poly, byte_order_);
}
// multi/collection
//result_type operator() (new_geometry::multi_point const& multi_pt) const
//{
// return multi_point_wkb(multi_pt, byte_order_);
//}
template <typename Geometry>
result_type operator() (Geometry const& geom) const
{
return multi_geom_wkb(geom, byte_order_);
}
wkbByteOrder byte_order_;
};
template <typename MultiGeometry>
wkb_buffer_ptr multi_geom_wkb(MultiGeometry const& multi_geom, wkbByteOrder byte_order)
{
size_t multi_size = 1 + 4 + 4;
std::vector<wkb_buffer_ptr> wkb_cont;
for (auto const& geom : multi_geom)
{
wkb_buffer_ptr wkb = geometry_to_wkb(byte_order)(geom);
multi_size += wkb->size();
wkb_cont.push_back(std::move(wkb));
}
wkb_buffer_ptr multi_wkb = std::make_unique<wkb_buffer>(multi_size);
wkb_stream ss(multi_wkb->buffer(), multi_wkb->size());
ss.write(reinterpret_cast<char*>(&byte_order),1);
write(ss, static_cast<int>(new_geometry::detail::geometry_type()(multi_geom)) , 4, byte_order);
write(ss, multi_geom.size(), 4 ,byte_order);
for ( wkb_buffer_ptr const& wkb : wkb_cont)
{
ss.write(wkb->buffer(), wkb->size());
}
return std::move(multi_wkb);
} }
} // ns detail
using wkb_buffer_ptr = detail::wkb_buffer_ptr;
template<typename GeometryType>
wkb_buffer_ptr to_wkb(GeometryType const& geom, wkbByteOrder byte_order )
{
return std::move(detail::geometry_to_wkb(byte_order)(geom));
}
}} }}
#endif // MAPNIK_GEOMETRY_TO_WKB_HPP #endif // MAPNIK_GEOMETRY_TO_WKB_HPP