pull in changes from master

This commit is contained in:
Dane Springmeyer 2013-09-24 22:57:01 -07:00
commit 681f8853d3
49 changed files with 1446 additions and 428 deletions

View file

@ -14,6 +14,12 @@ Released ...
Summary: TODO
- Added Async support to PostGIS plugin - https://github.com/mapnik/mapnik/wiki/PostGIS-Async
- Fixed alpha handling bug with `comp-op:dst-over` (#1995)
- Fixed alpha handling bug with building-fill-opacity (#2011)
- Optimized mapnik.Path.to_wkb
- Python: added `__geo_interface__` to mapnik.Feature and mapnik.Path (#2009)

View file

@ -1152,6 +1152,9 @@ if not preconfigured:
if env['THREADING'] == 'multi':
env.Append(CXXFLAGS = '-mt')
if env['SHAPE_MEMORY_MAPPED_FILE']:
env.Append(CPPDEFINES = '-DSHAPE_MEMORY_MAPPED_FILE')
# allow for mac osx /usr/lib/libicucore.dylib compatibility
# requires custom supplied headers since Apple does not include them
# details: http://lists.apple.com/archives/xcode-users/2005/Jun/msg00633.html

View file

@ -363,7 +363,7 @@ namespace agg
p[Order::R] = (value_type)(p[Order::R] + ((sr * d1a + base_mask) >> base_shift));
p[Order::G] = (value_type)(p[Order::G] + ((sg * d1a + base_mask) >> base_shift));
p[Order::B] = (value_type)(p[Order::B] + ((sb * d1a + base_mask) >> base_shift));
p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
p[Order::A] = (value_type)(p[Order::A] + ((sa * d1a + base_mask) >> base_shift));
}
};
@ -1444,68 +1444,8 @@ namespace agg
}
};
// colorize alpha values
// TODO - consider moving to image-filters:
// https://github.com/mapnik/mapnik/issues/1371
/*
template <typename ColorT, typename Order>
struct comp_op_rgba_colorize_alpha
{
typedef ColorT color_type;
typedef Order order_type;
typedef typename color_type::value_type value_type;
typedef typename color_type::calc_type calc_type;
typedef typename color_type::long_type long_type;
enum base_scale_e
{
base_shift = color_type::base_shift,
base_mask = color_type::base_mask
};
static AGG_INLINE void blend_pix(value_type* p,
// source rgb
unsigned sr, unsigned sg, unsigned sb,
// source alpha and opacity
unsigned sa, unsigned cover)
{
if(cover < 255)
{
sr = (sr * cover + 255) >> 8;
sg = (sg * cover + 255) >> 8;
sb = (sb * cover + 255) >> 8;
sa = (sa * cover + 255) >> 8;
}
if (sa > 0)
{
p[Order::R] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::G] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::B] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
// http://en.wikipedia.org/wiki/File:HSV-RGB-comparison.svg
if (p[Order::A] < 64) {
p[Order::G] = ((p[Order::A] - 64) * 4);
p[Order::B] = 255;
}
if (p[Order::A] >= 64 && p[Order::A] < 128) {
p[Order::G] = 255;
p[Order::B] = 255 - ((p[Order::A] - 64) * 4);
}
if (p[Order::A] >= 128 && p[Order::A] < 192) {
p[Order::R] = ((p[Order::A] - 128) * 4);
p[Order::G] = 255;
}
if (p[Order::A] >= 192) {
p[Order::R] = 255;
p[Order::G] = 255 - ((p[Order::A] - 192) * 4);
}
}
}
};
*/
// grain extract (GIMP)
// E = I - M + 128
template <typename ColorT, typename Order>
struct comp_op_rgba_grain_extract
{

View file

@ -30,6 +30,7 @@
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/noncopyable.hpp>
#include <mapnik/feature_style_processor_context.hpp>
// boost
#include <memory>
@ -109,6 +110,13 @@ public:
* @return The type of the datasource (Vector or Raster)
*/
virtual datasource_t type() const = 0;
virtual processor_context_ptr get_context(feature_style_context_map&) const { return processor_context_ptr(); }
virtual featureset_ptr features_with_context(const query& q,processor_context_ptr ctx= processor_context_ptr()) const
{
// default implementation without context use features method
return features(q);
}
virtual featureset_ptr features(query const& q) const = 0;
virtual featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const = 0;
virtual box2d<double> envelope() const = 0;

View file

@ -27,6 +27,7 @@
#include <mapnik/datasource.hpp> // for featureset_ptr
#include <mapnik/config.hpp>
// stl
#include <set>
#include <string>
@ -41,6 +42,7 @@ class projection;
class proj_transform;
class feature_type_style;
class rule_cache;
struct layer_rendering_material;
enum eAttributeCollectionPolicy
{
@ -67,6 +69,7 @@ public:
void apply(mapnik::layer const& lyr,
std::set<std::string>& names,
double scale_denom_override=0.0);
/*!
* \brief render a layer given a projection and scale.
*/
@ -91,6 +94,26 @@ private:
featureset_ptr features,
proj_transform const& prj_trans);
/*!
* \brief prepare features for rendering asynchronously.
*/
void prepare_layer(layer_rendering_material & mat,
feature_style_context_map & ctx_map,
Processor & p,
projection const& proj0,
double scale,
double scale_denom,
unsigned width,
unsigned height,
box2d<double> const& extent,
int buffer_size,
std::set<std::string>& names);
/*!
* \brief render features list queued when they are available.
*/
void render_material(layer_rendering_material & mat, Processor & p );
Map const& m_;
};
}

View file

