diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index aecc4536d..d57083fcc 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -91,10 +91,11 @@ public: double x = 0; double y = 0; rewind(0); - for (unsigned i=0;i 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; + } + } + } } } diff --git a/include/mapnik/json/geometry_generator_grammar.hpp b/include/mapnik/json/geometry_generator_grammar.hpp index 408bbf212..791b9db76 100644 --- a/include/mapnik/json/geometry_generator_grammar.hpp +++ b/include/mapnik/json/geometry_generator_grammar.hpp @@ -116,7 +116,28 @@ struct json_coordinate_policy : karma::real_policies { typedef boost::spirit::karma::real_policies base_type; 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(15 - boost::math::trunc(log10(traits::get_absolute_value(n)))); + } + + template + static bool dot(OutputIterator& sink, T n, unsigned precision) + { + if (n == 0) return true; + return base_type::dot(sink, n, precision); + } + + template + 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); + } }; } diff --git a/include/mapnik/json/geometry_grammar.hpp b/include/mapnik/json/geometry_grammar.hpp index 64a776f3e..4fd7159ca 100644 --- a/include/mapnik/json/geometry_grammar.hpp +++ b/include/mapnik/json/geometry_grammar.hpp @@ -69,7 +69,7 @@ struct close_path void operator() (T path) const { BOOST_ASSERT( path!=0 ); - path->close(); + path->set_close(); } }; diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index 10572ec12..399fc02eb 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -172,6 +172,8 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order) double x = 0; double y = 0; + double start_x = 0; + double start_y = 0; std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings 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) { rings.push_back(new linear_ring); // start new loop + start_x = x; + start_y = y; size += 4; // num_points } + else if (command == SEG_CLOSE) + { + x = start_x; + y = start_y; + } rings.back().push_back(std::make_pair(x,y)); size += 2 * 8; // point } diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index ee75c3dbd..929168e81 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -37,6 +37,7 @@ #include #include +#include // trunc to avoid needing C++11 //#define BOOST_SPIRIT_USE_PHOENIX_V3 1 namespace boost { namespace spirit { namespace traits { @@ -92,13 +93,40 @@ struct multi_geometry_ template struct result { typedef bool type; }; - bool operator() (geometry_container const& geom) const { return geom.size() > 1 ? true : false; } }; +template +struct get_x +{ + typedef T value_type; + + template + struct result { typedef double type; }; + + double operator() (value_type const& val) const + { + return boost::get<1>(val); + } +}; + +template +struct get_y +{ + typedef T value_type; + + template + struct result { typedef double type; }; + + double operator() (value_type const& val) const + { + return boost::get<2>(val); + } +}; + template struct multi_geometry_type { @@ -116,7 +144,27 @@ struct wkt_coordinate_policy : karma::real_policies { typedef boost::spirit::karma::real_policies base_type; 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(15 - boost::math::trunc(log10(traits::get_absolute_value(n)))); + } + + template + static bool dot(OutputIterator& sink, T n, unsigned precision) + { + if (n == 0) return true; + return base_type::dot(sink, n, precision); + } + + template + 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 polygon; karma::rule coords; - karma::rule, geometry_type const& ()> coords2; + karma::rule, geometry_type const& ()> coords2; karma::rule point_coord; - karma::rule polygon_coord; + karma::rule, coord_type (unsigned&, double&, double& )> polygon_coord; // phoenix functions phoenix::function > _type; phoenix::function > _first; + phoenix::function > _x; + phoenix::function > _y; // karma::real_generator > coordinate; }; diff --git a/include/mapnik/wkt/wkt_grammar.hpp b/include/mapnik/wkt/wkt_grammar.hpp index 5d5c20562..2dd3244d3 100644 --- a/include/mapnik/wkt/wkt_grammar.hpp +++ b/include/mapnik/wkt/wkt_grammar.hpp @@ -71,7 +71,7 @@ namespace mapnik { namespace wkt { void operator() (T path) const { BOOST_ASSERT( path!=0 ); - path->close(); + path->set_close(); } }; diff --git a/plugins/input/shape/shape_io.cpp b/plugins/input/shape/shape_io.cpp index 51c53e9df..12d481fad 100644 --- a/plugins/input/shape/shape_io.cpp +++ b/plugins/input/shape/shape_io.cpp @@ -175,7 +175,8 @@ void shape_io::read_polygon(shape_file::record_type & record, mapnik::geometry_c double x = record.read_double(); double y = record.read_double(); poly->move_to(x, y); - + double start_x = x; + double start_y = y; for (int j=start+1;jclose(x, y); - + if (x == start_x && y == start_y) + { + poly->close(x, y); + } + else + { + poly->line_to(x, y); + } geom.push_back(poly); } } diff --git a/src/wkb.cpp b/src/wkb.cpp index dfef08a69..a43754387 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -357,7 +357,18 @@ private: { 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 @@ -393,7 +404,16 @@ private: { 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 diff --git a/src/wkt/wkt_generator.cpp b/src/wkt/wkt_generator.cpp index 9e04640b1..03900ee4e 100644 --- a/src/wkt/wkt_generator.cpp +++ b/src/wkt/wkt_generator.cpp @@ -62,7 +62,11 @@ wkt_generator::wkt_generator(bool single) using boost::spirit::karma::_1; using boost::spirit::karma::lit; using boost::spirit::karma::_a; + using boost::spirit::karma::_b; + using boost::spirit::karma::_c; using boost::spirit::karma::_r1; + using boost::spirit::karma::_r2; + using boost::spirit::karma::_r3; using boost::spirit::karma::eps; using boost::spirit::karma::string; @@ -92,15 +96,23 @@ wkt_generator::wkt_generator(bool single) 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 = "),("] - .else_[_1 = "("] ] | &uint_ << ",") - << coordinate + .else_[_1 = "("]] + | + &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(' ') - << coordinate + << coordinate[_1 = _b] ; - coords2 %= *polygon_coord(_a) + coords2 %= *polygon_coord(_a,_b,_c) ; coords = point_coord % lit(',')