== TopoJSON parser ==

https://github.com/mbostock/topojson/wiki
This commit is contained in:
artemp 2013-09-30 11:16:58 +01:00
parent 2b50c105c3
commit c860ed4d99
3 changed files with 488 additions and 0 deletions

View file

@ -0,0 +1,100 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_TOPOJSON_GRAMMAR_HPP
#define MAPNIK_TOPOJSON_GRAMMAR_HPP
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
//
#include <mapnik/value.hpp>
#include <mapnik/topology.hpp>
//
#include <string>
namespace mapnik { namespace topojson {
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
struct where_message
{
typedef std::string result_type;
template <typename Iterator>
std::string operator() (Iterator first, Iterator last, std::size_t size) const
{
std::string str(first, last);
if (str.length() > size)
return str.substr(0, size) + "..." ;
return str;
}
};
template <typename Iterator>
struct topojson_grammar : qi::grammar<Iterator, space_type, topology()>
{
topojson_grammar();
private:
// generic JSON support
qi::rule<Iterator,space_type> value;
qi::symbols<char const, char const> unesc_char;
qi::uint_parser< unsigned, 16, 4, 4 > hex4 ;
qi::int_parser<mapnik::value_integer,10,1,-1> int__;
qi::rule<Iterator,std::string(), space_type> string_;
qi::rule<Iterator,space_type> key_value;
qi::rule<Iterator,space_type> number;
qi::rule<Iterator,space_type> object;
qi::rule<Iterator,space_type> array;
qi::rule<Iterator,space_type> pairs;
qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
// topoJSON
qi::rule<Iterator, space_type, mapnik::topojson::topology()> topology;
qi::rule<Iterator, space_type, std::vector<mapnik::topojson::geometry>()> objects;
qi::rule<Iterator, space_type, std::vector<mapnik::topojson::arc>()> arcs;
qi::rule<Iterator, space_type, mapnik::topojson::arc()> arc;
qi::rule<Iterator, space_type, mapnik::topojson::coordinate()> coordinate;
qi::rule<Iterator, space_type, mapnik::topojson::transform()> transform;
qi::rule<Iterator, space_type, mapnik::topojson::bounding_box()> bbox;
qi::rule<Iterator, space_type, mapnik::topojson::geometry()> geometry;
qi::rule<Iterator, space_type, mapnik::topojson::point()> point;
qi::rule<Iterator, space_type, mapnik::topojson::linestring()> linestring;
qi::rule<Iterator, space_type, mapnik::topojson::polygon()> polygon;
qi::rule<Iterator, space_type, std::vector<index_type>()> ring;
// properties
qi::rule<Iterator,space_type, mapnik::topojson::properties()> properties;
// error
boost::phoenix::function<where_message> where_message_;
};
}}
#endif //MAPNIK_TOPOJSON_GRAMMAR_HPP

View file

@ -0,0 +1,192 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include <mapnik/topojson_grammar.hpp>
//#define BOOST_SPIRIT_USE_PHOENIX_V3 1
//#include <boost/spirit/include/qi.hpp>
//#include <boost/spirit/include/phoenix.hpp>
//
//#include <mapnik/value.hpp>
//#include <mapnik/topology.hpp>
//
//#include <string>
namespace mapnik { namespace topojson {
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
template <typename Iterator>
topojson_grammar<Iterator>::topojson_grammar()
: topojson_grammar::base_type(topology, "topojson")
{
using qi::lit;
using qi::double_;
using qi::int_;
using qi::no_skip;
using qi::omit;
using qi::_val;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::fail;
using qi::on_error;
using standard_wide::char_;
using phoenix::construct;
// generic json types
value = object | array | string_ | number
;
pairs = key_value % lit(',')
;
key_value = (string_ >> lit(':') >> value)
;
object = lit('{') >> *pairs >> lit('}')
;
array = lit('[')
>> value >> *(lit(',') >> value)
>> lit(']')
;
number %= strict_double
| int__
| lit("true")[_val = true]
| lit("false")[_val = false]
| lit("null")
;
unesc_char.add
("\\\"", '\"') // quotation mark
("\\\\", '\\') // reverse solidus
("\\/", '/') // solidus
("\\b", '\b') // backspace
("\\f", '\f') // formfeed
("\\n", '\n') // newline
("\\r", '\r') // carrige return
("\\t", '\t') // tab
;
string_ %= lit('"') >> no_skip[*(unesc_char | "\\u" >> hex4 | (char_ - lit('"')))] >> lit('"')
;
// topo json
topology = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"Topology\"")
>> ( (lit(',') >> objects) ^ ( lit(',') >> arcs) ^ (lit(',') >> transform) ^ (lit(',') >> bbox))
>> lit('}')
;
transform = lit("\"transform\"") >> lit(':') >> lit('{')
>> lit("\"scale\"") >> lit(':')
>> lit('[')
>> double_ >> lit(',')
>> double_ >> lit(']') >> lit(',')
>> lit("\"translate\"") >> lit(':')
>> lit('[') >> double_ >> lit(',') >> double_ >> lit(']')
>> lit('}')
;
bbox = lit("\"bbox\"") >> lit(':')
>> lit('[') >> double_ >> lit(',') >> double_
>> lit(',') >> double_ >> lit(',') >> double_
>> lit(']')
;
objects = lit("\"objects\"") >> lit(':') >> lit('{')
>> omit[string_] >> lit(':') >> lit('{')
>> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") >> lit(',')
>> lit("\"geometries\"") >> lit(':') >> lit('[') >> -(geometry % lit(','))
>> lit(']') >> lit('}') >> lit('}')
;
geometry = point | linestring | polygon | omit[object]
;
point = lit('{')
>> lit("\"type\"") >> lit(':') >> lit("\"Point\"")
>> ((lit(',') >> lit("\"coordinates\"") >> lit(':') >> coordinate) ^ (lit(',') >> properties))
>> lit('}')
;
linestring = lit('{')
>> lit("\"type\"") >> lit(':') >> lit("\"LineString\"")
>> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[') >> int_ >> lit(']')) ^ (lit(',') >> properties))
>> lit('}')
;
polygon = lit('{')
>> lit("\"type\"") >> lit(':') >> lit("\"Polygon\"")
>> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[') >> -(ring % lit(',')) >> lit(']')) ^ (lit(',') >> properties))
>> lit('}')
;
ring = lit('[') >> -(int_ % lit(',')) >> lit(']')
;
properties = lit("\"properties\"")
>> lit(':')
>> object
;
arcs = lit("\"arcs\"") >> lit(':')
>> lit('[') >> -( arc % lit(',')) >> lit(']') ;
arc = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;
coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']');
topology.name("topology");
transform.name("transform");
objects.name("objects");
arc.name("arc");
arcs.name("arcs");
value.name("value");
coordinate.name("coordinate");
point.name("point");
linestring.name("linestring");
polygon.name("polygon");
on_error<fail>
(
topology
, std::clog
<< phoenix::val("Error! Expecting ")
<< _4 // what failed?
<< phoenix::val(" here: \"")
<< where_message_(_3, _2, 16) // where? 16 is max chars to output
<< phoenix::val("\"")
<< std::endl
);
}
}}

View file

@ -0,0 +1,196 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_TOPOLOGY_HPP
#define MAPNIK_TOPOLOGY_HPP
#include <vector>
#include <list>
#include <boost/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <boost/optional.hpp>
namespace mapnik { namespace topojson {
typedef int index_type;
struct coordinate
{
double x;
double y;
};
typedef boost::spirit::utree properties;
struct point
{
coordinate coord;
boost::optional<properties> props;
};
struct multi_point
{
std::vector<coordinate> points;
boost::optional<properties> props;
};
struct linestring
{
index_type ring ;
boost::optional<properties> props;
};
struct multi_linestring
{
std::vector<index_type> rings;
boost::optional<properties> props;
};
struct polygon
{
std::vector<std::vector<index_type> > rings;
boost::optional<properties> props;
};
struct multi_polygon
{
std::vector<polygon> polygons;//FIXME
boost::optional<properties> props;
};
struct invalid {};
typedef boost::variant<invalid,
point,
linestring,
polygon,
multi_point,
multi_linestring,
multi_polygon> geometry;
typedef std::tuple<double,double> pair_type;
struct arc
{
std::list<coordinate> coordinates;
};
struct transform
{
double scale_x = 1.0;
double scale_y = 1.0;
double translate_x = 0.0;
double translate_y = 0.0;
};
struct bounding_box
{
double minx;
double miny;
double maxx;
double maxy;
};
struct topology
{
std::vector<geometry> geometries;
std::vector<arc> arcs;
transform tr;
boost::optional<bounding_box> bbox;
};
}}
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::coordinate,
(double, x)
(double, y)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::arc,
(std::list<mapnik::topojson::coordinate>, coordinates)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::transform,
(double, scale_x)
(double, scale_y)
(double, translate_x)
(double, translate_y)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::bounding_box,
(double, minx)
(double, miny)
(double, maxx)
(double, maxy)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::point,
(mapnik::topojson::coordinate, coord)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_point,
(std::vector<mapnik::topojson::coordinate>, points)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::linestring,
(mapnik::topojson::index_type, ring)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_linestring,
(std::vector<mapnik::topojson::index_type>, rings)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::polygon,
(std::vector<std::vector<mapnik::topojson::index_type> >, rings)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_polygon,
(std::vector<mapnik::topojson::polygon>, polygons)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::topology,
(std::vector<mapnik::topojson::geometry>, geometries)
(std::vector<mapnik::topojson::arc>, arcs)
(mapnik::topojson::transform, tr)
(boost::optional<mapnik::topojson::bounding_box>, bbox)
)
#endif // MAPNIK_TOPOLOGY_HPP