Merge branch 'master' of github.com:mapnik/mapnik into layer-opacity

This commit is contained in:
Dane Springmeyer 2014-10-01 13:08:38 -07:00
commit 7be976d691
208 changed files with 3864 additions and 1870 deletions

View file

@ -2,12 +2,12 @@ language: cpp
compiler:
- clang
# - gcc
#- gcc
env:
matrix:
#- DEBUG=True ENABLE_LOG=True DEFAULT_LOG_SEVERITY=debug XMLPARSER="libxml2" DEMO=False BENCHMARK=False CUSTOM_CXXFLAGS="" CUSTOM_LDFLAGS=""
- DEBUG=False ENABLE_LOG=False DEFAULT_LOG_SEVERITY=none XMLPARSER="ptree" DEMO=False BENCHMARK=False CUSTOM_CXXFLAGS="" CUSTOM_LDFLAGS=""
#- DEBUG=True ENABLE_LOG=True DEFAULT_LOG_SEVERITY=debug XMLPARSER="libxml2" DEMO=False BENCHMARK=False CUSTOM_CXXFLAGS="" CUSTOM_LDFLAGS=""
- DEBUG=False ENABLE_LOG=False DEFAULT_LOG_SEVERITY=none XMLPARSER="ptree" DEMO=False BENCHMARK=False CUSTOM_CXXFLAGS="" CUSTOM_LDFLAGS=""
# travis + ubuntugis with gdal and postggis leads to many potential dead-end conflicts
# the below is thanks to https://github.com/CartoDB/Windshaft/blob/d82fe08b32fc7907bbe907ab290f8a082215ae26/.travis.yml#L1
@ -17,6 +17,10 @@ before_install:
- sudo apt-get -qq purge postgis* postgresql*
- sudo apt-add-repository -y ppa:cartodb/postgresql-9.3
- sudo apt-add-repository -y ppa:cartodb/gis
# we need at least g++-4.7 for c++11 features
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
# upgrade boost
- sudo add-apt-repository -y ppa:boost-latest/ppa
- sudo rm -Rf /var/lib/postgresql /etc/postgresql
- sudo apt-get update -qq
- sudo apt-get install -q postgresql-9.3-postgis-2.1
@ -26,26 +30,25 @@ before_install:
- sudo service postgresql restart
install:
- sudo add-apt-repository -y ppa:boost-latest/ppa
# we need at least g++-4.7 for c++11 features
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- sudo apt-get install -y ttf-wqy-microhei make libstdc++6 libstdc++-4.8-dev valgrind boost1.55 python-nose libicu-dev libproj-dev libcairo-dev python-cairo-dev libcairo-dev python-cairo-dev libpng-dev libjpeg-dev libtiff-dev libwebp-dev libz-dev libfreetype6-dev libxml2-dev libsqlite3-dev
#- sudo apt-get install -y libboost-python1.48-dev libboost-thread1.48-dev libboost-filesystem1.48-dev libboost-regex1.48-dev libboost-program-options1.48-dev
- sudo apt-get install -y boost1.55
- sudo apt-get install -y ttf-wqy-microhei make libstdc++6 libstdc++-4.8-dev valgrind python-nose libicu-dev libproj-dev libcairo-dev python-cairo-dev libcairo-dev python-cairo-dev libpng-dev libjpeg-dev libtiff-dev libwebp-dev libz-dev libfreetype6-dev libxml2-dev libsqlite3-dev
before_script:
- psql -U postgres -c 'create database template_postgis'
- psql -U postgres -c 'create extension postgis' -d template_postgis
- if [[ "${CXX}" == 'g++' ]]; then sudo apt-get install gcc-4.8 g++-4.8; export CXX="$(which g++-4.8)"; export CC="$(which gcc-4.8)"; fi;
- if [[ "${CXX}" == 'clang++' ]]; then export CXX="$(which clang++)"; export CC="$(which clang)"; fi;
- wget http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-0.9.34.tar.bz2
- tar xf harfbuzz-0.9.34.tar.bz2
- cd harfbuzz-0.9.34
- ./configure --prefix=/usr --with-icu --with-cairo=no --with-glib=no --with-gobject=no --with-graphite2=no --with-freetype --with-uniscribe=no --with-coretext=no && make && sudo make install
- if [[ "${CXX}" == 'g++' ]]; then export JOBS=2; sudo apt-get install gcc-4.8 g++-4.8; export CXX="$(which g++-4.8)"; export CC="$(which gcc-4.8)"; fi;
- if [[ "${CXX}" == 'clang++' ]]; then export JOBS=4; export CXX="$(which clang++)"; export CC="$(which clang)"; fi;
- wget http://www.freedesktop.org/software/harfbuzz/release/harfbuzz-0.9.35.tar.bz2
- tar xf harfbuzz-0.9.35.tar.bz2
- cd harfbuzz-0.9.35
- ./configure --prefix=/usr --with-icu --with-cairo=no --with-glib=no --with-gobject=no --with-graphite2=no --with-freetype --with-uniscribe=no --with-coretext=no && make -j2 && sudo make -j2 install
- cd ../
script:
- ./configure CXX="${CXX}" CC="${CC}" CUSTOM_CXXFLAGS="${CUSTOM_CXXFLAGS}" CUSTOM_LDFLAGS="${CUSTOM_LDFLAGS}" XML_PARSER="${XML_PARSER}" ENABLE_LOG="${ENABLE_LOG}" DEBUG="${DEBUG}" DEMO="${DEMO}" BENCHMARK="${BENCHMARK}" CPP_TESTS=True CAIRO=True FAST=True || cat config.log
- if [[ "${DEBUG}" == true ]]; then JOBS=1 make; else JOBS=1 make; fi;
- if [[ "${DEBUG}" == True ]]; then export JOBS=$((JOBS/2)); fi;
- make
- git clone https://github.com/mapbox/mapnik-test-data tests/data/mapnik-test-data
- make test
- source localize.sh && make grind

View file

