Merge branch 'master' into geometry-refactor
This commit is contained in:
commit
67d2a0e141
79 changed files with 1342 additions and 840 deletions
29
.travis.yml
29
.travis.yml
|
@ -1,4 +1,4 @@
|
|||
language: c
|
||||
language: cpp
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
@ -25,26 +25,28 @@ matrix:
|
|||
- os: linux
|
||||
sudo: false
|
||||
compiler: ": clang"
|
||||
env: JOBS=8 MASON_PUBLISH=true CXX="ccache clang++-3.5 -Qunused-arguments" CC="clang-3.5" TRIGGER=true
|
||||
env: JOBS=8 MASON_PUBLISH=true _CXX="ccache clang++-3.8 -Qunused-arguments" _CC="clang-3.8" TRIGGER=true
|
||||
addons:
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'clang-3.5' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test']
|
||||
packages: [ 'libstdc++6', 'libstdc++-5-dev']
|
||||
- os: linux
|
||||
sudo: false
|
||||
compiler: ": clang-coverage"
|
||||
env: JOBS=8 COVERAGE=true LLVM_VERSION="3.5" CXX="ccache clang++-3.5 -Qunused-arguments" CC="clang-3.5"
|
||||
env: JOBS=8 COVERAGE=true _CXX="ccache clang++-3.8 -Qunused-arguments" _CC="clang-3.8"
|
||||
addons:
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'clang-3.5', 'llvm-3.5-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test']
|
||||
packages: [ 'libstdc++6','libstdc++-5-dev' ]
|
||||
- os: osx
|
||||
compiler: clang
|
||||
compiler: ": clang-osx"
|
||||
# https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
|
||||
osx_image: xcode7.3 # upgrades clang from 6 -> 7
|
||||
env: JOBS=4 MASON_PUBLISH=true
|
||||
env: JOBS=4 MASON_PUBLISH=true _CXX="ccache clang++ -Qunused-arguments"
|
||||
|
||||
before_install:
|
||||
- if [[ ${_CXX:-false} != false ]]; then export CXX=${_CXX}; fi
|
||||
- if [[ ${_CC:-false} != false ]]; then export CC=${_CC}; fi
|
||||
- source scripts/travis-common.sh
|
||||
- export PYTHONUSERBASE=$(pwd)/mason_packages/.link
|
||||
- export PATH=${PREFIX}/bin:$(pwd)/mason_packages/.link/bin:${PYTHONUSERBASE}/bin:${PATH}
|
||||
|
@ -56,7 +58,6 @@ before_install:
|
|||
- git_submodule_update --init --depth=10
|
||||
|
||||
install:
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then export CCACHE_READONLY=1; fi
|
||||
- on 'linux' export PYTHONPATH=${PYTHONUSERBASE}/lib/python2.7/site-packages
|
||||
- on 'osx' export PYTHONPATH=${PYTHONUSERBASE}/lib/python/site-packages
|
||||
- on 'osx' export DATA_PATH=$(brew --prefix)/var/postgres
|
||||
|
@ -71,6 +72,13 @@ install:
|
|||
|
||||
before_script:
|
||||
- source bootstrap.sh
|
||||
- |
|
||||
if [[ $(uname -s) == 'Linux' ]]; then
|
||||
mason install clang 3.8.0
|
||||
export PATH=$(mason prefix clang 3.8.0)/bin:${PATH}
|
||||
which clang++
|
||||
export LLVM_COV="$(mason prefix clang 3.8.0)/bin/llvm-cov"
|
||||
fi
|
||||
- ccache --version
|
||||
- ccache -p || true
|
||||
- ccache --show-stats || true
|
||||
|
@ -79,6 +87,7 @@ before_script:
|
|||
script:
|
||||
- export SCONSFLAGS='--debug=time'
|
||||
- configure BENCHMARK=${BENCH}
|
||||
- cat config.log
|
||||
- make
|
||||
- make test
|
||||
- enabled ${COVERAGE} coverage
|
||||
|
|
|
@ -17,6 +17,8 @@ Released:
|
|||
- Raster scaling: fixed crash and clipping negative pixel values of floating point rasters (https://github.com/mapnik/mapnik/pull/3349)
|
||||
- Restored support for unquoted strings in expressions (https://github.com/mapnik/mapnik/pull/3390)
|
||||
- [TWKB](https://github.com/TWKB/) support via https://github.com/mapnik/mapnik/pull/3356 (#3355)
|
||||
- Visual test runner can render SVG, PDF and Postscript with Cairo renderer (https://github.com/mapnik/mapnik/pull/3418)
|
||||
- Scale factor is now applied also to `text-line-spacing` and transforms (https://github.com/mapnik/mapnik/pull/3416)
|
||||
|
||||
## 3.0.10
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ _/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/
|
|||
```
|
||||
|
||||
[![Build Status Linux](https://api.travis-ci.org/mapnik/mapnik.svg?branch=master)](http://travis-ci.org/mapnik/mapnik)
|
||||
[![CircleCI](https://circleci.com/gh/mapnik/mapnik.svg?style=svg)](https://circleci.com/gh/mapnik/mapnik)
|
||||
[![Build Status Windows](https://ci.appveyor.com/api/projects/status/hc9l7okdjtucfqqn?branch=master&svg=true)](https://ci.appveyor.com/project/Mapbox/mapnik)
|
||||
[![Coverage Status](https://coveralls.io/repos/mapnik/mapnik/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapnik/mapnik?branch=master)
|
||||
|
||||
|
@ -28,4 +29,4 @@ Please note that this project is released with a [Contributor Code of Conduct](h
|
|||
|
||||
# License
|
||||
|
||||
Mapnik software is free and is released under the LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html_)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information.
|
||||
Mapnik software is free and is released under the LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information.
|
||||
|
|
18
SConstruct
18
SConstruct
|
@ -704,11 +704,7 @@ def FindBoost(context, prefixes, thread_flag):
|
|||
BOOST_INCLUDE_DIR = None
|
||||
BOOST_APPEND = None
|
||||
env['BOOST_APPEND'] = str()
|
||||
|
||||
if env['THREADING'] == 'multi':
|
||||
search_lib = 'libboost_thread'
|
||||
else:
|
||||
search_lib = 'libboost_filesystem'
|
||||
search_lib = 'libboost_filesystem'
|
||||
|
||||
# note: must call normpath to strip trailing slash otherwise dirname
|
||||
# does not remove 'lib' and 'include'
|
||||
|
@ -1359,7 +1355,7 @@ if not preconfigured:
|
|||
|
||||
# test for C++11 support, which is required
|
||||
if not env['HOST'] and not conf.supports_cxx11():
|
||||
color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)")
|
||||
color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler")
|
||||
Exit(1)
|
||||
|
||||
if not env['HOST']:
|
||||
|
@ -1411,15 +1407,6 @@ if not preconfigured:
|
|||
['program_options', 'boost/program_options.hpp', False]
|
||||
]
|
||||
|
||||
if env['THREADING'] == 'multi':
|
||||
BOOST_LIBSHEADERS.append(['thread', 'boost/thread/mutex.hpp', True])
|
||||
# on solaris the configure checks for boost_thread
|
||||
# require the -pthreads flag to be able to check for
|
||||
# threading support, so we add as a global library instead
|
||||
# of attaching to cxxflags after configure
|
||||
if env['PLATFORM'] == 'SunOS':
|
||||
env.Append(CXXFLAGS = '-pthreads')
|
||||
|
||||
# if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests
|
||||
if env['PRIORITIZE_LINKING']:
|
||||
conf.prioritize_paths(silent=True)
|
||||
|
@ -1610,6 +1597,7 @@ if not preconfigured:
|
|||
# prepend to make sure we link locally
|
||||
env.Prepend(CPPPATH = '#deps/agg/include')
|
||||
env.Prepend(LIBPATH = '#deps/agg')
|
||||
env.Prepend(CPPPATH = '#deps/mapbox/variant/include')
|
||||
# prepend deps dir for auxillary headers
|
||||
env.Prepend(CPPPATH = '#deps')
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
environment:
|
||||
msvs_toolset: 14
|
||||
BOOST_VERSION: 59
|
||||
BOOST_VERSION: 60
|
||||
FASTBUILD: 1
|
||||
matrix:
|
||||
- platform: x64
|
||||
|
|
12
bootstrap.sh
12
bootstrap.sh
|
@ -10,7 +10,7 @@ todo
|
|||
- shrink icu data
|
||||
'
|
||||
|
||||
MASON_VERSION="694d08c"
|
||||
MASON_VERSION="b709931"
|
||||
|
||||
function setup_mason() {
|
||||
if [[ ! -d ./.mason ]]; then
|
||||
|
@ -20,7 +20,6 @@ function setup_mason() {
|
|||
echo "Updating to latest mason"
|
||||
(cd ./.mason && git fetch && git checkout ${MASON_VERSION})
|
||||
fi
|
||||
export MASON_DIR=$(pwd)/.mason
|
||||
export PATH=$(pwd)/.mason:$PATH
|
||||
export CXX=${CXX:-clang++}
|
||||
export CC=${CC:-clang}
|
||||
|
@ -32,7 +31,7 @@ function install() {
|
|||
mason install $1 $2
|
||||
mason link $1 $2
|
||||
if [[ ${3:-false} != false ]]; then
|
||||
LA_FILE=$(${MASON_DIR:-~/.mason}/mason prefix $1 $2)/lib/$3.la
|
||||
LA_FILE=$(mason prefix $1 $2)/lib/$3.la
|
||||
if [[ -f ${LA_FILE} ]]; then
|
||||
perl -i -p -e 's:\Q$ENV{HOME}/build/mapbox/mason\E:$ENV{PWD}:g' ${LA_FILE}
|
||||
else
|
||||
|
@ -63,8 +62,11 @@ function install_mason_deps() {
|
|||
wait
|
||||
install webp 0.4.2 libwebp &
|
||||
install gdal 1.11.2 libgdal &
|
||||
install boost 1.59.0 &
|
||||
install boost_liball 1.59.0 &
|
||||
install boost 1.61.0 &
|
||||
install boost_libsystem 1.61.0 &
|
||||
install boost_libfilesystem 1.61.0 &
|
||||
install boost_libprogram_options 1.61.0 &
|
||||
install boost_libregex 1.61.0 &
|
||||
install freetype 2.6 libfreetype &
|
||||
install harfbuzz 0.9.41 libharfbuzz &
|
||||
wait
|
||||
|
|
14
circle.yml
14
circle.yml
|
@ -7,7 +7,7 @@ machine:
|
|||
JOBS: 8
|
||||
CCACHE_TEMPDIR: /tmp/.ccache-temp
|
||||
CCACHE_COMPRESS: 1
|
||||
LLVM_VERSION: 3.7
|
||||
LLVM_VERSION: 3.8
|
||||
pre:
|
||||
- echo "here"
|
||||
post:
|
||||
|
@ -25,20 +25,16 @@ dependencies:
|
|||
pre:
|
||||
# https://discuss.circleci.com/t/add-ability-to-cache-apt-get-programs/598/3
|
||||
- sudo rm -rf /var/cache/apt/archives && sudo ln -s ~/.apt-cache /var/cache/apt/archives && mkdir -p ~/.apt-cache/partial
|
||||
- sudo wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- sudo add-apt-repository -y "deb http://llvm.org/apt/precise/ llvm-toolchain-precise-${LLVM_VERSION} main"
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -y
|
||||
override:
|
||||
- sudo apt-get install clang-${LLVM_VERSION} -y
|
||||
post:
|
||||
- which clang-${LLVM_VERSION}
|
||||
- which clang++-${LLVM_VERSION}
|
||||
- sudo apt-get update -y
|
||||
|
||||
database:
|
||||
pre:
|
||||
- ./bootstrap.sh
|
||||
- ./configure CC="clang-${LLVM_VERSION}" CXX="$(pwd)/mason_packages/.link/bin/ccache clang++-${LLVM_VERSION} -Qunused-arguments"
|
||||
- ./.mason/mason install clang ${LLVM_VERSION}.0
|
||||
- ./.mason/mason link clang ${LLVM_VERSION}.0
|
||||
- ./configure CC="$(pwd)/mason_packages/.link/bin/clang-${LLVM_VERSION}" CXX="$(pwd)/mason_packages/.link/bin/ccache $(pwd)/mason_packages/.link/bin/clang++-${LLVM_VERSION} -Qunused-arguments"
|
||||
- make
|
||||
override:
|
||||
- psql -c 'create database template_postgis;'
|
||||
|
|
|
@ -52,11 +52,11 @@ If you do not have svn installed you can grab gyp from:
|
|||
|
||||
Simply type:
|
||||
|
||||
make
|
||||
make
|
||||
|
||||
Then to run do:
|
||||
|
||||
./rundemo `mapnik-config --prefix`
|
||||
./rundemo `mapnik-config --prefix`
|
||||
|
||||
On OS X you can also create an xcode project:
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ int main ( int, char** )
|
|||
try {
|
||||
std::cout << " running demo ... \n";
|
||||
datasource_cache::instance().register_datasources("plugins/input/");
|
||||
freetype_engine::register_font("fonts/dejavu-fonts-ttf-2.34/ttf/DejaVuSans.ttf");
|
||||
freetype_engine::register_font("fonts/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf");
|
||||
|
||||
Map m(800,600);
|
||||
m.set_background(parse_color("white"));
|
||||
|
@ -230,7 +230,7 @@ int main ( int, char** )
|
|||
parameters p;
|
||||
p["type"]="shape";
|
||||
p["file"]="demo/data/boundaries";
|
||||
p["encoding"]="latin1";
|
||||
p["encoding"]="utf8";
|
||||
|
||||
layer lyr("Provinces");
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
|
@ -295,7 +295,7 @@ int main ( int, char** )
|
|||
parameters p;
|
||||
p["type"]="shape";
|
||||
p["file"]="demo/data/popplaces";
|
||||
p["encoding"] = "latin1";
|
||||
p["encoding"] = "utf8";
|
||||
layer lyr("Populated Places");
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]]
|
Binary file not shown.
2
deps/mapbox/variant
vendored
2
deps/mapbox/variant
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 3f025adbf599d8dd9bfca02d45b37e49a2cae841
|
||||
Subproject commit b5728ad76e1402c130a9330aa44b6f4b655b13b4
|
2
deps/mapnik/build.py
vendored
2
deps/mapnik/build.py
vendored
|
@ -7,7 +7,7 @@ subdirs = {
|
|||
'./sparsehash':{'dir':'sparsehash','glob':'*'},
|
||||
'./sparsehash/internal':{'dir':'sparsehash/internal','glob':'*'},
|
||||
'../agg/include':{'dir':'agg','glob':'agg*'},
|
||||
'../mapbox':{'dir':'mapbox/variant','glob':'*/*.hpp'}
|
||||
'../mapbox/variant/include':{'dir':'mapbox','glob':'*/*.hpp'}
|
||||
}
|
||||
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
|
|
|
@ -52,7 +52,10 @@
|
|||
|
||||
#define PROJ_ENVELOPE_POINTS 20
|
||||
|
||||
#ifndef BOOST_MPL_LIMIT_VECTOR_SIZE
|
||||
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
|
||||
#define BOOST_MPL_LIMIT_VECTOR_SIZE 30
|
||||
|
||||
#else
|
||||
#warning "WARNING: BOOST_MPL_LIMIT_VECTOR_SIZE is already defined. Ensure config.hpp is included before any Boost headers"
|
||||
#endif
|
||||
#endif // MAPNIK_CONFIG_HPP
|
||||
|
|
|
@ -49,7 +49,6 @@ struct geometry_empty
|
|||
using coord_type = T;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
using geometry_base = mapnik::util::variant<geometry_empty<T>,
|
||||
point<T>,
|
||||
|
@ -58,11 +57,12 @@ using geometry_base = mapnik::util::variant<geometry_empty<T>,
|
|||
multi_point<T>,
|
||||
multi_line_string<T>,
|
||||
multi_polygon<T>,
|
||||
mapnik::util::recursive_wrapper<geometry_collection<T> > >;
|
||||
geometry_collection<T> >;
|
||||
template <typename T>
|
||||
struct geometry : geometry_base<T>
|
||||
{
|
||||
using coord_type = T;
|
||||
|
||||
geometry()
|
||||
: geometry_base<T>() {} // empty
|
||||
|
||||
|
@ -72,6 +72,7 @@ struct geometry : geometry_base<T>
|
|||
|
||||
};
|
||||
|
||||
|
||||
template <typename T, template <typename...> class Cont>
|
||||
struct geometry_collection : Cont<geometry<T>>
|
||||
{
|
||||
|
|
68
include/mapnik/json/attribute_value_visitor.hpp
Normal file
68
include/mapnik/json/attribute_value_visitor.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2016 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_ATTRIBUTE_VALUE_VISITOR_HPP
|
||||
#define MAPNIK_JSON_ATTRIBUTE_VALUE_VISITOR_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/value.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/json/stringifier.hpp>
|
||||
#include <mapnik/json/value_converters.hpp>
|
||||
|
||||
namespace mapnik { namespace json {
|
||||
|
||||
struct attribute_value_visitor
|
||||
{
|
||||
public:
|
||||
attribute_value_visitor(mapnik::transcoder const& tr)
|
||||
: tr_(tr) {}
|
||||
|
||||
mapnik::value operator()(std::string const& val) const
|
||||
{
|
||||
return mapnik::value(tr_.transcode(val.c_str()));
|
||||
}
|
||||
|
||||
mapnik::value operator()(std::vector<mapnik::json::json_value> const& array) const
|
||||
{
|
||||
std::string str = stringifier()(array);
|
||||
return mapnik::value(tr_.transcode(str.c_str()));
|
||||
}
|
||||
|
||||
mapnik::value operator()(std::vector<std::pair<std::string, mapnik::json::json_value> > const& object) const
|
||||
{
|
||||
std::string str = stringifier()(object);
|
||||
return mapnik::value(tr_.transcode(str.c_str()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mapnik::value operator()(T const& val) const
|
||||
{
|
||||
return mapnik::value(val);
|
||||
}
|
||||
|
||||
mapnik::transcoder const& tr_;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif //MAPNIK_JSON_ATTRIBUTE_VALUE_VISITOR_HPP
|
|
@ -148,13 +148,10 @@ extract_bounding_box_grammar<Iterator, Boxes, ErrorHandler>::extract_bounding_bo
|
|||
json.value = json.object | json.array | json.string_ | json.number
|
||||
;
|
||||
|
||||
json.pairs = json.key_value % lit(',')
|
||||
json.key_value = json.string_ >> lit(':') >> json.value
|
||||
;
|
||||
|
||||
json.key_value = (json.string_ >> lit(':') >> json.value)
|
||||
;
|
||||
|
||||
json.object = lit('{') >> *json.pairs >> lit('}')
|
||||
json.object = lit('{') >> json.key_value % lit(',') >> lit('}')
|
||||
;
|
||||
|
||||
json.array = lit('[')
|
||||
|
|
|
@ -24,14 +24,10 @@
|
|||
#define MAPNIK_FEATURE_GRAMMAR_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/json/geometry_grammar.hpp>
|
||||
#include <mapnik/value.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/value.hpp>
|
||||
#include <mapnik/json/generic_json.hpp>
|
||||
#include <mapnik/json/value_converters.hpp>
|
||||
|
||||
#include <mapnik/json/geometry_grammar.hpp>
|
||||
#include <mapnik/json/attribute_value_visitor.hpp>
|
||||
#pragma GCC diagnostic push
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
|
@ -45,27 +41,6 @@ namespace qi = boost::spirit::qi;
|
|||
namespace phoenix = boost::phoenix;
|
||||
namespace fusion = boost::fusion;
|
||||
|
||||
class attribute_value_visitor
|
||||
|
||||
{
|
||||
public:
|
||||
attribute_value_visitor(mapnik::transcoder const& tr)
|
||||
: tr_(tr) {}
|
||||
|
||||
mapnik::value operator()(std::string const& val) const
|
||||
{
|
||||
return mapnik::value(tr_.transcode(val.c_str()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mapnik::value operator()(T const& val) const
|
||||
{
|
||||
return mapnik::value(val);
|
||||
}
|
||||
|
||||
mapnik::transcoder const& tr_;
|
||||
};
|
||||
|
||||
struct put_property
|
||||
{
|
||||
using result_type = void;
|
||||
|
@ -101,9 +76,6 @@ struct feature_grammar : qi::grammar<Iterator, void(FeatureType&), space_type>
|
|||
qi::rule<Iterator, space_type> feature_type;
|
||||
qi::rule<Iterator,void(FeatureType &),space_type> properties;
|
||||
qi::rule<Iterator,qi::locals<std::string>, void(FeatureType &),space_type> attributes;
|
||||
qi::rule<Iterator, json_value(), space_type> attribute_value;
|
||||
qi::rule<Iterator, qi::locals<std::int32_t>, std::string(), space_type> stringify_object;
|
||||
qi::rule<Iterator, qi::locals<std::int32_t>, std::string(), space_type> stringify_array;
|
||||
// functions
|
||||
phoenix::function<put_property> put_property_;
|
||||
phoenix::function<set_geometry_impl> set_geometry;
|
||||
|
|
|
@ -50,23 +50,22 @@ feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::tran
|
|||
using phoenix::construct;
|
||||
|
||||
// generic json types
|
||||
json_.value = json_.object | json_.array | json_.string_ | json_.number
|
||||
json_.value = json_.object | json_.array | json_.string_ | json_.number
|
||||
;
|
||||
|
||||
json_.pairs = json_.key_value % lit(',')
|
||||
;
|
||||
|
||||
json_.key_value = (json_.string_ > lit(':') > json_.value)
|
||||
json_.key_value = json_.string_ > lit(':') > json_.value
|
||||
;
|
||||
|
||||
json_.object = lit('{')
|
||||
> *json_.pairs
|
||||
> -(json_.key_value % lit(','))
|
||||
> lit('}')
|
||||
;
|
||||
|
||||
json_.array = lit('[')
|
||||
> json_.value > *(lit(',') > json_.value)
|
||||
> -(json_.value % lit(','))
|
||||
> lit(']')
|
||||
;
|
||||
|
||||
json_.number = json_.strict_double[_val = json_.double_converter(_1)]
|
||||
| json_.int__[_val = json_.integer_converter(_1)]
|
||||
| lit("true") [_val = true]
|
||||
|
@ -95,24 +94,13 @@ feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::tran
|
|||
> lit(':') > ((lit('{') > -attributes(_r1) > lit('}')) | lit("null"))
|
||||
;
|
||||
|
||||
attributes = (json_.string_ [_a = _1] > lit(':') > attribute_value [put_property_(_r1,_a,_1)]) % lit(',')
|
||||
;
|
||||
|
||||
attribute_value %= json_.number | json_.string_ | stringify_object | stringify_array
|
||||
;
|
||||
|
||||
stringify_object %= char_('{')[_a = 1 ] > *(eps(_a > 0) > (char_('{')[_a +=1] | char_('}')[_a -=1] | char_))
|
||||
;
|
||||
|
||||
stringify_array %= char_('[')[_a = 1 ] > *(eps(_a > 0) > (char_('[')[_a +=1] | char_(']')[_a -=1] | char_))
|
||||
attributes = (json_.string_ [_a = _1] > lit(':') > json_.value [put_property_(_r1,_a,_1)]) % lit(',')
|
||||
;
|
||||
|
||||
feature.name("Feature");
|
||||
feature_type.name("type");
|
||||
properties.name("properties");
|
||||
attributes.name("Attributes");
|
||||
attribute_value.name("Attribute Value");
|
||||
|
||||
on_error<fail>(feature, error_handler(_1, _2, _3, _4));
|
||||
|
||||
}
|
||||
|
|
|
@ -31,15 +31,44 @@
|
|||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/phoenix.hpp>
|
||||
#include <boost/fusion/include/std_pair.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik { namespace json {
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
namespace standard = boost::spirit::standard;
|
||||
namespace phoenix = boost::phoenix;
|
||||
using space_type = standard::space_type;
|
||||
using json_value = mapnik::util::variant<value_null,value_bool, value_integer, value_double, std::string>;
|
||||
|
||||
struct json_value;
|
||||
|
||||
using json_array = std::vector<json_value>;
|
||||
using json_object_element = std::pair<std::string, json_value>;
|
||||
using json_object = std::vector<json_object_element>;
|
||||
using json_value_base = mapnik::util::variant<value_null,
|
||||
value_bool,
|
||||
value_integer,
|
||||
value_double,
|
||||
std::string,
|
||||
mapnik::util::recursive_wrapper<json_array>,
|
||||
mapnik::util::recursive_wrapper<json_object> >;
|
||||
struct json_value : json_value_base
|
||||
{
|
||||
|
||||
#ifdef _WINDOWS
|
||||
json_value() = default;
|
||||
template <typename T>
|
||||
json_value(T && val)
|
||||
: json_value_base(std::forward<T>(val)) {}
|
||||
#else
|
||||
// MSVC 2015 inheriting constructors is not working in this context (support is apparently planned)
|
||||
using json_value_base::json_value_base;
|
||||
#endif
|
||||
};
|
||||
|
||||
using uchar = std::uint32_t; // a unicode code point
|
||||
|
||||
// unicode string grammar via boost/libs/spirit/example/qi/json/json/parser/grammar.hpp
|
||||
|
@ -121,10 +150,14 @@ unicode_string<Iterator>::unicode_string()
|
|||
|
||||
escape =
|
||||
('x' > hex) [push_utf8(_r1, _1)]
|
||||
| ('u' > hex4) [push_utf8(_r1, _1)]
|
||||
| ('U' > hex8) [push_utf8(_r1, _1)]
|
||||
| char_("0abtnvfre\"/\\N_LP \t") [push_esc(_r1, _1)]
|
||||
| eol // continue to next line
|
||||
|
|
||||
('u' > hex4) [push_utf8(_r1, _1)]
|
||||
|
|
||||
('U' > hex8) [push_utf8(_r1, _1)]
|
||||
|
|
||||
char_("0abtnvfre\"/\\N_LP \t") [push_esc(_r1, _1)]
|
||||
|
|
||||
eol // continue to next line
|
||||
;
|
||||
|
||||
char_esc =
|
||||
|
@ -132,7 +165,7 @@ unicode_string<Iterator>::unicode_string()
|
|||
;
|
||||
|
||||
double_quoted =
|
||||
'"'
|
||||
'"'
|
||||
> *(char_esc(_val) | (~char_('"')) [_val += _1])
|
||||
> '"'
|
||||
;
|
||||
|
@ -141,18 +174,17 @@ unicode_string<Iterator>::unicode_string()
|
|||
template <typename Iterator>
|
||||
struct generic_json
|
||||
{
|
||||
qi::rule<Iterator,space_type> value;
|
||||
qi::int_parser<mapnik::value_integer,10,1,-1> int__;
|
||||
qi::rule<Iterator, json_value(), space_type> value;
|
||||
qi::int_parser<mapnik::value_integer, 10, 1, -1> int__;
|
||||
unicode_string<Iterator> string_;
|
||||
qi::rule<Iterator,space_type> key_value;
|
||||
qi::rule<Iterator,json_value(),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;
|
||||
qi::rule<Iterator, json_object_element(), space_type> key_value;
|
||||
qi::rule<Iterator, json_value(), space_type> number;
|
||||
qi::rule<Iterator, json_object(), space_type> object;
|
||||
qi::rule<Iterator, json_array(), space_type> array;
|
||||
qi::real_parser<double, qi::strict_real_policies<double>> strict_double;
|
||||
// conversions
|
||||
boost::phoenix::function<mapnik::detail::value_converter<mapnik::value_integer> > integer_converter;
|
||||
boost::phoenix::function<mapnik::detail::value_converter<mapnik::value_double> > double_converter;
|
||||
boost::phoenix::function<mapnik::detail::value_converter<mapnik::value_integer>> integer_converter;
|
||||
boost::phoenix::function<mapnik::detail::value_converter<mapnik::value_double>> double_converter;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -47,7 +47,6 @@ geometry_grammar<Iterator, ErrorHandler>::geometry_grammar()
|
|||
qi::_a_type _a;
|
||||
qi::_b_type _b;
|
||||
qi::eps_type eps;
|
||||
qi::omit_type omit;
|
||||
using qi::fail;
|
||||
using qi::on_error;
|
||||
using phoenix::push_back;
|
||||
|
@ -58,26 +57,26 @@ geometry_grammar<Iterator, ErrorHandler>::geometry_grammar()
|
|||
json_.value = json_.object | json_.array | json_.string_ | json_.number
|
||||
;
|
||||
|
||||
json_.pairs = json_.key_value % lit(',')
|
||||
;
|
||||
|
||||
json_.key_value = (json_.string_ > lit(':') > json_.value)
|
||||
json_.key_value = json_.string_ > lit(':') > json_.value
|
||||
;
|
||||
|
||||
json_.object = lit('{')
|
||||
> *json_.pairs
|
||||
> -(json_.key_value % lit(','))
|
||||
> lit('}')
|
||||
;
|
||||
|
||||
json_.array = lit('[')
|
||||
> json_.value > *(lit(',') > json_.value)
|
||||
> -(json_.value % lit(','))
|
||||
> lit(']')
|
||||
;
|
||||
|
||||
json_.number = json_.strict_double
|
||||
| json_.int__
|
||||
| lit("true")
|
||||
| lit ("false")
|
||||
| lit("null")
|
||||
;
|
||||
|
||||
geometry = lit('{')[_a = 0]
|
||||
> (((lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1])
|
||||
|
|
||||
|
@ -85,7 +84,7 @@ geometry_grammar<Iterator, ErrorHandler>::geometry_grammar()
|
|||
|
|
||||
(lit("\"geometries\"") > lit(':') > lit('[') > geometry_collection[_val = _1] > lit(']'))
|
||||
|
|
||||
omit[json_.key_value]) % lit(',')) [create_geometry(_val,_a,_b)]
|
||||
json_.key_value) % lit(',')) [create_geometry(_val,_a,_b)]
|
||||
> lit('}')
|
||||
;
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#pragma GCC diagnostic push
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
|
@ -40,26 +39,6 @@ namespace mapnik { namespace json {
|
|||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
struct set_position_impl
|
||||
{
|
||||
using result_type = void;
|
||||
template <typename T0,typename T1>
|
||||
result_type operator() (T0 & coords, T1 const& pos) const
|
||||
{
|
||||
if (pos) coords = *pos;
|
||||
}
|
||||
};
|
||||
|
||||
struct push_position_impl
|
||||
{
|
||||
using result_type = void;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator() (T0 & coords, T1 const& pos) const
|
||||
{
|
||||
if (pos) coords.emplace_back(*pos);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
|
||||
struct positions_grammar :
|
||||
qi::grammar<Iterator,coordinates(),space_type>
|
||||
|
@ -70,8 +49,6 @@ struct positions_grammar :
|
|||
qi::rule<Iterator, positions(), space_type> ring;
|
||||
qi::rule<Iterator, std::vector<positions>(), space_type> rings;
|
||||
qi::rule<Iterator, std::vector<std::vector<positions> >(), space_type> rings_array;
|
||||
boost::phoenix::function<set_position_impl> set_position;
|
||||
boost::phoenix::function<push_position_impl> push_position;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -28,12 +28,33 @@
|
|||
#include <boost/spirit/include/phoenix_object.hpp>
|
||||
#include <boost/spirit/include/phoenix_stl.hpp>
|
||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
// stl
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace mapnik { namespace json {
|
||||
|
||||
struct set_position_impl
|
||||
{
|
||||
using result_type = void;
|
||||
template <typename T0,typename T1>
|
||||
result_type operator() (T0 & coords, T1 const& pos) const
|
||||
{
|
||||
if (pos) coords = *pos;
|
||||
}
|
||||
};
|
||||
|
||||
struct push_position_impl
|
||||
{
|
||||
using result_type = void;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator() (T0 & coords, T1 const& pos) const
|
||||
{
|
||||
if (pos) coords.emplace_back(*pos);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Iterator, typename ErrorHandler>
|
||||
positions_grammar<Iterator, ErrorHandler>::positions_grammar(ErrorHandler & error_handler)
|
||||
: positions_grammar::base_type(coords,"coordinates")
|
||||
|
@ -49,6 +70,9 @@ positions_grammar<Iterator, ErrorHandler>::positions_grammar(ErrorHandler & erro
|
|||
using qi::fail;
|
||||
using qi::on_error;
|
||||
|
||||
boost::phoenix::function<set_position_impl> set_position;
|
||||
boost::phoenix::function<push_position_impl> push_position;
|
||||
|
||||
coords = rings_array[_val = _1] | rings [_val = _1] | ring[_val = _1] | pos[set_position(_val,_1)]
|
||||
;
|
||||
pos = lit('[') > -(double_ > lit(',') > double_) > omit[*(lit(',') > double_)] > lit(']')
|
||||
|
|
101
include/mapnik/json/stringifier.hpp
Normal file
101
include/mapnik/json/stringifier.hpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2016 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_STRINGIFIER_HPP
|
||||
#define MAPNIK_JSON_STRINGIFIER_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/json/generic_json.hpp>
|
||||
#include <mapnik/util/conversions.hpp>
|
||||
#include <mapnik/util/variant.hpp>
|
||||
// stl
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace mapnik { namespace json {
|
||||
|
||||
struct stringifier
|
||||
{
|
||||
std::string operator()(std::string const& val) const
|
||||
{
|
||||
return "\"" + val + "\"";
|
||||
}
|
||||
|
||||
std::string operator()(value_null) const
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
std::string operator()(value_bool val) const
|
||||
{
|
||||
return val ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string operator()(value_integer val) const
|
||||
{
|
||||
std::string str;
|
||||
util::to_string(str, val);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string operator()(value_double val) const
|
||||
{
|
||||
std::string str;
|
||||
util::to_string(str, val);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string operator()(std::vector<mapnik::json::json_value> const& array) const
|
||||
{
|
||||
std::string str = "[";
|
||||
bool first = true;
|
||||
for (auto const& val : array)
|
||||
{
|
||||
if (first) first = false;
|
||||
else str += ",";
|
||||
str += mapnik::util::apply_visitor(*this, val);
|
||||
}
|
||||
str += "]";
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string operator()(std::vector<std::pair<std::string, mapnik::json::json_value>> const& object) const
|
||||
{
|
||||
std::string str = "{";
|
||||
bool first = true;
|
||||
for (auto const& kv : object)
|
||||
{
|
||||
if (first) first = false;
|
||||
else str += ",";
|
||||
str += kv.first;
|
||||
str += ":";
|
||||
str += mapnik::util::apply_visitor(*this, kv.second);
|
||||
}
|
||||
str += "}";
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif // MAPNIK_JSON_STRINGIFIER_HPP
|
|
@ -42,6 +42,138 @@ namespace qi = boost::spirit::qi;
|
|||
namespace fusion = boost::fusion;
|
||||
using space_type = mapnik::json::space_type;
|
||||
|
||||
struct create_point
|
||||
{
|
||||
using result_type = mapnik::topojson::point;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & coord, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::point pt;
|
||||
if (coord.template is<mapnik::topojson::coordinate>())
|
||||
{
|
||||
auto const& coord_ = coord.template get<mapnik::topojson::coordinate>();
|
||||
pt.coord = coord_;
|
||||
pt.props = props;
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_multi_point
|
||||
{
|
||||
using result_type = mapnik::topojson::multi_point;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & coords, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::multi_point mpt;
|
||||
if (coords.template is<std::vector<mapnik::topojson::coordinate>>())
|
||||
{
|
||||
auto const& points = coords.template get<std::vector<mapnik::topojson::coordinate>>();
|
||||
mpt. points = points;
|
||||
mpt.props = props;
|
||||
}
|
||||
return mpt;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_line_string
|
||||
{
|
||||
using result_type = mapnik::topojson::linestring;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & arcs, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::linestring line;
|
||||
if (arcs.template is<std::vector<index_type>>())
|
||||
{
|
||||
auto const& arcs_ = arcs.template get<std::vector<index_type>>();
|
||||
line.rings = arcs_;
|
||||
line.props = props;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_multi_line_string
|
||||
{
|
||||
using result_type = mapnik::topojson::multi_linestring;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & arcs, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::multi_linestring mline;
|
||||
if (arcs.template is<std::vector<std::vector<index_type>>>())
|
||||
{
|
||||
auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
|
||||
mline.lines = arcs_;
|
||||
mline.props = props;
|
||||
}
|
||||
return mline;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_polygon
|
||||
{
|
||||
using result_type = mapnik::topojson::polygon;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & arcs, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::polygon poly;
|
||||
if (arcs.template is<std::vector<std::vector<index_type>>>())
|
||||
{
|
||||
auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
|
||||
poly.rings = arcs_;
|
||||
poly.props = props;
|
||||
}
|
||||
return poly;
|
||||
}
|
||||
};
|
||||
|
||||
struct create_multi_polygon
|
||||
{
|
||||
using result_type = mapnik::topojson::multi_polygon;
|
||||
template <typename T0, typename T1>
|
||||
result_type operator()(T0 & arcs, T1 & props) const
|
||||
{
|
||||
mapnik::topojson::multi_polygon mpoly;
|
||||
if (arcs.template is<std::vector<std::vector<std::vector<index_type>>>>())
|
||||
{
|
||||
auto const& arcs_ = arcs.template get<std::vector<std::vector<std::vector<index_type>>>>();
|
||||
mpoly.polygons = arcs_;
|
||||
mpoly.props = props;
|
||||
}
|
||||
return mpoly;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct create_geometry_impl
|
||||
{
|
||||
using result_type = mapnik::topojson::geometry;
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
result_type operator()(T0 geom_type, T1 & coord, T2 & arcs, T3 & props) const
|
||||
{
|
||||
switch (geom_type)
|
||||
{
|
||||
case 1: //Point
|
||||
return create_point()(coord, props);
|
||||
case 2: //LineString
|
||||
return create_line_string()(arcs, props);
|
||||
case 3: //Polygon
|
||||
return create_polygon()(arcs, props);
|
||||
case 4: //MultiPoint
|
||||
return create_multi_point()(coord, props);
|
||||
case 5: //MultiLineString
|
||||
return create_multi_line_string()(arcs, props);
|
||||
case 6: //MultiPolygon
|
||||
return create_multi_polygon()(arcs, props);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mapnik::topojson::geometry(); //empty
|
||||
}
|
||||
};
|
||||
|
||||
using coordinates_type = util::variant<coordinate,std::vector<coordinate>>;
|
||||
using arcs_type = util::variant<std::vector<index_type>, std::vector<std::vector<index_type>>, std::vector<std::vector<std::vector<index_type>>>>;
|
||||
template <typename Iterator, typename ErrorHandler = json::error_handler<Iterator> >
|
||||
struct topojson_grammar : qi::grammar<Iterator, space_type, topology()>
|
||||
|
||||
|
@ -55,24 +187,18 @@ private:
|
|||
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::coordinate()> coordinate_;
|
||||
qi::rule<Iterator, space_type, coordinates_type()> coordinates;
|
||||
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::multi_point()> multi_point;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::linestring()> linestring;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::multi_linestring()> multi_linestring;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::polygon()> polygon;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::multi_polygon()> multi_polygon;
|
||||
qi::rule<Iterator, qi::locals<int, coordinates_type, arcs_type, properties>, mapnik::topojson::geometry(), space_type> geometry;
|
||||
qi::rule<Iterator, space_type, void(std::vector<mapnik::topojson::geometry>&)> geometry_collection;
|
||||
qi::rule<Iterator, space_type, std::vector<index_type>()> ring;
|
||||
qi::rule<Iterator, space_type, std::vector<std::vector<index_type>>()> rings;
|
||||
qi::rule<Iterator, space_type, arcs_type()> rings_array;
|
||||
// properties
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::properties()> properties;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::properties()> attributes;
|
||||
qi::rule<Iterator, space_type, mapnik::json::json_value()> attribute_value;
|
||||
// id
|
||||
qi::rule<Iterator,space_type> id;
|
||||
qi::rule<Iterator, space_type, mapnik::topojson::properties()> properties_;
|
||||
qi::symbols<char, int> geometry_type_dispatch;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -57,42 +57,6 @@ BOOST_FUSION_ADAPT_STRUCT(
|
|||
(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<std::vector<std::vector<mapnik::topojson::index_type> > >, polygons)
|
||||
(boost::optional<mapnik::topojson::properties>, props)
|
||||
)
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(
|
||||
mapnik::topojson::topology,
|
||||
(std::vector<mapnik::topojson::geometry>, geometries)
|
||||
|
@ -101,6 +65,8 @@ BOOST_FUSION_ADAPT_STRUCT(
|
|||
(boost::optional<mapnik::topojson::bounding_box>, bbox)
|
||||
)
|
||||
|
||||
|
||||
|
||||
namespace mapnik { namespace topojson {
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
@ -121,30 +87,43 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
|
|||
qi::_3_type _3;
|
||||
qi::_4_type _4;
|
||||
qi::_r1_type _r1;
|
||||
qi::_a_type _a;
|
||||
qi::_b_type _b;
|
||||
qi::_c_type _c;
|
||||
qi::_d_type _d;
|
||||
using qi::fail;
|
||||
using qi::on_error;
|
||||
using phoenix::push_back;
|
||||
using phoenix::construct;
|
||||
|
||||
geometry_type_dispatch.add
|
||||
("\"Point\"",1)
|
||||
("\"LineString\"",2)
|
||||
("\"Polygon\"",3)
|
||||
("\"MultiPoint\"",4)
|
||||
("\"MultiLineString\"",5)
|
||||
("\"MultiPolygon\"",6)
|
||||
("\"GeometryCollection\"",7)
|
||||
;
|
||||
|
||||
// error handler
|
||||
boost::phoenix::function<ErrorHandler> const error_handler;
|
||||
|
||||
boost::phoenix::function<create_geometry_impl> const create_geometry;
|
||||
// generic JSON types
|
||||
json.value = json.object | json.array | json.string_ | json.number
|
||||
;
|
||||
|
||||
json.pairs = json.key_value % lit(',')
|
||||
json.key_value = json.string_ > lit(':') > json.value
|
||||
;
|
||||
|
||||
json.key_value = (json.string_ >> lit(':') >> json.value)
|
||||
;
|
||||
|
||||
json.object = lit('{') >> *json.pairs >> lit('}')
|
||||
json.object = lit('{')
|
||||
> -(json.key_value % lit(','))
|
||||
> lit('}')
|
||||
;
|
||||
|
||||
json.array = lit('[')
|
||||
>> json.value >> *(lit(',') >> json.value)
|
||||
>> lit(']')
|
||||
> -(json.value % lit(','))
|
||||
> lit(']')
|
||||
;
|
||||
|
||||
json.number = json.strict_double[_val = json.double_converter(_1)]
|
||||
|
@ -181,101 +160,58 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
|
|||
>> lit('{')
|
||||
>> -((omit[json.string_]
|
||||
>> lit(':')
|
||||
>> (geometry_collection(_val) | geometry)) % lit(','))
|
||||
>> (geometry_collection(_val) | geometry[push_back(_val, _1)]) % lit(',')))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
geometry =
|
||||
point |
|
||||
linestring |
|
||||
polygon |
|
||||
multi_point |
|
||||
multi_linestring |
|
||||
multi_polygon |
|
||||
omit[json.object]
|
||||
geometry = lit('{')[_a = 0]
|
||||
> ((lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1])
|
||||
|
|
||||
(lit("\"coordinates\"") > lit(':') > coordinates[_b = _1])
|
||||
|
|
||||
(lit("\"arcs\"") > lit(':') > rings_array[_c = _1])
|
||||
|
|
||||
properties_[_d = _1]
|
||||
|
|
||||
json.key_value) % lit(',')
|
||||
> lit('}')[_val = create_geometry(_a, _b, _c, _d)]
|
||||
;
|
||||
|
||||
|
||||
geometry_collection = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> lit(',') >> lit("\"geometries\"") >> lit(':') >> lit('[') >> -(geometry[push_back(_r1, _1)] % lit(','))
|
||||
>> lit(']')
|
||||
>> lit('}')
|
||||
;
|
||||
point = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"Point\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> ((lit(',') >> lit("\"coordinates\"") >> lit(':') >> coordinate)
|
||||
^ (lit(',') >> properties) /*^ (lit(',') >> omit[id])*/)
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"")
|
||||
>> lit(',') >> lit("\"geometries\"") >> lit(':')
|
||||
>> lit('[')
|
||||
>> -(geometry[push_back(_r1, _1)] % lit(','))
|
||||
>> lit(']')
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
multi_point = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"MultiPoint\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> ((lit(',') >> lit("\"coordinates\"") >> lit(':')
|
||||
>> lit('[') >> -(coordinate % lit(',')) >> lit(']'))
|
||||
^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
linestring = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"LineString\"")
|
||||
>> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[') >> int_ >> lit(']'))
|
||||
^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
multi_linestring = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"MultiLineString\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[')
|
||||
>> -((lit('[') >> int_ >> lit(']')) % lit(',')) >> lit(']'))
|
||||
^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
polygon = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"Polygon\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> ((lit(',') >> lit("\"arcs\"") >> lit(':')
|
||||
>> lit('[') >> -(ring % lit(',')) >> lit(']'))
|
||||
^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
multi_polygon = lit('{')
|
||||
>> lit("\"type\"") >> lit(':') >> lit("\"MultiPolygon\"")
|
||||
>> -(lit(',') >> omit[bbox])
|
||||
>> ((lit(',') >> lit("\"arcs\"") >> lit(':')
|
||||
>> lit('[')
|
||||
>> -((lit('[') >> -(ring % lit(',')) >> lit(']')) % lit(','))
|
||||
>> lit(']')) ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
|
||||
>> lit('}')
|
||||
;
|
||||
|
||||
id = lit("\"id\"") >> lit(':') >> omit[json.value]
|
||||
;
|
||||
|
||||
ring = lit('[') >> -(int_ % lit(',')) >> lit(']')
|
||||
;
|
||||
rings = lit('[') >> -(ring % lit(',')) >> lit(']')
|
||||
;
|
||||
rings_array = lit('[') >> -(rings % lit(',')) >> lit(']')
|
||||
|
|
||||
rings
|
||||
|
|
||||
ring
|
||||
;
|
||||
|
||||
properties = lit("\"properties\"")
|
||||
properties_ = lit("\"properties\"")
|
||||
>> lit(':')
|
||||
>> (( lit('{') >> attributes >> lit('}')) | json.object)
|
||||
>> lit('{') >> (json.string_ >> lit(':') >> json.value) % lit(',') >> lit('}')
|
||||
;
|
||||
|
||||
attributes = (json.string_ >> lit(':') >> attribute_value) % lit(',')
|
||||
;
|
||||
|
||||
attribute_value %= json.number | json.string_ ;
|
||||
|
||||
arcs = lit("\"arcs\"") >> lit(':')
|
||||
>> lit('[') >> -( arc % lit(',')) >> lit(']') ;
|
||||
|
||||
arc = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;
|
||||
arc = lit('[') >> -(coordinate_ % lit(',')) >> lit(']') ;
|
||||
|
||||
coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']');
|
||||
coordinate_ = lit('[') > double_ > lit(',') > double_ > lit(']');
|
||||
|
||||
coordinates = (lit('[') >> coordinate_ % lit(',') > lit(']'))
|
||||
| coordinate_;
|
||||
|
||||
topology.name("topology");
|
||||
transform.name("transform");
|
||||
|
@ -283,13 +219,9 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
|
|||
arc.name("arc");
|
||||
arcs.name("arcs");
|
||||
json.value.name("value");
|
||||
coordinate.name("coordinate");
|
||||
|
||||
point.name("point");
|
||||
multi_point.name("multi_point");
|
||||
linestring.name("linestring");
|
||||
polygon.name("polygon");
|
||||
multi_polygon.name("multi_polygon");
|
||||
coordinate_.name("coordinate");
|
||||
geometry.name("geometry");
|
||||
properties_.name("properties");
|
||||
geometry_collection.name("geometry_collection");
|
||||
// error handler
|
||||
on_error<fail>(topology, error_handler(_1, _2, _3, _4));
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2015 Artem Pavlenko
|
||||
* Copyright (C) 2016 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -27,6 +27,7 @@
|
|||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/json/topology.hpp>
|
||||
#include <mapnik/json/attribute_value_visitor.hpp>
|
||||
#include <mapnik/feature_factory.hpp>
|
||||
#include <mapnik/geometry_adapters.hpp>
|
||||
#include <mapnik/geometry_correct.hpp>
|
||||
|
@ -39,6 +40,11 @@ struct bounding_box_visitor
|
|||
: topo_(topo),
|
||||
num_arcs_(topo_.arcs.size()) {}
|
||||
|
||||
box2d<double> operator() (mapnik::topojson::empty const&) const
|
||||
{
|
||||
return box2d<double>();
|
||||
}
|
||||
|
||||
box2d<double> operator() (mapnik::topojson::point const& pt) const
|
||||
{
|
||||
double x = pt.coord.x;
|
||||
|
@ -81,50 +87,15 @@ struct bounding_box_visitor
|
|||
box2d<double> operator() (mapnik::topojson::linestring const& line) const
|
||||
{
|
||||
box2d<double> bbox;
|
||||
bool first = true;
|
||||
if (num_arcs_ > 0)
|
||||
{
|
||||
index_type index = line.ring;
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
bool first = true;
|
||||
double px = 0, py = 0;
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
for (auto pt : arcs.coordinates)
|
||||
{
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
}
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
bbox.init(x, y, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
bbox.expand_to_include(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
box2d<double> operator() (mapnik::topojson::multi_linestring const& multi_line) const
|
||||
{
|
||||
box2d<double> bbox;
|
||||
if (num_arcs_ > 0)
|
||||
{
|
||||
bool first = true;
|
||||
for (auto index : multi_line.rings)
|
||||
for (auto index : line.rings)
|
||||
{
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
|
||||
double px = 0, py = 0;
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
for (auto pt : arcs.coordinates)
|
||||
|
@ -152,6 +123,47 @@ struct bounding_box_visitor
|
|||
return bbox;
|
||||
}
|
||||
|
||||
box2d<double> operator() (mapnik::topojson::multi_linestring const& multi_line) const
|
||||
{
|
||||
box2d<double> bbox;
|
||||
if (num_arcs_ > 0)
|
||||
{
|
||||
bool first = true;
|
||||
for (auto const& line : multi_line.lines)
|
||||
{
|
||||
for (auto index : line)
|
||||
{
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
double px = 0, py = 0;
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
for (auto pt : arcs.coordinates)
|
||||
{
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
}
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
bbox.init(x, y, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
bbox.expand_to_include(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
box2d<double> operator() (mapnik::topojson::polygon const& poly) const
|
||||
{
|
||||
box2d<double> bbox;
|
||||
|
@ -246,26 +258,6 @@ private:
|
|||
};
|
||||
|
||||
namespace {
|
||||
struct attribute_value_visitor
|
||||
|
||||
{
|
||||
public:
|
||||
attribute_value_visitor(mapnik::transcoder const& tr)
|
||||
: tr_(tr) {}
|
||||
|
||||
mapnik::value operator()(std::string const& val) const
|
||||
{
|
||||
return mapnik::value(tr_.transcode(val.c_str()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mapnik::value operator()(T const& val) const
|
||||
{
|
||||
return mapnik::value(val);
|
||||
}
|
||||
|
||||
mapnik::transcoder const& tr_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::transcoder const& tr)
|
||||
|
@ -274,7 +266,7 @@ void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::tr
|
|||
{
|
||||
for (auto const& p : *geom.props)
|
||||
{
|
||||
feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(attribute_value_visitor(tr),std::get<1>(p)));
|
||||
feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(mapnik::json::attribute_value_visitor(tr),std::get<1>(p)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -333,29 +325,31 @@ struct feature_generator
|
|||
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
|
||||
if (num_arcs_ > 0)
|
||||
{
|
||||
index_type index = line.ring;
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
double px = 0, py = 0;
|
||||
mapnik::geometry::line_string<double> line_string;
|
||||
line_string.reserve(arcs.coordinates.size());
|
||||
mapnik::geometry::line_string<double> line_string;
|
||||
|
||||
for (auto pt : arcs.coordinates)
|
||||
for (auto index : line.rings)
|
||||
{
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
double px = 0, py = 0;
|
||||
line_string.reserve(line_string.size() + arcs.coordinates.size());
|
||||
for (auto pt : arcs.coordinates)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
}
|
||||
line_string.add_coord(x,y);
|
||||
}
|
||||
line_string.add_coord(x,y);
|
||||
}
|
||||
feature->set_geometry(std::move(line_string));
|
||||
assign_properties(*feature, line, tr_);
|
||||
}
|
||||
feature->set_geometry(std::move(line_string));
|
||||
assign_properties(*feature, line, tr_);
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
@ -367,30 +361,34 @@ struct feature_generator
|
|||
{
|
||||
mapnik::geometry::multi_line_string<double> multi_line_string;
|
||||
bool hit = false;
|
||||
multi_line_string.reserve(multi_line.rings.size());
|
||||
for (auto const& index : multi_line.rings)
|
||||
for (auto const& line : multi_line.lines)
|
||||
{
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
multi_line_string.reserve(multi_line_string.size() + line.size());
|
||||
mapnik::geometry::line_string<double> line_string;
|
||||
for (auto index : line)
|
||||
{
|
||||
hit = true;
|
||||
double px = 0, py = 0;
|
||||
mapnik::geometry::line_string<double> line_string;
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
line_string.reserve(arcs.coordinates.size());
|
||||
for (auto pt : arcs.coordinates)
|
||||
index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
|
||||
if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
|
||||
{
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
hit = true;
|
||||
double px = 0, py = 0;
|
||||
auto const& arcs = topo_.arcs[arc_index];
|
||||
line_string.reserve(line_string.size() + arcs.coordinates.size());
|
||||
for (auto pt : arcs.coordinates)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
double x = pt.x;
|
||||
double y = pt.y;
|
||||
if (topo_.tr)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
}
|
||||
line_string.add_coord(x, y);
|
||||
}
|
||||
line_string.add_coord(x, y);
|
||||
|
||||
}
|
||||
multi_line_string.push_back(std::move(line_string));
|
||||
}
|
||||
multi_line_string.push_back(std::move(line_string));
|
||||
}
|
||||
if (hit)
|
||||
{
|
||||
|
@ -439,7 +437,7 @@ struct feature_generator
|
|||
}
|
||||
processed_coords.emplace_back(coordinate{x,y});
|
||||
}
|
||||
|
||||
linear_ring.reserve(linear_ring.size() + processed_coords.size());
|
||||
if (reverse)
|
||||
{
|
||||
for (auto const& c : processed_coords | boost::adaptors::reversed)
|
||||
|
@ -513,14 +511,15 @@ struct feature_generator
|
|||
|
||||
if (topo_.tr)
|
||||
{
|
||||
x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
|
||||
y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
|
||||
transform const& tr = *topo_.tr;
|
||||
x = (px += x) * tr.scale_x + tr.translate_x;
|
||||
y = (py += y) * tr.scale_y + tr.translate_y;
|
||||
}
|
||||
processed_coords.emplace_back(coordinate{x,y});
|
||||
}
|
||||
|
||||
using namespace boost::adaptors;
|
||||
|
||||
linear_ring.reserve(linear_ring.size() + processed_coords.size());
|
||||
if (reverse)
|
||||
{
|
||||
for (auto const& c : (processed_coords | reversed))
|
||||
|
|
|
@ -62,13 +62,13 @@ struct multi_point
|
|||
|
||||
struct linestring
|
||||
{
|
||||
index_type ring ;
|
||||
std::vector<index_type> rings ;
|
||||
boost::optional<properties> props;
|
||||
};
|
||||
|
||||
struct multi_linestring
|
||||
{
|
||||
std::vector<index_type> rings;
|
||||
std::vector<std::vector<index_type> > lines;
|
||||
boost::optional<properties> props;
|
||||
};
|
||||
|
||||
|
@ -84,7 +84,10 @@ struct multi_polygon
|
|||
boost::optional<properties> props;
|
||||
};
|
||||
|
||||
using geometry = util::variant<point,
|
||||
struct empty {};
|
||||
|
||||
using geometry = util::variant<empty,
|
||||
point,
|
||||
linestring,
|
||||
polygon,
|
||||
multi_point,
|
||||
|
|
|
@ -61,7 +61,7 @@ void render_point_symbolizer(point_symbolizer const &sym,
|
|||
|
||||
agg::trans_affine tr;
|
||||
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform, common.scale_factor_);
|
||||
|
||||
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||
agg::trans_affine recenter_tr = recenter * tr;
|
||||
|
|
|
@ -58,7 +58,7 @@ MAPNIK_DECL void evaluate_transform(agg::trans_affine& tr,
|
|||
feature_impl const& feature,
|
||||
attributes const& vars,
|
||||
transform_type const& trans_expr,
|
||||
double scale_factor=1.0);
|
||||
double scale_factor);
|
||||
|
||||
struct enumeration_wrapper
|
||||
{
|
||||
|
|
|
@ -163,6 +163,10 @@ protected:
|
|||
void init_marker() const;
|
||||
};
|
||||
|
||||
} //namespace
|
||||
namespace geometry {
|
||||
MAPNIK_DECL mapnik::box2d<double> envelope(mapnik::base_symbolizer_helper::geometry_cref const& geom);
|
||||
}
|
||||
|
||||
} //namespace mapnik
|
||||
|
||||
#endif // SYMBOLIZER_HELPERS_HPP
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define MAPNIK_UTIL_VARIANT_HPP
|
||||
|
||||
#include <mapnik/config.hpp>
|
||||
#include <mapbox/variant/variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#include <mapnik/warning_ignore.hpp>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // gcc
|
||||
#pragma GCC diagnostic ignored "-W#pragma-messages"
|
||||
#pragma GCC diagnostic ignored "-Wunsequenced"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
|
10
localize.sh
10
localize.sh
|
@ -1,10 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# TODO - use rpath to avoid needing this to run tests locally
|
||||
|
||||
export CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
if [ $(uname -s) = 'Darwin' ]; then
|
||||
export DYLD_LIBRARY_PATH="${CURRENT_DIR}/src/":${DYLD_LIBRARY_PATH}
|
||||
else
|
||||
export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH}
|
||||
if [[ $(uname -s) == 'Darwin' ]]; then
|
||||
export DYLD_LIBRARY_PATH="${CURRENT_DIR}/src/":${DYLD_LIBRARY_PATH:-""}
|
||||
elif [[ $(uname -s) == 'Linux' ]]; then
|
||||
export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH:-""}
|
||||
fi
|
||||
|
||||
export PATH=$(pwd)/utils/mapnik-render/:${PATH}
|
||||
|
|
|
@ -44,6 +44,41 @@ using mapnik::view_transform;
|
|||
using mapnik::datasource_exception;
|
||||
using mapnik::feature_factory;
|
||||
|
||||
#ifdef MAPNIK_LOG
|
||||
namespace {
|
||||
|
||||
void get_overview_meta(GDALRasterBand* band)
|
||||
{
|
||||
int band_overviews = band->GetOverviewCount();
|
||||
if (band_overviews > 0)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: " << band_overviews << " overviews found!";
|
||||
|
||||
for (int b = 0; b < band_overviews; b++)
|
||||
{
|
||||
GDALRasterBand * overview = band->GetOverview(b);
|
||||
MAPNIK_LOG_DEBUG(gdal) << "Overview= " << b
|
||||
<< " Width=" << overview->GetXSize()
|
||||
<< " Height=" << overview->GetYSize();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No overviews found!";
|
||||
}
|
||||
|
||||
int bsx,bsy;
|
||||
double scale;
|
||||
band->GetBlockSize(&bsx, &bsy);
|
||||
scale = band->GetScale();
|
||||
|
||||
MAPNIK_LOG_DEBUG(gdal) << "Block=" << bsx << "x" << bsy
|
||||
<< " Scale=" << scale
|
||||
<< " Type=" << GDALGetDataTypeName(band->GetRasterDataType())
|
||||
<< "Color=" << GDALGetColorInterpretationName(band->GetColorInterpretation());
|
||||
}
|
||||
} // anonymous ns
|
||||
#endif
|
||||
gdal_featureset::gdal_featureset(GDALDataset& dataset,
|
||||
int band,
|
||||
gdal_query q,
|
||||
|
@ -551,6 +586,32 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
|
|||
MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band";
|
||||
}
|
||||
}
|
||||
else if( dataset_.GetRasterCount() > 0 && dataset_.GetRasterBand(1) )
|
||||
{
|
||||
// Check if we have a non-alpha mask band (for example a TIFF internal mask)
|
||||
int flags = dataset_.GetRasterBand(1)->GetMaskFlags();
|
||||
GDALRasterBand* mask = 0;
|
||||
if (flags == GMF_PER_DATASET)
|
||||
{
|
||||
mask = dataset_.GetRasterBand(1)->GetMaskBand();
|
||||
}
|
||||
if (mask)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: found and processing mask band...";
|
||||
if (!raster_has_nodata)
|
||||
{
|
||||
raster_io_error = mask->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 3,
|
||||
image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
|
||||
if (raster_io_error == CE_Failure) {
|
||||
throw datasource_exception(CPLGetLastErrorMsg());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of mask band";
|
||||
}
|
||||
}
|
||||
}
|
||||
mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(intersect, image, filter_factor);
|
||||
// set nodata value to be used in raster colorizer
|
||||
if (nodata_value_) raster->set_nodata(*nodata_value_);
|
||||
|
@ -620,36 +681,3 @@ feature_ptr gdal_featureset::get_feature_at_point(mapnik::coord2d const& pt)
|
|||
}
|
||||
return feature_ptr();
|
||||
}
|
||||
|
||||
#ifdef MAPNIK_LOG
|
||||
void gdal_featureset::get_overview_meta(GDALRasterBand* band)
|
||||
{
|
||||
int band_overviews = band->GetOverviewCount();
|
||||
if (band_overviews > 0)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: " << band_overviews << " overviews found!";
|
||||
|
||||
for (int b = 0; b < band_overviews; b++)
|
||||
{
|
||||
GDALRasterBand * overview = band->GetOverview(b);
|
||||
MAPNIK_LOG_DEBUG(gdal) << "Overview= " << b
|
||||
<< " Width=" << overview->GetXSize()
|
||||
<< " Height=" << overview->GetYSize();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No overviews found!";
|
||||
}
|
||||
|
||||
int bsx,bsy;
|
||||
double scale;
|
||||
band->GetBlockSize(&bsx, &bsy);
|
||||
scale = band->GetScale();
|
||||
|
||||
MAPNIK_LOG_DEBUG(gdal) << "Block=" << bsx << "x" << bsy
|
||||
<< " Scale=" << scale
|
||||
<< " Type=" << GDALGetDataTypeName(band->GetRasterDataType())
|
||||
<< "Color=" << GDALGetColorInterpretationName(band->GetColorInterpretation());
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -73,11 +73,6 @@ public:
|
|||
private:
|
||||
mapnik::feature_ptr get_feature(mapnik::query const& q);
|
||||
mapnik::feature_ptr get_feature_at_point(mapnik::coord2d const& p);
|
||||
|
||||
#ifdef MAPNIK_LOG
|
||||
void get_overview_meta(GDALRasterBand * band);
|
||||
#endif
|
||||
|
||||
GDALDataset & dataset_;
|
||||
mapnik::context_ptr ctx_;
|
||||
int band_;
|
||||
|
|
|
@ -878,9 +878,10 @@ featureset_ptr pgraster_datasource::features_with_context(query const& q,process
|
|||
std::string table_with_bbox;
|
||||
std::string col = geometryColumn_;
|
||||
|
||||
if ( use_overviews_ ) {
|
||||
std::string sch = schema_;
|
||||
std::string tab = mapnik::sql_utils::unquote_double(raster_table_);
|
||||
if ( use_overviews_ && !overviews_.empty()) {
|
||||
std::string sch = overviews_[0].schema;
|
||||
std::string tab = overviews_[0].table;
|
||||
col = overviews_[0].column;
|
||||
const double scale = std::min(px_gw, px_gh);
|
||||
std::vector<pgraster_overview>::const_reverse_iterator i;
|
||||
for (i=overviews_.rbegin(); i!=overviews_.rend(); ++i) {
|
||||
|
|
|
@ -66,18 +66,9 @@ struct attr_value_converter
|
|||
{
|
||||
return mapnik::Boolean;
|
||||
}
|
||||
|
||||
mapnik::eAttributeType operator() (std::string const& /*val*/) const
|
||||
{
|
||||
return mapnik::String;
|
||||
}
|
||||
|
||||
mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const
|
||||
{
|
||||
return mapnik::String;
|
||||
}
|
||||
|
||||
mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const
|
||||
// string, object, array
|
||||
template <typename T>
|
||||
mapnik::eAttributeType operator() (T const& /*val*/) const
|
||||
{
|
||||
return mapnik::String;
|
||||
}
|
||||
|
@ -109,6 +100,11 @@ struct geometry_type_visitor
|
|||
{
|
||||
return static_cast<int>(mapnik::datasource_geometry_t::Polygon);
|
||||
}
|
||||
template <typename T>
|
||||
int operator() (T const& ) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct collect_attributes_visitor
|
||||
|
@ -117,6 +113,9 @@ struct collect_attributes_visitor
|
|||
collect_attributes_visitor(mapnik::layer_descriptor & desc):
|
||||
desc_(desc) {}
|
||||
|
||||
// no-op
|
||||
void operator() (mapnik::topojson::empty) {}
|
||||
//
|
||||
template <typename GeomType>
|
||||
void operator() (GeomType const& g)
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ commit_message_contains () {
|
|||
}
|
||||
|
||||
commit_message_parse () {
|
||||
if commit_message_contains '[skip tests]' || [[ $(uname -s) == 'Darwin' ]]; then
|
||||
if commit_message_contains '[skip tests]'; then
|
||||
config_override "CPP_TESTS = False"
|
||||
fi
|
||||
if commit_message_contains '[skip utils]'; then
|
||||
|
@ -92,8 +92,7 @@ configure () {
|
|||
|
||||
coverage () {
|
||||
./mason_packages/.link/bin/cpp-coveralls \
|
||||
--gcov /usr/bin/llvm-cov-${LLVM_VERSION} \
|
||||
--build-root . --gcov-options '\-lp' \
|
||||
--gcov ${LLVM_COV} \
|
||||
--exclude mason_packages \
|
||||
--exclude .sconf_temp --exclude benchmark --exclude deps \
|
||||
--exclude scons --exclude test --exclude demo --exclude docs \
|
||||
|
|
|
@ -92,7 +92,7 @@ struct agg_renderer_process_visitor_l
|
|||
value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
|
||||
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
|
||||
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
|
||||
image_rgba8 image(bbox_image.width(), bbox_image.height());
|
||||
render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image);
|
||||
|
|
|
@ -84,7 +84,7 @@ struct agg_renderer_process_visitor_p
|
|||
{
|
||||
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
|
||||
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
|
||||
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
|
||||
render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image);
|
||||
|
|
|
@ -63,7 +63,7 @@ void agg_renderer<T0,T1>::process(text_symbolizer const& sym,
|
|||
if (halo_transform)
|
||||
{
|
||||
agg::trans_affine halo_affine_transform;
|
||||
evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform);
|
||||
evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform, common_.scale_factor_);
|
||||
ren.set_halo_transform(halo_affine_transform);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ struct cairo_renderer_process_visitor_l
|
|||
mapnik::rasterizer ras;
|
||||
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
|
||||
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
|
||||
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
|
||||
render_pattern<image_rgba8>(ras, marker, image_tr, 1.0, image);
|
||||
|
|
|
@ -96,7 +96,7 @@ void cairo_renderer<T>::process(polygon_pattern_symbolizer const& sym,
|
|||
value_double opacity = get<value_double, keys::opacity>(sym, feature, common_.vars_);
|
||||
agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
|
||||
auto image_transform = get_optional<transform_type>(sym, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
|
||||
cairo_save_restore guard(context_);
|
||||
context_.set_operator(comp_op);
|
||||
|
|
|
@ -38,8 +38,6 @@ template MAPNIK_DECL mapnik::box2d<double> envelope(multi_line_string<double> co
|
|||
template MAPNIK_DECL mapnik::box2d<double> envelope(multi_polygon<double> const& geom);
|
||||
// collection
|
||||
template MAPNIK_DECL mapnik::box2d<double> envelope(geometry_collection<double> const& geom);
|
||||
//
|
||||
template MAPNIK_DECL mapnik::box2d<std::int64_t> envelope(geometry<std::int64_t> const& geom);
|
||||
|
||||
} // end ns geometry
|
||||
} // end ns mapnik
|
||||
|
|
|
@ -60,7 +60,7 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
|
|||
if (halo_transform)
|
||||
{
|
||||
agg::trans_affine halo_affine_transform;
|
||||
evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform);
|
||||
evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform, common_.scale_factor_);
|
||||
ren.set_halo_transform(halo_affine_transform);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, a
|
|||
{
|
||||
double width = 0.0;
|
||||
double height = 0.0;
|
||||
double half_stroke_width = 0.0;
|
||||
if (has_key(sym,keys::width) && has_key(sym,keys::height))
|
||||
{
|
||||
width = get<double>(sym, keys::width, feature, vars, 0.0);
|
||||
|
@ -50,6 +51,10 @@ void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, a
|
|||
{
|
||||
width = height = get<double>(sym, keys::height, feature, vars, 0.0);
|
||||
}
|
||||
if (has_key(sym,keys::stroke_width))
|
||||
{
|
||||
half_stroke_width = get<double>(sym, keys::stroke_width, feature, vars, 0.0) / 2.0;
|
||||
}
|
||||
svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
|
||||
styled_svg.push_attr();
|
||||
styled_svg.begin_path();
|
||||
|
@ -59,6 +64,10 @@ void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, a
|
|||
styled_svg.pop_attr();
|
||||
double lox,loy,hix,hiy;
|
||||
styled_svg.bounding_rect(&lox, &loy, &hix, &hiy);
|
||||
lox -= half_stroke_width;
|
||||
loy -= half_stroke_width;
|
||||
hix += half_stroke_width;
|
||||
hiy += half_stroke_width;
|
||||
styled_svg.set_dimensions(width,height);
|
||||
marker_ellipse.set_dimensions(width,height);
|
||||
marker_ellipse.set_bounding_box(lox,loy,hix,hiy);
|
||||
|
|
|
@ -200,20 +200,21 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co
|
|||
#ifdef MAPNIK_USE_PROJ4
|
||||
if (is_dest_longlat_)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<point_count; i++) {
|
||||
x[i*offset] *= DEG_TO_RAD;
|
||||
y[i*offset] *= DEG_TO_RAD;
|
||||
for (int i = 0; i < point_count; ++i)
|
||||
{
|
||||
x[i * offset] *= DEG_TO_RAD;
|
||||
y[i * offset] *= DEG_TO_RAD;
|
||||
}
|
||||
}
|
||||
|
||||
if (pj_transform( dest_.proj_, source_.proj_, point_count,
|
||||
offset, x,y,z) != 0)
|
||||
if (pj_transform(dest_.proj_, source_.proj_, point_count,
|
||||
offset, x, y, z) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int j=0; j<point_count; j++) {
|
||||
for (int j = 0; j < point_count; ++j)
|
||||
{
|
||||
if (x[j] == HUGE_VAL || y[j] == HUGE_VAL)
|
||||
{
|
||||
return false;
|
||||
|
@ -222,10 +223,10 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co
|
|||
|
||||
if (is_source_longlat_)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<point_count; i++) {
|
||||
x[i*offset] *= RAD_TO_DEG;
|
||||
y[i*offset] *= RAD_TO_DEG;
|
||||
for (int i = 0; i < point_count; ++i)
|
||||
{
|
||||
x[i * offset] *= RAD_TO_DEG;
|
||||
y[i * offset] *= RAD_TO_DEG;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -266,7 +267,7 @@ unsigned int proj_transform::backward (std::vector<geometry::point<double>> & ls
|
|||
double * x = reinterpret_cast<double*>(ptr);
|
||||
double * y = x + 1;
|
||||
double * z = nullptr;
|
||||
if(!backward(x, y, z, size, 2))
|
||||
if (!backward(x, y, z, size, 2))
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
@ -312,31 +313,24 @@ bool proj_transform::backward (box2d<double> & box) const
|
|||
if (is_source_equal_dest_)
|
||||
return true;
|
||||
|
||||
double llx = box.minx();
|
||||
double ulx = box.minx();
|
||||
double lly = box.miny();
|
||||
double lry = box.miny();
|
||||
double lrx = box.maxx();
|
||||
double urx = box.maxx();
|
||||
double uly = box.maxy();
|
||||
double ury = box.maxy();
|
||||
double z = 0.0;
|
||||
if (!backward(llx,lly,z))
|
||||
double x[4], y[4];
|
||||
x[0] = box.minx(); // llx 0
|
||||
y[0] = box.miny(); // lly 1
|
||||
x[1] = box.maxx(); // lrx 2
|
||||
y[1] = box.miny(); // lry 3
|
||||
x[2] = box.minx(); // ulx 4
|
||||
y[2] = box.maxy(); // uly 5
|
||||
x[3] = box.maxx(); // urx 6
|
||||
y[3] = box.maxy(); // ury 7
|
||||
|
||||
if (!backward(x, y, nullptr, 4, 1))
|
||||
return false;
|
||||
if (!backward(lrx,lry,z))
|
||||
return false;
|
||||
if (!backward(ulx,uly,z))
|
||||
return false;
|
||||
if (!backward(urx,ury,z))
|
||||
return false;
|
||||
double minx = std::min(ulx, llx);
|
||||
double miny = std::min(lly, lry);
|
||||
double maxx = std::max(urx, lrx);
|
||||
double maxy = std::max(ury, uly);
|
||||
box.init(minx,
|
||||
miny,
|
||||
maxx,
|
||||
maxy);
|
||||
|
||||
double minx = std::min(x[0], x[2]);
|
||||
double miny = std::min(y[0], y[1]);
|
||||
double maxx = std::max(x[1], x[3]);
|
||||
double maxy = std::max(y[2], y[3]);
|
||||
box.init(minx, miny, maxx, maxy);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -425,7 +419,6 @@ bool proj_transform::backward(box2d<double>& env, int points) const
|
|||
env.re_center(result.center().x, result.center().y);
|
||||
env.height(result.height());
|
||||
env.width(result.width());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ struct render_marker_symbolizer_visitor
|
|||
|
||||
if (auto image_transform = get_optional<transform_type>(sym_, keys::image_transform))
|
||||
{
|
||||
evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
|
||||
evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
}
|
||||
|
||||
vector_dispatch_type rasterizer_dispatch(marker_ptr,
|
||||
|
@ -183,7 +183,7 @@ struct render_marker_symbolizer_visitor
|
|||
|
||||
setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_);
|
||||
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
|
||||
box2d<double> const& bbox = mark.bounding_box();
|
||||
mapnik::image_rgba8 const& marker = mark.get_data();
|
||||
// - clamp sizes to > 4 pixels of interactivity
|
||||
|
|
|
@ -465,7 +465,7 @@ void text_symbolizer_helper::init_marker() const
|
|||
if (marker->is<marker_null>()) return;
|
||||
agg::trans_affine trans;
|
||||
auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
|
||||
if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform);
|
||||
if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform, scale_factor_);
|
||||
double width = marker->width();
|
||||
double height = marker->height();
|
||||
double px0 = - 0.5 * width;
|
||||
|
|
|
@ -51,7 +51,7 @@ text_line::text_line(text_line && rhs)
|
|||
|
||||
void text_line::add_glyph(glyph_info && glyph, double scale_factor_)
|
||||
{
|
||||
line_height_ = std::max(line_height_, glyph.line_height() + glyph.format->line_spacing);
|
||||
line_height_ = std::max(line_height_, glyph.line_height() + glyph.format->line_spacing * scale_factor_);
|
||||
double advance = glyph.advance();
|
||||
if (glyphs_.empty())
|
||||
{
|
||||
|
|
|
@ -72,8 +72,6 @@ DEFINE_NAME_TRAIT( int, "int")
|
|||
DEFINE_NAME_TRAIT( boolean_type, "boolean_type")
|
||||
#ifdef BIGINT
|
||||
DEFINE_NAME_TRAIT( mapnik::value_integer, "long long" )
|
||||
#else
|
||||
DEFINE_NAME_TRAIT( mapnik::value_integer, "int" )
|
||||
#endif
|
||||
DEFINE_NAME_TRAIT( std::string, "string" )
|
||||
DEFINE_NAME_TRAIT( color, "color" )
|
||||
|
@ -416,7 +414,9 @@ compile_get_opt_attr(boolean_type);
|
|||
compile_get_opt_attr(std::string);
|
||||
compile_get_opt_attr(int);
|
||||
compile_get_opt_attr(unsigned);
|
||||
#ifdef BIGINT
|
||||
compile_get_opt_attr(mapnik::value_integer);
|
||||
#endif
|
||||
compile_get_opt_attr(float);
|
||||
compile_get_opt_attr(double);
|
||||
compile_get_opt_attr(color);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6e4b7ff65b6a1f0b34ae7cad52fe2c921ca9ea3f
|
||||
Subproject commit e74f1cef09d579d6ff414cb56970adbe43b7a91b
|
|
@ -1 +1 @@
|
|||
Subproject commit 725bc22d285ef5a558e2e241fd22ff5489f056ce
|
||||
Subproject commit 5f0e6f86696a2a9a6733e42b1f400ba4ec2f8847
|
12
test/run
12
test/run
|
@ -1,5 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -o pipefail
|
||||
set -eu
|
||||
|
||||
failures=0
|
||||
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
||||
|
@ -18,9 +21,8 @@ if [ -d "test/data" ]; then
|
|||
|
||||
run_substep "Running C++ Unit tests..."
|
||||
if [[ -f ./test/unit/run ]]; then
|
||||
./test/unit/run
|
||||
failures=$((failures+$?))
|
||||
ran_a_test=true
|
||||
./test/unit/run || failures=$((failures+$?))
|
||||
else
|
||||
run_warn "Skipping unit tests since they were not built"
|
||||
fi
|
||||
|
@ -31,8 +33,7 @@ if [ -d "test/data" ]; then
|
|||
for FILE in test/standalone/*-bin; do
|
||||
found_test=true
|
||||
ran_a_test=true
|
||||
${FILE};
|
||||
failures=$((failures+$?))
|
||||
${FILE} || failures=$((failures+$?))
|
||||
done
|
||||
fi
|
||||
if [[ $found_test == false ]]; then
|
||||
|
@ -45,9 +46,8 @@ if [ -d "test/data" ]; then
|
|||
JOBS=1
|
||||
fi
|
||||
if [[ -f ./test/visual/run ]]; then
|
||||
./test/visual/run -j $JOBS
|
||||
ran_a_test=true
|
||||
failures=$((failures+$?))
|
||||
./test/visual/run -j $JOBS || failures=$((failures+$?))
|
||||
else
|
||||
run_warn "Skipping visual tests since they were not built"
|
||||
fi
|
||||
|
|
|
@ -106,13 +106,18 @@ inline std::size_t count_features(mapnik::featureset_ptr features) {
|
|||
}
|
||||
|
||||
using attr = std::tuple<std::string, mapnik::value>;
|
||||
|
||||
#define REQUIRE_ATTRIBUTES(feature, attrs) \
|
||||
REQUIRE(bool(feature)); \
|
||||
for (auto const &kv : attrs) { \
|
||||
REQUIRE(feature->has_key(std::get<0>(kv))); \
|
||||
CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv)); \
|
||||
} \
|
||||
|
||||
|
||||
inline void require_attributes(mapnik::feature_ptr feature,
|
||||
std::initializer_list<attr> const &attrs) {
|
||||
REQUIRE(bool(feature));
|
||||
for (auto const &kv : attrs) {
|
||||
REQUIRE(feature->has_key(std::get<0>(kv)));
|
||||
CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv));
|
||||
}
|
||||
REQUIRE_ATTRIBUTES(feature, attrs);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "catch.hpp"
|
||||
#include "ds_test_util.hpp"
|
||||
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/datasource.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
|
@ -654,5 +655,72 @@ TEST_CASE("geojson") {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("GeoJSON properties are properly expressed")
|
||||
{
|
||||
mapnik::transcoder tr("utf8");
|
||||
mapnik::parameters params;
|
||||
params["type"] = "geojson";
|
||||
|
||||
std::string filename("./test/data/json/escaped.geojson");
|
||||
params["file"] = filename;
|
||||
|
||||
// cleanup in the case of a failed previous run
|
||||
if (mapnik::util::exists(filename + ".index"))
|
||||
{
|
||||
mapnik::util::remove(filename + ".index");
|
||||
}
|
||||
|
||||
for (auto create_index : { true, false })
|
||||
{
|
||||
if (create_index)
|
||||
{
|
||||
CHECK(!mapnik::util::exists(filename + ".index"));
|
||||
int ret = create_disk_index(filename);
|
||||
int ret_posix = (ret >> 8) & 0x000000ff;
|
||||
INFO(ret);
|
||||
INFO(ret_posix);
|
||||
CHECK(mapnik::util::exists(filename + ".index"));
|
||||
}
|
||||
|
||||
for (auto cache_features : {true, false})
|
||||
{
|
||||
params["cache_features"] = cache_features;
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(bool(ds));
|
||||
auto fields = ds->get_descriptor().get_descriptors();
|
||||
std::initializer_list<std::string> names = {"NOM_FR","array","boolean","description","double","empty_array", "empty_object","int","name","object","spaces"};
|
||||
REQUIRE_FIELD_NAMES(fields, names);
|
||||
|
||||
auto fs = all_features(ds);
|
||||
REQUIRE(bool(fs));
|
||||
std::initializer_list<attr> attrs = {
|
||||
attr{"name", tr.transcode("Test")},
|
||||
attr{"NOM_FR", tr.transcode("Québec")},
|
||||
attr{"boolean", mapnik::value_bool("true")},
|
||||
attr{"description", tr.transcode("Test: \u005C")},
|
||||
attr{"double", mapnik::value_double(1.1)},
|
||||
attr{"int", mapnik::value_integer(1)},
|
||||
attr{"object", tr.transcode("{name:\"waka\",spaces:\"value with spaces\",int:1,double:1.1,boolean:false"
|
||||
",NOM_FR:\"Québec\",array:[\"string\",\"value with spaces\",3,1.1,null,true"
|
||||
",\"Québec\"],another_object:{name:\"nested object\"}}")},
|
||||
attr{"spaces", tr.transcode("this has spaces")},
|
||||
attr{"array", tr.transcode("[\"string\",\"value with spaces\",3,1.1,null,true,"
|
||||
"\"Québec\",{name:\"object within an array\"},"
|
||||
"[\"array\",\"within\",\"an\",\"array\"]]")},
|
||||
attr{"empty_array", tr.transcode("[]")},
|
||||
attr{"empty_object", tr.transcode("{}")},
|
||||
};
|
||||
auto feature = fs->next();
|
||||
REQUIRE(bool(feature));
|
||||
REQUIRE_ATTRIBUTES(feature, attrs);
|
||||
}
|
||||
// cleanup
|
||||
if (create_index && mapnik::util::exists(filename + ".index"))
|
||||
{
|
||||
mapnik::util::remove(filename + ".index");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,13 +29,15 @@
|
|||
#include <mapnik/util/fs.hpp>
|
||||
|
||||
/*
|
||||
Compile and run just this test:
|
||||
clang++ -o test-postgis -g -I./test/ test/unit/run.cpp test/unit/datasource/postgis.cpp `mapnik-config --all-flags` && ./test-postgis -d yes
|
||||
Compile and run just this test:
|
||||
clang++ -o test-postgis -g -I./test/ test/unit/run.cpp test/unit/datasource/postgis.cpp `mapnik-config --all-flags` && ./test-postgis -d yes
|
||||
*/
|
||||
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
int run(std::string const& command, bool okay_to_fail = false)
|
||||
namespace {
|
||||
|
||||
bool run(std::string const& command, bool okay_to_fail = false)
|
||||
{
|
||||
std::string cmd;
|
||||
if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
|
||||
|
@ -61,251 +63,278 @@ int run(std::string const& command, bool okay_to_fail = false)
|
|||
return worked;
|
||||
}
|
||||
|
||||
std::string dbname("mapnik-tmp-postgis-test-db");
|
||||
|
||||
std::string const dbname("mapnik-tmp-postgis-test-db");
|
||||
bool status = false;
|
||||
|
||||
bool ping_postmaster()
|
||||
{
|
||||
return (run("psql --version")
|
||||
&& run("dropdb --if-exists " + dbname)
|
||||
&& run("createdb -T template_postgis " + dbname));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("postgis") {
|
||||
|
||||
SECTION("Postgis data initialization")
|
||||
SECTION("Ping Postmaster (check if server is runnging and accessible")
|
||||
{
|
||||
//don't add 'true' here, to get error message, when drop fails. If it works nothing is output
|
||||
REQUIRE(run("dropdb --if-exists " + dbname));
|
||||
REQUIRE(run("createdb -T template_postgis " + dbname));
|
||||
//REQUIRE(run("createdb " + dbname));
|
||||
// Breaks when raster support is missing (unfortunately this is common)
|
||||
//REQUIRE(run("psql -c 'CREATE EXTENSION postgis;' " + dbname, true));
|
||||
REQUIRE(run("psql -q -f ./test/data/sql/postgis-create-db-and-tables.sql " + dbname));
|
||||
if (!ping_postmaster())
|
||||
{
|
||||
WARN("Can't run postgis.input tests - check postmaster is running and accessible");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
mapnik::parameters base_params;
|
||||
base_params["type"] = "postgis";
|
||||
base_params["dbname"] = dbname;
|
||||
|
||||
SECTION("Postgis should throw without 'table' parameter")
|
||||
if (status)
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with 'max_async_connection' greater than 'max_size'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["max_async_connection"] = "2";
|
||||
params["max_size"] = "1";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with invalid metadata query")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "does_not_exist";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with invalid key field")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_invalid_id";
|
||||
params["key_field"] = "id";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with multicolumn primary key")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_invalid_multi_col_pk";
|
||||
params["autodetect_key_field"] = "true";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw without geom column")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_no_geom_col";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
CHECK_THROWS(all_features(ds));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with invalid credentials")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["user"] = "not_a_valid_user";
|
||||
params["password"] = "not_a_valid_pwd";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis initialize dataset with persist_connection, schema, extent, geometry field, autodectect key field, simplify_geometries, row_limit")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["persist_connection"] = "false";
|
||||
params["table"] = "public.test";
|
||||
params["geometry_field"] = "geom";
|
||||
params["autodetect_key_field"] = "true";
|
||||
params["extent"] = "-1 -1, -1 2, 4 3, 3 -1, -1 -1";
|
||||
params["simplify_geometries"] = "true";
|
||||
params["row_limit"] = "1";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
}
|
||||
|
||||
SECTION("Postgis dataset geometry type")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test WHERE gid=1) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
|
||||
}
|
||||
|
||||
SECTION("Postgis query field names")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
REQUIRE(ds->type() == mapnik::datasource::datasource_t::Vector);
|
||||
auto fields = ds->get_descriptor().get_descriptors();
|
||||
require_field_names(fields, { "gid", "colbigint", "col_text", "col-char", "col+bool", "colnumeric", "colsmallint", "colfloat4", "colfloat8", "colcharacter" });
|
||||
require_field_types(fields, { mapnik::Integer, mapnik::Integer, mapnik::String, mapnik::String, mapnik::Boolean, mapnik::Double, mapnik::Integer, mapnik::Double, mapnik::Double, mapnik::String });
|
||||
}
|
||||
|
||||
SECTION("Postgis iterate features")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["key_field"] = "gid";
|
||||
params["max_async_connection"] = "2";
|
||||
//params["cursor_size"] = "2";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
|
||||
auto featureset = ds->features_at_point(mapnik::coord2d(1, 1));
|
||||
mapnik::feature_ptr feature;
|
||||
while ((bool(feature = featureset->next()))) {
|
||||
REQUIRE(feature->get(2).to_string() == feature->get("col_text").to_string());
|
||||
REQUIRE(feature->get(4).to_bool() == feature->get("col+bool").to_bool());
|
||||
REQUIRE(feature->get(5).to_double() == feature->get("colnumeric").to_double());
|
||||
REQUIRE(feature->get(5).to_string() == feature->get("colnumeric").to_string());
|
||||
SECTION("Postgis data initialization")
|
||||
{
|
||||
//don't add 'true' here, to get error message, when drop fails. If it works nothing is output
|
||||
REQUIRE(run("dropdb --if-exists " + dbname));
|
||||
REQUIRE(run("createdb -T template_postgis " + dbname));
|
||||
//REQUIRE(run("createdb " + dbname));
|
||||
// Breaks when raster support is missing (unfortunately this is common)
|
||||
//REQUIRE(run("psql -c 'CREATE EXTENSION postgis;' " + dbname, true));
|
||||
REQUIRE(run("psql -q -f ./test/data/sql/postgis-create-db-and-tables.sql " + dbname));
|
||||
}
|
||||
|
||||
featureset = all_features(ds);
|
||||
feature = featureset->next();
|
||||
//deactivate char tests for now: not yet implemented.
|
||||
//add at postgis_datasource.cpp:423
|
||||
//case 18: // char
|
||||
//REQUIRE("A" == feature->get("col-char").to_string());
|
||||
feature = featureset->next();
|
||||
//REQUIRE("B" == feature->get("col-char").to_string());
|
||||
feature = featureset->next();
|
||||
REQUIRE(false == feature->get("col+bool").to_bool());
|
||||
}
|
||||
mapnik::parameters base_params;
|
||||
base_params["type"] = "postgis";
|
||||
base_params["dbname"] = dbname;
|
||||
|
||||
SECTION("Postgis cursorresultest")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test) as data";
|
||||
params["cursor_size"] = "2";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
auto featureset = all_features(ds);
|
||||
CHECK(count_features(featureset) == 8);
|
||||
|
||||
featureset = all_features(ds);
|
||||
mapnik::feature_ptr feature;
|
||||
while (bool(feature = featureset->next())) {
|
||||
CHECK(feature->size() == 10);
|
||||
SECTION("Postgis should throw without 'table' parameter")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
featureset = all_features(ds);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPoint);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::LineString);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiLineString);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Polygon);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPolygon);
|
||||
require_geometry(featureset->next(), 3, mapnik::geometry::geometry_types::GeometryCollection);
|
||||
}
|
||||
SECTION("Postgis should throw with 'max_async_connection' greater than 'max_size'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["max_async_connection"] = "2";
|
||||
params["max_size"] = "1";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis bbox query")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM public.test) as data WHERE geom && !bbox!";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == -2);
|
||||
REQUIRE(ext.miny() == -2);
|
||||
REQUIRE(ext.maxx() == 5);
|
||||
REQUIRE(ext.maxy() == 4);
|
||||
}
|
||||
SECTION("Postgis should throw with invalid metadata query")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "does_not_exist";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis query extent: full dataset")
|
||||
{
|
||||
//include schema to increase coverage
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM public.test) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == -2);
|
||||
REQUIRE(ext.miny() == -2);
|
||||
REQUIRE(ext.maxx() == 5);
|
||||
REQUIRE(ext.maxy() == 4);
|
||||
}
|
||||
SECTION("Postgis should throw with invalid key field")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_invalid_id";
|
||||
params["key_field"] = "id";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with multicolumn primary key")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_invalid_multi_col_pk";
|
||||
params["autodetect_key_field"] = "true";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw without geom column")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test_no_geom_col";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
CHECK_THROWS(all_features(ds));
|
||||
}
|
||||
|
||||
SECTION("Postgis should throw with invalid credentials")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["user"] = "not_a_valid_user";
|
||||
params["password"] = "not_a_valid_pwd";
|
||||
CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
|
||||
}
|
||||
|
||||
SECTION("Postgis initialize dataset with persist_connection, schema, extent, geometry field, autodectect key field, simplify_geometries, row_limit")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["persist_connection"] = "false";
|
||||
params["table"] = "public.test";
|
||||
params["geometry_field"] = "geom";
|
||||
params["autodetect_key_field"] = "true";
|
||||
params["extent"] = "-1 -1, -1 2, 4 3, 3 -1, -1 -1";
|
||||
params["simplify_geometries"] = "true";
|
||||
params["row_limit"] = "1";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
}
|
||||
|
||||
SECTION("Postgis dataset geometry type")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test WHERE gid=1) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
|
||||
}
|
||||
|
||||
SECTION("Postgis query field names")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
REQUIRE(ds->type() == mapnik::datasource::datasource_t::Vector);
|
||||
auto fields = ds->get_descriptor().get_descriptors();
|
||||
require_field_names(fields, { "gid", "colbigint", "col_text", "col-char", "col+bool", "colnumeric", "colsmallint", "colfloat4", "colfloat8", "colcharacter" });
|
||||
require_field_types(fields, { mapnik::Integer, mapnik::Integer, mapnik::String, mapnik::String, mapnik::Boolean, mapnik::Double, mapnik::Integer, mapnik::Double, mapnik::Double, mapnik::String });
|
||||
}
|
||||
|
||||
SECTION("Postgis iterate features")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "test";
|
||||
params["key_field"] = "gid";
|
||||
params["max_async_connection"] = "2";
|
||||
//params["cursor_size"] = "2";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
|
||||
auto featureset = ds->features_at_point(mapnik::coord2d(1, 1));
|
||||
mapnik::feature_ptr feature;
|
||||
while ((bool(feature = featureset->next()))) {
|
||||
REQUIRE(feature->get(2).to_string() == feature->get("col_text").to_string());
|
||||
REQUIRE(feature->get(4).to_bool() == feature->get("col+bool").to_bool());
|
||||
REQUIRE(feature->get(5).to_double() == feature->get("colnumeric").to_double());
|
||||
REQUIRE(feature->get(5).to_string() == feature->get("colnumeric").to_string());
|
||||
}
|
||||
|
||||
featureset = all_features(ds);
|
||||
feature = featureset->next();
|
||||
//deactivate char tests for now: not yet implemented.
|
||||
//add at postgis_datasource.cpp:423
|
||||
//case 18: // char
|
||||
//REQUIRE("A" == feature->get("col-char").to_string());
|
||||
feature = featureset->next();
|
||||
//REQUIRE("B" == feature->get("col-char").to_string());
|
||||
feature = featureset->next();
|
||||
REQUIRE(false == feature->get("col+bool").to_bool());
|
||||
}
|
||||
|
||||
SECTION("Postgis cursorresultest")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test) as data";
|
||||
params["cursor_size"] = "2";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
auto featureset = all_features(ds);
|
||||
CHECK(count_features(featureset) == 8);
|
||||
|
||||
featureset = all_features(ds);
|
||||
mapnik::feature_ptr feature;
|
||||
while (bool(feature = featureset->next())) {
|
||||
CHECK(feature->size() == 10);
|
||||
}
|
||||
|
||||
featureset = all_features(ds);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPoint);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::LineString);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiLineString);
|
||||
require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Polygon);
|
||||
require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPolygon);
|
||||
require_geometry(featureset->next(), 3, mapnik::geometry::geometry_types::GeometryCollection);
|
||||
}
|
||||
|
||||
SECTION("Postgis bbox query")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM public.test) as data WHERE geom && !bbox!";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == -2);
|
||||
REQUIRE(ext.miny() == -2);
|
||||
REQUIRE(ext.maxx() == 5);
|
||||
REQUIRE(ext.maxy() == 4);
|
||||
}
|
||||
|
||||
SECTION("Postgis query extent: full dataset")
|
||||
{
|
||||
//include schema to increase coverage
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM public.test) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == -2);
|
||||
REQUIRE(ext.miny() == -2);
|
||||
REQUIRE(ext.maxx() == 5);
|
||||
REQUIRE(ext.maxy() == 4);
|
||||
}
|
||||
/* deactivated for merging: still investigating a proper fix
|
||||
SECTION("Postgis query extent from subquery")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test where gid=4) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
SECTION("Postgis query extent from subquery")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test where gid=4) as data";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
*/
|
||||
SECTION("Postgis query extent: from subquery with 'extent_from_subquery=true'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test where gid=4) as data";
|
||||
params["extent_from_subquery"] = "true";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
SECTION("Postgis query extent: from subquery with 'extent_from_subquery=true'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
params["table"] = "(SELECT * FROM test where gid=4) as data";
|
||||
params["extent_from_subquery"] = "true";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
/* deactivated for merging: still investigating a proper fix
|
||||
SECTION("Postgis query extent: subset with 'extent_from_subquery=true' and 'scale_denominator'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
// !!!! postgis-vt-util::z() returns 'null' when 'scale_denominator > 600000000'
|
||||
// https://github.com/mapbox/postgis-vt-util/blob/559f073877696a6bfea41baf3e1065f9cf4d18d1/postgis-vt-util.sql#L615-L617
|
||||
params["table"] = "(SELECT * FROM test where gid=4 AND z(!scale_denominator!) BETWEEN 0 AND 22) as data";
|
||||
params["extent_from_subquery"] = "true";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO("" << std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
SECTION("Postgis query extent: subset with 'extent_from_subquery=true' and 'scale_denominator'")
|
||||
{
|
||||
mapnik::parameters params(base_params);
|
||||
// !!!! postgis-vt-util::z() returns 'null' when 'scale_denominator > 600000000'
|
||||
// https://github.com/mapbox/postgis-vt-util/blob/559f073877696a6bfea41baf3e1065f9cf4d18d1/postgis-vt-util.sql#L615-L617
|
||||
params["table"] = "(SELECT * FROM test where gid=4 AND z(!scale_denominator!) BETWEEN 0 AND 22) as data";
|
||||
params["extent_from_subquery"] = "true";
|
||||
auto ds = mapnik::datasource_cache::instance().create(params);
|
||||
REQUIRE(ds != nullptr);
|
||||
mapnik::box2d<double> ext = ds->envelope();
|
||||
CAPTURE(ext);
|
||||
INFO("" << std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy());
|
||||
REQUIRE(ext.minx() == 0);
|
||||
REQUIRE(ext.miny() == 0);
|
||||
REQUIRE(ext.maxx() == 1);
|
||||
REQUIRE(ext.maxy() == 2);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "ds_test_util.hpp"
|
||||
|
||||
#include <mapnik/util/fs.hpp>
|
||||
#include <mapnik/util/file_io.hpp>
|
||||
|
@ -50,7 +51,7 @@ bool parse_topology(std::string const& filename, mapnik::topojson::topology & to
|
|||
|
||||
}
|
||||
|
||||
TEST_CASE("topology")
|
||||
TEST_CASE("topojson")
|
||||
{
|
||||
SECTION("geometry parsing")
|
||||
{
|
||||
|
@ -72,4 +73,42 @@ TEST_CASE("topology")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("TopoJSON properties are properly expressed")
|
||||
{
|
||||
std::string filename("./test/data/topojson/escaped.topojson");
|
||||
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
|
||||
mapnik::transcoder tr("utf8");
|
||||
mapnik::topojson::topology topo;
|
||||
REQUIRE(parse_topology(filename, topo));
|
||||
mapnik::value_integer feature_id = 0;
|
||||
for (auto const& geom : topo.geometries)
|
||||
{
|
||||
mapnik::box2d<double> bbox = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo), geom);
|
||||
CHECK(bbox.valid());
|
||||
mapnik::topojson::feature_generator<mapnik::context_ptr> visitor(ctx, tr, topo, feature_id);
|
||||
mapnik::feature_ptr feature = mapnik::util::apply_visitor(visitor, geom);
|
||||
CHECK(feature);
|
||||
CHECK(feature->envelope() == bbox);
|
||||
std::initializer_list<attr> attrs = {
|
||||
attr{"name", tr.transcode("Test")},
|
||||
attr{"NOM_FR", tr.transcode("Québec")},
|
||||
attr{"boolean", mapnik::value_bool("true")},
|
||||
attr{"description", tr.transcode("Test: \u005C")},
|
||||
attr{"double", mapnik::value_double(1.1)},
|
||||
attr{"int", mapnik::value_integer(1)},
|
||||
attr{"object", tr.transcode("{name:\"waka\",spaces:\"value with spaces\",int:1,double:1.1,boolean:false"
|
||||
",NOM_FR:\"Québec\",array:[\"string\",\"value with spaces\",3,1.1,null,true"
|
||||
",\"Québec\"],another_object:{name:\"nested object\"}}")},
|
||||
attr{"spaces", tr.transcode("this has spaces")},
|
||||
attr{"array", tr.transcode("[\"string\",\"value with spaces\",3,1.1,null,true,"
|
||||
"\"Québec\",{name:\"object within an array\"},"
|
||||
"[\"array\",\"within\",\"an\",\"array\"]]")},
|
||||
attr{"empty_array", tr.transcode("[]")},
|
||||
attr{"empty_object", tr.transcode("{}")},
|
||||
};
|
||||
REQUIRE_ATTRIBUTES(feature, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,15 +2,18 @@
|
|||
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/geometry_envelope.hpp>
|
||||
#include <mapnik/geometry_correct.hpp>
|
||||
|
||||
TEST_CASE("geometry ops - envelope") {
|
||||
namespace {
|
||||
|
||||
SECTION("envelope_test - double") {
|
||||
template <typename T>
|
||||
void envelope_test()
|
||||
{
|
||||
using namespace mapnik::geometry;
|
||||
using coord_type = T;
|
||||
|
||||
{
|
||||
geometry<double> geom(point<double>(1,2));
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(geom);
|
||||
geometry<coord_type> geom(point<coord_type>(1,2));
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE( bbox.minx() == 1 );
|
||||
REQUIRE( bbox.miny() == 2 );
|
||||
REQUIRE( bbox.maxx() == 1 );
|
||||
|
@ -18,80 +21,67 @@ SECTION("envelope_test - double") {
|
|||
}
|
||||
{
|
||||
// Test empty geom
|
||||
geometry<double> geom = mapnik::geometry::geometry_empty<double>();
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(geom);
|
||||
geometry<coord_type> geom = mapnik::geometry::geometry_empty<coord_type>();
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE_FALSE( bbox.valid() );
|
||||
}
|
||||
{
|
||||
line_string<double> line;
|
||||
line_string<coord_type> line;
|
||||
line.add_coord(0,0);
|
||||
line.add_coord(1,1);
|
||||
line.add_coord(2,2);
|
||||
geometry<double> geom(line);
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(geom);
|
||||
geometry<coord_type> geom(line);
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE( bbox.minx() == 0 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 2 );
|
||||
REQUIRE( bbox.maxy() == 2 );
|
||||
}
|
||||
{
|
||||
line_string<double> line;
|
||||
line_string<coord_type> line;
|
||||
line.add_coord(0,0);
|
||||
line.add_coord(1,1);
|
||||
line.add_coord(2,2);
|
||||
line_string<double> line2;
|
||||
line_string<coord_type> line2;
|
||||
line2.add_coord(0,0);
|
||||
line2.add_coord(-1,-1);
|
||||
line2.add_coord(-2,-2);
|
||||
multi_line_string<double> multi_line;
|
||||
multi_line_string<coord_type> multi_line;
|
||||
multi_line.emplace_back(std::move(line));
|
||||
multi_line.emplace_back(std::move(line2));
|
||||
geometry<double> geom(multi_line);
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(geom);
|
||||
geometry<coord_type> geom(multi_line);
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE( bbox.minx() == -2 );
|
||||
REQUIRE( bbox.miny() == -2 );
|
||||
REQUIRE( bbox.maxx() == 2 );
|
||||
REQUIRE( bbox.maxy() == 2 );
|
||||
}
|
||||
{
|
||||
polygon<double> poly;
|
||||
linear_ring<double> ring;
|
||||
polygon<coord_type> poly;
|
||||
linear_ring<coord_type> ring;
|
||||
ring.add_coord(0,0);
|
||||
ring.add_coord(-10,0);
|
||||
ring.add_coord(-10,10);
|
||||
ring.add_coord(0,10);
|
||||
ring.add_coord(0,0);
|
||||
poly.set_exterior_ring(std::move(ring));
|
||||
geometry<double> geom(poly);
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(geom);
|
||||
geometry<coord_type> geom(poly);
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE( bbox.minx() == -10 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
|
||||
multi_polygon<double> mp;
|
||||
multi_polygon<coord_type> mp;
|
||||
mp.push_back(poly);
|
||||
geometry<double> geom_mp(mp);
|
||||
geometry<coord_type> geom_mp(mp);
|
||||
bbox = mapnik::geometry::envelope(geom_mp);
|
||||
REQUIRE( bbox.minx() == -10 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
|
||||
correct(geom);
|
||||
bbox = mapnik::geometry::envelope(geom);
|
||||
REQUIRE( bbox.minx() == -10 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
correct(geom_mp);
|
||||
bbox = mapnik::geometry::envelope(geom_mp);
|
||||
REQUIRE( bbox.minx() == -10 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
|
||||
geometry_collection<double> gc;
|
||||
geometry_collection<coord_type> gc;
|
||||
bbox = mapnik::geometry::envelope(gc);
|
||||
REQUIRE_FALSE( bbox.valid() );
|
||||
gc.push_back(geom_mp);
|
||||
|
@ -100,7 +90,7 @@ SECTION("envelope_test - double") {
|
|||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
gc.emplace_back(point<double>(-50,-50));
|
||||
gc.emplace_back(point<coord_type>(-50,-50));
|
||||
bbox = mapnik::geometry::envelope(gc);
|
||||
REQUIRE( bbox.minx() == -50 );
|
||||
REQUIRE( bbox.miny() == -50 );
|
||||
|
@ -110,30 +100,30 @@ SECTION("envelope_test - double") {
|
|||
|
||||
{
|
||||
// polygon with hole
|
||||
polygon<double> poly;
|
||||
linear_ring<double> ring;
|
||||
polygon<coord_type> poly;
|
||||
linear_ring<coord_type> ring;
|
||||
ring.add_coord(0,0);
|
||||
ring.add_coord(-10,0);
|
||||
ring.add_coord(-10,10);
|
||||
ring.add_coord(0,10);
|
||||
ring.add_coord(0,0);
|
||||
poly.set_exterior_ring(std::move(ring));
|
||||
linear_ring<double> hole;
|
||||
linear_ring<coord_type> hole;
|
||||
hole.add_coord(-7,7);
|
||||
hole.add_coord(-7,3);
|
||||
hole.add_coord(-3,3);
|
||||
hole.add_coord(-3,7);
|
||||
hole.add_coord(-7,7);
|
||||
poly.add_hole(std::move(hole));
|
||||
geometry<double> geom(poly);
|
||||
mapnik::box2d<double> bbox = mapnik::geometry::envelope(poly);
|
||||
geometry<coord_type> geom(poly);
|
||||
mapnik::box2d<coord_type> bbox = mapnik::geometry::envelope(poly);
|
||||
REQUIRE( bbox.minx() == -10 );
|
||||
REQUIRE( bbox.miny() == 0 );
|
||||
REQUIRE( bbox.maxx() == 0 );
|
||||
REQUIRE( bbox.maxy() == 10 );
|
||||
// add another hole inside the first hole
|
||||
// which should be considered a hit
|
||||
linear_ring<double> fill;
|
||||
linear_ring<coord_type> fill;
|
||||
fill.add_coord(-6,4);
|
||||
fill.add_coord(-6,6);
|
||||
fill.add_coord(-4,6);
|
||||
|
@ -149,3 +139,14 @@ SECTION("envelope_test - double") {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("geometry ops - envelope") {
|
||||
|
||||
SECTION("envelope_test")
|
||||
{
|
||||
envelope_test<int>();
|
||||
envelope_test<double>();
|
||||
envelope_test<float>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
15
test/unit/geometry/geometry_test_helper.cpp
Normal file
15
test/unit/geometry/geometry_test_helper.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/geometry_envelope.hpp>
|
||||
#include <mapnik/geometry_envelope_impl.hpp>
|
||||
|
||||
|
||||
namespace mapnik { namespace geometry {
|
||||
// instantiate types required by geometry_envelope_test
|
||||
template mapnik::box2d<int> envelope(geometry<int> const& geom);
|
||||
template mapnik::box2d<float> envelope(geometry<float> const& geom);
|
||||
template mapnik::box2d<int> envelope(polygon<int> const& geom);
|
||||
template mapnik::box2d<float> envelope(polygon<float> const& geom);
|
||||
template mapnik::box2d<int> envelope(geometry_collection<int> const& geom);
|
||||
template mapnik::box2d<float> envelope(geometry_collection<float> const& geom);
|
||||
|
||||
}}
|
|
@ -38,10 +38,21 @@
|
|||
#if defined(GRID_RENDERER)
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
#include <mapnik/cairo/cairo_renderer.hpp>
|
||||
#include <mapnik/cairo/cairo_image_util.hpp>
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
#include <cairo-svg.h>
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PS_SURFACE
|
||||
#include <cairo-ps.h>
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PDF_SURFACE
|
||||
#include <cairo-pdf.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SVG_RENDERER)
|
||||
#include <mapnik/svg/output/svg_renderer.hpp>
|
||||
#endif
|
||||
|
@ -53,7 +64,7 @@ namespace visual_tests
|
|||
{
|
||||
|
||||
template <typename ImageType>
|
||||
struct renderer_base
|
||||
struct raster_renderer_base
|
||||
{
|
||||
using image_type = ImageType;
|
||||
|
||||
|
@ -80,7 +91,35 @@ struct renderer_base
|
|||
}
|
||||
};
|
||||
|
||||
struct agg_renderer : renderer_base<mapnik::image_rgba8>
|
||||
struct vector_renderer_base
|
||||
{
|
||||
using image_type = std::string;
|
||||
|
||||
static constexpr const bool support_tiles = false;
|
||||
|
||||
unsigned compare(image_type const & actual, boost::filesystem::path const& reference) const
|
||||
{
|
||||
std::ifstream stream(reference.string().c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!stream)
|
||||
{
|
||||
throw std::runtime_error("Could not open: " + reference.string());
|
||||
}
|
||||
std::string expected(std::istreambuf_iterator<char>(stream.rdbuf()), std::istreambuf_iterator<char>());
|
||||
return std::max(actual.size(), expected.size()) - std::min(actual.size(), expected.size());
|
||||
}
|
||||
|
||||
void save(image_type const & image, boost::filesystem::path const& path) const
|
||||
{
|
||||
std::ofstream file(path.string().c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
|
||||
if (!file)
|
||||
{
|
||||
throw std::runtime_error("Cannot open file for writing: " + path.string());
|
||||
}
|
||||
file << image;
|
||||
}
|
||||
};
|
||||
|
||||
struct agg_renderer : raster_renderer_base<mapnik::image_rgba8>
|
||||
{
|
||||
static constexpr const char * name = "agg";
|
||||
|
||||
|
@ -94,7 +133,7 @@ struct agg_renderer : renderer_base<mapnik::image_rgba8>
|
|||
};
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
struct cairo_renderer : renderer_base<mapnik::image_rgba8>
|
||||
struct cairo_renderer : raster_renderer_base<mapnik::image_rgba8>
|
||||
{
|
||||
static constexpr const char * name = "cairo";
|
||||
|
||||
|
@ -111,14 +150,65 @@ struct cairo_renderer : renderer_base<mapnik::image_rgba8>
|
|||
return image;
|
||||
}
|
||||
};
|
||||
|
||||
using surface_create_type = cairo_surface_t *(&)(cairo_write_func_t, void *, double, double);
|
||||
|
||||
template <surface_create_type SurfaceCreateFunction>
|
||||
struct cairo_vector_renderer : vector_renderer_base
|
||||
{
|
||||
static cairo_status_t write(void *closure,
|
||||
const unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
std::ostringstream & ss = *reinterpret_cast<std::ostringstream*>(closure);
|
||||
ss.write(reinterpret_cast<char const *>(data), length);
|
||||
return ss ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR;
|
||||
}
|
||||
|
||||
image_type render(mapnik::Map const & map, double scale_factor) const
|
||||
{
|
||||
std::ostringstream ss(std::stringstream::binary);
|
||||
mapnik::cairo_surface_ptr image_surface(
|
||||
SurfaceCreateFunction(write, &ss, map.width(), map.height()),
|
||||
mapnik::cairo_surface_closer());
|
||||
mapnik::cairo_ptr image_context(mapnik::create_context(image_surface));
|
||||
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map, image_context, scale_factor);
|
||||
ren.apply();
|
||||
cairo_surface_finish(&*image_surface);
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
struct cairo_svg_renderer : cairo_vector_renderer<cairo_svg_surface_create_for_stream>
|
||||
{
|
||||
static constexpr const char * name = "cairo-svg";
|
||||
static constexpr const char * ext = ".svg";
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_PS_SURFACE
|
||||
struct cairo_ps_renderer : cairo_vector_renderer<cairo_ps_surface_create_for_stream>
|
||||
{
|
||||
static constexpr const char * name = "cairo-ps";
|
||||
static constexpr const char * ext = ".ps";
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_PDF_SURFACE
|
||||
struct cairo_pdf_renderer : cairo_vector_renderer<cairo_pdf_surface_create_for_stream>
|
||||
{
|
||||
static constexpr const char * name = "cairo-pdf";
|
||||
static constexpr const char * ext = ".pdf";
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SVG_RENDERER)
|
||||
struct svg_renderer : renderer_base<std::string>
|
||||
struct svg_renderer : vector_renderer_base
|
||||
{
|
||||
static constexpr const char * name = "svg";
|
||||
static constexpr const char * ext = ".svg";
|
||||
static constexpr const bool support_tiles = false;
|
||||
|
||||
image_type render(mapnik::Map const & map, double scale_factor) const
|
||||
{
|
||||
|
@ -128,35 +218,11 @@ struct svg_renderer : renderer_base<std::string>
|
|||
ren.apply();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
unsigned compare(image_type const & actual, boost::filesystem::path const& reference) const
|
||||
{
|
||||
std::ifstream stream(reference.string().c_str(),std::ios_base::in|std::ios_base::binary);
|
||||
if (!stream.is_open())
|
||||
{
|
||||
throw std::runtime_error("could not open: '" + reference.string() + "'");
|
||||
}
|
||||
std::string expected(std::istreambuf_iterator<char>(stream.rdbuf()),(std::istreambuf_iterator<char>()));
|
||||
stream.close();
|
||||
return std::max(actual.size(), expected.size()) - std::min(actual.size(), expected.size());
|
||||
}
|
||||
|
||||
void save(image_type const & image, boost::filesystem::path const& path) const
|
||||
{
|
||||
std::ofstream file(path.string().c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
|
||||
if (!file) {
|
||||
throw std::runtime_error((std::string("cannot open file for writing file ") + path.string()).c_str());
|
||||
} else {
|
||||
file << image;
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(GRID_RENDERER)
|
||||
struct grid_renderer : renderer_base<mapnik::image_rgba8>
|
||||
struct grid_renderer : raster_renderer_base<mapnik::image_rgba8>
|
||||
{
|
||||
static constexpr const char * name = "grid";
|
||||
|
||||
|
@ -335,6 +401,15 @@ private:
|
|||
using renderer_type = mapnik::util::variant<renderer<agg_renderer>
|
||||
#if defined(HAVE_CAIRO)
|
||||
,renderer<cairo_renderer>
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
,renderer<cairo_svg_renderer>
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PS_SURFACE
|
||||
,renderer<cairo_ps_renderer>
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PDF_SURFACE
|
||||
,renderer<cairo_pdf_renderer>
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SVG_RENDERER)
|
||||
,renderer<svg_renderer>
|
||||
|
|
|
@ -48,30 +48,48 @@ namespace po = boost::program_options;
|
|||
|
||||
runner::renderer_container create_renderers(po::variables_map const & args,
|
||||
boost::filesystem::path const & output_dir,
|
||||
bool append_all = false)
|
||||
bool force_append = false)
|
||||
{
|
||||
boost::filesystem::path reference_dir(args["images-dir"].as<std::string>());
|
||||
bool overwrite = args.count("overwrite");
|
||||
runner::renderer_container renderers;
|
||||
|
||||
if (append_all || args.count(agg_renderer::name))
|
||||
if (force_append || args.count(agg_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<agg_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#if defined(HAVE_CAIRO)
|
||||
if (append_all || args.count(cairo_renderer::name))
|
||||
if (force_append || args.count(cairo_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<cairo_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
if (args.count(cairo_svg_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<cairo_svg_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PS_SURFACE
|
||||
if (args.count(cairo_ps_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<cairo_ps_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PDF_SURFACE
|
||||
if (args.count(cairo_pdf_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<cairo_pdf_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SVG_RENDERER)
|
||||
if (append_all || args.count(svg_renderer::name))
|
||||
if (force_append || args.count(svg_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<svg_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
#endif
|
||||
#if defined(GRID_RENDERER)
|
||||
if (append_all || args.count(grid_renderer::name))
|
||||
if (force_append || args.count(grid_renderer::name))
|
||||
{
|
||||
renderers.emplace_back(renderer<grid_renderer>(output_dir, reference_dir, overwrite));
|
||||
}
|
||||
|
@ -112,6 +130,15 @@ int main(int argc, char** argv)
|
|||
(agg_renderer::name, "render with AGG renderer")
|
||||
#if defined(HAVE_CAIRO)
|
||||
(cairo_renderer::name, "render with Cairo renderer")
|
||||
#ifdef CAIRO_HAS_SVG_SURFACE
|
||||
(cairo_svg_renderer::name, "render with Cairo SVG renderer")
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PS_SURFACE
|
||||
(cairo_ps_renderer::name, "render with Cairo PS renderer")
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_PDF_SURFACE
|
||||
(cairo_pdf_renderer::name, "render with Cairo PDF renderer")
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SVG_RENDERER)
|
||||
(svg_renderer::name, "render with SVG renderer")
|
||||
|
@ -183,7 +210,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
std::cerr << "Error runnig tests: " << e.what() << std::endl;
|
||||
std::cerr << "Error running tests: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue