+ ensure 'close path' handled correcly
(currenlty SEG_CLOSE command must have valid x,y) + implement real_policies in wkt and geojson generators
This commit is contained in:
parent
e7891a99ce
commit
274fbf8f7a
9 changed files with 162 additions and 22 deletions
|
@ -91,10 +91,11 @@ public:
|
||||||
double x = 0;
|
double x = 0;
|
||||||
double y = 0;
|
double y = 0;
|
||||||
rewind(0);
|
rewind(0);
|
||||||
for (unsigned i=0;i<size();++i)
|
for (unsigned i=0; i < size(); ++i)
|
||||||
{
|
{
|
||||||
vertex(&x,&y);
|
unsigned cmd = vertex(&x,&y);
|
||||||
if (i==0)
|
if (cmd == SEG_CLOSE) continue;
|
||||||
|
if (i == 0)
|
||||||
{
|
{
|
||||||
result.init(x,y,x,y);
|
result.init(x,y,x,y);
|
||||||
}
|
}
|
||||||
|
@ -126,11 +127,31 @@ public:
|
||||||
push_vertex(x,y,SEG_CLOSE);
|
push_vertex(x,y,SEG_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close()
|
void set_close()
|
||||||
{
|
{
|
||||||
if (cont_.size() > 3)
|
if (cont_.size() > 3)
|
||||||
{
|
{
|
||||||
cont_.set_command(cont_.size() - 1, SEG_CLOSE);
|
unsigned cmd;
|
||||||
|
double x,y;
|
||||||
|
int index = cont_.size() - 1;
|
||||||
|
unsigned last_cmd = cont_.get_vertex(index,&x,&y);
|
||||||
|
if (last_cmd == SEG_LINETO)
|
||||||
|
{
|
||||||
|
double last_x = x;
|
||||||
|
double last_y = y;
|
||||||
|
for (int pos = index - 1; pos >=0 ; --pos)
|
||||||
|
{
|
||||||
|
cmd = cont_.get_vertex(pos,&x,&y);
|
||||||
|
if (cmd == SEG_MOVETO)
|
||||||
|
{
|
||||||
|
if (x == last_x && y == last_y)
|
||||||
|
{
|
||||||
|
cont_.set_command(index , SEG_CLOSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,28 @@ struct json_coordinate_policy : karma::real_policies<T>
|
||||||
{
|
{
|
||||||
typedef boost::spirit::karma::real_policies<T> base_type;
|
typedef boost::spirit::karma::real_policies<T> base_type;
|
||||||
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
||||||
static unsigned precision(T n) { return 12 ;}
|
|
||||||
|
static unsigned precision(T n)
|
||||||
|
{
|
||||||
|
if (n == 0.0) return 0;
|
||||||
|
using namespace boost::spirit;
|
||||||
|
return static_cast<unsigned>(15 - boost::math::trunc(log10(traits::get_absolute_value(n))));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
static bool dot(OutputIterator& sink, T n, unsigned precision)
|
||||||
|
{
|
||||||
|
if (n == 0) return true;
|
||||||
|
return base_type::dot(sink, n, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
static bool fraction_part(OutputIterator& sink, T n
|
||||||
|
, unsigned adjprec, unsigned precision)
|
||||||
|
{
|
||||||
|
if (n == 0) return true;
|
||||||
|
return base_type::fraction_part(sink, n, adjprec, precision);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ struct close_path
|
||||||
void operator() (T path) const
|
void operator() (T path) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT( path!=0 );
|
BOOST_ASSERT( path!=0 );
|
||||||
path->close();
|
path->set_close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,8 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
|
||||||
|
|
||||||
double x = 0;
|
double x = 0;
|
||||||
double y = 0;
|
double y = 0;
|
||||||
|
double start_x = 0;
|
||||||
|
double start_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)
|
for (unsigned i=0; i< num_points; ++i)
|
||||||
{
|
{
|
||||||
|
@ -179,8 +181,15 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
|
||||||
if (command == SEG_MOVETO)
|
if (command == SEG_MOVETO)
|
||||||
{
|
{
|
||||||
rings.push_back(new linear_ring); // start new loop
|
rings.push_back(new linear_ring); // start new loop
|
||||||
|
start_x = x;
|
||||||
|
start_y = y;
|
||||||
size += 4; // num_points
|
size += 4; // num_points
|
||||||
}
|
}
|
||||||
|
else if (command == SEG_CLOSE)
|
||||||
|
{
|
||||||
|
x = start_x;
|
||||||
|
y = start_y;
|
||||||
|
}
|
||||||
rings.back().push_back(std::make_pair(x,y));
|
rings.back().push_back(std::make_pair(x,y));
|
||||||
size += 2 * 8; // point
|
size += 2 * 8; // point
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <boost/fusion/include/boost_tuple.hpp>
|
#include <boost/fusion/include/boost_tuple.hpp>
|
||||||
#include <boost/type_traits/remove_pointer.hpp>
|
#include <boost/type_traits/remove_pointer.hpp>
|
||||||
|
|
||||||
|
#include <boost/math/special_functions/trunc.hpp> // trunc to avoid needing C++11
|
||||||
//#define BOOST_SPIRIT_USE_PHOENIX_V3 1
|
//#define BOOST_SPIRIT_USE_PHOENIX_V3 1
|
||||||
|
|
||||||
namespace boost { namespace spirit { namespace traits {
|
namespace boost { namespace spirit { namespace traits {
|
||||||
|
@ -92,13 +93,40 @@ struct multi_geometry_
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
struct result { typedef bool type; };
|
struct result { typedef bool type; };
|
||||||
|
|
||||||
bool operator() (geometry_container const& geom) const
|
bool operator() (geometry_container const& geom) const
|
||||||
{
|
{
|
||||||
return geom.size() > 1 ? true : false;
|
return geom.size() > 1 ? true : false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct get_x
|
||||||
|
{
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct result { typedef double type; };
|
||||||
|
|
||||||
|
double operator() (value_type const& val) const
|
||||||
|
{
|
||||||
|
return boost::get<1>(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct get_y
|
||||||
|
{
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct result { typedef double type; };
|
||||||
|
|
||||||
|
double operator() (value_type const& val) const
|
||||||
|
{
|
||||||
|
return boost::get<2>(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct multi_geometry_type
|
struct multi_geometry_type
|
||||||
{
|
{
|
||||||
|
@ -116,7 +144,27 @@ struct wkt_coordinate_policy : karma::real_policies<T>
|
||||||
{
|
{
|
||||||
typedef boost::spirit::karma::real_policies<T> base_type;
|
typedef boost::spirit::karma::real_policies<T> base_type;
|
||||||
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
||||||
static unsigned precision(T n) { return 6 ;}
|
static unsigned precision(T n)
|
||||||
|
{
|
||||||
|
if (n == 0.0) return 0;
|
||||||
|
using namespace boost::spirit; // for traits
|
||||||
|
return static_cast<unsigned>(15 - boost::math::trunc(log10(traits::get_absolute_value(n))));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
static bool dot(OutputIterator& sink, T n, unsigned precision)
|
||||||
|
{
|
||||||
|
if (n == 0) return true;
|
||||||
|
return base_type::dot(sink, n, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
static bool fraction_part(OutputIterator& sink, T n
|
||||||
|
, unsigned adjprec, unsigned precision)
|
||||||
|
{
|
||||||
|
if (n == 0) return true;
|
||||||
|
return base_type::fraction_part(sink, n, adjprec, precision);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -136,13 +184,15 @@ struct wkt_generator :
|
||||||
karma::rule<OutputIterator, geometry_type const& ()> polygon;
|
karma::rule<OutputIterator, geometry_type const& ()> polygon;
|
||||||
|
|
||||||
karma::rule<OutputIterator, geometry_type const& ()> coords;
|
karma::rule<OutputIterator, geometry_type const& ()> coords;
|
||||||
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> coords2;
|
karma::rule<OutputIterator, karma::locals<unsigned,double,double>, geometry_type const& ()> coords2;
|
||||||
karma::rule<OutputIterator, coord_type ()> point_coord;
|
karma::rule<OutputIterator, coord_type ()> point_coord;
|
||||||
karma::rule<OutputIterator, coord_type (unsigned& )> polygon_coord;
|
karma::rule<OutputIterator, karma::locals<double,double>, coord_type (unsigned&, double&, double& )> polygon_coord;
|
||||||
|
|
||||||
// phoenix functions
|
// phoenix functions
|
||||||
phoenix::function<detail::get_type<geometry_type> > _type;
|
phoenix::function<detail::get_type<geometry_type> > _type;
|
||||||
phoenix::function<detail::get_first<geometry_type> > _first;
|
phoenix::function<detail::get_first<geometry_type> > _first;
|
||||||
|
phoenix::function<detail::get_x<typename geometry_type::value_type> > _x;
|
||||||
|
phoenix::function<detail::get_y<typename geometry_type::value_type> > _y;
|
||||||
//
|
//
|
||||||
karma::real_generator<double, detail::wkt_coordinate_policy<double> > coordinate;
|
karma::real_generator<double, detail::wkt_coordinate_policy<double> > coordinate;
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace mapnik { namespace wkt {
|
||||||
void operator() (T path) const
|
void operator() (T path) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT( path!=0 );
|
BOOST_ASSERT( path!=0 );
|
||||||
path->close();
|
path->set_close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,8 @@ void shape_io::read_polygon(shape_file::record_type & record, mapnik::geometry_c
|
||||||
double x = record.read_double();
|
double x = record.read_double();
|
||||||
double y = record.read_double();
|
double y = record.read_double();
|
||||||
poly->move_to(x, y);
|
poly->move_to(x, y);
|
||||||
|
double start_x = x;
|
||||||
|
double start_y = y;
|
||||||
for (int j=start+1;j<end-1;j++)
|
for (int j=start+1;j<end-1;j++)
|
||||||
{
|
{
|
||||||
x = record.read_double();
|
x = record.read_double();
|
||||||
|
@ -184,8 +185,14 @@ void shape_io::read_polygon(shape_file::record_type & record, mapnik::geometry_c
|
||||||
}
|
}
|
||||||
x = record.read_double();
|
x = record.read_double();
|
||||||
y = record.read_double();
|
y = record.read_double();
|
||||||
poly->close(x, y);
|
if (x == start_x && y == start_y)
|
||||||
|
{
|
||||||
|
poly->close(x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
poly->line_to(x, y);
|
||||||
|
}
|
||||||
geom.push_back(poly);
|
geom.push_back(poly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
24
src/wkb.cpp
24
src/wkb.cpp
|
@ -357,7 +357,18 @@ private:
|
||||||
{
|
{
|
||||||
poly->line_to(ar[j].x, ar[j].y);
|
poly->line_to(ar[j].x, ar[j].y);
|
||||||
}
|
}
|
||||||
poly->close(ar[num_points-1].x, ar[num_points-1].y);
|
|
||||||
|
if (ar[0].x == ar[num_points-1].x &&
|
||||||
|
ar[0].y == ar[num_points-1].y)
|
||||||
|
{
|
||||||
|
poly->close(ar[num_points-1].x, ar[num_points-1].y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leave un-closed polygon intact - don't attempt to close them
|
||||||
|
poly->line_to(ar[num_points-1].x, ar[num_points-1].y);
|
||||||
|
}
|
||||||
|
poly->set_close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (poly->size() > 2) // ignore if polygon has less than 3 vertices
|
if (poly->size() > 2) // ignore if polygon has less than 3 vertices
|
||||||
|
@ -393,7 +404,16 @@ private:
|
||||||
{
|
{
|
||||||
poly->line_to(ar[j].x, ar[j].y);
|
poly->line_to(ar[j].x, ar[j].y);
|
||||||
}
|
}
|
||||||
poly->close(ar[num_points-1].x, ar[num_points-1].y);
|
if (ar[0].x == ar[num_points-1].x &&
|
||||||
|
ar[0].y == ar[num_points-1].y)
|
||||||
|
{
|
||||||
|
poly->close(ar[num_points-1].x, ar[num_points-1].y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leave un-closed polygon intact- don't attempt to close them
|
||||||
|
poly->line_to(ar[num_points-1].x, ar[num_points-1].y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (poly->size() > 2) // ignore if polygon has less than 3 vertices
|
if (poly->size() > 2) // ignore if polygon has less than 3 vertices
|
||||||
|
|
|
@ -62,7 +62,11 @@ wkt_generator<OutputIterator, Geometry>::wkt_generator(bool single)
|
||||||
using boost::spirit::karma::_1;
|
using boost::spirit::karma::_1;
|
||||||
using boost::spirit::karma::lit;
|
using boost::spirit::karma::lit;
|
||||||
using boost::spirit::karma::_a;
|
using boost::spirit::karma::_a;
|
||||||
|
using boost::spirit::karma::_b;
|
||||||
|
using boost::spirit::karma::_c;
|
||||||
using boost::spirit::karma::_r1;
|
using boost::spirit::karma::_r1;
|
||||||
|
using boost::spirit::karma::_r2;
|
||||||
|
using boost::spirit::karma::_r3;
|
||||||
using boost::spirit::karma::eps;
|
using boost::spirit::karma::eps;
|
||||||
using boost::spirit::karma::string;
|
using boost::spirit::karma::string;
|
||||||
|
|
||||||
|
@ -92,15 +96,23 @@ wkt_generator<OutputIterator, Geometry>::wkt_generator(bool single)
|
||||||
point_coord = &uint_ << coordinate << lit(' ') << coordinate
|
point_coord = &uint_ << coordinate << lit(' ') << coordinate
|
||||||
;
|
;
|
||||||
|
|
||||||
polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1]
|
polygon_coord %= ( &uint_(mapnik::SEG_MOVETO)
|
||||||
|
<< eps[_r1 += 1][_a = _r2 = _x(_val)][ _b = _r3 = _y(_val)]
|
||||||
<< string[ if_ (_r1 > 1) [_1 = "),("]
|
<< string[ if_ (_r1 > 1) [_1 = "),("]
|
||||||
.else_[_1 = "("] ] | &uint_ << ",")
|
.else_[_1 = "("]]
|
||||||
<< coordinate
|
|
|
||||||
|
&uint_(mapnik::SEG_LINETO)
|
||||||
|
<< lit(',') << eps[_a = _x(_val)][_b = _y(_val)]
|
||||||
|
|
|
||||||
|
&uint_(mapnik::SEG_CLOSE)
|
||||||
|
<< lit(',') << eps[_a = _r2][_b = _r3]
|
||||||
|
)
|
||||||
|
<< coordinate[_1 = _a]
|
||||||
<< lit(' ')
|
<< lit(' ')
|
||||||
<< coordinate
|
<< coordinate[_1 = _b]
|
||||||
;
|
;
|
||||||
|
|
||||||
coords2 %= *polygon_coord(_a)
|
coords2 %= *polygon_coord(_a,_b,_c)
|
||||||
;
|
;
|
||||||
|
|
||||||
coords = point_coord % lit(',')
|
coords = point_coord % lit(',')
|
||||||
|
|
Loading…
Add table
Reference in a new issue