@ -9,6 +9,14 @@ To configure and build Mapnik do:
$ make
```
To trigger parallel compilation you can pass a JOBS value to make:
```bash
$ JOBS=4 make
```
(Note that compiling Mapnik needs several GBytes of RAM. If you use parallel compiliation it needs more.)
To use a Python interpreter that is not named `python` for your build, do
something like the following instead:
@ -61,7 +69,7 @@ Mapnik Core depends on:
* libz - Zlib compression
* libfreetype - Freetype2 for font support (Install requires freetype-config)
* libxml2 - XML parsing (Install requires xml2-config)
* libharfbuzz - an OpenType text shaping engine
* libharfbuzz - an OpenType text shaping engine (>=0.9.34 needed for CSS font-feature-settings support)
Mapnik Core optionally depends on:

View file

@ -5,12 +5,6 @@ PYTHON = python
ifeq ($(JOBS),)
JOBS:=1
ifeq ($(OS),Linux)
JOBS:=$(shell grep -c ^processor /proc/cpuinfo)
endif
ifeq ($(OS),Darwin)
JOBS:=$(shell sysctl -n hw.ncpu)
endif
endif
all: mapnik
@ -24,7 +18,8 @@ mapnik:
clean:
@$(PYTHON) scons/scons.py -j$(JOBS) -c --config=cache --implicit-cache --max-drift=1
@if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi
@if test -e "config.log"; then rm "config.log"; fi
@if test -e "config.log"; then rm "config.log"; fi
@if test -e "config.cache"; then rm "config.cache"; fi
@if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi
@find ./ -name "*.pyc" -exec rm {} \;
@find ./ -name "*.os" -exec rm {} \;
@ -35,7 +30,6 @@ clean:
@if test -e "bindings/python/mapnik/paths.py"; then rm "bindings/python/mapnik/paths.py"; fi
distclean:
@if test -e "config.cache"; then rm "config.cache"; fi
if test -e "config.py"; then mv "config.py" "config.py.backup"; fi
reset: distclean

View file

@ -396,7 +396,6 @@ opts.AddVariables(
ListVariable('BINDINGS','Language bindings to build','all',['python']),
EnumVariable('THREADING','Set threading support','multi', ['multi','single']),
EnumVariable('XMLPARSER','Set xml parser','libxml2', ['libxml2','ptree']),
('JOBS', 'Set the number of parallel compilations', "1", lambda key, value, env: int(value), int),
BoolVariable('DEMO', 'Compile demo c++ application', 'True'),
BoolVariable('PGSQL2SQLITE', 'Compile and install a utility to convert postgres tables to sqlite', 'False'),
BoolVariable('SHAPEINDEX', 'Compile and install a utility to generate shapefile indexes in the custom format (.index) Mapnik supports', 'True'),
@ -502,8 +501,9 @@ elif HELP_REQUESTED:
# need no-op for clean on fresh checkout
# https://github.com/mapnik/mapnik/issues/2112
if ('-c' in command_line_args) or ('--clean' in command_line_args) and not os.path.exists(SCONS_CONFIGURE_CACHE):
print 'all good: nothing to clean'
if not os.path.exists(SCONS_LOCAL_LOG) and not os.path.exists(SCONS_CONFIGURE_CACHE) \
and ('-c' in command_line_args or '--clean' in command_line_args):
print 'all good: nothing to clean, but you might want to run "make distclean"'
Exit(0)
# initially populate environment with defaults and any possible custom arguments
@ -1910,9 +1910,6 @@ if not HELP_REQUESTED:
SetOption('implicit_cache', 1)
SetOption('max_drift', 1)
if env['JOBS'] > 1:
SetOption("num_jobs", env['JOBS'])
# Build agg first, doesn't need anything special
if env['RUNTIME_LINK'] == 'shared':
SConscript('deps/agg/build.py')

View file

@ -5,17 +5,14 @@
#include <mapnik/params.hpp>
#include <mapnik/value_types.hpp>
// boost
#define BOOST_CHRONO_HEADER_ONLY
#include <boost/chrono/process_cpu_clocks.hpp>
#include <boost/chrono.hpp>
// stl
#include <chrono>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <thread>
#include <vector>
#include <set>
#include <iomanip>
namespace benchmark {
@ -88,8 +85,8 @@ int run(T const& test_runner, std::string const& name)
std::clog << "test did not validate: " << name << "\n";
return -1;
}
boost::chrono::process_cpu_clock::time_point start;
boost::chrono::process_cpu_clock::duration elapsed;
std::chrono::high_resolution_clock::time_point start;
std::chrono::high_resolution_clock::duration elapsed;
std::stringstream s;
s << name << ":"
<< std::setw(45 - (int)s.tellp()) << std::right
@ -104,18 +101,18 @@ int run(T const& test_runner, std::string const& name)
{
tg.emplace_back(new std::thread(test_runner));
}
start = boost::chrono::process_cpu_clock::now();
start = std::chrono::high_resolution_clock::now();
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
elapsed = boost::chrono::process_cpu_clock::now() - start;
elapsed = std::chrono::high_resolution_clock::now() - start;
}
else
{
start = boost::chrono::process_cpu_clock::now();
start = std::chrono::high_resolution_clock::now();
test_runner();
elapsed = boost::chrono::process_cpu_clock::now() - start;
elapsed = std::chrono::high_resolution_clock::now() - start;
}
s << std::setw(65 - (int)s.tellp()) << std::right
<< boost::chrono::duration_cast<boost::chrono::milliseconds>(elapsed) << "\n";
<< std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() << " milliseconds\n";
std::clog << s.str();
return 0;
}

View file

@ -17,6 +17,7 @@ test_env.Append(CPPDEFINES = env['LIBMAPNIK_DEFINES'])
if test_env['HAS_CAIRO']:
test_env.PrependUnique(CPPPATH=test_env['CAIRO_CPPPATHS'])
test_env.Append(CPPDEFINES = '-DHAVE_CAIRO')
test_env['LINKFLAGS'] = copy(test_env['LIBMAPNIK_LINKFLAGS'])
if env['PLATFORM'] == 'Darwin':
test_env.Append(LINKFLAGS='-F/ -framework CoreFoundation')

View file

@ -8,68 +8,78 @@
<Style name="marking" filter-mode="first">
<Rule>
<Filter>([class] = 'railways')</Filter>
<LineSymbolizer stroke="#ffffff" stroke-width="1.8" stroke-dasharray="5, 5" />
<LineSymbolizer stroke="#ffffff" stroke-width="1.8" stroke-dasharray="5, 5" clip="false" />
</Rule>
</Style>
<Style name="fill" filter-mode="first">
<Rule>
<Filter>([class] = 'minorroads')</Filter>
<LineSymbolizer stroke-width="2.5" stroke="#ffffff" stroke-linecap="round" />
<LineSymbolizer stroke-width="2.5" stroke="#ffffff" stroke-linecap="round" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'mainroads')</Filter>
<LineSymbolizer stroke-width="4" stroke="#ff9999" stroke-linecap="round" />
<LineSymbolizer stroke-width="4" stroke="#ff9999" stroke-linecap="round" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'motorways')</Filter>
<LineSymbolizer stroke-width="6" stroke="#ff6666" stroke-linecap="round" />
<LineSymbolizer stroke-width="6" stroke="#ff6666" stroke-linecap="round" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'railways')</Filter>
<LineSymbolizer stroke-width="3" stroke="#333333" stroke-linecap="round" />
<LineSymbolizer stroke-width="3" stroke="#333333" stroke-linecap="round" clip="false" />
</Rule>
</Style>
<Style name="bridge" filter-mode="first">
<Rule>
<Filter>([class] = 'railways') and ([bridge] = 1)</Filter>
<LineSymbolizer stroke-width="6" stroke="#ffffff" />
<LineSymbolizer stroke-width="6" stroke="#ffffff" clip="false" />
</Rule>
</Style>
<Style name="casing" filter-mode="first">
<Rule>
<Filter>([class] = 'railways') and ([bridge] = 1)</Filter>
<LineSymbolizer stroke-width="8" stroke="#333333" />
<LineSymbolizer stroke-width="8" stroke="#333333" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'minorroads')</Filter>
<LineSymbolizer stroke-width="3" stroke="#a69269" />
<LineSymbolizer stroke-width="3" stroke="#a69269" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'mainroads')</Filter>
<LineSymbolizer stroke-width="5" stroke="#ff0000" />
<LineSymbolizer stroke-width="5" stroke="#ff0000" clip="false" />
</Rule>
<Rule>
<Filter>([class] = 'motorways')</Filter>
<LineSymbolizer stroke-width="8" stroke="#990000" />
<LineSymbolizer stroke-width="8" stroke="#990000" clip="false" />
</Rule>
</Style>
<Style name="labels">
<Rule>
<TextSymbolizer halo-rasterizer="fast" placement="line" face-name="DejaVu Sans Book" halo-radius="2" allow-overlap="true">[type]</TextSymbolizer>
<TextSymbolizer
halo-rasterizer="fast"
placement="line"
face-name="DejaVu Sans Book"
halo-radius="2"
allow-overlap="false"
clip="false"
>[type]</TextSymbolizer>
</Rule>
</Style>
<Layer name="layer"
srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
<!--
<StyleName>casing</StyleName>
<StyleName>bridge</StyleName>
<StyleName>fill</StyleName>
<StyleName>marking</StyleName>
-->
<StyleName>labels</StyleName>
<Datasource>
<!--
ogr2ogr -f CSV tests/visual_tests/data/roads.csv -lco GEOMETRY=AS_WKT tests/visual_tests/data/grouped-rendering.sqlite roads -sql "SELECT fid,geometry, type, tunnel, bridge, oneway, class, z_order, CAST((z_order / 10.0) AS INTEGER) AS z FROM roads ORDER BY z_order"
-->
<Parameter name="file">./roads.csv</Parameter>
<Parameter name="extent">1477001.12245,6890242.37746,1480004.49012,6892244.62256</Parameter>
<Parameter name="type">csv</Parameter>
</Datasource>
</Layer>

View file

@ -9,19 +9,31 @@ public:
: test_case(params) {}
bool validate() const
{
return true;
std::size_t count = 0;
std::size_t expected_count = mapnik::freetype_engine::face_names().size();
mapnik::freetype_engine engine;
for (std::string const& name : mapnik::freetype_engine::face_names())
{
mapnik::face_ptr f = engine.create_face(name);
if (f) ++count;
}
return count == expected_count;
}
void operator()() const
{
mapnik::freetype_engine engine;
unsigned long count = 0;
std::size_t expected_count = mapnik::freetype_engine::face_names().size();
for (unsigned i=0;i<iterations_;++i)
{
for ( std::string const& name : mapnik::freetype_engine::face_names())
std::size_t count = 0;
for (std::string const& name : mapnik::freetype_engine::face_names())
{
mapnik::face_ptr f = engine.create_face(name);
if (f) ++count;
}
if (count != expected_count) {
std::clog << "warning: face creation not working as expected\n";
}
}
}
};
@ -37,6 +49,6 @@ int main(int argc, char** argv)
}
std::size_t face_count = mapnik::freetype_engine::face_names().size();
test test_runner(params);
return run(test_runner,(boost::format("font_engine: creating %ld faces") % (face_count * 1000 * 10)).str());
return run(test_runner,(boost::format("font_engine: creating %ld faces") % (face_count)).str());
}

View file

@ -52,13 +52,13 @@ py_env['LIBS'] = [env['MAPNIK_NAME'],env['BOOST_PYTHON_LIB']]
link_all_libs = env['LINKING'] == 'static' or env['RUNTIME_LINK'] == 'static' or (env['PLATFORM'] == 'Darwin' and not env['PYTHON_DYNAMIC_LOOKUP'])
if link_all_libs:
py_env.AppendUnique(LIBS=env['LIBMAPNIK_LIBS'])
# even though boost_thread is no longer used in mapnik core
# we need to link in for boost_python to avoid missing symbol: _ZN5boost6detail12get_tss_dataEPKv / boost::detail::get_tss_data
py_env.AppendUnique(LIBS = 'boost_thread%s' % env['BOOST_APPEND'])
if link_all_libs:
py_env.AppendUnique(LIBS=env['LIBMAPNIK_LIBS'])
# note: on linux -lrt must be linked after thread to avoid: undefined symbol: clock_gettime
if env['RUNTIME_LINK'] == 'static' and env['PLATFORM'] == 'Linux':
py_env.AppendUnique(LIBS='rt')

View file

@ -30,11 +30,9 @@
#include <boost/python/call_method.hpp>
#include <boost/python/tuple.hpp>
#include <boost/python/to_python_converter.hpp>
#include <boost/noncopyable.hpp>
// mapnik
#include <mapnik/value_types.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/feature_factory.hpp>
@ -56,7 +54,7 @@ using mapnik::context_ptr;
using mapnik::feature_kv_iterator;
mapnik::geometry_type const& (mapnik::feature_impl::*get_geometry_by_const_ref)(std::size_t) const = &mapnik::feature_impl::get_geometry;
boost::ptr_vector<mapnik::geometry_type> const& (mapnik::feature_impl::*get_paths_by_const_ref)() const = &mapnik::feature_impl::paths;
mapnik::geometry_container const& (mapnik::feature_impl::*get_paths_by_const_ref)() const = &mapnik::feature_impl::paths;
void feature_add_geometries_from_wkb(mapnik::feature_impl & feature, std::string wkb)
{

View file

@ -28,12 +28,12 @@
#include <boost/python/exception_translator.hpp>
#include <boost/python/manage_new_object.hpp>
#include <boost/python/iterator.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/noncopyable.hpp>
#include <boost/version.hpp>
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/wkt/wkt_factory.hpp> // from_wkt
#include <mapnik/util/geometry_to_wkt.hpp>
#include <mapnik/json/geometry_parser.hpp> // from_geojson

View file

@ -25,6 +25,7 @@
#include <mapnik/rule.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/text/placements/dummy.hpp>
#include <mapnik/text/text_properties.hpp>
#include <mapnik/datasource_cache.hpp>

View file

@ -47,7 +47,6 @@ using mapnik::layer;
using mapnik::box2d;
using mapnik::coord2d;
using mapnik::feature_ptr;
using mapnik::geometry_ptr;
using mapnik::view_transform;
using mapnik::projection;
using mapnik::scale_denominator;

View file

@ -25,7 +25,7 @@
#include <mapnik/noncopyable.hpp>
#include <mapnik/rule.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/symbolizer.hpp>
// boost
#include <boost/concept_check.hpp>

View file

@ -19,6 +19,8 @@
#include "agg_array.h"
#include <mapnik/config.hpp>
namespace agg
{
@ -32,7 +34,7 @@ namespace agg
};
//--------------------------------------------------------------curve3_inc
class curve3_inc
class MAPNIK_DECL curve3_inc
{
public:
curve3_inc() :
@ -91,7 +93,7 @@ namespace agg
//-------------------------------------------------------------curve3_div
class curve3_div
class MAPNIK_DECL curve3_div
{
public:
curve3_div() :
@ -164,7 +166,7 @@ namespace agg
//-------------------------------------------------------------curve4_points
struct curve4_points
struct MAPNIK_DECL curve4_points
{
double cp[8];
curve4_points() {}
@ -191,7 +193,7 @@ namespace agg
//-------------------------------------------------------------curve4_inc
class curve4_inc
class MAPNIK_DECL curve4_inc
{
public:
curve4_inc() :
@ -371,7 +373,7 @@ namespace agg
//-------------------------------------------------------------curve4_div
class curve4_div
class MAPNIK_DECL curve4_div
{
public:
curve4_div() :
@ -471,7 +473,7 @@ namespace agg
//-----------------------------------------------------------------curve3
class curve3
class MAPNIK_DECL curve3
{
public:
curve3() : m_approximation_method(curve_div) {}
@ -576,7 +578,7 @@ namespace agg
//-----------------------------------------------------------------curve4
class curve4
class MAPNIK_DECL curve4
{
public:
curve4() : m_approximation_method(curve_div) {}

View file

@ -21,6 +21,7 @@
#include <cmath>
#include "agg_basics.h"
#include <mapnik/config.hpp>
namespace agg
{
@ -84,7 +85,7 @@ namespace agg
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
//----------------------------------------------------------------------
struct trans_affine
struct MAPNIK_DECL trans_affine
{
static const trans_affine identity;
double sx, shy, shx, sy, tx, ty;

View file

@ -17,6 +17,7 @@
#define AGG_VCGEN_CONTOUR_INCLUDED
#include "agg_math_stroke.h"
#include <mapnik/config.hpp>
namespace agg
{
@ -25,7 +26,7 @@ namespace agg
//
// See Implementation agg_vcgen_contour.cpp
//
class vcgen_contour
class MAPNIK_DECL vcgen_contour
{
enum status_e
{

View file

@ -17,7 +17,7 @@
#define AGG_VCGEN_STROKE_INCLUDED
#include "agg_math_stroke.h"
#include <mapnik/config.hpp>
namespace agg
{
@ -28,7 +28,7 @@ namespace agg
// Stroke generator
//
//------------------------------------------------------------------------
class vcgen_stroke
class MAPNIK_DECL vcgen_stroke
{
enum status_e
{

View file

@ -2839,11 +2839,17 @@ void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
//the AEL before we process the horizontal edges at the bottom of the next,
//we need to create 'ghost' Join records of 'contrubuting' horizontals that
//we can compare with horizontals at the bottom of the next SB.
if (isTopOfScanbeam)
if (isTopOfScanbeam)
{
if (outPt->Pt == horzEdge->Top)
{
AddGhostJoin(outPt, horzEdge->Bot);
}
else
{
AddGhostJoin(outPt, horzEdge->Top);
}
}
}
//------------------------------------------------------------------------------

View file

@ -49,10 +49,6 @@
_START_GOOGLE_NAMESPACE_
template <bool> struct SparsehashCompileAssert { };
#define SPARSEHASH_COMPILE_ASSERT(expr, msg) \
typedef SparsehashCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
namespace sparsehash_internal {
// Adaptor methods for reading/writing data from an INPUT or OUPTUT
@ -162,9 +158,6 @@ template <typename INPUT, typename IntType>
bool read_bigendian_number(INPUT* fp, IntType* value, size_t length) {
*value = 0;
unsigned char byte;
// We require IntType to be unsigned or else the shifting gets all screwy.
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
serializing_int_requires_an_unsigned_type);
for (size_t i = 0; i < length; ++i) {
if (!read_data(fp, &byte, sizeof(byte))) return false;
*value |= static_cast<IntType>(byte) << ((length - 1 - i) * 8);
@ -175,9 +168,6 @@ bool read_bigendian_number(INPUT* fp, IntType* value, size_t length) {
template <typename OUTPUT, typename IntType>
bool write_bigendian_number(OUTPUT* fp, IntType value, size_t length) {
unsigned char byte;
// We require IntType to be unsigned or else the shifting gets all screwy.
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
serializing_int_requires_an_unsigned_type);
for (size_t i = 0; i < length; ++i) {
byte = (sizeof(value) <= length-1 - i)
? 0 : static_cast<unsigned char>((value >> ((length-1 - i) * 8)) & 255);
@ -375,7 +365,6 @@ class sh_hashtable_settings : public HashFunc {
} // namespace sparsehash_internal
#undef SPARSEHASH_COMPILE_ASSERT
_END_GOOGLE_NAMESPACE_
#endif // UTIL_GTL_HASHTABLE_COMMON_H_

View file

@ -17,6 +17,8 @@ Also read the design philosophy page for the motivations that lead to code decis
Templates are good, within reason. We seek to use templates where possible for flexible code, but not in cases where functional patterns would be just as concise and clear.
Since version 3.0 we use C++11 which brings many advantages and makes the code easier to write and to read.
In general we use Boost, it makes more possible in C++. It is a big build time dependency (as in time to compile against and # of headers) but ultimately compiles to small object code and is very fast (particularly spirit). It also has no dependencies itself (it's really an extension to the C++ language) so requiring it is much easier than requiring a hard dependency that itself has other dependencies. This is a big reason that we prefer AGG to Cairo as our primary renderer. Also AGG produces the best visual output and strikes an excellent balance between speed and thread safety by using very lightweight objects. Cairo not so much.
You will also notice that we don't use many of the standard geo libraries when we could. For instance we don't use GDAL, OGR, or GEOS anywhere in core, and only leverage them in optional plugins. We feel we can often write code that is faster and more thread safe than these libraries but that still does the job. If this ever changes we can adapt and start using these libraries or others as dependencies - nothing is nicer than standing on the shoulders of giants when it makes sense.
@ -102,20 +104,26 @@ which triggers locks
(int)value; // no
#### Use const keyword after the type
std::string const& variable_name // preferred, for consistency
const std::string & variable_name // no
#### Pass built-in types by value, all others by const&
void my_function(int double val); // if int, char, double, etc pass by value
void my_function(std::string const& val); // if std::string or user type, pass by const&
#### Shared pointers should be created with [boost::make_shared](http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/make_shared.html) where possible
Since Mapnik 3.0 use std::make_shared.
#### Use assignment operator for zero initialized numbers
double num = 0; // please
@ -129,18 +137,21 @@ which triggers locks
void foo (int a) // no
#### Separate arguments by a single space:
void foo(int a, float b) // please
void foo(int a,float b) // no
#### Space between operators:
if (a == b) // please
if(a==b) // no
#### Braces should always be used:
if (!file)
@ -160,6 +171,7 @@ which triggers locks
// more...
}
#### Prefer `empty()` over `size() == 0` if container supports it
This avoids implicit conversions to bool and reduces compiler warnings.
@ -171,8 +183,7 @@ This avoids implicit conversions to bool and reduces compiler warnings.
### Other C++ style resources
Many also follow the useful [google](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) which mostly fits our style. However, Google obviously has to maintain a lot of aging codebases. Mapnik can move faster, so we don't follow all
of those style recommendations.
Many also follow the useful [Google style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) which mostly fits our style. However, Google obviously has to maintain a lot of aging codebases. Mapnik can move faster, so we don't follow all of those style recommendations.
### Emacs helper

View file

@ -1,19 +1,19 @@
# Design philosophy
Above all Mapnik is about making beautiful maps. This aim drives us to be constantly forward looking. Progress in technology and design are reshaping the art of the possible for maps. Mapnik joins the best ideas in high quality graphics with robust patterns and algorithms for spatial data access. The goal should be no less than enabling a new generation of map makers and gorgous maps.
Above all Mapnik is about making beautiful maps. This aim drives us to be constantly forward looking. Progress in technology and design are reshaping the art of the possible for maps. Mapnik joins the best ideas in high quality graphics with robust patterns and algorithms for spatial data access. The goal should be no less than enabling a new generation of map makers and gorgeous maps.
Mapnik is a library. It is not a server - rather it's for writing servers. Or for writing desktop graphics engines to display maps. Or for visualizing new galaxies - its up to you. If you have an inclination for scripting and something to render in real world or celestial coordinates, Mapnik is for you. Mapnik is not a full solution, or even half a solution. At its best, Mapnik is a drawing api that provides the right tools for the developer to make sense of, and art from, geodata.
But Mapnik is not just about drawing on a canvas. Beautiful maps can also be interactive maps and Mapnik aims to provide very flexible, custom access to geo features both in its C++ api and in binding languages. MetaWriters and the Grid renderer are two recent advances that enable highly interactive feature display in mapping applications using JSON serialized features, but more will come.
Mapnik core is simple set of objects providing structures for features and the ability to query, filter, cache, and render them. This design can be lightweight, flexible, and high performance because the core library does have to worry about where data comes from or where it goes after rendering. Datasources are separate plugin libraries loaded at runtime that, when called, provide feature arrays. The core classes make no assumptions about map size, format, or projection. The core is designed to make writing a high performance tile server, that renders on-demand and uses multi-threaded or multi-process concurrency, as easy as possible.
Mapnik core is a simple set of objects providing structures for features and the ability to query, filter, cache, and render them. This design can be lightweight, flexible, and high performance because the core library does not have to worry about where data comes from or where it goes after rendering. Datasources are separate plugin libraries loaded at runtime that, when called, provide feature arrays. The core classes make no assumptions about map size, format, or projection. The core is designed to make writing a high performance tile server, that renders on-demand and uses multi-threaded or multi-process concurrency, as easy as possible.
Chasing beauty and speed, as technology advances, requires experimentation and a
frequent stream of new ideas. To write fast and creative code we strive to avoid hard dependencies on older libraries or libraries that attempt to do too much at the cost of performance. At the same time, to be able to maintain ambitious goals we cannot write boilerplate code or attempt to write robust code for domains outside of mapping and graphics. As such we rely as much as possible on the Boost libraries.
Mapnik is cross platform because the C++ language and the Boost makes this feasible
Mapnik is cross platform because the C++ language and Boost makes this feasible
enough it would be a shame not to be. But our development target is the latest
release of linux, particularly server based distributions, and many Mapnik developers
release of Linux, particularly server based distributions, and many Mapnik developers
use OSX as a development environment.
If you are having fun using Mapnik, stick with it. But, Mapnik is not always the right tool, of course. If you have small sets of data (MB's), try just rendering it in a web browser client using a javascript mapping api. Or if you need to set up an array of OGC Web services, use GeoServer. Lastly, if you are looking for a full solution for web cartography, use TileMill.

View file

@ -30,9 +30,6 @@
// boost
#include <boost/operators.hpp>
// stl
#include <iomanip>
// agg
// forward declare so that apps using mapnik do not need agg headers
namespace agg {
@ -105,6 +102,7 @@ public:
bool from_string(std::string const& str);
bool valid() const;
void move(T x, T y);
std::string to_string() const;
// define some operators
box2d_type& operator+=(box2d_type const& other);
@ -124,13 +122,7 @@ inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
const box2d<T>& e)
{
std::basic_ostringstream<charT,traits> s;
s.copyfmt(out);
s.width(0);
s << "box2d(" << std::fixed << std::setprecision(16)
<< e.minx() << ',' << e.miny() << ','
<< e.maxx() << ',' << e.maxy() << ')';
out << s.str();
out << e.to_string();
return out;
}
}

View file

@ -34,7 +34,8 @@
#include <mapnik/text/placements_list.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
// stl
#include <memory>
@ -51,7 +52,6 @@
namespace mapnik {
class text_path;
template <typename T> class box2d;
using ErrorStatus = cairo_status_t;

View file

@ -34,12 +34,6 @@
#include <mapnik/function_call.hpp>
#include <mapnik/util/variant.hpp>
#if defined(BOOST_REGEX_HAS_ICU)
#include <boost/regex/icu.hpp>
#else
#include <boost/regex.hpp>
#endif
namespace mapnik {
namespace {
@ -107,24 +101,13 @@ struct evaluate_expression : util::static_visitor<T>
value_type operator() (regex_match_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_match(v.to_unicode(),x.pattern);
#else
return boost::regex_match(v.to_string(),x.pattern);
#endif
return x.apply(v);
}
value_type operator() (regex_replace_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_replace(v.to_unicode(),x.pattern,x.format);
#else
std::string repl = boost::regex_replace(v.to_string(),x.pattern,x.format);
mapnik::transcoder tr_("utf8");
return tr_.transcode(repl.c_str());
#endif
return x.apply(v);
}
value_type operator() (unary_function_call const& call) const
@ -206,24 +189,13 @@ struct evaluate_expression<T, boost::none_t> : util::static_visitor<T>
value_type operator() (regex_match_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_match(v.to_unicode(),x.pattern);
#else
return boost::regex_match(v.to_string(),x.pattern);
#endif
return x.apply(v);
}
value_type operator() (regex_replace_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_replace(v.to_unicode(),x.pattern,x.format);
#else
std::string repl = boost::regex_replace(v.to_string(),x.pattern,x.format);
mapnik::transcoder tr_("utf8");
return tr_.transcode(repl.c_str());
#endif
return x.apply(v);
}
value_type operator() (unary_function_call const& call) const

View file

@ -29,12 +29,7 @@
#include <mapnik/expression_node.hpp>
#include <mapnik/function_call.hpp>
#include <mapnik/util/variant.hpp>
// boost
#if defined(BOOST_REGEX_HAS_ICU)
#include <boost/regex/icu.hpp>
#else
#include <boost/regex.hpp>
#endif
#include <mapnik/feature.hpp>
namespace mapnik
{
@ -130,24 +125,13 @@ struct evaluate : util::static_visitor<T1>
value_type operator() (regex_match_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_match(v.to_unicode(),x.pattern);
#else
return boost::regex_match(v.to_string(),x.pattern);
#endif
return x.apply(v);
}
value_type operator() (regex_replace_node const& x) const
{
value_type v = util::apply_visitor(*this, x.expr);
#if defined(BOOST_REGEX_HAS_ICU)
return boost::u32regex_replace(v.to_unicode(),x.pattern,x.format);
#else
std::string repl = boost::regex_replace(v.to_string(),x.pattern,x.format);
mapnik::transcoder tr_("utf8");
return tr_.transcode(repl.c_str());
#endif
return x.apply(v);
}
value_type operator() (unary_function_call const& call) const

View file

@ -126,6 +126,17 @@ struct integer_parser
using type = qi::int_parser<T,10,1,-1>;
};
struct unary_function_types : qi::symbols<char, unary_function_impl>
{
unary_function_types();
};
struct binary_function_types : qi::symbols<char, binary_function_impl>
{
binary_function_types();
};
#ifdef __GNUC__
template <typename Iterator>
struct MAPNIK_DECL expression_grammar : qi::grammar<Iterator, expr_node(), space_type>

View file

@ -28,6 +28,7 @@
#include <mapnik/expression_grammar.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/function_call.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
@ -43,24 +44,38 @@ namespace mapnik {
namespace mapnik
{
unary_function_types::unary_function_types()
{
add
("sin", sin_impl())
("cos", cos_impl())
("tan", tan_impl())
("atan", atan_impl())
("exp", exp_impl())
("abs", abs_impl())
("length",length_impl())
;
}
binary_function_types::binary_function_types()
{
add
("min", binary_function_impl(min_impl))
("max", binary_function_impl(max_impl))
("pow", binary_function_impl(pow_impl))
;
}
template <typename T0,typename T1>
expr_node regex_match_impl::operator() (T0 & node, T1 const& pattern) const
{
#if defined(BOOST_REGEX_HAS_ICU)
return regex_match_node(node,tr_.transcode(pattern.c_str()));
#else
return regex_match_node(node,pattern);
#endif
return regex_match_node(tr_,node,pattern);
}
template <typename T0,typename T1,typename T2>
expr_node regex_replace_impl::operator() (T0 & node, T1 const& pattern, T2 const& format) const
{
#if defined(BOOST_REGEX_HAS_ICU)
return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str()));
#else
return regex_replace_node(node,pattern,format);
#endif
return regex_replace_node(tr_,node,pattern,format);
}
template <typename Iterator>

View file

@ -26,16 +26,12 @@
// mapnik
#include <mapnik/value_types.hpp>
#include <mapnik/value.hpp>
#include <mapnik/config.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/function_call.hpp>
#include <mapnik/expression_node_types.hpp>
// boost
#if defined(BOOST_REGEX_HAS_ICU)
#include <boost/regex/icu.hpp>
#else
#include <boost/regex.hpp>
#endif
namespace mapnik
{
@ -86,46 +82,6 @@ struct binary_node
expr_node left,right;
};
#if defined(BOOST_REGEX_HAS_ICU)
struct regex_match_node
{
regex_match_node (expr_node const& a, mapnik::value_unicode_string const& ustr);
expr_node expr;
boost::u32regex pattern;
};
struct regex_replace_node
{
regex_replace_node (expr_node const& a, mapnik::value_unicode_string const& ustr, mapnik::value_unicode_string const& f);
expr_node expr;
boost::u32regex pattern;
mapnik::value_unicode_string format;
};
#else
struct regex_match_node
{
regex_match_node (expr_node const& a, std::string const& str);
expr_node expr;
boost::regex pattern;
};
struct regex_replace_node
{
regex_replace_node (expr_node const& a, std::string const& str, std::string const& f);
expr_node expr;
boost::regex pattern;
std::string format;
};
#endif
using unary_function_impl = std::function<value_type(value_type const&)>;
using binary_function_impl = std::function<value_type(value_type const&, value_type const&)>;
struct unary_function_call
{
using argument_type = expr_node;
@ -148,6 +104,29 @@ struct binary_function_call
argument_type arg2;
};
// pimpl
struct _regex_match_impl;
struct _regex_replace_impl;
struct MAPNIK_DECL regex_match_node
{
regex_match_node(transcoder const& tr, expr_node const& a, std::string const& ustr);
mapnik::value apply(mapnik::value const& v) const;
std::string to_string() const;
expr_node expr;
// TODO - use unique_ptr once https://github.com/mapnik/mapnik/issues/2457 is fixed
std::shared_ptr<_regex_match_impl> impl_;
};
struct MAPNIK_DECL regex_replace_node
{
regex_replace_node(transcoder const& tr, expr_node const& a, std::string const& ustr, std::string const& f);
mapnik::value apply(mapnik::value const& v) const;
std::string to_string() const;
expr_node expr;
// TODO - use unique_ptr once https://github.com/mapnik/mapnik/issues/2457 is fixed
std::shared_ptr<_regex_replace_impl> impl_;
};
inline expr_node & operator- (expr_node& expr)
{

View file

@ -29,6 +29,7 @@
#include <mapnik/value.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/noncopyable.hpp>

View file

@ -24,28 +24,104 @@
#define MAPNIK_FUNCTION_CALL_HPP
#include <mapnik/value.hpp>
#include <mapnik/expression_node.hpp>
#include <functional>
#include <boost/spirit/include/qi_symbols.hpp>
#include <algorithm>
#include <cmath>
namespace mapnik {
using value_type = mapnik::value;
namespace qi = boost::spirit::qi;
struct unary_function_types : qi::symbols<char, unary_function_impl>
{
unary_function_types();
};
struct binary_function_types : qi::symbols<char, binary_function_impl>
{
binary_function_types();
};
using unary_function_impl = std::function<value_type(value_type const&)>;
using binary_function_impl = std::function<value_type(value_type const&, value_type const&)>;
char const* unary_function_name(unary_function_impl const& fun);
char const* binary_function_name(binary_function_impl const& fun);
// functions
// exp
struct exp_impl
{
//using type = T;
value_type operator() (value_type const& val) const
{
return std::exp(val.to_double());
}
};
// sin
struct sin_impl
{
value_type operator() (value_type const& val) const
{
return std::sin(val.to_double());
}
};
// cos
struct cos_impl
{
value_type operator() (value_type const& val) const
{
return std::cos(val.to_double());
}
};
// tan
struct tan_impl
{
value_type operator() (value_type const& val) const
{
return std::tan(val.to_double());
}
};
// atan
struct atan_impl
{
value_type operator()(value_type const& val) const
{
return std::atan(val.to_double());
}
};
// abs
struct abs_impl
{
value_type operator() (value_type const& val) const
{
return std::fabs(val.to_double());
}
};
// length
struct length_impl
{
value_type operator() (value_type const& val) const
{
return val.to_unicode().length();
}
};
// min
inline value_type min_impl(value_type const& arg1, value_type const& arg2)
{
return std::min(arg1.to_double(), arg2.to_double());
}
// max
inline value_type max_impl(value_type const& arg1, value_type const& arg2)
{
return std::max(arg1.to_double(), arg2.to_double());
}
// pow
inline value_type pow_impl(value_type const& arg1, value_type const& arg2)
{
return std::pow(arg1.to_double(), arg2.to_double());
}
} // namespace mapnik
#endif //MAPNIK_FUNCTION_CALL_HPP
#endif // MAPNIK_FUNCTION_CALL_HPP

View file

@ -32,6 +32,7 @@
// stl
#include <cmath>
#include <vector>
#include <algorithm>
namespace mapnik
{

View file

@ -28,10 +28,6 @@
#include <mapnik/box2d.hpp>
#include <mapnik/noncopyable.hpp>
// boost
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>
namespace mapnik {
template <typename T, template <typename> class Container=vertex_vector>
@ -154,8 +150,6 @@ public:
};
using geometry_type = geometry<double,vertex_vector>;
using geometry_ptr = std::shared_ptr<geometry_type>;
using geometry_container = boost::ptr_vector<geometry_type>;
}

View file

@ -0,0 +1,35 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 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_GEOMETRY_CONTAINER_HPP
#define MAPNIK_GEOMETRY_CONTAINER_HPP
// boost
#include <boost/ptr_container/ptr_vector.hpp>
namespace mapnik {
using geometry_container = boost::ptr_vector<geometry_type>;
}
#endif // MAPNIK_GEOMETRY_CONTAINER_HPP

View file

@ -25,9 +25,13 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/expression_node_types.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/expression.hpp>
#include <memory>
#include <vector>
namespace mapnik
{

View file

@ -24,20 +24,20 @@
#define MAPNIK_JSON_ERROR_HANDLER_HPP
#include <string>
#include <mapnik/debug.hpp>
#include <boost/spirit/home/support/info.hpp>
namespace mapnik { namespace json {
struct where_message
template <typename Iterator>
struct error_handler
{
using result_type = std::string;
template <typename Iterator>
std::string operator() (Iterator first, Iterator last, std::size_t size) const
using result_type = void;
void operator() (
Iterator first, Iterator last,
Iterator err_pos, boost::spirit::info const& what) const
{
std::string str(first, last);
if (str.length() > size)
return str.substr(0, size) + "..." ;
return str;
MAPNIK_LOG_ERROR(error_handler) << what << " expected but got: " << std::string(err_pos, std::min(err_pos + 16,last));
}
};

View file

@ -22,6 +22,7 @@
// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/feature_collection_grammar.hpp>
// spirit::qi

View file

@ -27,6 +27,7 @@
#include <mapnik/value_types.hpp>
#include <mapnik/value.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/json/geometry_generator_grammar.hpp>
#include <mapnik/feature_kv_iterator.hpp>

View file

@ -27,11 +27,11 @@
#include <mapnik/json/geometry_grammar.hpp>
#include <mapnik/value.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value.hpp>
#include <mapnik/json/generic_json.hpp>
#include <mapnik/json/value_converters.hpp>
#include <mapnik/debug.hpp>
// spirit::qi
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
@ -89,18 +89,6 @@ struct extract_geometry
}
};
template <typename Iterator>
struct error_handler
{
using result_type = void;
void operator() (
Iterator first, Iterator last,
Iterator err_pos, boost::spirit::info const& what) const
{
MAPNIK_LOG_WARN(error_handler) << what << " expected in input";
}
};
template <typename Iterator, typename FeatureType, typename ErrorHandler = error_handler<Iterator> >
struct feature_grammar :
qi::grammar<Iterator, void(FeatureType&),

View file

@ -30,8 +30,7 @@ template <typename Iterator, typename FeatureType, typename ErrorHandler>
feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::transcoder const& tr)
: feature_grammar::base_type(feature,"feature"),
json_(),
put_property_(put_property(tr)),
error_handler(ErrorHandler())
put_property_(put_property(tr))
{
qi::lit_type lit;
qi::long_long_type long_long;
@ -114,8 +113,10 @@ feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::tran
attribute_value %= json_.number | json_.string_ ;
feature.name("Feature");
feature_type.name("Feature Type");
properties.name("Properties");
attributes.name("Attributes");
attribute_value.name("Attribute Value");
on_error<fail>(feature, error_handler(_1, _2, _3, _4));

View file

@ -56,7 +56,6 @@ struct generic_json
boost::phoenix::function<detail::value_converter<mapnik::value_double> > double_converter;
};
}}
#endif // MAPNIK_GENERIC_JSON_HPP

View file

@ -29,7 +29,7 @@
#include <mapnik/make_unique.hpp>
#include <mapnik/json/positions_grammar.hpp>
#include <mapnik/json/geometry_util.hpp>
#include <mapnik/json/error_handler.hpp>
// spirit::qi
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
@ -40,7 +40,7 @@ namespace qi = boost::spirit::qi;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
template <typename Iterator>
template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct geometry_grammar :
qi::grammar<Iterator,void(mapnik::geometry_container& )
, space_type>
@ -51,8 +51,9 @@ struct geometry_grammar :
qi::symbols<char, int> geometry_type_dispatch;
qi::rule<Iterator,void(mapnik::geometry_container& ),space_type> geometry_collection;
positions_grammar<Iterator> coordinates;
boost::phoenix::function<where_message> where_message_;
boost::phoenix::function<create_geometry_impl> create_geometry;
// error handler
boost::phoenix::function<ErrorHandler> const error_handler;
};
}}

View file

@ -21,6 +21,7 @@
*****************************************************************************/
// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/geometry_grammar.hpp>
#include <mapnik/json/positions_grammar_impl.hpp>
@ -33,8 +34,8 @@
namespace mapnik { namespace json {
template <typename Iterator>
geometry_grammar<Iterator>::geometry_grammar()
template <typename Iterator, typename ErrorHandler >
geometry_grammar<Iterator, ErrorHandler>::geometry_grammar()
: geometry_grammar::base_type(start,"geometry")
{
@ -83,20 +84,10 @@ geometry_grammar<Iterator>::geometry_grammar()
// give some rules names
geometry.name("Geometry");
geometry_collection.name("GeometryCollection");
geometry_type_dispatch.name("Geometry dispatch");
geometry_type_dispatch.name("Geometry type");
coordinates.name("Coordinates");
// error handler
on_error<fail>
(
start
, std::clog
<< boost::phoenix::val("Error! Expecting ")
<< _4 // what failed?
<< boost::phoenix::val(" here: \"")
<< where_message_(_3, _2, 16) // max 16 chars
<< boost::phoenix::val("\"")
<< std::endl
);
on_error<fail>(start, error_handler(_1, _2, _3, _4));
}
}}

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/json/geometry_grammar.hpp>
// boost
@ -33,7 +34,7 @@
namespace mapnik { namespace json {
inline bool from_geojson(std::string const& json, boost::ptr_vector<geometry_type> & paths)
inline bool from_geojson(std::string const& json, geometry_container & paths)
{
using namespace boost::spirit;
static const geometry_grammar<std::string::const_iterator> g;

View file

@ -62,7 +62,7 @@ struct push_position_impl
}
};
template <typename Iterator>
template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct positions_grammar :
qi::grammar<Iterator,coordinates(),space_type>
{
@ -74,7 +74,8 @@ struct positions_grammar :
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;
boost::phoenix::function<where_message> message;
// error handler
boost::phoenix::function<ErrorHandler> const error_handler;
};
}}

View file

@ -34,8 +34,8 @@
namespace mapnik { namespace json {
template <typename Iterator>
positions_grammar<Iterator>::positions_grammar()
template <typename Iterator, typename ErrorHandler>
positions_grammar<Iterator, ErrorHandler>::positions_grammar()
: positions_grammar::base_type(coords,"coordinates")
{
qi::lit_type lit;
@ -49,29 +49,24 @@ positions_grammar<Iterator>::positions_grammar()
using qi::fail;
using qi::on_error;
coords = pos[set_position(_val,_1)] | ring[_val = _1] | rings [_val = _1] | rings_array[_val = _1]
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(']')
pos = lit('[') > -(double_ > lit(',') > double_) > omit[*(lit(',') > double_)] > lit(']')
;
ring = lit('[') >> pos[push_position(_val,_1)] % lit(',') >> lit(']')
ring = lit('[') >> pos[push_position(_val,_1)] % lit(',') > lit(']')
;
rings = lit('[') >> ring % lit(',') >> lit(']')
rings = lit('[') >> ring % lit(',') > lit(']')
;
rings_array = lit('[') >> rings % lit(',') >> lit(']')
rings_array = lit('[') >> rings % lit(',') > lit(']')
;
coords.name("Coordinates");
pos.name("Position");
ring.name("Ring");
rings.name("Rings");
rings_array.name("Rings array");
// error handler
on_error<fail>
(
coords,
std::clog
<< boost::phoenix::val("Error! Expecting ")
<< _4 // what failed?
<< boost::phoenix::val(" here: \"")
<< message(_3, _2, 16) // max 16 chars
<< boost::phoenix::val("\"")
<< std::endl
);
on_error<fail>(coords, error_handler(_1, _2, _3, _4));
}
}}

View file

@ -23,6 +23,8 @@
#ifndef MAPNIK_SYMBOLIZER_GRAMMAR_HPP
#define MAPNIK_SYMBOLIZER_GRAMMAR_HPP
#include <mapnik/config.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
@ -31,6 +33,7 @@
#include <mapnik/util/variant.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_utils.hpp>
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/generic_json.hpp>
namespace mapnik { namespace json {
@ -113,7 +116,7 @@ struct put_property
}
};
template <typename Iterator>
template <typename Iterator, typename ErrorHandler = error_handler<Iterator>>
struct symbolizer_grammar : qi::grammar<Iterator, space_type, symbolizer()>
{
using json_value_type = util::variant<value_null,value_bool,value_integer,value_double, std::string>;
@ -121,21 +124,15 @@ struct symbolizer_grammar : qi::grammar<Iterator, space_type, symbolizer()>
: symbolizer_grammar::base_type(sym, "symbolizer"),
json_()
{
using qi::lit;
using qi::double_;
using qi::int_;
using qi::no_skip;
using qi::omit;
using qi::_val;
using qi::_a;
using qi::_r1;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::fail;
using qi::on_error;
using standard_wide::char_;
qi::lit_type lit;
qi::double_type double_;
qi::int_type int_;
qi::no_skip_type no_skip;
qi::_val_type _val;
qi::_a_type _a;
qi::_r1_type _r1;
qi::_1_type _1;
standard_wide::char_type char_;
using phoenix::construct;
// generic json types
@ -196,7 +193,7 @@ struct symbolizer_grammar : qi::grammar<Iterator, space_type, symbolizer()>
property = (json_.string_ [_a = _1] >> lit(':') >> property_value [put_property_(_r1,_a,_1)]) % lit(',')
;
property_value %= json.number | json.string_ ;
property_value %= json_.number | json_.string_ ;
}
@ -210,7 +207,7 @@ struct symbolizer_grammar : qi::grammar<Iterator, space_type, symbolizer()>
phoenix::function<put_property> put_property_;
// error
//boost::phoenix::function<where_message> where_message_;
//qi::on_error<qi::fail>(sym, error_handler(_1, _2, _3, _4));
};

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/value.hpp>
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/generic_json.hpp>
#include <mapnik/json/topology.hpp>
#include <mapnik/json/value_converters.hpp>
@ -44,21 +45,7 @@ namespace fusion = boost::fusion;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
struct where_message
{
using result_type = std::string;
template <typename Iterator>
std::string operator() (Iterator first, Iterator last, std::size_t size) const
{
std::string str(first, last);
if (str.length() > size)
return str.substr(0, size) + "..." ;
return str;
}
};
template <typename Iterator>
template <typename Iterator, typename ErrorHandler = json::error_handler<Iterator> >
struct topojson_grammar : qi::grammar<Iterator, space_type, topology()>
{
@ -91,8 +78,8 @@ private:
qi::rule<Iterator, space_type, mapnik::json::json_value()> attribute_value;
// id
qi::rule<Iterator,space_type> id;
// error
boost::phoenix::function<where_message> where_message_;
// error handler
boost::phoenix::function<ErrorHandler> const error_handler;
};
}}

View file

@ -30,8 +30,8 @@ namespace fusion = boost::fusion;
namespace standard_wide = boost::spirit::standard_wide;
using standard_wide::space_type;
template <typename Iterator>
topojson_grammar<Iterator>::topojson_grammar()
template <typename Iterator, typename ErrorHandler>
topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
: topojson_grammar::base_type(topology, "topojson")
{
qi::lit_type lit;
@ -220,19 +220,8 @@ topojson_grammar<Iterator>::topojson_grammar()
polygon.name("polygon");
multi_polygon.name("multi_polygon");
geometry_collection.name("geometry_collection");
on_error<fail>
(
topology
, std::clog
<< phoenix::val("Error! Expecting ")
<< _4 // what failed?
<< phoenix::val(" here: \"")
<< where_message_(_3, _2, 16) // where? 16 is max chars to output
<< phoenix::val("\"")
<< std::endl
);
// error handler
on_error<fail>(topology, error_handler(_1, _2, _3, _4));
}
}}

View file

@ -60,11 +60,14 @@
// stl
#include <memory>
#include <type_traits> // remove_reference
#include <cmath>
namespace mapnik {
struct clip_poly_tag;
using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;
template <typename SvgRenderer, typename Detector, typename RendererContext>
struct vector_markers_rasterizer_dispatch : mapnik::noncopyable
{
@ -80,7 +83,7 @@ struct vector_markers_rasterizer_dispatch : mapnik::noncopyable
attribute_source_type const& attrs,
box2d<double> const& bbox,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
@ -145,7 +148,7 @@ private:
RasterizerType & ras_;
box2d<double> const& bbox_;
agg::trans_affine const& marker_trans_;
markers_symbolizer const& sym_;
symbolizer_base const& sym_;
Detector & detector_;
feature_impl & feature_;
attributes const& vars_;
@ -168,7 +171,7 @@ struct raster_markers_rasterizer_dispatch : mapnik::noncopyable
raster_markers_rasterizer_dispatch(image_data_32 const& src,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
@ -299,7 +302,7 @@ private:
RasterizerType & ras_;
image_data_32 const& src_;
agg::trans_affine const& marker_trans_;
markers_symbolizer const& sym_;
symbolizer_base const& sym_;
Detector & detector_;
feature_impl & feature_;
attributes const& vars_;
@ -308,137 +311,29 @@ private:
};
template <typename T>
void build_ellipse(T const& sym, mapnik::feature_impl & feature, attributes const& vars, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path)
{
double width = 0.0;
double height = 0.0;
if (has_key<double>(sym,keys::width) && has_key<double>(sym,keys::height))
{
width = get<double>(sym, keys::width, feature, vars, 0.0);
height = get<double>(sym, keys::height, feature, vars, 0.0);
}
else if (has_key<double>(sym,keys::width))
{
width = height = get<double>(sym, keys::width, feature, vars, 0.0);
}
else if (has_key<double>(sym,keys::height))
{
width = height = get<double>(sym, keys::height, feature, vars, 0.0);
}
svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
styled_svg.push_attr();
styled_svg.begin_path();
agg::ellipse c(0, 0, width/2.0, height/2.0);
styled_svg.storage().concat_path(c);
styled_svg.end_path();
styled_svg.pop_attr();
double lox,loy,hix,hiy;
styled_svg.bounding_rect(&lox, &loy, &hix, &hiy);
styled_svg.set_dimensions(width,height);
marker_ellipse.set_dimensions(width,height);
marker_ellipse.set_bounding_box(lox,loy,hix,hiy);
}
void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);
template <typename Attr>
bool push_explicit_style(Attr const& src, Attr & dst,
markers_symbolizer const& sym,
bool push_explicit_style(svg_attribute_type const& src,
svg_attribute_type & dst,
symbolizer_base const& sym,
feature_impl & feature,
attributes const& vars)
{
auto fill_color = get_optional<color>(sym, keys::fill, feature, vars);
auto fill_opacity = get_optional<double>(sym, keys::fill_opacity, feature, vars);
auto stroke_color = get_optional<color>(sym, keys::stroke, feature, vars);
auto stroke_width = get_optional<double>(sym, keys::stroke_width, feature, vars);
auto stroke_opacity = get_optional<double>(sym, keys::stroke_opacity, feature, vars);
if (fill_color ||
fill_opacity ||
stroke_color ||
stroke_width ||
stroke_opacity)
{
bool success = false;
for(unsigned i = 0; i < src.size(); ++i)
{
success = true;
dst.push_back(src[i]);
mapnik::svg::path_attributes & attr = dst.last();
if (attr.stroke_flag)
{
if (stroke_width)
{
attr.stroke_width = *stroke_width;
}
if (stroke_color)
{
color const& s_color = *stroke_color;
attr.stroke_color = agg::rgba(s_color.red()/255.0,
s_color.green()/255.0,
s_color.blue()/255.0,
s_color.alpha()/255.0);
}
if (stroke_opacity)
{
attr.stroke_opacity = *stroke_opacity;
}
}
if (attr.fill_flag)
{
if (fill_color)
{
color const& f_color = *fill_color;
attr.fill_color = agg::rgba(f_color.red()/255.0,
f_color.green()/255.0,
f_color.blue()/255.0,
f_color.alpha()/255.0);
}
if (fill_opacity)
{
attr.fill_opacity = *fill_opacity;
}
}
}
return success;
}
return false;
}
attributes const& vars);
template <typename T>
void setup_transform_scaling(agg::trans_affine & tr,
double svg_width,
double svg_height,
mapnik::feature_impl & feature,
attributes const& vars,
T const& sym)
{
double width = get<double>(sym, keys::width, feature, vars, 0.0);
double height = get<double>(sym, keys::height, feature, vars, 0.0);
if (width > 0 && height > 0)
{
double sx = width/svg_width;
double sy = height/svg_height;
tr *= agg::trans_affine_scaling(sx,sy);
}
else if (width > 0)
{
double sx = width/svg_width;
tr *= agg::trans_affine_scaling(sx);
}
else if (height > 0)
{
double sy = height/svg_height;
tr *= agg::trans_affine_scaling(sy);
}
}
symbolizer_base const& sym);
// Apply markers to a feature with multiple geometries
template <typename Converter>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, markers_symbolizer const& sym)
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, symbolizer_base const& sym)
{
std::size_t geom_count = feature.paths().size();
if (geom_count == 1)
{
converter.apply(feature.paths()[0]);
converter.apply(const_cast<geometry_type&>(feature.paths()[0]));
}
else if (geom_count > 1)
{
@ -477,7 +372,7 @@ void apply_markers_multi(feature_impl const& feature, attributes const& vars, Co
}
if (largest)
{
converter.apply(*largest);
converter.apply(const_cast<geometry_type&>(*largest));
}
}
else
@ -488,7 +383,7 @@ void apply_markers_multi(feature_impl const& feature, attributes const& vars, Co
}
for (geometry_type const& path : feature.paths())
{
converter.apply(path);
converter.apply(const_cast<geometry_type&>(path));
}
}
}

View file

@ -30,8 +30,6 @@
#include <mapnik/markers_placements/vertext_last.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/util/variant.hpp>
#include <boost/functional/value_factory.hpp>
#include <boost/function.hpp>
namespace mapnik
{
@ -86,18 +84,21 @@ private:
Detector &detector,
markers_placement_params const& params)
{
static const std::map<marker_placement_e, boost::function<markers_placement(
Locator &locator,
Detector &detector,
markers_placement_params const& params)>> factories =
{
{ MARKER_POINT_PLACEMENT, boost::value_factory<markers_point_placement<Locator, Detector>>() },
{ MARKER_INTERIOR_PLACEMENT, boost::value_factory<markers_interior_placement<Locator, Detector>>() },
{ MARKER_LINE_PLACEMENT, boost::value_factory<markers_line_placement<Locator, Detector>>() },
{ MARKER_VERTEX_FIRST_PLACEMENT, boost::value_factory<markers_vertex_first_placement<Locator, Detector>>() },
{ MARKER_VERTEX_LAST_PLACEMENT, boost::value_factory<markers_vertex_last_placement<Locator, Detector>>() }
};
return factories.at(placement_type)(locator, detector, params);
switch (placement_type)
{
case MARKER_POINT_PLACEMENT:
return markers_point_placement<Locator, Detector>(locator,detector,params);
case MARKER_INTERIOR_PLACEMENT:
return markers_interior_placement<Locator, Detector>(locator,detector,params);
case MARKER_LINE_PLACEMENT:
return markers_line_placement<Locator, Detector>(locator,detector,params);
case MARKER_VERTEX_FIRST_PLACEMENT:
return markers_vertex_first_placement<Locator, Detector>(locator,detector,params);
case MARKER_VERTEX_LAST_PLACEMENT:
return markers_vertex_last_placement<Locator, Detector>(locator,detector,params);
default: // point
return markers_point_placement<Locator, Detector>(locator,detector,params);
}
}
markers_placement placement_;

View file

@ -26,22 +26,18 @@
#ifdef MAPNIK_LOG
#include <mapnik/debug.hpp>
#endif
#include <mapnik/global.hpp>
#include <mapnik/config.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/proj_transform.hpp>
// boost
#include <boost/math/constants/constants.hpp>
// stl
#include <cmath>
#include <vector>
#include <cstddef>
namespace mapnik
{
const double pi = boost::math::constants::pi<double>();
template <typename Geometry>
struct MAPNIK_DECL offset_converter
{
@ -176,13 +172,13 @@ private:
static double explement_reflex_angle(double angle)
{
if (angle > pi)
if (angle > M_PI)
{
return angle - 2 * pi;
return angle - 2 * M_PI;
}
else if (angle < -pi)
else if (angle < -M_PI)
{
return angle + 2 * pi;
return angle + 2 * M_PI;
}
else
{
@ -320,22 +316,22 @@ private:
{
if (joint_angle > 0.0)
{
joint_angle = joint_angle - 2 * pi;
joint_angle = joint_angle - 2 * M_PI;
}
else
{
bulge_steps = 1 + static_cast<int>(std::floor(half_turns / pi));
bulge_steps = 1 + static_cast<int>(std::floor(half_turns / M_PI));
}
}
else
{
if (joint_angle < 0.0)
{
joint_angle = joint_angle + 2 * pi;
joint_angle = joint_angle + 2 * M_PI;
}
else
{
bulge_steps = 1 + static_cast<int>(std::floor(half_turns / pi));
bulge_steps = 1 + static_cast<int>(std::floor(half_turns / M_PI));
}
}
@ -344,14 +340,14 @@ private:
{
// inside turn (sharp/obtuse angle)
MAPNIK_LOG_DEBUG(ctrans) << "offset_converter:"
<< " Sharp joint [<< inside turn " << int(joint_angle*180/pi)
<< " Sharp joint [<< inside turn " << int(joint_angle*180/M_PI)
<< " degrees >>]";
}
else
{
// outside turn (reflex angle)
MAPNIK_LOG_DEBUG(ctrans) << "offset_converter:"
<< " Bulge joint >)) outside turn " << int(joint_angle*180/pi)
<< " Bulge joint >)) outside turn " << int(joint_angle*180/M_PI)
<< " degrees ((< with " << bulge_steps << " segments";
}
#endif

View file

@ -28,26 +28,26 @@
#include <mapnik/value_types.hpp>
#include <mapnik/boolean.hpp>
#include <mapnik/util/conversions.hpp>
// boost
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
// stl
#include <string>
#include <sstream>
#include <stdexcept>
namespace mapnik { namespace detail {
template <typename T>
struct extract_value
{
static inline boost::optional<T> do_extract_from_string(std::string const& /*source*/)
{
std::string err_msg = (boost::format("No conversion from std::string to %s") % typeid(T).name()).str();
throw std::runtime_error(err_msg);
std::ostringstream s;
s << "No conversion from std::string to " << typeid(T).name();
throw std::runtime_error(s.str());
}
};
@ -138,10 +138,10 @@ struct value_extractor_visitor : public util::static_visitor<>
}
catch (boost::bad_lexical_cast const& )
{
std::string err_msg = (boost::format("Failed converting from %s to %s")
% typeid(T1).name()
% typeid(T).name()).str();
throw std::runtime_error(err_msg);
std::ostringstream s;
s << "Failed converting from " << typeid(T1).name()
<< " to " << typeid(T).name();
throw std::runtime_error(s.str());
}
}

View file

@ -25,7 +25,7 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/symbolizer.hpp> // for transform_list_ptr
#include <mapnik/symbolizer_base.hpp> // for transform_list_ptr
namespace mapnik {

View file

@ -28,6 +28,7 @@
#include <mapnik/box2d.hpp> // for box2d
#include <mapnik/view_transform.hpp> // for view_transform
#include <mapnik/attribute.hpp>
#include <mapnik/noncopyable.hpp>
// fwd declarations to speed up compile
namespace mapnik {
@ -39,16 +40,15 @@ namespace mapnik {
namespace mapnik {
struct renderer_common
struct renderer_common : private mapnik::noncopyable
{
renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor);
renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor,
std::shared_ptr<label_collision_detector4> detector);
renderer_common(request const &req, attributes const& vars, unsigned offset_x, unsigned offset_y,
renderer_common(Map const &m, request const &req, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor);
renderer_common(renderer_common const& other);
unsigned width_;
unsigned height_;
@ -63,7 +63,7 @@ struct renderer_common
std::shared_ptr<label_collision_detector4> detector_;
private:
renderer_common(unsigned width, unsigned height, double scale_factor,
renderer_common(Map const &m, unsigned width, unsigned height, double scale_factor,
attributes const& vars, view_transform &&t, std::shared_ptr<label_collision_detector4> detector);
};

View file

@ -38,6 +38,7 @@
#include <mapnik/util/conversions.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/noncopyable.hpp>
// agg
#include <agg_trans_affine.h>
@ -48,6 +49,35 @@ class proj_transform;
struct glyph_info;
class text_symbolizer_helper;
struct virtual_renderer_common : private mapnik::noncopyable
{
virtual_renderer_common(renderer_common & common) :
width_(common.width_),
height_(common.height_),
scale_factor_(common.scale_factor_),
vars_(common.vars_),
shared_font_engine_(common.shared_font_engine_),
font_engine_(*shared_font_engine_),
font_manager_(common.font_manager_),
query_extent_(common.query_extent_),
t_(common.t_),
detector_(std::make_shared<label_collision_detector4>(common.detector_->extent())) {}
unsigned & width_;
unsigned & height_;
double & scale_factor_;
attributes & vars_;
// TODO: dirty hack for cairo renderer, figure out how to remove this
std::shared_ptr<freetype_engine> & shared_font_engine_;
freetype_engine & font_engine_;
face_manager<freetype_engine> & font_manager_;
box2d<double> & query_extent_;
view_transform & t_;
std::shared_ptr<label_collision_detector4> detector_;
};
// General:
// The approach here is to run the normal symbolizers, but in
@ -117,7 +147,7 @@ struct render_thunk_extractor : public util::static_visitor<>
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
renderer_common & common,
virtual_renderer_common & common,
box2d<double> const& clipping_extent);
void operator()(point_symbolizer const& sym) const;
@ -140,7 +170,7 @@ private:
feature_impl & feature_;
attributes const& vars_;
proj_transform const& prj_trans_;
renderer_common & common_;
virtual_renderer_common & common_;
box2d<double> clipping_extent_;
void update_box() const;
@ -211,8 +241,7 @@ void render_group_symbolizer(group_symbolizer const& sym,
// create a copied 'virtual' common renderer for processing sub feature symbolizers
// create an empty detector for it, so we are sure we won't hit anything
renderer_common virtual_renderer(common);
virtual_renderer.detector_ = std::make_shared<label_collision_detector4>(common.detector_->extent());
virtual_renderer_common virtual_renderer(common);
// keep track of which lists of render thunks correspond to
// entries in the group_layout_manager.

View file

@ -26,14 +26,10 @@
#include <mapnik/renderer_common.hpp>
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
// boost
#include <boost/mpl/vector.hpp>
namespace mapnik {
template <typename T0, typename T1, typename T2>
@ -47,15 +43,6 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
using namespace mapnik::svg;
using vector_dispatch_type = T0;
using raster_dispatch_type = T1;
using renderer_context_type = T2;
using svg_attribute_type = agg::pod_bvector<path_attributes>;
using conv_types = boost::mpl::vector<clip_line_tag,
clip_poly_tag,
transform_tag,
affine_transform_tag,
simplify_tag, smooth_tag,
offset_transform_tag>;
std::string filename = get<std::string>(sym, keys::file, feature, common.vars_, "shape://ellipse");
bool clip = get<value_bool>(sym, keys::clip, feature, common.vars_, false);
@ -105,9 +92,13 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
snap_to_pixels,
renderer_context);
vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
using vertex_converter_type = vertex_converter<vector_dispatch_type,clip_line_tag,
clip_poly_tag,
transform_tag,
affine_transform_tag,
simplify_tag, smooth_tag,
offset_transform_tag>;
vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
@ -145,9 +136,13 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
snap_to_pixels,
renderer_context);
vertex_converter<box2d<double>, vector_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
using vertex_converter_type = vertex_converter<vector_dispatch_type,clip_line_tag,
clip_poly_tag,
transform_tag,
affine_transform_tag,
simplify_tag, smooth_tag,
offset_transform_tag>;
vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{
geometry_type::types type = feature.paths()[0].type();
@ -184,9 +179,13 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
common.vars_,
renderer_context);
vertex_converter<box2d<double>, raster_dispatch_type, markers_symbolizer,
view_transform, proj_transform, agg::trans_affine, conv_types, feature_impl>
converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
using vertex_converter_type = vertex_converter<raster_dispatch_type,clip_line_tag,
clip_poly_tag,
transform_tag,
affine_transform_tag,
simplify_tag, smooth_tag,
offset_transform_tag>;
vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_);
if (clip && feature.paths().size() > 0) // optional clip (default: true)
{

View file

@ -25,6 +25,7 @@
#include <mapnik/geom_util.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
@ -32,23 +33,18 @@
namespace mapnik {
template <typename F>
template <typename F,typename RendererType>
void render_point_symbolizer(point_symbolizer const &sym,
mapnik::feature_impl &feature,
proj_transform const &prj_trans,
renderer_common &common,
RendererType &common,
F render_marker)
{
std::string filename = get<std::string>(sym, keys::file, feature, common.vars_);
boost::optional<mapnik::marker_ptr> marker;
if (!filename.empty())
{
marker = marker_cache::instance().find(filename, true);
}
else
{
marker.reset(std::make_shared<mapnik::marker>());
}
boost::optional<mapnik::marker_ptr> marker = filename.empty()
? std::make_shared<mapnik::marker>()
: marker_cache::instance().find(filename, true);
if (marker)
{
double opacity = get<double>(sym,keys::opacity,feature, common.vars_, 1.0);

View file

@ -23,7 +23,11 @@
#ifndef MAPNIK_RENDERER_COMMON_PROCESS_POLYGON_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_PROCESS_POLYGON_SYMBOLIZER_HPP
#include <mapnik/renderer_common.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/feature.hpp>
namespace mapnik {

View file

@ -26,6 +26,7 @@
// mapnik
#include <mapnik/warp.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/feature.hpp>

View file

@ -27,9 +27,6 @@
#include <mapnik/config.hpp>
#include <mapnik/box2d.hpp>
// boost
#include <boost/optional/optional.hpp>
namespace mapnik
{

View file

@ -25,7 +25,7 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/expression.hpp>
// stl

View file

@ -25,7 +25,8 @@
// mapnik
#include <mapnik/color.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
// stl
#include <string>

View file

@ -25,24 +25,21 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <vector>
// fwd declare
namespace mapnik { namespace svg {
struct path_output_attributes;
struct rect_output_attributes;
struct root_output_attributes;
} }
struct path_output_attributes;
struct rect_output_attributes;
struct root_output_attributes;
}}
// boost
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/karma_omit.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/karma_nonterminal.hpp>
#include <boost/spirit/include/karma_rule.hpp>
#include <boost/fusion/adapted/struct.hpp>
/*!
* mapnik::svg::path_output_attributes is adapted as a fusion sequence
@ -61,7 +58,7 @@ BOOST_FUSION_ADAPT_STRUCT(
(std::string, stroke_linecap_)
(std::string, stroke_linejoin_)
(double, stroke_dashoffset_)
)
);
/*!
* mapnik::svg::rect_output_attributes is adapted as a fusion sequence
@ -74,7 +71,7 @@ BOOST_FUSION_ADAPT_STRUCT(
(unsigned, width_)
(unsigned, height_)
(std::string, fill_color_)
)
);
/*!
* mapnik::svg::root_output_attributes is adapted as a fusion sequence
@ -86,98 +83,38 @@ BOOST_FUSION_ADAPT_STRUCT(
(unsigned, height_)
(double, svg_version_)
(std::string, svg_namespace_url_)
)
);
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::phoenix;
template <typename OutputIterator>
struct svg_path_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::path_output_attributes()>
{
explicit svg_path_attributes_grammar()
: svg_path_attributes_grammar::base_type(svg_path_attributes)
{
karma::lit_type lit;
karma::double_type double_;
karma::string_type kstring;
svg_path_attributes =
lit("fill=\"")
<< kstring
<< lit("\" fill-opacity=\"") << double_
<< lit("\" stroke=\"") << kstring
<< lit("\" stroke-opacity=\"") << double_
<< lit("\" stroke-width=\"") << double_ << lit("px")
<< lit("\" stroke-linecap=\"") << kstring
<< lit("\" stroke-linejoin=\"") << kstring
<< lit("\" stroke-dashoffset=\"") << double_ << lit("px") << lit('"');
}
explicit svg_path_attributes_grammar();
karma::rule<OutputIterator, mapnik::svg::path_output_attributes()> svg_path_attributes;
};
template <typename OutputIterator>
struct svg_path_dash_array_grammar : karma::grammar<OutputIterator, mapnik::dash_array()>
{
explicit svg_path_dash_array_grammar()
: svg_path_dash_array_grammar::base_type(svg_path_dash_array)
{
karma::double_type double_;
karma::lit_type lit;
svg_path_dash_array = lit("stroke-dasharray=\"") <<
-((double_ << lit(',') << double_) % lit(',')) << lit('"');
}
explicit svg_path_dash_array_grammar();
karma::rule<OutputIterator, mapnik::dash_array()> svg_path_dash_array;
};
template <typename OutputIterator>
struct svg_rect_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::rect_output_attributes()>
{
explicit svg_rect_attributes_grammar()
: svg_rect_attributes_grammar::base_type(svg_rect_attributes)
{
karma::lit_type lit;
karma::int_type int_;
karma::string_type kstring;
svg_rect_attributes =
lit("x=\"")
<< int_
<< lit("\" y=\"") << int_
<< lit("\" width=\"") << int_ << lit("px")
<< lit("\" height=\"") << int_ << lit("px")
<< lit("\" fill=\"") << kstring << lit('"');
}
explicit svg_rect_attributes_grammar();
karma::rule<OutputIterator, mapnik::svg::rect_output_attributes()> svg_rect_attributes;
};
template <typename OutputIterator>
struct svg_root_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::root_output_attributes()>
{
explicit svg_root_attributes_grammar()
: svg_root_attributes_grammar::base_type(svg_root_attributes)
{
karma::lit_type lit;
karma::int_type int_;
karma::string_type kstring;
karma::double_type double_;
svg_root_attributes =
lit("width=\"")
<< int_
<< lit("px")
<< lit("\" height=\"") << int_ << lit("px")
<< lit("\" version=\"") << double_
<< lit("\" xmlns=\"") << kstring
<< lit("\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"");
}
explicit svg_root_attributes_grammar();
karma::rule<OutputIterator, mapnik::svg::root_output_attributes()> svg_root_attributes;
};
}

View file

@ -0,0 +1,103 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// NOTE: This is an implementation header file and is only meant to be included
// from implementation files. It therefore doesn't have an include guard.
// mapnik
#include <mapnik/svg/output/svg_output_grammars.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace mapnik { namespace svg {
using namespace boost::spirit;
template <typename OutputIterator>
svg_path_attributes_grammar<OutputIterator>::svg_path_attributes_grammar()
: svg_path_attributes_grammar::base_type(svg_path_attributes)
{
karma::lit_type lit;
karma::double_type double_;
karma::string_type kstring;
svg_path_attributes =
lit("fill=\"")
<< kstring
<< lit("\" fill-opacity=\"") << double_
<< lit("\" stroke=\"") << kstring
<< lit("\" stroke-opacity=\"") << double_
<< lit("\" stroke-width=\"") << double_ << lit("px")
<< lit("\" stroke-linecap=\"") << kstring
<< lit("\" stroke-linejoin=\"") << kstring
<< lit("\" stroke-dashoffset=\"") << double_ << lit("px") << lit('"');
}
template <typename OutputIterator>
svg_path_dash_array_grammar<OutputIterator>::svg_path_dash_array_grammar()
: svg_path_dash_array_grammar::base_type(svg_path_dash_array)
{
karma::double_type double_;
karma::lit_type lit;
svg_path_dash_array = lit("stroke-dasharray=\"") <<
-((double_ << lit(',') << double_) % lit(',')) << lit('"');
}
template <typename OutputIterator>
svg_rect_attributes_grammar<OutputIterator>::svg_rect_attributes_grammar()
: svg_rect_attributes_grammar::base_type(svg_rect_attributes)
{
karma::lit_type lit;
karma::int_type int_;
karma::string_type kstring;
svg_rect_attributes =
lit("x=\"")
<< int_
<< lit("\" y=\"") << int_
<< lit("\" width=\"") << int_ << lit("px")
<< lit("\" height=\"") << int_ << lit("px")
<< lit("\" fill=\"") << kstring << lit('"');
}
template <typename OutputIterator>
svg_root_attributes_grammar<OutputIterator>::svg_root_attributes_grammar()
: svg_root_attributes_grammar::base_type(svg_root_attributes)
{
karma::lit_type lit;
karma::int_type int_;
karma::string_type kstring;
karma::double_type double_;
svg_root_attributes =
lit("width=\"")
<< int_
<< lit("px")
<< lit("\" height=\"") << int_ << lit("px")
<< lit("\" version=\"") << double_
<< lit("\" xmlns=\"") << kstring
<< lit("\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"");
}
}
}

View file

@ -25,21 +25,18 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/image_scaling.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/simplify.hpp>
#include <mapnik/enumeration.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/expression_node.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/path_expression.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/color.hpp>
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/util/dasharray_parser.hpp>
@ -47,101 +44,19 @@
// stl
#include <type_traits>
#include <algorithm>
#include <memory>
#include <vector>
#include <string>
#include <functional>
#include <map>
#include <tuple>
namespace agg { struct trans_affine; }
// boost
#include <boost/optional.hpp>
namespace mapnik
{
// fwd declares
// TODO - move these transform declares to own header
namespace detail { struct transform_node; }
using transform_list = std::vector<detail::transform_node>;
using transform_list_ptr = std::shared_ptr<transform_list>;
using transform_type = transform_list_ptr;
class feature_impl;
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);
struct enumeration_wrapper
{
int value;
enumeration_wrapper() = delete;
template <typename T>
explicit enumeration_wrapper(T value_)
: value(value_) {}
inline operator int() const
{
return value;
}
};
using dash_array = std::vector<std::pair<double,double> >;
class text_placements;
using text_placements_ptr = std::shared_ptr<text_placements>;
namespace detail {
using value_base_type = util::variant<value_bool,
value_integer,
enumeration_wrapper,
value_double,
std::string,
color,
expression_ptr,
path_expression_ptr,
transform_type,
text_placements_ptr,
dash_array,
raster_colorizer_ptr,
group_symbolizer_properties_ptr,
font_feature_settings_ptr>;
struct strict_value : value_base_type
{
// default ctor
strict_value()
: value_base_type() {}
// copy ctor
strict_value(const char* val)
: value_base_type(val) {}
template <typename T>
strict_value(T const& obj)
: value_base_type(typename detail::mapnik_value_type<T>::type(obj))
{}
// move ctor
template <typename T>
strict_value(T && obj) noexcept
: value_base_type(std::move(obj)) {}
};
}
struct MAPNIK_DECL symbolizer_base
{
using value_type = detail::strict_value;
using key_type = mapnik::keys;
using cont_type = std::map<key_type, value_type>;
cont_type properties;
};
inline bool is_expression(symbolizer_base::value_type const& val)
{
return (val.get_type_index() == 6);
}
// symbolizer properties target types
enum class property_types : std::uint8_t
{
@ -179,12 +94,6 @@ enum class property_types : std::uint8_t
target_font_feature_settings
};
inline bool operator==(symbolizer_base const& lhs, symbolizer_base const& rhs)
{
return lhs.properties.size() == rhs.properties.size() &&
std::equal(lhs.properties.begin(), lhs.properties.end(), rhs.properties.begin());
}
template <typename T>
struct evaluate_path_wrapper
{
@ -410,7 +319,7 @@ struct evaluate_expression_wrapper<mapnik::dash_array>
dash_array dash;
std::vector<double> buf;
std::string str = val.to_string();
if (util::parse_dasharray(str.begin(),str.end(),buf))
if (util::parse_dasharray(str,buf))
{
util::add_dashes(buf,dash);
}
@ -559,33 +468,6 @@ using property_meta_type = std::tuple<const char*, mapnik::symbolizer_base::valu
MAPNIK_DECL property_meta_type const& get_meta(mapnik::keys key);
MAPNIK_DECL mapnik::keys get_key(std::string const& name);
// concrete symbolizer types
struct MAPNIK_DECL point_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL line_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL polygon_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL text_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL shield_symbolizer : public text_symbolizer {};
struct MAPNIK_DECL line_pattern_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL polygon_pattern_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL markers_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL building_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL group_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL debug_symbolizer : public symbolizer_base {};
// symbolizer
using symbolizer = util::variant<point_symbolizer,
line_symbolizer,
line_pattern_symbolizer,
polygon_symbolizer,
polygon_pattern_symbolizer,
raster_symbolizer,
shield_symbolizer,
text_symbolizer,
building_symbolizer,
markers_symbolizer,
group_symbolizer,
debug_symbolizer>;
}

View file

@ -0,0 +1,169 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_SYMBOLIZER_BASE_HPP
#define MAPNIK_SYMBOLIZER_BASE_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/path_expression.hpp>
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/util/variant.hpp>
// stl
#include <memory>
#include <vector>
#include <iosfwd>
#include <map>
namespace agg { struct trans_affine; }
namespace mapnik
{
// fwd declares
// TODO - move these transform declares to own header
namespace detail { struct transform_node; }
using transform_list = std::vector<detail::transform_node>;
using transform_list_ptr = std::shared_ptr<transform_list>;
using transform_type = transform_list_ptr;
class feature_impl;
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);
struct enumeration_wrapper
{
int value;
enumeration_wrapper() = delete;
template <typename T>
explicit enumeration_wrapper(T value_)
: value(value_) {}
inline operator int() const
{
return value;
}
};
using dash_array = std::vector<std::pair<double,double> >;
class text_placements;
using text_placements_ptr = std::shared_ptr<text_placements>;
namespace detail {
using value_base_type = util::variant<value_bool,
value_integer,
enumeration_wrapper,
value_double,
std::string,
color,
expression_ptr,
path_expression_ptr,
transform_type,
text_placements_ptr,
dash_array,
raster_colorizer_ptr,
group_symbolizer_properties_ptr,
font_feature_settings_ptr>;
struct strict_value : value_base_type
{
// default ctor
strict_value()
: value_base_type() {}
// copy ctor
strict_value(const char* val)
: value_base_type(val) {}
template <typename T>
strict_value(T const& obj)
: value_base_type(typename detail::mapnik_value_type<T>::type(obj))
{}
// move ctor
template <typename T>
strict_value(T && obj) noexcept
: value_base_type(std::move(obj)) {}
};
}
struct MAPNIK_DECL symbolizer_base
{
using value_type = detail::strict_value;
using key_type = mapnik::keys;
using cont_type = std::map<key_type, value_type>;
cont_type properties;
};
inline bool is_expression(symbolizer_base::value_type const& val)
{
return val.is<expression_ptr>();
}
inline bool operator==(symbolizer_base const& lhs, symbolizer_base const& rhs)
{
return lhs.properties.size() == rhs.properties.size() &&
std::equal(lhs.properties.begin(), lhs.properties.end(), rhs.properties.begin());
}
// concrete symbolizer types
struct MAPNIK_DECL point_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL line_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL polygon_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL text_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL shield_symbolizer : public text_symbolizer {};
struct MAPNIK_DECL line_pattern_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL polygon_pattern_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL markers_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL building_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL group_symbolizer : public symbolizer_base {};
struct MAPNIK_DECL debug_symbolizer : public symbolizer_base {};
// symbolizer
using symbolizer = util::variant<point_symbolizer,
line_symbolizer,
line_pattern_symbolizer,
polygon_symbolizer,
polygon_pattern_symbolizer,
raster_symbolizer,
shield_symbolizer,
text_symbolizer,
building_symbolizer,
markers_symbolizer,
group_symbolizer,
debug_symbolizer>;
}
#endif // MAPNIK_SYMBOLIZER_BASE_HPP

View file

@ -158,6 +158,7 @@ enum horizontal_alignment_enum
H_MIDDLE,
H_RIGHT,
H_AUTO,
H_ADJUST,
horizontal_alignment_enum_MAX
};

View file

@ -24,7 +24,7 @@
#define MAPNIK_SYMBOLIZER_HASH_HPP
// mapnik
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/util/variant.hpp>
// stl
#include <typeinfo>

View file

@ -37,6 +37,7 @@
#include <mapnik/config_error.hpp>
#include <mapnik/evaluate_global_attributes.hpp>
#include <mapnik/parse_transform.hpp>
#include <mapnik/util/dasharray_parser.hpp>
#include <mapnik/util/variant.hpp>
namespace mapnik {
@ -314,8 +315,6 @@ inline void set_property(Symbolizer & sym, mapnik::keys key, T const& val)
}
}
template <typename Symbolizer, typename T>
inline void set_property_from_value(Symbolizer & sym, mapnik::keys key, T const& val)
{
@ -371,7 +370,6 @@ struct set_symbolizer_property_impl
}
else
{
ex.append_context(std::string("set_symbolizer_property '") + name + "'", node);
throw;
}
}
@ -398,7 +396,7 @@ struct set_symbolizer_property_impl<Symbolizer,dash_array,false>
{
std::vector<double> buf;
dash_array dash;
if (util::parse_dasharray((*str).begin(),(*str).end(),buf) && util::add_dashes(buf,dash))
if (util::parse_dasharray(*str,buf) && util::add_dashes(buf,dash))
{
put(sym,key,dash);
}
@ -436,54 +434,46 @@ struct set_symbolizer_property_impl<Symbolizer, T, true>
static void apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
{
using value_type = T;
try
boost::optional<std::string> enum_str = node.get_opt_attr<std::string>(name);
if (enum_str)
{
boost::optional<std::string> enum_str = node.get_opt_attr<std::string>(name);
if (enum_str)
boost::optional<value_type> enum_val = detail::enum_traits<value_type>::from_string(*enum_str);
if (enum_val)
{
boost::optional<T> enum_val = detail::enum_traits<T>::from_string(*enum_str);
if (enum_val)
put(sym, key, *enum_val);
}
else
{
boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
if (val)
{
put(sym, key, *enum_val);
}
else
{
boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
if (val)
// first try pre-evaluating expression
auto result = pre_evaluate_expression<value>(*val);
if (std::get<1>(result))
{
// first try pre-evaluating expression
auto result = pre_evaluate_expression<value>(*val);
if (std::get<1>(result))
boost::optional<value_type> enum_val = detail::enum_traits<value_type>::from_string(std::get<0>(result).to_string());
if (enum_val)
{
boost::optional<T> enum_val = detail::enum_traits<T>::from_string(std::get<0>(result).to_string());
if (enum_val)
{
put(sym, key, *enum_val);
}
else
{
// can't evaluate
throw config_error("failed to parse symbolizer property: '" + name + "'");
}
put(sym, key, *enum_val);
}
else
{
// put expression_ptr
put(sym, key, *val);
// can't evaluate
throw config_error("failed to parse '" + name + "'");
}
}
else
{
throw config_error("failed to parse symbolizer property: '" + name + "'");
// put expression_ptr
put(sym, key, *val);
}
}
else
{
throw config_error("failed to parse '" + name + "'");
}
}
}
catch (config_error const& ex)
{
ex.append_context(std::string("set_symbolizer_property '") + name + "'", node);
throw;
}
}
};

View file

@ -60,7 +60,7 @@ private:
using font_feature_settings_ptr = std::shared_ptr<font_feature_settings>;
constexpr unsigned int font_feature_range_global_start = 0u;
constexpr unsigned int font_feature_range_global_end = std::numeric_limits<unsigned int>::max();
static const unsigned int font_feature_range_global_end = std::numeric_limits<unsigned int>::max();
constexpr hb_feature_t font_feature_liga_off = { HB_TAG('l', 'i', 'g', 'a'), 0, font_feature_range_global_start, font_feature_range_global_end };

View file

@ -23,14 +23,18 @@
#ifndef FORMATTING_FORMAT_HPP
#define FORMATTING_FORMAT_HPP
// mapnik
#include <mapnik/text/formatting/base.hpp>
#include <mapnik/text/text_properties.hpp>
#include <mapnik/feature.hpp>
// boost
#include <boost/property_tree/ptree_fwd.hpp>
namespace mapnik { namespace formatting {
namespace mapnik {
class feature_impl;
namespace formatting {
class MAPNIK_DECL format_node: public node
{

View file

@ -24,12 +24,17 @@
// mapnik
#include <mapnik/text/formatting/base.hpp>
#include <mapnik/feature.hpp>
// boost
#include <boost/property_tree/ptree_fwd.hpp>
// stl
#include <vector>
namespace mapnik {
class feature_impl;
namespace formatting {
class MAPNIK_DECL list_node: public node {
public:

View file

@ -22,13 +22,16 @@
#ifndef FORMATTING_TEXT_HPP
#define FORMATTING_TEXT_HPP
// mapnik
#include <mapnik/text/formatting/base.hpp>
#include <mapnik/feature.hpp>
// boost
#include <boost/property_tree/ptree_fwd.hpp>
namespace mapnik {
class feature_impl;
namespace formatting {
class MAPNIK_DECL text_node: public node {
public:

View file

@ -29,7 +29,6 @@
#include <mapnik/text/placements/base.hpp>
#include <mapnik/text/placements_list.hpp>
#include <mapnik/text/rotation.hpp>
#include <mapnik/text/vertex_cache.hpp>
#include <mapnik/noncopyable.hpp>
namespace mapnik
@ -40,6 +39,8 @@ using DetectorType = label_collision_detector4;
class feature_impl;
class vertex_cache;
class text_placement_info;
struct glyph_info;
class placement_finder : mapnik::noncopyable
{

View file

@ -67,6 +67,8 @@ bool placement_finder::find_line_placements(T & path, bool points)
{
continue;
}
layouts_.adjust(pp.length(), scale_factor_);
}
double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width());
@ -74,7 +76,7 @@ bool placement_finder::find_line_placements(T & path, bool points)
//horizontal_alignment_e halign = layouts_.back()->horizontal_alignment();
// halign == H_LEFT -> don't move
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO)
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO || horizontal_alignment_ == H_ADJUST)
{
if (!pp.forward(spacing / 2.0)) continue;
}

View file

@ -24,7 +24,6 @@
//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/rotation.hpp>
#include <mapnik/marker_cache.hpp>

View file

@ -23,13 +23,15 @@
#ifndef MAPNIK_PROPERTIES_UTIL_HPP
#define MAPNIK_PROPERTIES_UTIL_HPP
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/ptree_helpers.hpp>
#include <mapnik/config_error.hpp>
#include <boost/optional.hpp>
#include <string>
// boost
#include <boost/property_tree/ptree_fwd.hpp>
namespace mapnik { namespace detail {
template <typename T, class Enable = void>

View file

@ -26,7 +26,7 @@
// mapnik
#include <mapnik/text/placement_finder.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/noncopyable.hpp>
// agg
#include <agg_trans_affine.h>

View file

@ -23,17 +23,16 @@
#define SYMBOLIZER_HELPERS_HPP
//mapnik
#include <mapnik/symbolizer.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/text/placement_finder.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/vertex_converters.hpp>
namespace mapnik {
class feature_impl;
class proj_transform;
class view_transform;
struct symbolizer_base;
template <typename T>
struct placement_finder_adapter
{
@ -56,10 +55,7 @@ struct placement_finder_adapter
};
using conv_types = boost::mpl::vector<clip_line_tag , transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
using vertex_converter_type = vertex_converter<box2d<double>, placement_finder_adapter<placement_finder> , symbolizer_base,
view_transform, proj_transform, agg::trans_affine,
conv_types, feature_impl>;
using vertex_converter_type = vertex_converter<placement_finder_adapter<placement_finder>,clip_line_tag , transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
class base_symbolizer_helper
{

View file

@ -110,6 +110,10 @@ public:
void evaluate_properties(feature_impl const& feature, attributes const& attr);
text_line const& longest_line() const;
void set_character_spacing(double spacing, double scale_factor);
private:
void break_line(text_line & line, double wrap_width, unsigned text_ratio, bool wrap_before);
void break_line(text_line & line, char wrap_char,
@ -186,6 +190,8 @@ public:
inline double width() const { return bounds_.width(); }
inline double height() const { return bounds_.height(); }
void adjust(double width, double scale_factor);
private:
text_layout_vector layouts_;

View file

@ -52,6 +52,8 @@ public:
// Iterator beyond last glyph.
const_iterator end() const;
// Width of all glyphs without character spacing.
double glyphs_width() const { return glyphs_width_; }
// Width of all glyphs including character spacing.
double width() const { return width_; }
// Real line height. For first line: max_char_height(), for all others: line_height().
@ -75,14 +77,21 @@ public:
// Number of glyphs.
unsigned size() const;
unsigned space_count() const { return space_count_; }
void set_character_spacing(double character_spacing, double scale_factor);
private:
glyph_vector glyphs_;
double line_height_; // Includes line spacing (returned by freetype)
double max_char_height_; // Height of 'X' character of the largest font in this run. //TODO: Initialize this!
double width_;
double glyphs_width_;
unsigned first_char_;
unsigned last_char_;
bool first_line_;
unsigned space_count_;
};
} //namespace mapnik

View file

@ -1,203 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_TEXT_PATH_HPP
#define MAPNIK_TEXT_PATH_HPP
// mapnik
#include <mapnik/text/char_info.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/value_types.hpp>
//stl
#include <vector>
// boost
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>
namespace mapnik
{
class string_info : private mapnik::noncopyable
{
protected:
using characters_t = std::vector<char_info>;
characters_t characters_;
mapnik::value_unicode_string text_;
bool is_rtl;
public:
string_info(mapnik::value_unicode_string const& text)
: characters_(),
text_(text),
is_rtl(false)
{
}
string_info()
: characters_(),
text_(),
is_rtl(false)
{
}
void add_info(char_info const& info)
{
characters_.push_back(info);
}
void add_text(mapnik::value_unicode_string const& text)
{
text_ += text;
}
std::size_t num_characters() const
{
return characters_.size();
}
void set_rtl(bool value)
{
is_rtl = value;
}
bool get_rtl() const
{
return is_rtl;
}
char_info const& at(std::size_t i) const
{
return characters_[i];
}
char_info const& operator[](std::size_t i) const
{
return at(i);
}
mapnik::value_unicode_string const& get_string() const
{
return text_;
}
bool has_line_breaks() const
{
// uint16_t
UChar break_char = '\n';
return (text_.indexOf(break_char) >= 0);
}
// Resets object to initial state.
void clear()
{
text_.remove();
characters_.clear();
}
};
using char_info_ptr = char_info const *;
// List of all characters and their positions and formats for a placement.
class text_path : mapnik::noncopyable
{
struct character_node
{
char_info_ptr c;
pixel_position pos;
double angle;
character_node(char_info_ptr c_, double x_, double y_, double angle_)
: c(c_),
pos(x_, y_),
angle(angle_)
{
}
~character_node() {}
void vertex(char_info_ptr & c_, double & x_, double & y_, double & angle_) const
{
c_ = c;
x_ = pos.x;
y_ = pos.y;
angle_ = angle;
}
};
mutable int itr_;
public:
using character_nodes_t = std::vector<character_node>;
pixel_position center;
character_nodes_t nodes_;
text_path(double x, double y)
: itr_(0),
center(x,y),
nodes_()
{
}
~text_path() {}
/** Adds a new char to the list. */
void add_node(char_info_ptr c, double x, double y, double angle)
{
nodes_.push_back(character_node(c, x, y, angle));
}
/** Return node. Always returns a new node. Has no way to report that there are no more nodes. */
void vertex(char_info_ptr & c, double & x, double & y, double & angle) const
{
nodes_[itr_++].vertex(c, x, y, angle);
}
/** Start again at first node. */
void rewind() const
{
itr_ = 0;
}
/** Number of nodes. */
std::size_t num_nodes() const
{
return nodes_.size();
}
/** Delete all nodes. */
void clear()
{
nodes_.clear();
}
};
using text_path_ptr = std::shared_ptr<text_path>;
using placements_type = boost::ptr_vector<text_path>;
}
#endif // MAPNIK_TEXT_PATH_HPP

View file

@ -27,21 +27,29 @@
#include <mapnik/color.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/value.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/font_set.hpp>
#include <mapnik/enumeration.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/text/formatting/base.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/noncopyable.hpp>
// stl
#include <map>
#include <functional>
// boost
#include <boost/optional.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
namespace mapnik { namespace detail {
namespace mapnik {
class feature_impl;
class text_layout;
namespace detail {
struct evaluated_format_properties
{
@ -134,8 +142,6 @@ struct MAPNIK_DECL text_layout_properties
[](double dx, double dy) { return pixel_position(dx,dy);};
};
class text_layout;
struct text_properties_expressions
{
symbolizer_base::value_type label_placement = enumeration_wrapper(POINT_PLACEMENT);

View file

@ -24,6 +24,10 @@
#define MAPNIK_TRANSFORM_PATH_ADAPTER_HPP
#include <mapnik/proj_transform.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/config.hpp>
#include <cstddef>
namespace mapnik {

View file

@ -26,15 +26,14 @@
//mapnik
#include <mapnik/config.hpp>
#include <mapnik/noncopyable.hpp>
// icu
#include <mapnik/value_types.hpp>
#include <unicode/ucnv.h>
// stl
#include <cstdint>
#include <string>
struct UConverter;
namespace mapnik {
class MAPNIK_DECL transcoder : private mapnik::noncopyable
@ -49,13 +48,4 @@ private:
};
}
namespace U_ICU_NAMESPACE {
inline std::size_t hash_value(mapnik::value_unicode_string const& val)
{
return val.hashCode();
}
}
#endif // MAPNIK_UNICODE_HPP

View file

@ -25,11 +25,11 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/util/path_iterator.hpp>
// boost
#include <boost/spirit/include/support_container.hpp>
#include <boost/concept_check.hpp>
namespace boost { namespace spirit { namespace traits {
@ -60,9 +60,8 @@ template <>
struct end_container<mapnik::geometry_type const>
{
static mapnik::util::path_iterator<mapnik::geometry_type>
call (mapnik::geometry_type const& g)
call (mapnik::geometry_type const&)
{
boost::ignore_unused_variable_warning(g);
return mapnik::util::path_iterator<mapnik::geometry_type>();
}
};

View file

@ -23,42 +23,12 @@
#ifndef MAPNIK_UTIL_DASHARRAY_PARSER_HPP
#define MAPNIK_UTIL_DASHARRAY_PARSER_HPP
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <vector>
#include <string>
namespace mapnik { namespace util {
template <typename Iterator>
bool parse_dasharray(Iterator first, Iterator last, std::vector<double>& dasharray)
{
using namespace boost::spirit;
qi::double_type double_;
qi::_1_type _1;
qi::lit_type lit;
qi::char_type char_;
qi::ascii::space_type space;
qi::no_skip_type no_skip;
// SVG
// dasharray ::= (length | percentage) (comma-wsp dasharray)?
// no support for 'percentage' as viewport is unknown at load_map
//
bool r = qi::phrase_parse(first, last,
(double_[boost::phoenix::push_back(boost::phoenix::ref(dasharray), _1)] %
no_skip[char_(", ")]
| lit("none")),
space);
if (first != last)
{
return false;
}
return r;
}
bool parse_dasharray(std::string const& value, std::vector<double>& dasharray);
inline bool add_dashes(std::vector<double> & buf, std::vector<std::pair<double,double> > & dash)
{

View file

@ -26,6 +26,7 @@
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/svg/geometry_svg_generator.hpp>
// boost

View file

@ -27,6 +27,7 @@
#include <mapnik/config.hpp>
#include <mapnik/make_unique.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/vertex.hpp>
// stl
@ -187,7 +188,7 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
using point_type = std::pair<double,double>;
using linear_ring = std::vector<point_type>;
boost::ptr_vector<linear_ring> rings;
std::vector<linear_ring> rings;
double x = 0;
double y = 0;
@ -197,8 +198,10 @@ wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
unsigned command = g.vertex(i,&x,&y);
if (command == SEG_MOVETO)
{
rings.push_back(new linear_ring); // start new loop
rings.back().emplace_back(x,y);
linear_ring ring;
ring.reserve(1);
ring.emplace_back(x,y);
rings.push_back(std::move(ring)); // start new loop
size += 4; // num_points
size += 2 * 8; // point
}

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/wkt/wkt_generator_grammar.hpp>
namespace mapnik { namespace util {

View file

@ -26,12 +26,9 @@
// mapnik
#include <mapnik/value_types.hpp>
#include <mapnik/value_hash.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/util/variant.hpp>
// boost
#include <boost/functional/hash.hpp>
// stl
#include <string>
#include <cmath>

View file

@ -26,10 +26,13 @@
// mapnik
#include <mapnik/util/variant.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/unicode.hpp>
// stl
#include <functional>
// icu
#include <unicode/unistr.h>
namespace mapnik { namespace detail {
template <class T>
@ -48,7 +51,7 @@ struct value_hasher: public util::static_visitor<std::size_t>
std::size_t operator() (value_unicode_string const& val) const
{
return hash_value(val);
return val.hashCode();
}
template <class T>

View file

@ -37,25 +37,7 @@
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/symbolizer.hpp>
// boost
#include <boost/type_traits/is_same.hpp>
// mpl
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
// fusion
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/container/vector.hpp>
#include <mapnik/geometry.hpp>
// agg
#include "agg_math_stroke.h"
#include "agg_trans_affine.h"
@ -68,6 +50,7 @@
#include "agg_conv_transform.h"
// stl
#include <type_traits>
#include <stdexcept>
#include <array>
@ -91,11 +74,6 @@ struct converter_traits
{
using geometry_type = T0;
using conv_type = geometry_type;
template <typename Args>
static void setup(geometry_type & , Args const& )
{
throw std::runtime_error("invalid call to setup");
}
};
template <typename T>
@ -107,10 +85,7 @@ struct converter_traits<T,mapnik::smooth_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
auto const& feat = boost::fusion::at_c<6>(args);
auto const& vars = boost::fusion::at_c<7>(args);
geom.smooth_value(get<value_double>(sym, keys::smooth, feat, vars));
geom.smooth_value(get<value_double>(args.sym, keys::smooth, args.feature, args.vars));
}
};
@ -123,11 +98,8 @@ struct converter_traits<T,mapnik::simplify_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
auto const& feat = boost::fusion::at_c<6>(args);
auto const& vars = boost::fusion::at_c<7>(args);
geom.set_simplify_algorithm(static_cast<simplify_algorithm_e>(get<value_integer>(sym, keys::simplify_algorithm, feat, vars)));
geom.set_simplify_tolerance(get<value_double>(sym, keys::simplify_tolerance, feat, vars));
geom.set_simplify_algorithm(static_cast<simplify_algorithm_e>(get<value_integer>(args.sym, keys::simplify_algorithm, args.feature, args.vars)));
geom.set_simplify_tolerance(get<value_double>(args.sym, keys::simplify_tolerance,args.feature, args.vars));
}
};
@ -140,7 +112,7 @@ struct converter_traits<T, mapnik::clip_line_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<0> >::type box = boost::fusion::at_c<0>(args);
auto const& box = args.bbox;
geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
}
};
@ -154,10 +126,10 @@ struct converter_traits<T, mapnik::dash_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
auto const& feat = boost::fusion::at_c<6>(args);
auto const& vars = boost::fusion::at_c<7>(args);
double scale_factor = boost::fusion::at_c<8>(args);
auto const& sym = args.sym;
auto const& feat = args.feature;
auto const& vars = args.vars;
double scale_factor = args.scale_factor;
auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray, feat, vars);
if (dash)
{
@ -213,13 +185,13 @@ struct converter_traits<T, mapnik::stroke_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
auto const& feat = boost::fusion::at_c<6>(args);
auto const& vars = boost::fusion::at_c<7>(args);
auto const& sym = args.sym;
auto const& feat = args.feature;
auto const& vars = args.vars;
set_join_caps(sym, geom, feat, vars);
double miterlimit = get<value_double>(sym, keys::stroke_miterlimit, feat, vars, 4.0);
geom.generator().miter_limit(miterlimit);
double scale_factor = boost::fusion::at_c<8>(args);
double scale_factor = args.scale_factor;
double width = get<value_double>(sym, keys::stroke_width, feat, vars, 1.0);
geom.generator().width(width * scale_factor);
}
@ -233,9 +205,8 @@ struct converter_traits<T,mapnik::clip_poly_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<0> >::type box = boost::fusion::at_c<0>(args);
auto const& box = args.bbox;
geom.clip_box(box.minx(),box.miny(),box.maxx(),box.maxy());
//geom.set_clip_box(box);
}
};
@ -245,10 +216,7 @@ struct converter_traits<T,mapnik::close_poly_tag>
using geometry_type = T;
using conv_type = typename agg::conv_close_polygon<geometry_type>;
template <typename Args>
static void setup(geometry_type & , Args const&)
{
// no-op
}
static void setup(geometry_type & , Args const&) {}
};
template <typename T>
@ -260,8 +228,8 @@ struct converter_traits<T,mapnik::transform_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
geom.set_proj_trans(boost::fusion::at_c<4>(args));
geom.set_trans(boost::fusion::at_c<3>(args));
geom.set_proj_trans(args.prj_trans);
geom.set_trans(args.tr);
}
};
@ -279,7 +247,7 @@ struct converter_traits<T,mapnik::affine_transform_tag>
template <typename Args>
static void setup(geometry_type & geom, Args & args)
{
geom.transformer(boost::fusion::at_c<5>(args));
geom.transformer(args.affine_trans);
}
};
@ -292,118 +260,127 @@ struct converter_traits<T,mapnik::offset_transform_tag>
template <typename Args>
static void setup(geometry_type & geom, Args const& args)
{
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
auto const& feat = boost::fusion::at_c<6>(args);
auto const& vars = boost::fusion::at_c<7>(args);
auto const& sym = args.sym;
auto const& feat = args.feature;
auto const& vars = args.vars;
double offset = get<value_double>(sym, keys::offset, feat, vars);
double scale_factor = boost::fusion::at_c<8>(args);
geom.set_offset(offset * scale_factor);
geom.set_offset(offset * args.scale_factor);
}
};
template <bool>
struct converter_fwd
template <typename Dispatcher, typename... ConverterTypes>
struct converters_helper;
template <typename Dispatcher, typename Current, typename... ConverterTypes>
struct converters_helper<Dispatcher,Current,ConverterTypes...>
{
template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
static void forward(Base& base, T0 & geom,T1 const& args)
template <typename Converter>
static void set(Dispatcher & disp, int state)
{
using geometry_type = T0;
using conv_tag = T2;
using conv_type = typename detail::converter_traits<geometry_type,conv_tag>::conv_type;
conv_type conv(geom);
detail::converter_traits<conv_type,conv_tag>::setup(conv,args);
base.template dispatch<Iter,End>(conv, typename boost::is_same<Iter,End>::type());
}
};
template <>
struct converter_fwd<true>
{
template <typename Base, typename T0,typename T1,typename T2, typename Iter,typename End>
static void forward(Base& base, T0 & geom,T1 const& args)
{
base.template dispatch<Iter,End>(geom, typename boost::is_same<Iter,End>::type());
}
};
template <typename A, typename C>
struct dispatcher
{
using this_type = dispatcher;
using args_type = A;
using conv_types = C;
dispatcher(args_type const& args)
: args_(args)
{
//std::memset(&vec_[0], 0, sizeof(unsigned)*vec_.size());
std::fill(vec_.begin(), vec_.end(), 0);
}
template <typename Iter, typename End, typename Geometry>
void dispatch(Geometry & geom, boost::mpl::true_)
{
boost::fusion::at_c<1>(args_).add_path(geom);
}
template <typename Iter, typename End, typename Geometry>
void dispatch(Geometry & geom, boost::mpl::false_)
{
using conv_tag = typename boost::mpl::deref<Iter>::type;
using conv_type = typename detail::converter_traits<Geometry,conv_tag>::conv_type;
using Next = typename boost::mpl::next<Iter>::type;
std::size_t index = boost::mpl::distance<Iter,End>::value - 1;
if (vec_[index] == 1)
if (std::is_same<Converter,Current>::value)
{
converter_fwd<boost::is_same<Geometry,conv_type>::value>::
template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
constexpr std::size_t index = sizeof...(ConverterTypes) ;
disp.vec_[index] = state;
}
else
{
converter_fwd<boost::mpl::true_::value>::
template forward<this_type,Geometry,args_type,conv_tag,Next,End>(*this,geom,args_);
converters_helper<Dispatcher,ConverterTypes...>:: template set<Converter>(disp, state);
}
}
template <typename Geometry>
void apply(Geometry & geom)
static void forward(Dispatcher & disp, Geometry & geom)
{
using begin = typename boost::mpl::begin<conv_types>::type;
using end = typename boost::mpl::end <conv_types>::type;
dispatch<begin,end,Geometry>(geom, boost::false_type());
constexpr std::size_t index = sizeof...(ConverterTypes);
if (disp.vec_[index] == 1)
{
using conv_type = typename detail::converter_traits<Geometry,Current>::conv_type;
conv_type conv(geom);
detail::converter_traits<conv_type,Current>::setup(conv,disp.args_);
converters_helper<Dispatcher, ConverterTypes...>::forward(disp, conv);
}
else
{
converters_helper<Dispatcher,ConverterTypes...>::forward(disp, geom);
}
}
};
template <typename Dispatcher>
struct converters_helper<Dispatcher>
{
template <typename Converter>
static void set(Dispatcher & disp, int state) {}
template <typename Geometry>
static void forward(Dispatcher & disp, Geometry & geom)
{
disp.args_.proc.add_path(geom);
}
};
template <typename Args, typename... ConverterTypes>
struct dispatcher : mapnik::noncopyable
{
using this_type = dispatcher;
using args_type = Args;
dispatcher(typename Args::processor_type & proc, box2d<double> const& bbox, symbolizer_base const& sym, view_transform const& tr,
proj_transform const& prj_trans, agg::trans_affine const& affine_trans, feature_impl const& feature,
attributes const& vars, double scale_factor)
: args_(proc,bbox,sym,tr,prj_trans,affine_trans,feature,vars,scale_factor)
{
std::fill(vec_.begin(), vec_.end(), 0);
}
std::array<unsigned, boost::mpl::size<conv_types>::value> vec_;
std::array<unsigned, sizeof...(ConverterTypes)> vec_;
args_type args_;
};
template <typename Processor>
struct arguments : mapnik::noncopyable
{
using processor_type = Processor;
arguments(Processor & proc, box2d<double> const& bbox, symbolizer_base const& sym, view_transform const& tr,
proj_transform const& prj_trans, agg::trans_affine const& affine_trans, feature_impl const& feature,
attributes const& vars, double scale_factor)
: proc(proc),
bbox(bbox),
sym(sym),
tr(tr),
prj_trans(prj_trans),
affine_trans(affine_trans),
feature(feature),
vars(vars),
scale_factor(scale_factor) {}
Processor & proc;
box2d<double> const& bbox;
symbolizer_base const& sym;
view_transform const& tr;
proj_transform const& prj_trans;
agg::trans_affine const& affine_trans;
feature_impl const& feature;
attributes const& vars;
double scale_factor;
};
}
template <typename B, typename R, typename S, typename T, typename P, typename A, typename C, typename F >
template <typename Processor, typename... ConverterTypes >
struct vertex_converter : private mapnik::noncopyable
{
using conv_types = C;
using bbox_type = B;
using rasterizer_type = R;
using symbolizer_type = S;
using trans_type = T;
using proj_trans_type = P;
using affine_trans_type = A;
using feature_type = F;
using args_type = typename boost::fusion::vector<
bbox_type const&,
rasterizer_type&,
symbolizer_type const&,
trans_type const&,
proj_trans_type const&,
affine_trans_type const&,
feature_type const&,
attributes const&,
double //scale-factor
>;
using bbox_type = box2d<double>;
using processor_type = Processor;
using symbolizer_type = symbolizer_base;
using trans_type = view_transform;
using proj_trans_type = proj_transform;
using affine_trans_type = agg::trans_affine;
using feature_type = feature_impl;
using args_type = detail::arguments<Processor>;
using dispatcher_type = detail::dispatcher<args_type,ConverterTypes...>;
vertex_converter(bbox_type const& b,
rasterizer_type & ras,
vertex_converter(bbox_type const& bbox,
processor_type & proc,
symbolizer_type const& sym,
trans_type const& tr,
proj_trans_type const& prj_trans,
@ -411,44 +388,26 @@ struct vertex_converter : private mapnik::noncopyable
feature_type const& feature,
attributes const& vars,
double scale_factor)
: disp_(args_type(boost::cref(b),
boost::ref(ras),
boost::cref(sym),
boost::cref(tr),
boost::cref(prj_trans),
boost::cref(affine_trans),
boost::cref(feature),
boost::cref(vars),
scale_factor)) {}
: disp_(proc,bbox,sym,tr,prj_trans,affine_trans,feature,vars,scale_factor) {}
template <typename Geometry>
void apply(Geometry & geom)
void apply(geometry_type & geom)
{
using geometry_type = Geometry;
disp_.template apply<geometry_type>(geom);
detail::converters_helper<dispatcher_type, ConverterTypes...>:: template forward<geometry_type>(disp_, geom);
}
template <typename Conv>
template <typename Converter>
void set()
{
using iter = typename boost::mpl::find<conv_types,Conv>::type;
using end = typename boost::mpl::end<conv_types>::type;
std::size_t index = boost::mpl::distance<iter,end>::value - 1;
if (index < disp_.vec_.size())
disp_.vec_[index]=1;
detail::converters_helper<dispatcher_type, ConverterTypes...>:: template set<Converter>(disp_, 1);
}
template <typename Conv>
template <typename Converter>
void unset()
{
using iter = typename boost::mpl::find<conv_types,Conv>::type;
using end = typename boost::mpl::end<conv_types>::type;
std::size_t index = boost::mpl::distance<iter,end>::value - 1;
if (index < disp_.vec_.size())
disp_.vec_[index]=0;
detail::converters_helper<dispatcher_type, ConverterTypes...>:: template set<Converter>(disp_, 0);
}
detail::dispatcher<args_type,conv_types> disp_;
dispatcher_type disp_;
};
}

View file

@ -24,15 +24,10 @@
#define MAPNIK_VIEW_TRANSFORM_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/proj_transform.hpp>
// stl
#include <cstddef>
namespace mapnik
{

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/noncopyable.hpp>
namespace mapnik

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/wkt/wkt_grammar.hpp>
// stl

View file

@ -29,6 +29,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_container.hpp>
#include <mapnik/vertex.hpp>
namespace mapnik { namespace wkt {

View file

@ -694,10 +694,7 @@ void csv_datasource::parse_csv(T & stream,
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String));
}
}
else if ((value[0] >= '0' && value[0] <= '9') ||
value[0] == '-' ||
value[0] == '+' ||
value[0] == '.')
else if (csv_utils::is_likely_number(value))
{
bool has_e = value.find("e") != std::string::npos;
if (has_dot || has_e)

View file

@ -26,9 +26,15 @@
#include <string>
#include <boost/algorithm/string.hpp>
#include <cstdio>
namespace csv_utils
{
static inline bool is_likely_number(std::string const& value)
{
return( strspn( value.c_str(), "e-.+0123456789" ) == value.size() );
}
static inline void fix_json_quoting(std::string & csv_line)
{
std::string wrapping_char;

Some files were not shown because too many files have changed in this diff Show more