@ -0,0 +1,44 @@
/*****************************************************************************
*
* 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 FEATURE_STYLE_PROCESSOR_CONTEXT_HPP
#define FEATURE_STYLE_PROCESSOR_CONTEXT_HPP
// stl
#include <map>
#include <string>
#include <memory>
namespace mapnik {
class IProcessorContext {
public:
virtual ~IProcessorContext() {}
};
typedef std::shared_ptr<IProcessorContext> processor_context_ptr;
typedef std::map<std::string, processor_context_ptr > feature_style_context_map;
}
#endif // FEATURE_STYLE_PROCESSOR_CONTEXT_HPP

View file

@ -45,10 +45,11 @@
#include <mapnik/proj_transform.hpp>
#include <mapnik/util/featureset_buffer.hpp>
// boost
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/concept_check.hpp>
#include <boost/foreach.hpp>
// stl
#include <vector>
@ -126,6 +127,25 @@ struct has_process
);
};
// Store material for layer rendering in a two step process
struct layer_rendering_material {
layer const& lay_;
projection const& proj0_;
projection proj1_;
box2d<double> layer_ext2_;
std::vector<feature_type_style const*> active_styles_;
std::vector<featureset_ptr> featureset_ptr_list_;
std::vector<rule_cache> rule_caches_;
layer_rendering_material(layer const& lay, projection const& dest) :
lay_(lay),
proj0_(dest),
proj1_(lay.srs(),true) {}
};
typedef std::shared_ptr<layer_rendering_material> layer_rendering_material_ptr;
template <typename Processor>
feature_style_processor<Processor>::feature_style_processor(Map const& m, double scale_factor)
: m_(m)
@ -148,27 +168,54 @@ void feature_style_processor<Processor>::apply(double scale_denom)
scale_denom = mapnik::scale_denominator(m_.scale(),proj.is_geographic());
scale_denom *= p.scale_factor();
for (auto const& lyr : m_.layers() )
// Asynchronous query supports:
// This is a two steps process,
// first we setup all queries at layer level
// in a second time, we fetch the results and
// do the actual rendering
std::vector<layer_rendering_material_ptr> mat_list;
// Define processing context map used by datasources
// implementing asynchronous queries
feature_style_context_map ctx_map;
for ( layer const& lyr : m_.layers() )
{
if (lyr.visible(scale_denom))
{
std::set<std::string> names;
apply_to_layer(lyr,
p,
proj,
m_.scale(),
scale_denom,
m_.width(),
m_.height(),
m_.get_current_extent(),
m_.buffer_size(),
names);
layer_rendering_material_ptr mat = std::make_shared<layer_rendering_material>(lyr, proj);
prepare_layer(*mat,
ctx_map,
p,
proj,
m_.scale(),
scale_denom,
m_.width(),
m_.height(),
m_.get_current_extent(),
m_.buffer_size(),
names);
// Store active material
if (!mat->active_styles_.empty())
{
mat_list.push_back(mat);
}
}
}
for ( layer_rendering_material_ptr mat : mat_list )
{
if (!mat->active_styles_.empty())
{
render_material(*mat,p);
}
}
p.end_map_processing(m_);
}
template <typename Processor>
@ -199,8 +246,12 @@ void feature_style_processor<Processor>::apply(mapnik::layer const& lyr,
p.end_map_processing(m_);
}
/*!
* \brief render a layer given a projection and scale.
*/
template <typename Processor>
void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Processor & p,
void feature_style_processor<Processor>::apply_to_layer(layer const& lay,
Processor & p,
projection const& proj0,
double scale,
double scale_denom,
@ -210,6 +261,42 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
int buffer_size,
std::set<std::string>& names)
{
feature_style_context_map ctx_map;
layer_rendering_material mat(lay, proj0);
prepare_layer(mat,
ctx_map,
p,
proj0,
m_.scale(),
scale_denom,
m_.width(),
m_.height(),
m_.get_current_extent(),
m_.buffer_size(),
names);
if (!mat.active_styles_.empty())
{
render_material(mat,p);
}
}
template <typename Processor>
void feature_style_processor<Processor>::prepare_layer(layer_rendering_material & mat,
feature_style_context_map & ctx_map,
Processor & p,
projection const& proj0,
double scale,
double scale_denom,
unsigned width,
unsigned height,
box2d<double> const& extent,
int buffer_size,
std::set<std::string>& names)
{
layer const& lay = mat.lay_;
std::vector<std::string> const& style_names = lay.styles();
unsigned int num_styles = style_names.size();
@ -228,8 +315,8 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
return;
}
projection proj1(lay.srs(),true);
proj_transform prj_trans(proj0,proj1);
processor_context_ptr current_ctx = ds->get_context(ctx_map);
proj_transform prj_trans(mat.proj0_,mat.proj1_);
box2d<double> query_ext = extent; // unbuffered
box2d<double> buffered_query_ext(query_ext); // buffered
@ -288,6 +375,8 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
early_return = true;
}
std::vector<feature_type_style const*> & active_styles = mat.active_styles_;
if (early_return)
{
// check for styles needing compositing operations applied
@ -299,13 +388,13 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
{
continue;
}
if (style->comp_op() || style->image_filters().size() > 0)
{
if (style->active(scale_denom))
{
// trigger any needed compositing ops
p.start_style_processing(*style);
p.end_style_processing(*style);
// we'll have to handle compositing ops
active_styles.push_back(&(*style));
}
}
}
@ -319,7 +408,9 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
query_ext.clip(*maximum_extent);
}
box2d<double> layer_ext2 = lay.envelope();
box2d<double> & layer_ext2 = mat.layer_ext2_;
layer_ext2 = lay.envelope();
if (fw_success)
{
if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS))
@ -344,9 +435,9 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
height/qh);
query q(layer_ext,res,scale_denom,extent);
std::vector<feature_type_style const*> active_styles;
std::vector<rule_cache> & rule_caches = mat.rule_caches_;
attribute_collector collector(names);
std::vector<rule_cache> rule_caches;
// iterate through all named styles collecting active styles and attribute names
for (std::string const& style_name : style_names)
{
@ -362,19 +453,19 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
std::vector<rule> const& rules = style->get_rules();
bool active_rules = false;
rule_cache cache;
for (auto const& r : rules)
rule_cache rc;
for(rule const& r : rules)
{
if (r.active(scale_denom))
{
cache.add_rule(r);
rc.add_rule(r);
active_rules = true;
collector(r);
}
}
if (active_rules)
{
rule_caches.push_back(std::move(cache));
rule_caches.push_back(std::move(rc));
active_styles.push_back(&(*style));
}
}
@ -405,78 +496,141 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
{
q.add_property_name(group_by);
}
}
bool cache_features = lay.cache_features() && active_styles.size() > 1;
bool cache_features = lay.cache_features() && active_styles.size() > 1;
std::string group_by = lay.group_by();
// Render incrementally when the column that we group by changes value.
if (!group_by.empty())
std::vector<featureset_ptr> & featureset_ptr_list = mat.featureset_ptr_list_;
if ( (group_by != "") || cache_features)
{
featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx));
}
else
{
for(size_t i = 0 ; i < active_styles.size(); i++)
{
featureset_ptr features = ds->features(q);
if (features)
{
std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>();
feature_ptr feature, prev;
while ((feature = features->next()))
{
if (prev && prev->get(group_by) != feature->get(group_by))
{
// We're at a value boundary, so render what we have
// up to this point.
int i = 0;
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style, rule_caches[i], cache, prj_trans);
i++;
}
cache->clear();
}
cache->push(feature);
prev = feature;
}
int i = 0;
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style, rule_caches[i], cache, prj_trans);
i++;
}
}
featureset_ptr_list.push_back(ds->features_with_context(q,current_ctx));
}
else if (cache_features)
}
}
template <typename Processor>
void feature_style_processor<Processor>::render_material(layer_rendering_material & mat, Processor & p )
{
std::vector<feature_type_style const*> & active_styles = mat.active_styles_;
std::vector<featureset_ptr> & featureset_ptr_list = mat.featureset_ptr_list_;
if (featureset_ptr_list.empty())
{
// The datasource wasn't querried because of early return
// but we have to apply compositing operations on styles
for (feature_type_style const* style : active_styles)
{
featureset_ptr features = ds->features(q);
p.start_style_processing(*style);
p.end_style_processing(*style);
}
return;
}
p.start_layer_processing(mat.lay_, mat.layer_ext2_);
layer const& lay = mat.lay_;
std::vector<rule_cache> & rule_caches = mat.rule_caches_;
proj_transform prj_trans(mat.proj0_,mat.proj1_);
bool cache_features = lay.cache_features() && active_styles.size() > 1;
datasource_ptr ds = lay.datasource();
std::string group_by = lay.group_by();
// Render incrementally when the column that we group by
// changes value.
if (group_by != "")
{
featureset_ptr features = *featureset_ptr_list.begin();
if (features) {
// Cache all features into the memory_datasource before rendering.
std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>();
if (features)
feature_ptr feature, prev;
while ((feature = features->next()))
{
feature_ptr feature;
while ((feature = features->next()))
if (prev && prev->get(group_by) != feature->get(group_by))
{
cache->push(feature);
// We're at a value boundary, so render what we have
// up to this point.
int i = 0;
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style,
rule_caches[i],
cache,
prj_trans);
i++;
}
cache->clear();
}
cache->push(feature);
prev = feature;
}
int i = 0;
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style, rule_caches[i++], cache, prj_trans);
render_style(p, style, rule_caches[i], cache, prj_trans);
i++;
}
cache->clear();
}
// We only have a single style and no grouping.
else
{
int i = 0;
for (feature_type_style const* style : active_styles)
}
else if (cache_features)
{
std::shared_ptr<featureset_buffer> cache = std::make_shared<featureset_buffer>();
featureset_ptr features = *featureset_ptr_list.begin();
if (features) {
// Cache all features into the memory_datasource before rendering.
feature_ptr feature;
while ((feature = features->next()))
{
render_style(p, style, rule_caches[i++], ds->features(q), prj_trans);
cache->push(feature);
}
}
int i = 0;
for (feature_type_style const* style : active_styles)
{
cache->prepare();
render_style(p, style,
rule_caches[i],
cache, prj_trans);
i++;
}
}
// We only have a single style and no grouping.
else
{
int i = 0;
std::vector<featureset_ptr>::iterator featuresets = featureset_ptr_list.begin();
for (feature_type_style const* style : active_styles)
{
featureset_ptr features = *featuresets++;
render_style(p, style,
rule_caches[i],
features,
prj_trans);
i++;
}
}
p.end_layer_processing(lay);
}
p.end_layer_processing(mat.lay_);
}
template <typename Processor>
void feature_style_processor<Processor>::render_style(
@ -525,7 +679,7 @@ void feature_style_processor<Processor>::render_style(
}
if (do_else)
{
for (rule const* r : rc.get_else_rules() )
for( rule const* r : rc.get_else_rules() )
{
was_painted = true;
rule::symbolizers const& symbols = r->get_symbolizers();
@ -540,7 +694,7 @@ void feature_style_processor<Processor>::render_style(
}
if (do_also)
{
for ( rule const* r : rc.get_also_rules() )
for( rule const* r : rc.get_also_rules() )
{
was_painted = true;
rule::symbolizers const& symbols = r->get_symbolizers();

View file

@ -75,7 +75,6 @@ enum composite_mode_e
saturation,
_color,
_value
//colorize_alpha
};
MAPNIK_DECL boost::optional<composite_mode_e> comp_op_from_string(std::string const& name);

View file

@ -143,7 +143,7 @@ struct multi_geometry_type
for ( ; itr != end; ++itr)
{
if (type != 0u && itr->type() != type)
if (type != 0u && static_cast<unsigned>(itr->type()) != type)
{
collection = true;
break;
@ -233,8 +233,8 @@ struct geometry_generator_grammar :
<< karma::string[ if_ (_r1 > 1) [_1 = "],["]
.else_[_1 = '[' ]]
|
&uint_(mapnik::SEG_LINETO))
<< lit(',')
&uint_(mapnik::SEG_LINETO)
<< lit(','))
<< lit('[') << coord_type
<< lit(',')
<< coord_type << lit(']')

View file

@ -27,8 +27,7 @@
#include <mapnik/geometry.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/text_properties.hpp>
//#include <mapnik/text_placements/base.hpp>
#include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/text_path.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/noncopyable.hpp>

View file

@ -168,7 +168,10 @@ public:
bool has_else_filter() const;
void set_also(bool also_filter);
bool has_also_filter() const;
bool active(double scale) const;
inline bool active(double scale) const
{
return ( scale >= min_scale_ - 1e-6 && scale < max_scale_ + 1e-6 && !syms_.empty());
}
private:

View file

@ -28,6 +28,7 @@
#include <mapnik/feature.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/processed_text.hpp>
#include <mapnik/text_path.hpp>
//boost
@ -47,10 +48,7 @@ namespace mapnik {
namespace mapnik {
typedef boost::ptr_vector<text_path> placements_type;
template <typename DetectorT> class placement_finder;
/** Helper object that does all the TextSymbolizer placment finding
/** Helper object that does all the TextSymbolizer placement finding
* work except actually rendering the object. */
template <typename FaceManagerT, typename DetectorT>
class text_symbolizer_helper

View file

@ -34,6 +34,7 @@
// boost
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>
namespace mapnik
{
@ -196,6 +197,7 @@ public:
};
typedef std::shared_ptr<text_path> text_path_ptr;
typedef boost::ptr_vector<text_path> placements_type;
}
#endif // MAPNIK_TEXT_PATH_HPP

View file

@ -27,9 +27,6 @@
#include <boost/type_traits/is_same.hpp>
// mpl
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/deref.hpp>
@ -39,15 +36,13 @@
#include <boost/mpl/int.hpp>
// fusion
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/array.hpp>
// mapnik
#include <mapnik/agg_helpers.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/offset_converter.hpp>
#include <mapnik/simplify_converter.hpp>
#include <mapnik/noncopyable.hpp>
@ -61,7 +56,6 @@
#include "agg_conv_stroke.h"
#include "agg_conv_dash.h"
#include "agg_conv_transform.h"
#include "agg_path_storage.h"
// stl
#include <stdexcept>

View file

@ -0,0 +1,214 @@
/*****************************************************************************
*
* 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 POSTGIS_ASYNCRESULTSET_HPP
#define POSTGIS_ASYNCRESULTSET_HPP
#include <mapnik/debug.hpp>
#include <mapnik/datasource.hpp>
#include "connection_manager.hpp"
#include "resultset.hpp"
#include <queue>
#include <memory>
class postgis_processor_context;
typedef std::shared_ptr<postgis_processor_context> postgis_processor_context_ptr;
class AsyncResultSet : public IResultSet, private mapnik::noncopyable
{
public:
AsyncResultSet(postgis_processor_context_ptr const& ctx,
std::shared_ptr< Pool<Connection,ConnectionCreator> > const& pool,
std::shared_ptr<Connection> const& conn, std::string const& sql )
: ctx_(ctx),
pool_(pool),
conn_(conn),
sql_(sql),
is_closed_(false)
{
}
virtual bool use_connection() { return true; }
virtual ~AsyncResultSet()
{
close();
}
virtual void close()
{
if (!is_closed_)
{
rs_.reset();
is_closed_ = true;
if (conn_)
{
conn_.reset();
}
}
}
virtual int getNumFields() const
{
return rs_->getNumFields();
}
virtual bool next()
{
bool next_res = false;
if (!rs_)
{
// Ensure connection is valid
if (conn_ && conn_->isOK())
{
rs_ = conn_->getAsyncResult();
}
else
{
throw mapnik::datasource_exception("invalid connection in AsyncResultSet::next");
}
}
next_res = rs_->next();
if (!next_res)
{
rs_.reset();
rs_ = conn_->getNextAsyncResult();
if (rs_ && rs_->next())
{
return true;
}
close();
prepare_next();
}
return next_res;
}
virtual const char* getFieldName(int index) const
{
return rs_->getFieldName(index);
}
virtual int getFieldLength(int index) const
{
return rs_->getFieldLength(index);
}
virtual int getFieldLength(const char* name) const
{
return rs_->getFieldLength(name);
}
virtual int getTypeOID(int index) const
{
return rs_->getTypeOID(index);
}
virtual int getTypeOID(const char* name) const
{
return rs_->getTypeOID(name);
}
virtual bool isNull(int index) const
{
return rs_->isNull(index);
}
virtual const char* getValue(int index) const
{
return rs_->getValue(index);
}
virtual const char* getValue(const char* name) const
{
return rs_->getValue(name);
}
private:
postgis_processor_context_ptr ctx_;
std::shared_ptr< Pool<Connection,ConnectionCreator> > pool_;
std::shared_ptr<Connection> conn_;
std::string sql_;
std::shared_ptr<ResultSet> rs_;
bool is_closed_;
void prepare()
{
conn_ = pool_->borrowObject();
if (conn_ && conn_->isOK())
{
conn_->executeAsyncQuery(sql_, 1);
}
else
{
throw mapnik::datasource_exception("Postgis Plugin: bad connection");
}
}
void prepare_next();
};
class postgis_processor_context : public mapnik::IProcessorContext
{
public:
postgis_processor_context()
: num_async_requests_(0) {}
~postgis_processor_context() {}
void add_request(std::shared_ptr<AsyncResultSet> const& req)
{
q_.push(req);
}
std::shared_ptr<AsyncResultSet> pop_next_request()
{
std::shared_ptr<AsyncResultSet> r;
if (!q_.empty())
{
r = q_.front();
q_.pop();
}
return r;
}
int num_async_requests_;
private:
typedef std::queue<std::shared_ptr<AsyncResultSet> > async_queue;
async_queue q_;
};
inline void AsyncResultSet::prepare_next()
{
// ensure cnx pool has unused cnx
std::shared_ptr<AsyncResultSet> next = ctx_->pop_next_request();
if (next)
{
next->prepare();
}
}
#endif // POSTGIS_ASYNCRESULTSET_HPP

View file

@ -28,10 +28,8 @@
#include <mapnik/datasource.hpp>
#include <mapnik/timer.hpp>
// boost
#include <boost/make_shared.hpp>
// std
#include <memory>
#include <sstream>
#include <iostream>
@ -70,9 +68,7 @@ public:
if (! closed_)
{
PQfinish(conn_);
MAPNIK_LOG_DEBUG(postgis) << "postgis_connection: postgresql connection closed - " << conn_;
closed_ = true;
}
}
@ -107,15 +103,15 @@ public:
if (! result || (PQresultStatus(result) != PGRES_TUPLES_OK))
{
std::string err_msg = status();
err_msg += "\nFull sql was: '";
std::string err_msg = "Postgis Plugin: ";
err_msg += status();
err_msg += "\nin executeQuery Full sql was: '";
err_msg += sql;
err_msg += "'\n";
if (result)
{
PQclear(result);
}
throw mapnik::datasource_exception(err_msg);
}
@ -136,6 +132,66 @@ public:
return status;
}
bool executeAsyncQuery(std::string const& sql, int type = 0)
{
int result = 0;
if (type == 1)
{
result = PQsendQueryParams(conn_,sql.c_str(), 0, 0, 0, 0, 0, 1);
}
else
{
result = PQsendQuery(conn_, sql.c_str());
}
if (result != 1)
{
std::string err_msg = "Postgis Plugin: ";
err_msg += status();
err_msg += "\nin executeAsyncQuery Full sql was: '";
err_msg += sql;
err_msg += "'\n";
clearAsyncResult(PQgetResult(conn_));
close();
throw mapnik::datasource_exception(err_msg);
}
return result;
}
std::shared_ptr<ResultSet> getNextAsyncResult()
{
PGresult *result = PQgetResult(conn_);
if( result && (PQresultStatus(result) != PGRES_TUPLES_OK))
{
std::string err_msg = "Postgis Plugin: ";
err_msg += status();
err_msg += "\nin getNextAsyncResult";
clearAsyncResult(result);
// We need to guarde against losing the connection
// (i.e db restart) so here we invalidate the full connection
close();
throw mapnik::datasource_exception(err_msg);
}
return std::make_shared<ResultSet>(result);
}
std::shared_ptr<ResultSet> getAsyncResult()
{
PGresult *result = PQgetResult(conn_);
if ( !result || (PQresultStatus(result) != PGRES_TUPLES_OK))
{
std::string err_msg = "Postgis Plugin: ";
err_msg += status();
err_msg += "\nin getAsyncResult";
clearAsyncResult(result);
// We need to be guarded against losing the connection
// (i.e db restart), we invalidate the full connection
close();
throw mapnik::datasource_exception(err_msg);
}
return std::make_shared<ResultSet>(result);
}
std::string client_encoding() const
{
return PQparameterStatus(conn_, "client_encoding");
@ -151,9 +207,7 @@ public:
if (! closed_)
{
PQfinish(conn_);
MAPNIK_LOG_DEBUG(postgis) << "postgis_connection: datasource closed, also closing connection - " << conn_;
closed_ = true;
}
}
@ -169,6 +223,16 @@ private:
PGconn *conn_;
int cursorId;
bool closed_;
void clearAsyncResult(PGresult *result) const
{
// Clear all pending results
while(result)
{
PQclear(result);
result = PQgetResult(conn_);
}
}
};
#endif //CONNECTION_HPP

View file

@ -31,12 +31,12 @@
// boost
#include <memory>
#include <boost/make_shared.hpp>
#include <boost/optional.hpp>
// stl
#include <string>
#include <sstream>
#include <memory>
using mapnik::Pool;
using mapnik::singleton;
@ -101,8 +101,12 @@ private:
class ConnectionManager : public singleton <ConnectionManager,CreateStatic>
{
friend class CreateStatic<ConnectionManager>;
public:
typedef Pool<Connection,ConnectionCreator> PoolType;
private:
friend class CreateStatic<ConnectionManager>;
typedef std::map<std::string,std::shared_ptr<PoolType> > ContType;
typedef std::shared_ptr<Connection> HolderType;
ContType pools_;

View file

@ -28,56 +28,23 @@
#include "connection.hpp"
#include "resultset.hpp"
class CursorResultSet : public IResultSet
class CursorResultSet : public IResultSet, private mapnik::noncopyable
{
public:
CursorResultSet(std::shared_ptr<Connection> const &conn, std::string cursorName, int fetch_count)
: conn_(conn),
cursorName_(cursorName),
fetch_size_(fetch_count),
is_closed_(false),
refCount_(new int(1))
is_closed_(false)
{
getNextResultSet();
}
CursorResultSet(const CursorResultSet& rhs)
: conn_(rhs.conn_),
cursorName_(rhs.cursorName_),
rs_(rhs.rs_),
fetch_size_(rhs.fetch_size_),
is_closed_(rhs.is_closed_),
refCount_(rhs.refCount_)
{
(*refCount_)++;
}
virtual ~CursorResultSet()
{
if (--(*refCount_)==0)
{
close();
delete refCount_,refCount_=0;
}
close();
}
CursorResultSet& operator=(const CursorResultSet& rhs)
{
if (this==&rhs) return *this;
if (--(refCount_)==0)
{
close();
delete refCount_,refCount_=0;
}
conn_=rhs.conn_;
cursorName_=rhs.cursorName_;
rs_=rhs.rs_;
refCount_=rhs.refCount_;
fetch_size_=rhs.fetch_size_;
is_closed_ = false;
(*refCount_)++;
return *this;
}
virtual void close()
{
@ -92,6 +59,7 @@ public:
conn_->execute(s.str());
is_closed_ = true;
conn_.reset();
}
}
@ -105,6 +73,7 @@ public:
if (rs_->next()) {
return true;
} else if (rs_->size() == 0) {
close();
return false;
} else {
getNextResultSet();
@ -171,7 +140,8 @@ private:
std::shared_ptr<ResultSet> rs_;
int fetch_size_;
bool is_closed_;
int *refCount_;
};
#endif // POSTGIS_CURSORRESULTSET_HPP

View file

@ -23,6 +23,8 @@
#include "connection_manager.hpp"
#include "postgis_datasource.hpp"
#include "postgis_featureset.hpp"
#include "asyncresultset.hpp"
// mapnik
#include <mapnik/debug.hpp>
@ -36,9 +38,9 @@
// boost
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <boost/make_shared.hpp>
// stl
#include <memory>
#include <string>
#include <algorithm>
#include <set>
@ -67,22 +69,25 @@ postgis_datasource::postgis_datasource(parameters const& params)
srid_(*params.get<int>("srid", 0)),
extent_initialized_(false),
simplify_geometries_(false),
desc_(*params.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
desc_(*params.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
params.get<std::string>("port"),
params.get<std::string>("dbname"),
params.get<std::string>("user"),
params.get<std::string>("password"),
params.get<std::string>("connect_timeout", "4")),
bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
persist_connection_(*params.get<mapnik::boolean>("persist_connection", true)),
extent_from_subquery_(*params.get<mapnik::boolean>("extent_from_subquery", false)),
// params below are for testing purposes only (will likely be removed at any time)
intersect_min_scale_(*params.get<int>("intersect_min_scale", 0)),
intersect_max_scale_(*params.get<int>("intersect_max_scale", 0))
bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
pool_max_size_(*params_.get<int>("max_size", 10)),
persist_connection_(*params.get<mapnik::boolean>("persist_connection", true)),
extent_from_subquery_(*params.get<mapnik::boolean>("extent_from_subquery", false)),
max_async_connections_(*params_.get<int>("max_async_connection", 1)),
asynchronous_request_(false),
// params below are for testing purposes only and may be removed at any time
intersect_min_scale_(*params.get<int>("intersect_min_scale", 0)),
intersect_max_scale_(*params.get<int>("intersect_max_scale", 0))
{
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "postgis_datasource::init");
@ -98,16 +103,29 @@ postgis_datasource::postgis_datasource(parameters const& params)
extent_initialized_ = extent_.from_string(*ext);
}
// NOTE: In multithread environment, pool_max_size_ should be
// max_async_connections_ * num_threads
if(max_async_connections_ > 1)
{
if(max_async_connections_ > pool_max_size_)
{
std::ostringstream err;
err << "PostGIS Plugin: Error: 'max_async_connections ("
<< max_async_connections_ << ") must be <= max_size(" << pool_max_size_ << ")";
throw mapnik::datasource_exception(err.str());
}
asynchronous_request_ = true;
}
boost::optional<int> initial_size = params.get<int>("initial_size", 1);
boost::optional<int> max_size = params.get<int>("max_size", 10);
boost::optional<mapnik::boolean> autodetect_key_field = params.get<mapnik::boolean>("autodetect_key_field", false);
boost::optional<mapnik::boolean> estimate_extent = params.get<mapnik::boolean>("estimate_extent", false);
estimate_extent_ = estimate_extent && *estimate_extent;
boost::optional<mapnik::boolean> simplify_opt = params.get<mapnik::boolean>("simplify_geometries", false);
simplify_geometries_ = simplify_opt && *simplify_opt;
ConnectionManager::instance().registerPool(creator_, *initial_size, *max_size);
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
ConnectionManager::instance().registerPool(creator_, *initial_size, pool_max_size_);
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
@ -413,6 +431,10 @@ postgis_datasource::postgis_datasource(parameters const& params)
rs->close();
}
// Close explicitly the connection so we can 'fork()' without sharing open connections
conn->close();
}
}
@ -420,7 +442,7 @@ postgis_datasource::~postgis_datasource()
{
if (! persist_connection_)
{
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
@ -557,156 +579,222 @@ std::string postgis_datasource::populate_tokens(std::string const& sql, double s
}
std::shared_ptr<IResultSet> postgis_datasource::get_resultset(std::shared_ptr<Connection> const &conn, std::string const& sql) const
std::shared_ptr<IResultSet> postgis_datasource::get_resultset(std::shared_ptr<Connection> &conn, std::string const& sql, CnxPool_ptr const& pool, processor_context_ptr ctx) const
{
if (cursor_fetch_size_ > 0)
if (!ctx)
{
// cursor
std::ostringstream csql;
std::string cursor_name = conn->new_cursor_name();
csql << "DECLARE " << cursor_name << " BINARY INSENSITIVE NO SCROLL CURSOR WITH HOLD FOR " << sql << " FOR READ ONLY";
if (! conn->execute(csql.str()))
// ! asynchronous_request_
if (cursor_fetch_size_ > 0)
{
// TODO - better error
throw mapnik::datasource_exception("Postgis Plugin: error creating cursor for data select." );
// cursor
std::ostringstream csql;
std::string cursor_name = conn->new_cursor_name();
csql << "DECLARE " << cursor_name << " BINARY INSENSITIVE NO SCROLL CURSOR WITH HOLD FOR " << sql << " FOR READ ONLY";
if (! conn->execute(csql.str()))
{
// TODO - better error
throw mapnik::datasource_exception("Postgis Plugin: error creating cursor for data select." );
}
return std::make_shared<CursorResultSet>(conn, cursor_name, cursor_fetch_size_);
}
else
{
// no cursor
return conn->executeQuery(sql, 1);
}
return std::make_shared<CursorResultSet>(conn, cursor_name, cursor_fetch_size_);
}
else
{
// no cursor
return conn->executeQuery(sql, 1);
{ // asynchronous requests
std::shared_ptr<postgis_processor_context> pgis_ctxt = std::static_pointer_cast<postgis_processor_context>(ctx);
if (conn)
{
// lauch async req & create asyncresult with conn
conn->executeAsyncQuery(sql, 1);
return std::make_shared<AsyncResultSet>(pgis_ctxt, pool, conn, sql);
}
else
{
// create asyncresult with null connection
std::shared_ptr<AsyncResultSet> res = std::make_shared<AsyncResultSet>(pgis_ctxt, pool, conn, sql);
pgis_ctxt->add_request(res);
return res;
}
}
}
featureset_ptr postgis_datasource::features(const query& q) const
processor_context_ptr postgis_datasource::get_context(feature_style_context_map & ctx) const
{
if (!asynchronous_request_)
{
return processor_context_ptr();
}
std::string ds_name(name());
feature_style_context_map::const_iterator itr = ctx.find(ds_name);
if (itr != ctx.end())
{
return itr->second;
}
else
{
return ctx.insert(std::make_pair(ds_name,std::make_shared<postgis_processor_context>())).first->second;
}
}
featureset_ptr postgis_datasource::features(query const& q) const
{
// if the driver is in asynchronous mode, return the appropriate fetaures
if (asynchronous_request_ )
{
return features_with_context(q,std::make_shared<postgis_processor_context>());
}
else
{
return features_with_context(q);
}
}
featureset_ptr postgis_datasource::features_with_context(query const& q,processor_context_ptr proc_ctx) const
{
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features");
mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features_with_context");
#endif
box2d<double> const& box = q.get_bbox();
double scale_denom = q.scale_denominator();
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
if (conn && conn->isOK())
shared_ptr<Connection> conn;
if ( asynchronous_request_ )
{
if (geometryColumn_.empty())
// limit use to num_async_request_ => if reached don't borrow the last connexion object
std::shared_ptr<postgis_processor_context> pgis_ctxt = std::static_pointer_cast<postgis_processor_context>(proc_ctx);
if ( pgis_ctxt->num_async_requests_ < max_async_connections_ )
{
std::ostringstream s_error;
s_error << "PostGIS: geometry name lookup failed for table '";
if (! schema_.empty())
{
s_error << schema_ << ".";
}
s_error << geometry_table_
<< "'. Please manually provide the 'geometry_field' parameter or add an entry "
<< "in the geometry_columns for '";
if (! schema_.empty())
{
s_error << schema_ << ".";
}
s_error << geometry_table_ << "'.";
throw mapnik::datasource_exception(s_error.str());
conn = pool->borrowObject();
pgis_ctxt->num_async_requests_++;
}
std::ostringstream s;
const double px_gw = 1.0 / boost::get<0>(q.resolution());
const double px_gh = 1.0 / boost::get<1>(q.resolution());
s << "SELECT ST_AsBinary(";
if (simplify_geometries_) {
s << "ST_Simplify(";
}
s << "\"" << geometryColumn_ << "\"";
if (simplify_geometries_) {
// 1/20 of pixel seems to be a good compromise to avoid
// drop of collapsed polygons.
// See https://github.com/mapnik/mapnik/issues/1639
const double tolerance = std::min(px_gw, px_gh) / 20.0;
s << ", " << tolerance << ")";
}
s << ") AS geom";
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
std::set<std::string> const& props = q.property_names();
std::set<std::string>::const_iterator pos = props.begin();
std::set<std::string>::const_iterator end = props.end();
if (! key_field_.empty())
}
else
{
// Always get a connection in synchronous mode
conn = pool->borrowObject();
if(!conn )
{
mapnik::sql_utils::quote_attr(s, key_field_);
ctx->push(key_field_);
for (; pos != end; ++pos)
{
if (*pos != key_field_)
{
mapnik::sql_utils::quote_attr(s, *pos);
ctx->push(*pos);
}
}
throw mapnik::datasource_exception("Postgis Plugin: Null connection");
}
else
}
if (geometryColumn_.empty())
{
std::ostringstream s_error;
s_error << "PostGIS: geometry name lookup failed for table '";
if (! schema_.empty())
{
for (; pos != end; ++pos)
s_error << schema_ << ".";
}
s_error << geometry_table_
<< "'. Please manually provide the 'geometry_field' parameter or add an entry "
<< "in the geometry_columns for '";
if (! schema_.empty())
{
s_error << schema_ << ".";
}
s_error << geometry_table_ << "'.";
throw mapnik::datasource_exception(s_error.str());
}
std::ostringstream s;
const double px_gw = 1.0 / boost::get<0>(q.resolution());
const double px_gh = 1.0 / boost::get<1>(q.resolution());
s << "SELECT ST_AsBinary(";
if (simplify_geometries_) {
s << "ST_Simplify(";
}
s << "\"" << geometryColumn_ << "\"";
if (simplify_geometries_) {
// 1/20 of pixel seems to be a good compromise to avoid
// drop of collapsed polygons.
// See https://github.com/mapnik/mapnik/issues/1639
const double tolerance = std::min(px_gw, px_gh) / 2.0;
s << ", " << tolerance << ")";
}
s << ") AS geom";
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
std::set<std::string> const& props = q.property_names();
std::set<std::string>::const_iterator pos = props.begin();
std::set<std::string>::const_iterator end = props.end();
if (! key_field_.empty())
{
mapnik::sql_utils::quote_attr(s, key_field_);
ctx->push(key_field_);
for (; pos != end; ++pos)
{
if (*pos != key_field_)
{
mapnik::sql_utils::quote_attr(s, *pos);
ctx->push(*pos);
}
}
std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh);
s << " FROM " << table_with_bbox;
if (row_limit_ > 0)
{
s << " LIMIT " << row_limit_;
}
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str());
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty());
}
else
{
std::string err_msg = "Postgis Plugin:";
if (conn)
for (; pos != end; ++pos)
{
err_msg += conn->status();
mapnik::sql_utils::quote_attr(s, *pos);
ctx->push(*pos);
}
else
{
err_msg += " Null connection";
}
throw mapnik::datasource_exception(err_msg);
}
std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh);
s << " FROM " << table_with_bbox;
if (row_limit_ > 0)
{
s << " LIMIT " << row_limit_;
}
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx);
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty());
}
return featureset_ptr();
}
featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double tol) const
{
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "postgis_datasource::features_at_point");
#endif
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
@ -775,7 +863,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
s << " LIMIT " << row_limit_;
}
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str());
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool);
return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty());
}
}
@ -790,7 +878,7 @@ box2d<double> postgis_datasource::envelope() const
return extent_;
}
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();
@ -881,7 +969,7 @@ boost::optional<mapnik::datasource::geometry_t> postgis_datasource::get_geometry
{
boost::optional<mapnik::datasource::geometry_t> result;
shared_ptr< Pool<Connection,ConnectionCreator> > pool = ConnectionManager::instance().getPool(creator_.id());
CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
if (pool)
{
shared_ptr<Connection> conn = pool->borrowObject();

View file

@ -36,10 +36,9 @@
// boost
#include <boost/optional.hpp>
#include <memory>
// stl
#include <memory>
#include <vector>
#include <string>
@ -49,6 +48,8 @@
using mapnik::transcoder;
using mapnik::datasource;
using mapnik::feature_style_context_map;
using mapnik::processor_context_ptr;
using mapnik::box2d;
using mapnik::layer_descriptor;
using mapnik::featureset_ptr;
@ -57,6 +58,8 @@ using mapnik::query;
using mapnik::parameters;
using mapnik::coord2d;
typedef std::shared_ptr< ConnectionManager::PoolType> CnxPool_ptr;
class postgis_datasource : public datasource
{
public:
@ -64,7 +67,9 @@ public:
~postgis_datasource();
mapnik::datasource::datasource_t type() const;
static const char * name();
featureset_ptr features(const query& q) const;
processor_context_ptr get_context(feature_style_context_map &) const;
featureset_ptr features_with_context(query const& q, processor_context_ptr ctx= processor_context_ptr()) const;
featureset_ptr features(query const& q) const;
featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const;
mapnik::box2d<double> envelope() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
@ -74,8 +79,7 @@ private:
std::string sql_bbox(box2d<double> const& env) const;
std::string populate_tokens(std::string const& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const;
std::string populate_tokens(std::string const& sql) const;
std::shared_ptr<IResultSet> get_resultset(std::shared_ptr<Connection> const &conn, std::string const& sql) const;
std::shared_ptr<IResultSet> get_resultset(std::shared_ptr<Connection> &conn, std::string const& sql, CnxPool_ptr const& pool, processor_context_ptr ctx= processor_context_ptr()) const;
static const std::string GEOMETRY_COLUMNS;
static const std::string SPATIAL_REF_SYS;
static const double FMAX;
@ -102,10 +106,12 @@ private:
const std::string scale_denom_token_;
const std::string pixel_width_token_;
const std::string pixel_height_token_;
int pool_max_size_;
bool persist_connection_;
bool extent_from_subquery_;
bool estimate_extent_;
// params below are for testing purposes only (will likely be removed at any time)
int max_async_connections_;
bool asynchronous_request_;
int intersect_min_scale_;
int intersect_max_scale_;
};

View file

@ -35,14 +35,13 @@
#include <mapnik/util/trim.hpp>
#include <mapnik/global.hpp> // for int2net
// boost
#include <boost/cstdint.hpp> // for boost::int16_t
// stl
#include <sstream>
#include <string>
#include <memory>
using mapnik::geometry_type;
using mapnik::byte;

View file

@ -29,9 +29,6 @@
#include <mapnik/feature.hpp>
#include <mapnik/unicode.hpp>
// boost
using mapnik::Featureset;
using mapnik::box2d;
using mapnik::feature_ptr;

View file

@ -45,49 +45,16 @@ public:
virtual const char* getValue(const char* name) const = 0;
};
class ResultSet : public IResultSet
class ResultSet : public IResultSet, private mapnik::noncopyable
{
public:
ResultSet(PGresult *res)
: res_(res),
pos_(-1),
refCount_(new int(1))
pos_(-1)
{
numTuples_ = PQntuples(res_);
}
ResultSet(const ResultSet& rhs)
: res_(rhs.res_),
pos_(rhs.pos_),
numTuples_(rhs.numTuples_),
refCount_(rhs.refCount_)
{
(*refCount_)++;
}
ResultSet& operator=(const ResultSet& rhs)
{
if (this == &rhs)
{
return *this;
}
if (--(refCount_) == 0)
{
close();
delete refCount_;
refCount_ = 0;
}
res_ = rhs.res_;
pos_ = rhs.pos_;
numTuples_ = rhs.numTuples_;
refCount_ = rhs.refCount_;
(*refCount_)++;
return *this;
}
virtual void close()
{
PQclear(res_);
@ -96,13 +63,7 @@ public:
virtual ~ResultSet()
{
if (--(*refCount_) == 0)
{
PQclear(res_);
delete refCount_;
refCount_ = 0;
}
PQclear(res_);
}
virtual int getNumFields() const
@ -184,7 +145,6 @@ private:
PGresult* res_;
int pos_;
int numTuples_;
int *refCount_;
};
#endif // POSTGIS_RESULTSET_HPP

View file

@ -455,7 +455,7 @@ void agg_renderer<T>::debug_draw_box(R& buf, box2d<double> const& box,
// render the outline
ras_ptr->reset();
ras_ptr->add_path(sbox);
ren.color(agg::rgba8(0x33, 0x33, 0xff, 0xcc)); // blue is fine
ren.color(agg::rgba8_pre(0x33, 0x33, 0xff, 0xcc)); // blue is fine
agg::render_scanlines(*ras_ptr, sl_line, ren);
}

View file

@ -132,7 +132,7 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
path_type faces_path (t_,*faces,prj_trans);
ras_ptr->add_path(faces_path);
ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
ren.color(agg::rgba8_pre(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
agg::render_scanlines(*ras_ptr, sl, ren);
ras_ptr->reset();
//
@ -166,13 +166,13 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
agg::conv_stroke<path_type> stroke(path);
stroke.width(scale_factor_);
ras_ptr->add_path(stroke);
ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
ren.color(agg::rgba8_pre(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
agg::render_scanlines(*ras_ptr, sl, ren);
ras_ptr->reset();
path_type roof_path (t_,*roof,prj_trans);
ras_ptr->add_path(roof_path);
ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
ren.color(agg::rgba8_pre(r, g, b, int(a * sym.get_opacity())));
agg::render_scanlines(*ras_ptr, sl, ren);
}

View file

@ -60,18 +60,18 @@ public:
pattern_source(mapnik::image_data_32 const& pattern)
: pattern_(pattern) {}
unsigned int width() const
inline unsigned int width() const
{
return pattern_.width();
}
unsigned int height() const
inline unsigned int height() const
{
return pattern_.height();
}
agg::rgba8 pixel(int x, int y) const
inline agg::rgba8 pixel(int x, int y) const
{
unsigned c = pattern_(x,y);
return agg::rgba8(c & 0xff,
return agg::rgba8_pre(c & 0xff,
(c >> 8) & 0xff,
(c >> 16) & 0xff,
(c >> 24) & 0xff);
@ -107,12 +107,10 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
if (!(*mark)->is_bitmap())
{
MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer";
return;
}
boost::optional<image_ptr> pat = (*mark)->get_bitmap_data();
if (!pat) return;
agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4);

View file

@ -335,10 +335,6 @@ if env['SVG_RENDERER']: # svg backend
lib_env.Append(CPPDEFINES = '-DSVG_RENDERER')
libmapnik_defines.append('-DSVG_RENDERER')
if env['SHAPE_MEMORY_MAPPED_FILE']:
lib_env.Append(CPPDEFINES = '-DSHAPE_MEMORY_MAPPED_FILE')
libmapnik_defines.append('-DSHAPE_MEMORY_MAPPED_FILE')
if env.get('BOOST_LIB_VERSION_FROM_HEADER'):
boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1])
if boost_version_from_header < 46:

View file

@ -75,7 +75,6 @@ static const comp_op_lookup_type comp_lookup = boost::assign::list_of<comp_op_lo
(saturation,"saturation")
(_color,"color")
(_value,"value")
//(colorize_alpha,"colorize-alpha")
;
boost::optional<composite_mode_e> comp_op_from_string(std::string const& name)

View file

@ -34,7 +34,6 @@
// boost
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/tuple/tuple.hpp>

View file

@ -266,9 +266,4 @@ bool rule::has_also_filter() const
return also_filter_;
}
bool rule::active(double scale) const
{
return ( !syms_.empty() && scale >= min_scale_ - 1e-6 && scale < max_scale_ + 1e-6);
}
}

View file

@ -505,5 +505,4 @@ agg::trans_affine const& shield_symbolizer_helper<FaceManagerT, DetectorT>::get_
template class text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4>;
template class shield_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4>;
template class mapnik::placement_finder<mapnik::label_collision_detector4>;
} //namespace

View file

@ -8,10 +8,7 @@
</Rule>
</Style>
<!--
<Style name="style" comp-op="colorize-alpha">
-->
<Style name="style">
<Style name="style" image-filters="colorize-alpha(blue,purple,red,orange,yellow,green)">
<Rule>
<PointSymbolizer file="../images/marker.png" allow-overlap="true" />
</Rule>

View file

@ -32,6 +32,23 @@ wkts = [
[2,"MULTIPOLYGON(((-178.32319 71.518365,-178.321586 71.518439,-178.259635 71.510688,-178.304862 71.513129,-178.32319 71.518365)),((-178.32319 71.518365,-178.341544 71.517524,-178.32244 71.505439,-178.215323 71.478034,-178.193473 71.47663,-178.147757 71.485175,-178.124442 71.481879,-178.005729 71.448615,-178.017203 71.441413,-178.054191 71.428778,-178.047049 71.425727,-178.033439 71.417792,-178.026236 71.415107,-178.030082 71.413459,-178.039908 71.40766,-177.970878 71.39643,-177.779837 71.333197,-177.718375 71.305243,-177.706412 71.3039,-177.68212 71.304877,-177.670279 71.301825,-177.655387 71.293158,-177.587577 71.285956,-177.548575 71.294867,-177.531119 71.296332,-177.51409 71.293402,-177.498649 71.284735,-177.506217 71.268622,-177.486991 71.258734,-177.459708 71.249884,-177.443412 71.237006,-177.445914 71.222663,-177.457755 71.209357,-177.507804 71.173774,-177.581168 71.147589,-177.637626 71.117011,-177.684134 71.110968,-177.751883 71.092963,-177.819266 71.084662,-177.877677 71.052558,-177.930472 71.041449,-178.206595 71.038398,-178.310111 71.013617,-178.875907 70.981024,-178.980277 70.95069,-179.342093 70.908026,-179.336234 70.911078,-179.322257 70.921698,-179.364493 70.930243,-179.457511 70.915534,-179.501212 70.919684,-179.666007 70.965461,-179.853385 70.979438,-179.888785 70.993598,-179.907523 70.996772,-179.999989 70.992011,-179.999989 71.024848,-179.999989 71.058661,-179.999989 71.126166,-179.999989 71.187018,-179.999989 71.224189,-179.999989 71.27497,-179.999989 71.312079,-179.999989 71.356024,-179.999989 71.410041,-179.999989 71.487799,-179.999989 71.536689,-179.862845 71.538642,-179.912223 71.555854,-179.900748 71.558478,-179.798819 71.569098,-179.757438 71.583197,-179.735953 71.586432,-179.715445 71.583258,-179.697501 71.577338,-179.678702 71.573676,-179.610831 71.585211,-179.372062 71.569098,-179.326774 71.555487,-179.306815 71.557563,-179.287162 71.562934,-179.24285 71.569098,-179.204642 71.583197,-179.074576 71.600043,-178.395438 71.539008,-178.32319 71.518365)))"]
]
geojson = [
[1,'{"type":"Point","coordinates":[30,10]}'],
[1,'{"type":"Point","coordinates":[30.0,10.0]}'],
[1,'{"type":"Point","coordinates":[30.1,10.1]}'],
[1,'{"type":"LineString","coordinates":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}'],
[1,'{"type":"Polygon","coordinates":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}'],
[1,'{"type":"Polygon","coordinates":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}'],
[4,'{"type":"MultiPoint","coordinates":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}'],
[2,'{"type":"MultiLineString","coordinates":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}'],
[3,'{"type":"GeometryCollection","geometries":[{"type":"Polygon","coordinates":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{"type":"Point","coordinates":[2.0,3.0]},{"type":"LineString","coordinates":[[2.0,3.0],[3.0,4.0]]}]}'],
[1,'{"type":"Polygon","coordinates":[[[-178.32319,71.518365],[-178.321586,71.518439],[-178.259635,71.510688],[-178.304862,71.513129],[-178.32319,71.518365]],[[-178.32319,71.518365],[-178.341544,71.517524],[-178.32244,71.505439],[-178.215323,71.478034],[-178.193473,71.47663],[-178.147757,71.485175],[-178.124442,71.481879],[-178.005729,71.448615],[-178.017203,71.441413],[-178.054191,71.428778],[-178.047049,71.425727],[-178.033439,71.417792],[-178.026236,71.415107],[-178.030082,71.413459],[-178.039908,71.40766],[-177.970878,71.39643],[-177.779837,71.333197],[-177.718375,71.305243],[-177.706412,71.3039],[-177.68212,71.304877],[-177.670279,71.301825],[-177.655387,71.293158],[-177.587577,71.285956],[-177.548575,71.294867],[-177.531119,71.296332],[-177.51409,71.293402],[-177.498649,71.284735],[-177.506217,71.268622],[-177.486991,71.258734],[-177.459708,71.249884],[-177.443412,71.237006],[-177.445914,71.222663],[-177.457755,71.209357],[-177.507804,71.173774],[-177.581168,71.147589],[-177.637626,71.117011],[-177.684134,71.110968],[-177.751883,71.092963],[-177.819266,71.084662],[-177.877677,71.052558],[-177.930472,71.041449],[-178.206595,71.038398],[-178.310111,71.013617],[-178.875907,70.981024],[-178.980277,70.95069],[-179.342093,70.908026],[-179.336234,70.911078],[-179.322257,70.921698],[-179.364493,70.930243],[-179.457511,70.915534],[-179.501212,70.919684],[-179.666007,70.965461],[-179.853385,70.979438],[-179.888785,70.993598],[-179.907523,70.996772],[-179.999989,70.992011],[-179.999989,71.024848],[-179.999989,71.058661],[-179.999989,71.126166],[-179.999989,71.187018],[-179.999989,71.224189],[-179.999989,71.27497],[-179.999989,71.312079],[-179.999989,71.356024],[-179.999989,71.410041],[-179.999989,71.487799],[-179.999989,71.536689],[-179.862845,71.538642],[-179.912223,71.555854],[-179.900748,71.558478],[-179.798819,71.569098],[-179.757438,71.583197],[-179.735953,71.586432],[-179.715445,71.583258],[-179.697501,71.577338],[-179.678702,71.573676],[-179.610831,71.585211],[-179.372062,71.569098],[-179.326774,71.555487],[-179.306815,71.557563],[-179.287162,71.562934],[-179.24285,71.569098],[-179.204642,71.583197],[-179.074576,71.600043],[-178.395438,71.539008],[-178.32319,71.518365]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[-178.32319,71.518365],[-178.321586,71.518439],[-178.259635,71.510688],[-178.304862,71.513129],[-178.32319,71.518365]]],[[[-178.32319,71.518365],[-178.341544,71.517524],[-178.32244,71.505439],[-178.215323,71.478034],[-178.193473,71.47663],[-178.147757,71.485175],[-178.124442,71.481879],[-178.005729,71.448615],[-178.017203,71.441413],[-178.054191,71.428778],[-178.047049,71.425727],[-178.033439,71.417792],[-178.026236,71.415107],[-178.030082,71.413459],[-178.039908,71.40766],[-177.970878,71.39643],[-177.779837,71.333197],[-177.718375,71.305243],[-177.706412,71.3039],[-177.68212,71.304877],[-177.670279,71.301825],[-177.655387,71.293158],[-177.587577,71.285956],[-177.548575,71.294867],[-177.531119,71.296332],[-177.51409,71.293402],[-177.498649,71.284735],[-177.506217,71.268622],[-177.486991,71.258734],[-177.459708,71.249884],[-177.443412,71.237006],[-177.445914,71.222663],[-177.457755,71.209357],[-177.507804,71.173774],[-177.581168,71.147589],[-177.637626,71.117011],[-177.684134,71.110968],[-177.751883,71.092963],[-177.819266,71.084662],[-177.877677,71.052558],[-177.930472,71.041449],[-178.206595,71.038398],[-178.310111,71.013617],[-178.875907,70.981024],[-178.980277,70.95069],[-179.342093,70.908026],[-179.336234,70.911078],[-179.322257,70.921698],[-179.364493,70.930243],[-179.457511,70.915534],[-179.501212,70.919684],[-179.666007,70.965461],[-179.853385,70.979438],[-179.888785,70.993598],[-179.907523,70.996772],[-179.999989,70.992011],[-179.999989,71.024848],[-179.999989,71.058661],[-179.999989,71.126166],[-179.999989,71.187018],[-179.999989,71.224189],[-179.999989,71.27497],[-179.999989,71.312079],[-179.999989,71.356024],[-179.999989,71.410041],[-179.999989,71.487799],[-179.999989,71.536689],[-179.862845,71.538642],[-179.912223,71.555854],[-179.900748,71.558478],[-179.798819,71.569098],[-179.757438,71.583197],[-179.735953,71.586432],[-179.715445,71.583258],[-179.697501,71.577338],[-179.678702,71.573676],[-179.610831,71.585211],[-179.372062,71.569098],[-179.326774,71.555487],[-179.306815,71.557563],[-179.287162,71.562934],[-179.24285,71.569098],[-179.204642,71.583197],[-179.074576,71.600043],[-178.395438,71.539008],[-178.32319,71.518365]]]]}']
]
wkbs = [
[ 0, "Point EMPTY", '010400000000000000'],
[ 0, "MULTIPOINT EMPTY", '010400000000000000'],
@ -64,21 +81,6 @@ wkbs = [
[ 0, "0000", '0104' ],
]
geojson = [
[1,'{"type":"Point","coordinates":[30,10]}'],
[1,'{"type":"Point","coordinates":[30.0,10.0]}'],
[1,'{"type":"Point","coordinates":[30.1,10.1]}'],
[1,'{"type":"LineString","coordinates":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}'],
[1,'{"type":"Polygon","coordinates":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}'],
[1,'{"type":"Polygon","coordinates":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}'],
[4,'{"type":"MultiPoint","coordinates":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}'],
[2,'{"type":"MultiLineString","coordinates":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}'],
[3,'{"type":"GeometryCollection","geometries":[{"type":"Polygon","coordinates":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{"type":"Point","coordinates":[2.0,3.0]},{"type":"LineString","coordinates":[[2.0,3.0],[3.0,4.0]]}]}'],
[1,'{"type":"Polygon","coordinates":[[[-178.32319,71.518365],[-178.321586,71.518439],[-178.259635,71.510688],[-178.304862,71.513129],[-178.32319,71.518365]],[[-178.32319,71.518365],[-178.341544,71.517524],[-178.32244,71.505439],[-178.215323,71.478034],[-178.193473,71.47663],[-178.147757,71.485175],[-178.124442,71.481879],[-178.005729,71.448615],[-178.017203,71.441413],[-178.054191,71.428778],[-178.047049,71.425727],[-178.033439,71.417792],[-178.026236,71.415107],[-178.030082,71.413459],[-178.039908,71.40766],[-177.970878,71.39643],[-177.779837,71.333197],[-177.718375,71.305243],[-177.706412,71.3039],[-177.68212,71.304877],[-177.670279,71.301825],[-177.655387,71.293158],[-177.587577,71.285956],[-177.548575,71.294867],[-177.531119,71.296332],[-177.51409,71.293402],[-177.498649,71.284735],[-177.506217,71.268622],[-177.486991,71.258734],[-177.459708,71.249884],[-177.443412,71.237006],[-177.445914,71.222663],[-177.457755,71.209357],[-177.507804,71.173774],[-177.581168,71.147589],[-177.637626,71.117011],[-177.684134,71.110968],[-177.751883,71.092963],[-177.819266,71.084662],[-177.877677,71.052558],[-177.930472,71.041449],[-178.206595,71.038398],[-178.310111,71.013617],[-178.875907,70.981024],[-178.980277,70.95069],[-179.342093,70.908026],[-179.336234,70.911078],[-179.322257,70.921698],[-179.364493,70.930243],[-179.457511,70.915534],[-179.501212,70.919684],[-179.666007,70.965461],[-179.853385,70.979438],[-179.888785,70.993598],[-179.907523,70.996772],[-179.999989,70.992011],[-179.999989,71.024848],[-179.999989,71.058661],[-179.999989,71.126166],[-179.999989,71.187018],[-179.999989,71.224189],[-179.999989,71.27497],[-179.999989,71.312079],[-179.999989,71.356024],[-179.999989,71.410041],[-179.999989,71.487799],[-179.999989,71.536689],[-179.862845,71.538642],[-179.912223,71.555854],[-179.900748,71.558478],[-179.798819,71.569098],[-179.757438,71.583197],[-179.735953,71.586432],[-179.715445,71.583258],[-179.697501,71.577338],[-179.678702,71.573676],[-179.610831,71.585211],[-179.372062,71.569098],[-179.326774,71.555487],[-179.306815,71.557563],[-179.287162,71.562934],[-179.24285,71.569098],[-179.204642,71.583197],[-179.074576,71.600043],[-178.395438,71.539008],[-178.32319,71.518365]]]}'],
[2,'{"type":"MultiPolygon","coordinates":[[[[-178.32319,71.518365],[-178.321586,71.518439],[-178.259635,71.510688],[-178.304862,71.513129],[-178.32319,71.518365]]],[[[-178.32319,71.518365],[-178.341544,71.517524],[-178.32244,71.505439],[-178.215323,71.478034],[-178.193473,71.47663],[-178.147757,71.485175],[-178.124442,71.481879],[-178.005729,71.448615],[-178.017203,71.441413],[-178.054191,71.428778],[-178.047049,71.425727],[-178.033439,71.417792],[-178.026236,71.415107],[-178.030082,71.413459],[-178.039908,71.40766],[-177.970878,71.39643],[-177.779837,71.333197],[-177.718375,71.305243],[-177.706412,71.3039],[-177.68212,71.304877],[-177.670279,71.301825],[-177.655387,71.293158],[-177.587577,71.285956],[-177.548575,71.294867],[-177.531119,71.296332],[-177.51409,71.293402],[-177.498649,71.284735],[-177.506217,71.268622],[-177.486991,71.258734],[-177.459708,71.249884],[-177.443412,71.237006],[-177.445914,71.222663],[-177.457755,71.209357],[-177.507804,71.173774],[-177.581168,71.147589],[-177.637626,71.117011],[-177.684134,71.110968],[-177.751883,71.092963],[-177.819266,71.084662],[-177.877677,71.052558],[-177.930472,71.041449],[-178.206595,71.038398],[-178.310111,71.013617],[-178.875907,70.981024],[-178.980277,70.95069],[-179.342093,70.908026],[-179.336234,70.911078],[-179.322257,70.921698],[-179.364493,70.930243],[-179.457511,70.915534],[-179.501212,70.919684],[-179.666007,70.965461],[-179.853385,70.979438],[-179.888785,70.993598],[-179.907523,70.996772],[-179.999989,70.992011],[-179.999989,71.024848],[-179.999989,71.058661],[-179.999989,71.126166],[-179.999989,71.187018],[-179.999989,71.224189],[-179.999989,71.27497],[-179.999989,71.312079],[-179.999989,71.356024],[-179.999989,71.410041],[-179.999989,71.487799],[-179.999989,71.536689],[-179.862845,71.538642],[-179.912223,71.555854],[-179.900748,71.558478],[-179.798819,71.569098],[-179.757438,71.583197],[-179.735953,71.586432],[-179.715445,71.583258],[-179.697501,71.577338],[-179.678702,71.573676],[-179.610831,71.585211],[-179.372062,71.569098],[-179.326774,71.555487],[-179.306815,71.557563],[-179.287162,71.562934],[-179.24285,71.569098],[-179.204642,71.583197],[-179.074576,71.600043],[-178.395438,71.539008],[-178.32319,71.518365]]]]}']]
def test_path_geo_interface():
path = mapnik.Path()
path.add_wkt('POINT(0 0)')
@ -180,6 +182,17 @@ def compare_wkt_from_wkt(wkt,num=None):
for idx,path in enumerate(paths2):
eq_(f.geometries()[idx].to_wkb(mapnik.wkbByteOrder.XDR),path.to_wkb(mapnik.wkbByteOrder.XDR))
def compare_wkt_to_geojson(idx,wkt,num=None):
paths = reader.read(wkt);
# ensure both have same result
if num:
eq_(len(paths),num)
gj = paths.to_geojson()
eq_(len(gj) > 1,True)
a = json.loads(gj)
e = json.loads(geojson[idx][1])
eq_(a,e)
def test_wkt_simple():
for wkt in wkts:
try:
@ -194,6 +207,15 @@ def test_wkb_simple():
except RuntimeError, e:
raise RuntimeError('%s %s' % (e, wkt))
def test_wkt_to_geojson():
idx = -1
for wkt in wkts:
try:
idx += 1
compare_wkt_to_geojson(idx,wkt[1],wkt[0])
except RuntimeError, e:
raise RuntimeError('%s %s' % (e, wkt))
@raises(IndexError)
def test_geometry_index_error():
wkt = 'Point (0 0)'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -152,6 +152,18 @@ INSERT INTO test10(gid, bool_field, geom) values (2, FALSE, ST_MakePoint(1,1));
INSERT INTO test10(gid, bool_field, geom) values (3, null, ST_MakePoint(1,1));
'''
insert_table_11 = """
CREATE TABLE test11(gid serial PRIMARY KEY, label varchar(40), geom geometry);
INSERT INTO test11(label,geom) values ('label_1',GeomFromEWKT('SRID=4326;POINT(0 0)'));
INSERT INTO test11(label,geom) values ('label_2',GeomFromEWKT('SRID=4326;POINT(-2 2)'));
INSERT INTO test11(label,geom) values ('label_3',GeomFromEWKT('SRID=4326;MULTIPOINT(2 1,1 2)'));
INSERT INTO test11(label,geom) values ('label_4',GeomFromEWKT('SRID=4326;LINESTRING(0 0,1 1,1 2)'));
INSERT INTO test11(label,geom) values ('label_5',GeomFromEWKT('SRID=4326;MULTILINESTRING((1 0,0 1,3 2),(3 2,5 4))'));
INSERT INTO test11(label,geom) values ('label_6',GeomFromEWKT('SRID=4326;POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'));
INSERT INTO test11(label,geom) values ('label_7',GeomFromEWKT('SRID=4326;MULTIPOLYGON(((1 1,3 1,3 3,1 3,1 1),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'));
INSERT INTO test11(label,geom) values ('label_8',GeomFromEWKT('SRID=4326;GEOMETRYCOLLECTION(POLYGON((1 1, 2 1, 2 2, 1 2,1 1)),POINT(2 3),LINESTRING(2 3,3 4))'));
"""
def postgis_setup():
call('dropdb %s' % MAPNIK_TEST_DBNAME,silent=True)
@ -169,6 +181,7 @@ def postgis_setup():
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_8),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_9),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_10),silent=False)
call('''psql -q %s -c "%s"''' % (MAPNIK_TEST_DBNAME,insert_table_11),silent=False)
def postgis_takedown():
pass
@ -475,16 +488,20 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
max_size=20,
geometry_field='geom')
fs = ds.all_features()
eq_(len(fs),8)
def test_threaded_create(NUM_THREADS=100):
# run one to start before thread loop
# to ensure that a throw stops the test
# from running all threads
create_ds()
runs = 0
for i in range(NUM_THREADS):
t = threading.Thread(target=create_ds)
t.start()
t.join()
runs +=1
eq_(runs,NUM_THREADS)
def create_ds_and_error():
try:
@ -492,7 +509,8 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
table='asdfasdfasdfasdfasdf',
max_size=20)
fs = ds.all_features()
except: pass
except Exception, e:
eq_('in executeQuery' in str(e),True)
def test_threaded_create2(NUM_THREADS=10):
for i in range(NUM_THREADS):
@ -656,6 +674,33 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
fs = ds.featureset()
feat = fs.next() ## should throw since key_field is null: StopIteration: No more features.
def test_psql_error_should_not_break_connection_pool():
# Bad request, will trigger an error when returning result
ds_bad = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table="""(SELECT geom as geom,label::int from test11) as failure_table""",
max_async_connection=5,geometry_field='geom',srid=4326)
# Good request
ds_good = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table="test",
max_async_connection=5,geometry_field='geom',srid=4326)
# This will/should trigger a PSQL error
failed = False
try:
fs = ds_bad.featureset()
for feature in fs:
pass
except RuntimeError:
failed = True
eq_(failed,True)
# Should be ok
fs = ds_good.featureset()
count = 0
for feature in fs:
count += 1
eq_(count,8)
atexit.register(postgis_takedown)
if __name__ == "__main__":

View file

@ -0,0 +1,7 @@
i|wkt
1|LINESTRING(10 0, 20 0)
1|LINESTRING(10 10, 20 10)
1|LINESTRING(15 5, 20 5)
1|LINESTRING(15 5, 20 5)
1|LINESTRING(10 5, 15 5)
1|LINESTRING(10 5, 15 5)
1 i wkt
2 1 LINESTRING(10 0, 20 0)
3 1 LINESTRING(10 10, 20 10)
4 1 LINESTRING(15 5, 20 5)
5 1 LINESTRING(15 5, 20 5)
6 1 LINESTRING(10 5, 15 5)
7 1 LINESTRING(10 5, 15 5)

View file

@ -0,0 +1,138 @@
{
"keys": [
"",
"1",
"2"
],
"data": {},
"grid": [
" ",
" ",
" ",
" ! ",
" !!! ",
" !!!!! ",
" !!!!!!! ",
" !!!!!!!!! ",
" !!!!!!!!!!! ",
" !!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ## !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" #### # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ###### ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ######## ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########## ####### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ############ ######### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ############## ########### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"############################ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########################## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ############## ########### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ############ ######### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ########## ####### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ######## ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ###### ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" #### # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" ## !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!! ",
" !!!!!!!!!!! ",
" !!!!!!!!! ",
" !!!!!!! ",
" !!!!! ",
" !!! ",
" ! ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" !! ! ",
" !!!! !!! ",
" !!!!!! !!!!! ",
" !!!!!!!! !!!!!!! ",
" !!!!!!!!!! !!!!!!!!! ",
" !!!!!!!!!!!! !!!!!!!!!!! ",
" !!!!!!!!!!!!!! !!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! ",
" !!!!!!!!!!!!!! !!!!!!!!!!!!!! ",
" !!!!!!!!!!!! !!!!!!!!!!!! ",
" !!!!!!!!!! !!!!!!!!!! ",
" !!!!!!!! !!!!!!!! ",
" !!!!!! !!!!!! ",
" !!!! !!!! ",
" !! !! ",
" ",
" ",
" "
]
}

View file

@ -0,0 +1,140 @@
{
"keys": [
"2",
"",
"6",
"4",
"1"
],
"data": {},
"grid": [
" ",
" ",
" ",
" ",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"###################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"####################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"####################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"####################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"####################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"####################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"###################################################################$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%",
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
]
}

View file

@ -0,0 +1,144 @@
{
"keys": [
"",
"4",
"3",
"2",
"1",
"8",
"7",
"6",
"5"
],
"data": {},
"grid": [
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" !!!!!!!! ##### ##### $$$$$$$$$$ %%%%%%%%% ",
" !! !! ### ## $$ $$ %% %% ",
" !! ! # # $$ $$ %% %% ",
" !! !! # # $$ $ % % ",
" ! !! # # $ $ % % ",
" ! ! # # $ $ % %",
"! ! # $ $ % ",
"! ! # $ $ % ",
"&&&&&&&&&&&&&&&&&&&&&&&&&& ''''''''''''''''''''''# (((((((((((((((((((((((((( )))))))))))))))))))))))))",
"! ! $ $ % ",
"! ! # # $ $ % %",
" ! ! ## # $ $ %% %",
" !! ! # # $ $ % % ",
" !! !! ## ## $ $ %% % ",
" ! ! ## # $$ $$ %% %% ",
" !!! !!! ### ### $$$ $$ %%% %% ",
" !!!!!!!!!! ##### $$$$$$$$ %%%%%%%% ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,21 @@
<Map srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
background-color="green"
background-image="../../data/images/checker.jpg"
background-image-opacity=".5"
background-image-comp-op="soft-light"
>
<Style name="ellipse">
<Rule>
<BuildingSymbolizer fill="white" fill-opacity=".5" />
</Rule>
</Style>
<Layer name="layer" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<StyleName>ellipse</StyleName>
<Datasource>
<Parameter name="type">csv</Parameter>
<Parameter name="file">../data/marker-multi-policy.csv</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -0,0 +1,19 @@
<Map
background-color="#808080"
srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<Style name="My Style" comp-op="src-over">
<Rule>
<LineSymbolizer stroke-width="30" stroke="rgba(255,255,255,1)" stroke-linecap="round" stroke-linejoin="round" comp-op="dst-over" />
</Rule>
</Style>
<Layer name="layer" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">csv</Parameter>
<Parameter name="file">../data/crossing-lines.csv</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -0,0 +1,21 @@
<Map
background-color="green"
background-image="../../data/images/checker.jpg"
background-image-opacity=".5"
background-image-comp-op="soft-light"
srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<Layer name="layer" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">csv</Parameter>
<Parameter name="file">../data/line-offset.csv</Parameter>
</Datasource>
</Layer>
<Style name="My Style">
<Rule>
<LinePatternSymbolizer file="../../data/raster/white-alpha.png" comp-op="difference"/>
</Rule>
</Style>
</Map>

View file

@ -170,7 +170,10 @@ files = {
'style-level-compositing-tiled-0,1':{'sizes':[(512,512)],'bbox':merc_z1_bboxes['0,1']},
'style-level-compositing-tiled-1,1':{'sizes':[(512,512)],'bbox':merc_z1_bboxes['1,1']},
'marker-path-expression':{},
'map-background-image-compositing':{'sizes':[(512,512)]}
'map-background-image-compositing':{'sizes':[(512,512)]},
'building-symbolizer-opacity':{'sizes':[(512,512)]},
'line-pattern-symbolizer-opacity':{'sizes':[(512,512)]},
'dst-over-compositing':{'sizes':[(512,512)]},
}
class Reporting: