diff --git a/include/mapnik/json/extract_bounding_box_grammar.hpp b/include/mapnik/json/extract_bounding_box_grammar.hpp new file mode 100644 index 000000000..406d26fb2 --- /dev/null +++ b/include/mapnik/json/extract_bounding_box_grammar.hpp @@ -0,0 +1,122 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP +#define MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP + +// mapnik +#include +#include +#include + +// boost +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-local-typedef" +#include +#include +#include +#pragma GCC diagnostic pop + +// stl +#include + +namespace mapnik { namespace json { + +struct empty {}; +using position = std::tuple; +//using positions = std::vector; +using boxes = std::vector>>; + +namespace qi = boost::spirit::qi; +namespace standard_wide = boost::spirit::standard_wide; +using standard_wide::space_type; + +struct calculate_bounding_box_impl +{ + using result_type = void;// box2d; + template + result_type operator() (T0 & bbox, T1 const& pos) const + { + if (pos) + { + double x = std::get<0>(*pos); + double y = std::get<1>(*pos); + if (!bbox.valid()) + { + bbox.init(x, y, x, y); // TODO: add init(x,y) convinience method + } + else + { + bbox.expand_to_include(x, y); + } + } + } +}; + +struct push_box_impl +{ + using result_type = void; + template + result_type operator() (T & boxes, std::size_t offset, box2d const& box) const + { + boxes.emplace_back(offset, box); + } +}; + +struct offset_impl +{ + using result_type = std::size_t; + template + std::size_t operator() (T0 const& begin, T1 const& range) const + { + //std::cerr << std::distance(range.begin(),range.end()) << std::endl; + //std::cerr << std::string(range.begin(),range.end()) << std::endl; + return std::distance(begin, range.begin()); + } +}; + +template > +struct extract_bounding_box_grammar : + qi::grammar +{ + extract_bounding_box_grammar(); + qi::rule start; + qi::rule>, void(boxes&), space_type> features; + qi::rule const&), space_type> feature; + qi::rule bounding_box; + qi::rule>, box2d(), space_type> coords; + qi::rule(), space_type> pos; + qi::rule&), space_type> ring; + qi::rule&), space_type> rings; + qi::rule&), space_type> rings_array; + + boost::phoenix::function offset; + boost::phoenix::function push_box; + boost::phoenix::function calculate_bounding_box; + // error handler + boost::phoenix::function const error_handler; +}; + +}} + +#endif // MAPNIK_JSON_EXTRACT_BOUNDING_BOX_GRAMMAR_HPP diff --git a/include/mapnik/json/extract_bounding_box_grammar_impl.hpp b/include/mapnik/json/extract_bounding_box_grammar_impl.hpp new file mode 100644 index 000000000..494fa73f0 --- /dev/null +++ b/include/mapnik/json/extract_bounding_box_grammar_impl.hpp @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +// mapnik +#include + +// boost +#include +#include +#include +#include +#include +#include +// stl +#include +#include + +namespace mapnik { namespace json { + +namespace repo = boost::spirit::repository; + +template +extract_bounding_box_grammar::extract_bounding_box_grammar() + : extract_bounding_box_grammar::base_type(start,"bounding boxes") +{ + qi::lit_type lit; + qi::double_type double_; + qi::_val_type _val; + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + qi::omit_type omit; + qi::_r1_type _r1; + qi::_r2_type _r2; + qi::_r3_type _r3; + qi::_a_type _a; + qi::_b_type _b; + using qi::fail; + using qi::on_error; + using qi::skip; + using qi::lexeme; + using qi::raw; + using boost::phoenix::push_back; + using boost::spirit::repository::qi::seek; + using boost::spirit::repository::qi::iter_pos; + + start = features(_r1) + ; + + //features = iter_pos[_a = _1] >> *(iter_pos[_b = _1] >> seek[lexeme[skip[lit('{') >> lit("\"type\"") >> ":" >> "\"Feature\""]]] + // >> feature(_r1, _a, _b)) + // ; + + features = iter_pos[_a = _1] >> -(lit('{') >> -lit("\"type\"") >> lit(':') >> lit("\"FeatureCollection\"") + >> lit(',') >> lit("\"features\"") >> lit(':')) + >> lit('[') >> *(raw[seek[lexeme[skip[iter_pos > lit('{') > lit("\"type\"") > lit(':') > lit("\"Feature\"")]]]] [_b = _1] + > feature(_r1, _a, _b)) + ; + //features = iter_pos[_a = _1] >> seek[lexeme[skip[lit("\"type\"") >> lit(':') >> " ]]] + // >> iter_pos[_b = _1] >> *(lit(':') >> feature(_r1, _a, _b) | seek["\"type\""] >> iter_pos[_b = _1]) + // ; + + feature = /*lit("\"Feature\"") >> */bounding_box(_r1, offset(_r2, _r3)) + ; + bounding_box = seek["\"coordinates\""] >> lit(':') >> coords[push_box(_r1, _r2, _1)] + ; + coords = (rings_array(_a) | rings (_a) | ring(_a) | pos[calculate_bounding_box(_a,_1)])[_val = _a] + ; + pos = lit('[') > -(double_ > lit(',') > double_) > omit[*(lit(',') > double_)] > lit(']') + ; + ring = lit('[') >> pos[calculate_bounding_box(_r1,_1)] % lit(',') > lit(']') + ; + rings = lit('[') >> ring(_r1) % lit(',') > lit(']') + ; + rings_array = lit('[') >> rings(_r1) % lit(',') > lit(']') + ; + + coords.name("Coordinates"); + pos.name("Position"); + ring.name("Ring"); + rings.name("Rings"); + rings_array.name("Rings array"); + + // error handler + on_error(coords, error_handler(_1, _2, _3, _4)); +} + +}}