Merge branch 'master' of github.com:mapnik/mapnik

This commit is contained in:
kunitoki 2011-10-28 18:29:06 +02:00
commit de307ad564
42 changed files with 408 additions and 191 deletions

View file

@ -3,7 +3,7 @@
----------------
Mapnik Changelog
----------------
A simple log of core changes affecting Mapnik usage.
Developers: Please commit along with changes.
@ -18,6 +18,7 @@ Mapnik 2.1.0
- Fixed bug in shield line placement when dx/dy are used to shift the label relative to the placement point (Matt Amos) (#908)
- Added <layer_by_sql> parameter in OGR plugin to select a layer by SQL query (besides name or index): see http://www.gdal.org/ogr/ogr_sql.html for specifications (kunitoki) (#472)
Mapnik 2.0.0
@ -45,7 +46,7 @@ Mapnik 2.0.0
- Added map.base parameter that can be set to control where files with relative paths should be interpreted
from when a map is loaded from a string or saved to a string. It defaults to an empty string which means
that the base path will be the current working directory of the mapnik process. When a stylesheet is read
from a file that files directory is used. And a custom value can still be passed as an argument to
from a file that files directory is used. And a custom value can still be passed as an argument to
load_map_from_string().
- Added python function 'render_grid' to allow conversion of grid buffer to python object containing list of grid
@ -112,7 +113,7 @@ Mapnik 2.0.0
Mapnik 0.7.2 Release
--------------------
- Added forward compatibility for Mapnik 2.0 XML syntax (https://trac.mapnik.org/wiki/Mapnik2/Changes)
- Build fixes to ensure boost_threads are not used unless THREADING=multi build option is used
@ -167,9 +168,9 @@ Mapnik 0.7.0 Release
* Use the gdaladdo utility to add overviews to existing GDAL datasets
- PostGIS: Added an optional 'geometry_table' parameter. The 'geometry_table' used by Mapnik to look up
- PostGIS: Added an optional 'geometry_table' parameter. The 'geometry_table' used by Mapnik to look up
metadata in the geometry_columns and calculate extents (when the 'geometry_field' and 'srid' parameters
are not supplied). If 'geometry_table' is not specified Mapnik will attempt to determine the name of the
are not supplied). If 'geometry_table' is not specified Mapnik will attempt to determine the name of the
table to query based on parsing the 'table' parameter, which may fail for complex queries with more than
one 'from' keyword. Using this parameter should allow for existing metadata and table indexes to be used
while opening the door to much more complicated subqueries being passed to the 'table' parameter without
@ -191,7 +192,7 @@ Mapnik 0.7.0 Release
query to be used by indexes. (#415)
* Pass the bbox token inside a subquery like: !bbox!
* Valid Usages include:
<Parameter name="table">
@ -210,7 +211,7 @@ Mapnik 0.7.0 Release
- PostGIS Plugin: Added support for quoted table names (r1454) (#393)
- PostGIS: Add a 'persist_connection' option (default true), that when false will release
- PostGIS: Add a 'persist_connection' option (default true), that when false will release
the idle psql connection after datasource goes out of scope (r1337) (#433,#434)
- PostGIS: Added support for BigInt (int8) postgres type (384)
@ -234,14 +235,14 @@ Mapnik 0.7.0 Release
- PolygonSymbolizer: Added 'gamma' attribute to allow for dilation of polygon edges - a solution
to gap artifacts or "ghost lines" between adjacent polygons and allows for slight sharpening of
the edges of non overlapping polygons. Accepts any values but 0-1 is the recommended range.
- TextSymbolizer: Large set of new attributes: 'text_transform', 'line_spacing', 'character_spacing',
- TextSymbolizer: Large set of new attributes: 'text_transform', 'line_spacing', 'character_spacing',
'wrap_character', 'wrap_before', 'horizontal_alignment', 'justify_alignment', and 'opacity'.
* More details at changesets: r1254 and r1341
- SheildSymbolizer: Added special new attributes: 'unlock_image', 'VERTEX' placement, 'no_text' and many
attributes previously only supported in the TextSymbolizer: 'allow_overlap', 'vertical_alignment',
attributes previously only supported in the TextSymbolizer: 'allow_overlap', 'vertical_alignment',
'horizontal_alignment', 'justify_alignment', 'wrap_width', 'wrap_character', 'wrap_before', 'text_transform',
'line_spacing', 'character_spacing', and 'opacity'.
@ -281,7 +282,7 @@ Mapnik 0.7.0 Release
- Python: Ensured mapnik::config_errors now throw RuntimeError exception instead of UserWarning exception (#442)
- Filters: Added support for '!=' as an alias to '<>' for not-equals filters (avoids &lt;&gt;) (r1326) (#427)
- Filters: Added support for '!=' as an alias to '<>' for not-equals filters (avoids &lt;&gt;) (r1326) (#427)
- SCons: Improved boost auto-detection (r1255,r1279)
@ -303,7 +304,7 @@ Mapnik 0.6.1 Release
(Packaged from r1247)
- Plugins: expose list of registered plugins as a 'plugin_names()' method of DatasourceCache (r1180)
- Plugins: expose list of registered plugins as a 'plugin_names()' method of DatasourceCache (r1180)
- XML: Fixed serialization and parsing bugs related to handling of integers and Enums (#328,#353)

View file

@ -425,7 +425,6 @@ pickle_store = [# Scons internal variables
'PYTHON_INSTALL_LOCATION',
'PYTHON_SYS_PREFIX',
'COLOR_PRINT',
'HAS_BOOST_SYSTEM',
'SVN_REVISION',
'HAS_CAIRO',
'HAS_PYCAIRO',
@ -1126,18 +1125,14 @@ if not preconfigured:
conf.FindBoost(BOOST_SEARCH_PREFIXES,thread_flag)
# boost system is used in boost 1.35 and greater
env['HAS_BOOST_SYSTEM'] = False
boost_lib_version_from_header = conf.GetBoostLibVersion()
if boost_lib_version_from_header:
boost_version_from_header = int(boost_lib_version_from_header.split('_')[1])
if boost_version_from_header >= 35:
env['HAS_BOOST_SYSTEM'] = True
# The other required boost headers.
BOOST_LIBSHEADERS = [
['system', 'boost/system/system_error.hpp', env['HAS_BOOST_SYSTEM']],
['system', 'boost/system/system_error.hpp', True],
['filesystem', 'boost/filesystem/operations.hpp', True],
['regex', 'boost/regex.hpp', True],
['program_options', 'boost/program_options.hpp', False]

View file

@ -736,7 +736,7 @@ namespace agg
template<class VertexSource>
void join_path(VertexSource& vs, unsigned path_id = 0)
{
double x, y;
double x=0.0, y=0.0;
unsigned cmd;
vs.rewind(path_id);
cmd = vs.vertex(&x, &y);

View file

@ -323,68 +323,65 @@ namespace agg
int y2;
int lprev;
if(close_polygon)
if(close_polygon && (m_src_vertices.size() >= 3))
{
if(m_src_vertices.size() >= 3)
dv.idx = 2;
v = &m_src_vertices[m_src_vertices.size() - 1];
x1 = v->x;
y1 = v->y;
lprev = v->len;
v = &m_src_vertices[0];
x2 = v->x;
y2 = v->y;
dv.lcurr = v->len;
line_parameters prev(x1, y1, x2, y2, lprev);
v = &m_src_vertices[1];
dv.x1 = v->x;
dv.y1 = v->y;
dv.lnext = v->len;
dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
v = &m_src_vertices[dv.idx];
dv.x2 = v->x;
dv.y2 = v->y;
dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
dv.xb1 = 0;
dv.yb1 = 0;
dv.xb2 = 0;
dv.yb2 = 0;
switch(m_line_join)
{
dv.idx = 2;
case outline_no_join:
dv.flags = 3;
break;
v = &m_src_vertices[m_src_vertices.size() - 1];
x1 = v->x;
y1 = v->y;
lprev = v->len;
case outline_miter_join:
case outline_round_join:
dv.flags =
(prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
break;
v = &m_src_vertices[0];
x2 = v->x;
y2 = v->y;
dv.lcurr = v->len;
line_parameters prev(x1, y1, x2, y2, lprev);
v = &m_src_vertices[1];
dv.x1 = v->x;
dv.y1 = v->y;
dv.lnext = v->len;
dv.curr = line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
v = &m_src_vertices[dv.idx];
dv.x2 = v->x;
dv.y2 = v->y;
dv.next = line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
dv.xb1 = 0;
dv.yb1 = 0;
dv.xb2 = 0;
dv.yb2 = 0;
switch(m_line_join)
{
case outline_no_join:
dv.flags = 3;
break;
case outline_miter_join:
case outline_round_join:
dv.flags =
(prev.diagonal_quadrant() == dv.curr.diagonal_quadrant()) |
((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant()) << 1);
break;
case outline_miter_accurate_join:
dv.flags = 0;
break;
}
if((dv.flags & 1) == 0 && m_line_join != outline_round_join)
{
bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
}
if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
{
bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
}
draw(dv, 0, m_src_vertices.size());
case outline_miter_accurate_join:
dv.flags = 0;
break;
}
if((dv.flags & 1) == 0 && m_line_join != outline_round_join)
{
bisectrix(prev, dv.curr, &dv.xb1, &dv.yb1);
}
if((dv.flags & 2) == 0 && m_line_join != outline_round_join)
{
bisectrix(dv.curr, dv.next, &dv.xb2, &dv.yb2);
}
draw(dv, 0, m_src_vertices.size());
}
else
{

View file

@ -78,8 +78,8 @@ namespace agg
//--------------------------------------------------------------------
void rounded_rect::normalize_radius()
{
double dx = fabs(m_y2 - m_y1);
double dy = fabs(m_x2 - m_x1);
double dx = fabs(m_x2 - m_x1);
double dy = fabs(m_y2 - m_y1);
double k = 1.0;
double t;

View file

@ -15,11 +15,33 @@ Look through the code to get an idea, and do not hesitate to ask questions.
Also read the design philosophy page for the motivations that lead to code decisions.
Templates are good, within reason. We seek to use templates were possible for flexible code, but not in cases where functional
patterns would be just as concise and clear.
In general we use Boost, it makes more possible in C++. It is a big build time dependency (as in time to compile against and # of headers) but ultimately compiles to small object code and is very fast (particularly spirit). It also has no dependencies itself (it's really an extension to the C++ language) so requiring it is much easier than requiring a hard dependency that itself has other dependencies. This is a big reason that we prefer AGG to Cairo as our primary renderer. Also AGG, besides producing the best visual output, strikes an excellent balance between speed and thread safety by using very lightweight objects. Cairo not so much.
You will also notice that we don't use many of the standard geo libraries when we could. For instance we don't use GDAL, OGR, or GEOS anywhere in core, and only leverage them in optional plugins. We feel we can often write code that is faster and more thread safe than these libraries but that still does the job. If this ever changes we can adapt and start using these libraries or others as dependencies - nothing is nicer than standing on the shoulders of giants when it makes sense.
## Code commits best practices.
#### Big changes - awesome as pull requests
We love big, aggressive refactoring - but ideally in branches. Even if the changes should go directly into the mainline code and are stable, very big changes are useful to see as a group and branches are cheap. So, branch and commit then create a pull request against master so that other developers can take a quick look. This is a great way for informal code review when a full issue is not warrented.
#### Commits that fix issues should note the issue #
git commit plugins/input/ogr/ -m "implemented sql query in OGR plugin (closes #472)"
#### Commits that relate to issues should reference them:
git commit tests/python_tests/sqlite_test.py -m "more robust sqlite tests - refs #928"
#### Commits that add a new feature or fix should be added to the CHANGELOG
Ideally the CHANGELOG can be a very concise place to look for the most important recent development and should not read like a full commit log. So, some developers may prefer to weekly or monthly look back over their commits and summarize all at once with additions to the CHANGELOG. Other developers may prefer to add as they go.
## License
Mapnik is licensed LGPL, which means that you are a free to use the code in any of your applications whether they be open source or not. It also means that if you contribute code to Mapnik that others are free to continue using Mapnik in the same way, even with your new additions. If you choose to redistribute an application using Mapnik just make sure to provide any source code modifications you make back to the community. For the actual details see the full LGPL license in the COPYING doc.
@ -67,13 +89,19 @@ If you see bits of code around that do not follow these please don't hesitate to
#### Indentation is four spaces
#### Use C++ style casts
static_cast<int>(value); // yes
(int)value; // no
#### Shared pointers should be created with [boost::make_shared](http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/make_shared.html) where possible
#### Function definitions should not be separated from their arguments:
void foo(int a) { ... } // please
void foo(int a) // please
void foo (int a) { ... } // no
void foo (int a) // no
#### Separate arguments by a single space:
@ -87,7 +115,18 @@ If you see bits of code around that do not follow these please don't hesitate to
if(a==b) // no
#### Braces should ideally be on a separate line:
#### Braces should always be used:
if (!file)
{
throw mapnik::datasource_exception("not found"); // please
}
if (!file)
throw mapnik::datasource_exception("not found"); // no
#### Braces should be on a separate line:
if (a == b)
{

View file

@ -23,10 +23,15 @@
#ifndef MAPNIK_ATTRIBUTE_HPP
#define MAPNIK_ATTRIBUTE_HPP
// mapnik
#include <mapnik/value.hpp>
// stl
#include <string>
namespace mapnik {
static mapnik::value _null_value;
struct attribute
{
std::string name_;
@ -36,7 +41,13 @@ struct attribute
template <typename V ,typename F>
V value(F const& f) const
{
return f[name_];
typedef typename F::const_iterator const_iterator;
const_iterator itr = f.find(name_);
if (itr != f.end())
{
return itr->second;
}
return _null_value;
}
std::string const& name() const { return name_;}
};

View file

@ -223,11 +223,13 @@ struct expression_grammar : qi::grammar<Iterator, expr_node(), space_type>
| '(' >> expr [_val = _1 ] >> ')'
;
attr %= '[' >> +(char_ - ']') >> ']';
#if BOOST_VERSION > 104200
ustring %= '\'' >> no_skip[*~char_('\'')] >> '\'';
attr %= '[' >> no_skip[+~char_(']')] >> ']';
#else
ustring %= '\'' >> lexeme[*(char_-'\'')] >> '\'';
attr %= '[' >> lexeme[+(char_ - ']')] >> ']';
#endif
}

View file

@ -65,6 +65,7 @@ private:
std::map<std::string,value> props_;
public:
typedef std::map<std::string,value>::iterator iterator;
typedef std::map<std::string,value>::const_iterator const_iterator;
explicit feature(int id)
: properties(props_),
id_(id),
@ -145,7 +146,7 @@ public:
{
return props_;
}
iterator begin()
{
return props_.begin();
@ -155,12 +156,27 @@ public:
{
return props_.end();
}
const_iterator begin() const
{
return props_.begin();
}
const_iterator end() const
{
return props_.end();
}
const_iterator find(std::string const& key) const
{
return props_.find(key);
}
std::string to_string() const
{
std::stringstream ss;
ss << "feature (" << std::endl;
ss << " id:" << id_ << std::endl;
ss << "feature "
<< id_ << " (" << std::endl;
for (std::map<std::string,value>::const_iterator itr=props_.begin();
itr != props_.end();++itr)
{

View file

@ -119,7 +119,13 @@ public:
{
if (! FT_Set_Pixel_Sizes( face_, 0, size ))
return true;
return false;
}
bool set_character_sizes(float size)
{
if ( !FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0))
return true;
return false;
}
@ -184,6 +190,14 @@ public:
(*face)->set_pixel_sizes(size);
}
}
void set_character_sizes(float size)
{
for (std::vector<face_ptr>::iterator face = faces_.begin(); face != faces_.end(); ++face)
{
(*face)->set_character_sizes(size);
}
}
private:
std::vector<face_ptr> faces_;
std::map<unsigned, dimension_t> dimension_cache_;
@ -198,7 +212,7 @@ public:
void init(double radius)
{
FT_Stroker_Set(s_, (FT_Fixed) radius * (1<<6),
FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)),
FT_STROKER_LINECAP_ROUND,
FT_STROKER_LINEJOIN_ROUND,
0);
@ -332,11 +346,17 @@ struct text_renderer : private boost::noncopyable
halo_radius_(0.0),
opacity_(1.0) {}
void set_pixel_size(unsigned size)
{
faces_->set_pixel_sizes(size);
}
void set_character_size(float size)
{
faces_->set_character_sizes(size);
}
void set_fill(mapnik::color const& fill)
{
fill_=fill;

View file

@ -290,7 +290,10 @@ template MAPNIK_DECL std::string save_to_string<image_data_32>(image_data_32 con
rgba_palette const&);
template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
std::string const&,
std::string const&);
template MAPNIK_DECL std::string save_to_string<image_view<image_data_32> > (image_view<image_data_32> const&,
std::string const&,
rgba_palette const&);
#endif

View file

@ -47,11 +47,22 @@ struct placement;
class metawriter_property_map
{
public:
typedef std::map<std::string, UnicodeString> property_map;
typedef property_map::const_iterator const_iterator;
metawriter_property_map() {}
UnicodeString const& operator[](std::string const& key) const;
UnicodeString& operator[](std::string const& key) {return m_[key];}
std::map<std::string, UnicodeString>::const_iterator find(std::string const& key) const
{
return m_.find(key);
}
std::map<std::string, UnicodeString>::const_iterator end() const
{
return m_.end();
}
private:
std::map<std::string, UnicodeString> m_;
property_map m_;
UnicodeString not_found_;
};

View file

@ -38,11 +38,11 @@ struct MAPNIK_DECL shield_symbolizer : public text_symbolizer,
{
shield_symbolizer(expression_ptr name,
std::string const& face_name,
unsigned size,
float size,
color const& fill,
path_expression_ptr file);
shield_symbolizer(expression_ptr name,
unsigned size,
float size,
color const& fill,
path_expression_ptr file);

View file

@ -112,7 +112,7 @@ public:
/* NOTE: Values are public and non-virtual to avoid any performance problems. */
position displacement;
unsigned text_size;
float text_size;
horizontal_alignment_e halign;
justify_alignment_e jalign;
vertical_alignment_e valign;
@ -127,9 +127,9 @@ public:
text_size_(10), halign_(H_MIDDLE), jalign_(J_MIDDLE), valign_(V_MIDDLE) {}
virtual text_placement_info_ptr get_placement_info() const =0;
virtual void set_default_text_size(unsigned size) { text_size_ = size; }
unsigned get_default_text_size() const { return text_size_; }
virtual void set_default_text_size(float size) { text_size_ = size; }
float get_default_text_size() const { return text_size_; }
virtual void set_default_displacement(position const& displacement) { displacement_ = displacement;}
position const& get_default_displacement() { return displacement_; }
@ -144,7 +144,7 @@ public:
virtual ~text_placements() {}
protected:
unsigned text_size_;
float text_size_;
position displacement_;
horizontal_alignment_e halign_;
justify_alignment_e jalign_;

View file

@ -44,10 +44,10 @@ namespace mapnik
struct MAPNIK_DECL text_symbolizer : public symbolizer_base
{
text_symbolizer(expression_ptr name, std::string const& face_name,
unsigned size, color const& fill,
float size, color const& fill,
text_placements_ptr placements = boost::make_shared<text_placements_dummy>()
);
text_symbolizer(expression_ptr name, unsigned size, color const& fill,
text_symbolizer(expression_ptr name, float size, color const& fill,
text_placements_ptr placements = boost::make_shared<text_placements_dummy>()
);
text_symbolizer(text_symbolizer const& rhs);
@ -80,8 +80,8 @@ struct MAPNIK_DECL text_symbolizer : public symbolizer_base
void set_force_odd_labels(bool force);
double get_max_char_angle_delta() const; // maximum change in angle between adjacent characters
void set_max_char_angle_delta(double angle);
unsigned get_text_size() const;
void set_text_size(unsigned size);
float get_text_size() const;
void set_text_size(float size);
std::string const& get_face_name() const;
void set_face_name(std::string face_name);
font_set const& get_fontset() const;

View file

@ -59,9 +59,9 @@ void agg_renderer<T>::process(glyph_symbolizer const& sym,
}
// set font size
unsigned size = sym.eval_size(feature);
ren.set_pixel_size(size * scale_factor_);
faces->set_pixel_sizes(size * scale_factor_);
float size = sym.eval_size(feature);
ren.set_character_size(size * scale_factor_);
faces->set_character_sizes(size * scale_factor_);
// Get and render text path
//

View file

@ -129,7 +129,7 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
{
text_renderer<T> ren(pixmap_, faces, *strk);
ren.set_pixel_size(sym.get_text_size() * scale_factor_);
ren.set_character_size(sym.get_text_size() * scale_factor_);
ren.set_fill(sym.get_fill());
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);

View file

@ -103,12 +103,13 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'");
}
text_renderer<T> ren(pixmap_, faces, *strk);
ren.set_pixel_size(placement_options->text_size * scale_factor_);
ren.set_character_size(placement_options->text_size * scale_factor_);
ren.set_fill(fill);
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
ren.set_opacity(sym.get_text_opacity());
box2d<double> dims(0,0,width_,height_);
placement_finder<label_collision_detector4> finder(*detector_,dims);

View file

@ -53,9 +53,11 @@ ABI_VERSION = env['ABI_VERSION']
filesystem = 'boost_filesystem%s' % env['BOOST_APPEND']
regex = 'boost_regex%s' % env['BOOST_APPEND']
system = 'boost_system%s' % env['BOOST_APPEND']
# clear out and re-set libs for this env
lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','jpeg','proj',env['ICU_LIB_NAME'],filesystem,regex]
lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','jpeg','proj',env['ICU_LIB_NAME'],filesystem,system,regex]
if len(env['EXTRA_FREETYPE_LIBS']):
lib_env['LIBS'].extend(copy(env['EXTRA_FREETYPE_LIBS']))
@ -67,8 +69,6 @@ lib_env['LIBS'].append('xml2')
if env['THREADING'] == 'multi':
lib_env['LIBS'].append('boost_thread%s' % env['BOOST_APPEND'])
if env['HAS_BOOST_SYSTEM']:
lib_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND'])
if not env['RUNTIME_LINK'] == 'static':

View file

@ -1138,7 +1138,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym,
placement_finder<label_collision_detector4> finder(detector_);
faces->set_pixel_sizes(placement_options->text_size);
faces->set_character_sizes(placement_options->text_size);
faces->get_string_info(info);
int w = (*marker)->width();
@ -1466,7 +1466,7 @@ void cairo_renderer_base::process(glyph_symbolizer const& sym,
// set font size
unsigned size = sym.eval_size(feature);
faces->set_pixel_sizes(size);
faces->set_character_sizes(size);
// Get and render text path
//
@ -1563,7 +1563,7 @@ void cairo_renderer_base::process(text_symbolizer const& sym,
cairo_context context(context_);
string_info info(text);
faces->set_pixel_sizes(placement_options->text_size);
faces->set_character_sizes(placement_options->text_size);
faces->get_string_info(info);
placement_finder<label_collision_detector4> finder(detector_);

View file

@ -97,7 +97,7 @@ unsigned glyph_symbolizer::eval_size(Feature const& feature) const
#ifdef MAPNIK_DEBUG
std::clog << "size_result=" << result.to_string() << "\n";
#endif
unsigned size = static_cast<unsigned>(result.to_int());
float size = static_cast<float>(result.to_double());
#ifdef MAPNIK_DEBUG
std::clog << "size=" << size << "\n";
#endif

View file

@ -110,7 +110,7 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
{
text_renderer<T> ren(pixmap_, faces, *strk);
ren.set_pixel_size(sym.get_text_size() * scale_factor_ * (1.0/pixmap_.get_resolution()));
ren.set_character_size(sym.get_text_size() * scale_factor_ * (1.0/pixmap_.get_resolution()));
ren.set_fill(sym.get_fill());
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);

View file

@ -77,7 +77,7 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
throw config_error("Unable to find specified font face '" + sym.get_face_name() + "'");
}
text_renderer<T> ren(pixmap_, faces, *strk);
ren.set_pixel_size(placement_options->text_size * (scale_factor_ * (1.0/pixmap_.get_resolution())));
ren.set_character_size(placement_options->text_size * (scale_factor_ * (1.0/pixmap_.get_resolution())));
ren.set_fill(fill);
ren.set_halo_fill(sym.get_halo_fill());
ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);

View file

@ -1244,10 +1244,10 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
optional<std::string> fontset_name =
get_opt_attr<std::string>(sym, "fontset-name");
unsigned size = get_attr(sym, "size", 10U);
float size = get_attr(sym, "size", 10.0f);
color c = get_attr(sym, "fill", color(0,0,0));
text_symbolizer text_symbol = text_symbolizer(parse_expression(name, "utf8"), size, c, placement_finder);
optional<std::string> orientation = get_opt_attr<std::string>(sym, "orientation");
@ -1486,7 +1486,7 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
optional<std::string> fontset_name =
get_opt_attr<std::string>(sym, "fontset-name");
unsigned size = get_attr(sym, "size", 10U);
float size = get_attr(sym, "size", 10.0f);
color fill = get_attr(sym, "fill", color(0,0,0));
std::string image_file = get_attr<std::string>(sym, "file");

View file

@ -37,7 +37,7 @@ namespace mapnik
shield_symbolizer::shield_symbolizer(
expression_ptr name,
std::string const& face_name,
unsigned size,
float size,
color const& fill,
path_expression_ptr file)
: text_symbolizer(name, face_name, size, fill),
@ -50,7 +50,7 @@ shield_symbolizer::shield_symbolizer(
shield_symbolizer::shield_symbolizer(
expression_ptr name,
unsigned size,
float size,
color const& fill,
path_expression_ptr file)
: text_symbolizer(name, size, fill),

View file

@ -87,7 +87,7 @@ IMPLEMENT_ENUM( text_transform_e, text_transform_strings )
text_symbolizer::text_symbolizer(expression_ptr name, std::string const& face_name,
unsigned size, color const& fill,
float size, color const& fill,
text_placements_ptr placements)
: symbolizer_base(),
name_(name),
@ -120,7 +120,7 @@ text_symbolizer::text_symbolizer(expression_ptr name, std::string const& face_na
set_text_size(size);
}
text_symbolizer::text_symbolizer(expression_ptr name, unsigned size, color const& fill,
text_symbolizer::text_symbolizer(expression_ptr name, float size, color const& fill,
text_placements_ptr placements)
: symbolizer_base(),
name_(name),
@ -378,12 +378,12 @@ void text_symbolizer::set_max_char_angle_delta(double angle)
max_char_angle_delta_ = angle;
}
void text_symbolizer::set_text_size(unsigned size)
void text_symbolizer::set_text_size(float size)
{
placement_options_->set_default_text_size(size);
}
unsigned text_symbolizer::get_text_size() const
float text_symbolizer::get_text_size() const
{
return placement_options_->get_default_text_size();
}

View file

@ -67,7 +67,7 @@ public:
wkbGeometryCollectionZ=1007
};
wkb_reader(const char* wkb,unsigned size, wkbFormat format)
wkb_reader(const char* wkb, unsigned size, wkbFormat format)
: wkb_(wkb),
size_(size),
pos_(0),
@ -76,16 +76,16 @@ public:
// try to determine WKB format automatically
if (format_ == wkbAuto)
{
if (size >= 44
&& (unsigned char)(wkb_[0]) == (unsigned char)(0x00)
&& (unsigned char)(wkb_[38]) == (unsigned char)(0x7C))
{
format_ = wkbSpatiaLite;
}
else
{
format_ = wkbGeneric;
}
if (size >= 44
&& (unsigned char)(wkb_[0]) == (unsigned char)(0x00)
&& (unsigned char)(wkb_[38]) == (unsigned char)(0x7C))
{
format_ = wkbSpatiaLite;
}
else
{
format_ = wkbGeneric;
}
}
switch (format_)

View file

@ -10,13 +10,9 @@ system = 'boost_system%s' % env['BOOST_APPEND']
regex = 'boost_regex%s' % env['BOOST_APPEND']
libraries = [filesystem, 'mapnik2']
if env['PLATFORM'] == 'Darwin':
libraries.append(env['ICU_LIB_NAME'])
libraries.append(regex)
if env['HAS_BOOST_SYSTEM']:
libraries.append(system)
libraries.append(env['ICU_LIB_NAME'])
libraries.append(regex)
libraries.append(system)
for cpp_test in glob.glob('path_element_test.cpp'):
env.Program(cpp_test.replace('.cpp',''), [cpp_test], CPPPATH=headers, LIBS=libraries)

View file

@ -25,7 +25,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">multipolygon</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -3,7 +3,6 @@
<Datasource name="sqlite">
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
<Parameter name="multiple_geometries">true</Parameter>
</Datasource>

View file

@ -13,7 +13,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">lines</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>

View file

@ -37,7 +37,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>
<!--

View file

@ -1,4 +1,4 @@
<Map srs="+init=epsg:4326" minimum-version="0.7.2">
<Map srs="+init=epsg:4326" background-color="white" minimum-version="0.7.2">
<Style name="1">
<Rule>

View file

@ -23,7 +23,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -45,7 +45,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>

View file

@ -20,7 +20,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>

View file

@ -48,7 +48,6 @@
<Parameter name="type">sqlite</Parameter>
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -38,7 +38,6 @@
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
<Parameter name="geometry_field">geometry</Parameter>
<Parameter name="table">point</Parameter>
<Parameter name="wkb_format">spatialite</Parameter>
</Datasource>
</Layer>

Binary file not shown.

View file

@ -1,23 +1,24 @@
#encoding: utf8
import itertools
import unittest
from nose.tools import *
import mapnik2
from binascii import unhexlify
from utilities import Todo
class FeatureTest(unittest.TestCase):
def makeOne(self, *args, **kw):
from mapnik2 import Feature
return Feature(*args, **kw)
return mapnik2.Feature(*args, **kw)
def test_default_constructor(self):
f = self.makeOne(1)
self.failUnless(f is not None)
def test_python_extended_constructor(self):
from mapnik2 import Box2d
f = self.makeOne(1, 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))', foo="bar")
self.failUnlessEqual(f['foo'], 'bar')
self.failUnlessEqual(f.envelope(),Box2d(10.0,10.0,45.0,45.0))
self.failUnlessEqual(f.envelope(),mapnik2.Box2d(10.0,10.0,45.0,45.0))
def test_set_get_properties(self):
f = self.makeOne(1)
@ -33,13 +34,12 @@ class FeatureTest(unittest.TestCase):
test_val(v)
def test_add_wkt_geometry(self):
from mapnik2 import Box2d
def add_geom_wkt(wkt):
f = self.makeOne(1)
self.failUnlessEqual(len(f.geometries()), 0)
f.add_geometries_from_wkt(wkt)
self.failUnlessEqual(len(f.geometries()), 3)
e = Box2d()
e = mapnik2.Box2d()
self.failUnlessEqual(e.valid(), False)
for g in f.geometries():
if not e.valid():
@ -48,13 +48,13 @@ class FeatureTest(unittest.TestCase):
e +=g.envelope()
self.failUnlessEqual(e, f.envelope())
from binascii import unhexlify
def add_geom_wkb(wkb):
f = self.makeOne(1)
self.failUnlessEqual(len(f.geometries()), 0)
f.add_geometries_from_wkb(unhexlify(wkb))
self.failUnlessEqual(len(f.geometries()), 1)
e = Box2d()
e = mapnik2.Box2d()
self.failUnlessEqual(e.valid(), False)
for g in f.geometries():
if not e.valid():
@ -63,10 +63,44 @@ class FeatureTest(unittest.TestCase):
e +=g.envelope()
self.failUnlessEqual(e, f.envelope())
def run() :
add_geom_wkt('GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10),POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10)))')
add_geom_wkb('010300000001000000050000000000000000003e4000000000000024400000000000002440000000000000344000000000000034400000000000004440000000000000444000000000000044400000000000003e400000000000002440') # POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))
run()
def test_feature_expression_evaluation():
f = mapnik2.Feature(1)
f['name'] = 'a'
eq_(f['name'],u'a')
expr = mapnik2.Expression("[name]='a'")
evaluated = expr.evaluate(f)
eq_(evaluated,True)
num_attributes = len(f)
eq_(num_attributes,1)
eq_(f.id(),1)
# https://github.com/mapnik/mapnik/issues/933
def test_feature_expression_evaluation_missing_attr():
f = mapnik2.Feature(1)
f['name'] = u'a'
eq_(f['name'],u'a')
expr = mapnik2.Expression("[fielddoesnotexist]='a'")
evaluated = expr.evaluate(f)
eq_(evaluated,False)
num_attributes = len(f)
eq_(num_attributes,1)
eq_(f.id(),1)
# https://github.com/mapnik/mapnik/issues/934
def test_feature_expression_evaluation_attr_with_spaces():
f = mapnik2.Feature(1)
f['name with space'] = u'a'
eq_(f['name with space'],u'a')
expr = mapnik2.Expression("[name with space]='a'")
eq_(str(expr),"[name with space]='a'")
eq_(expr.evaluate(f),True)
if __name__ == "__main__":
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -10,10 +10,6 @@ def setup():
# from another directory we need to chdir()
os.chdir(execution_path('.'))
# Note that without an extent or a spatial index, a sqlite
# datasource will error on creation. We use this fact to test
# database attachdb and initdb options
def test_attachdb_with_relative_file():
# The point table and index is in the qgis_spatiallite.sqlite
# database. If either is not found, then this fails
@ -21,15 +17,24 @@ def test_attachdb_with_relative_file():
table='point',
attachdb='scratch@qgis_spatiallite.sqlite'
)
fs = ds.featureset()
feature = fs.next()
eq_(feature['pkuid'],1)
def test_attachdb_with_multiple_files():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
attachdb='scratch1@:memory:,scratch2@:memory:',
initdb='create table scratch1.attachedtest (the_geom);\n' +
'create virtual table scratch2.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax);\n' +
'insert into scratch2.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375)\n'
initdb='''
create table scratch1.attachedtest (the_geom);
create virtual table scratch2.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax);
insert into scratch2.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375);
'''
)
fs = ds.featureset()
feature = fs.next()
# the above should not throw but will result in no features
eq_(feature,None)
def test_attachdb_with_absolute_file():
# The point table and index is in the qgis_spatiallite.sqlite
@ -38,29 +43,88 @@ def test_attachdb_with_absolute_file():
table='point',
attachdb='scratch@qgis_spatiallite.sqlite'
)
fs = ds.featureset()
feature = fs.next()
eq_(feature['pkuid'],1)
def test_attachdb_with_index():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
attachdb='scratch@:memory:',
initdb='create table scratch.attachedtest (the_geom);\n' +
'create virtual table scratch.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax);\n' +
'insert into scratch.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375)\n'
initdb='''
create table scratch.attachedtest (the_geom);
create virtual table scratch.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax);
insert into scratch.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375);
'''
)
fs = ds.featureset()
feature = fs.next()
eq_(feature,None)
def test_attachdb_with_explicit_index():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='attachedtest',
index_table='myindex',
attachdb='scratch@:memory:',
initdb='create table scratch.attachedtest (the_geom);\n' +
'create virtual table scratch.myindex using rtree(pkid,xmin,xmax,ymin,ymax);\n' +
'insert into scratch.myindex values (1,-7799225.5,-7778571.0,1393264.125,1417719.375)\n'
initdb='''
create table scratch.attachedtest (the_geom);
create virtual table scratch.myindex using rtree(pkid,xmin,xmax,ymin,ymax);
insert into scratch.myindex values (1,-7799225.5,-7778571.0,1393264.125,1417719.375);
'''
)
fs = ds.featureset()
feature = fs.next()
eq_(feature,None)
def test_dequoting_of_subqueries():
# The point table and index is in the qgis_spatiallite.sqlite
# database. If either is not found, then this fails
def test_attachdb_with_sql_join():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select * from world_merc INNER JOIN business on world_merc.iso3 = business.ISO3 limit 100)',
attachdb='busines@business.sqlite'
)
fs = ds.featureset()
feature = fs.next()
eq_(feature.id(),1)
expected = {
1995:0,
1996:0,
1997:0,
1998:0,
1999:0,
2000:0,
2001:0,
2002:0,
2003:0,
2004:0,
2005:0,
2006:0,
2007:0,
2008:0,
2009:0,
2010:0,
# this appears to be sqlites way of
# automatically handling clashing column names
'ISO3:1':'ATG',
'OGC_FID':1,
'area':44,
'fips':u'AC',
'iso2':u'AG',
'iso3':u'ATG',
'lat':17.078,
'lon':-61.783,
'name':u'Antigua and Barbuda',
'pop2005':83039,
'region':19,
'subregion':29,
'un':28
}
for k,v in expected.items():
try:
eq_(feature[str(k)],v)
except:
#import pdb;pdb.set_trace()
print 'invalid key/v %s/%s for: %s' % (k,v,feature)
def test_subqueries():
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='world_merc',
)
@ -68,25 +132,65 @@ def test_dequoting_of_subqueries():
feature = fs.next()
eq_(feature['OGC_FID'],1)
eq_(feature['fips'],u'AC')
eq_(feature['iso2'],u'AG')
eq_(feature['iso3'],u'ATG')
eq_(feature['un'],28)
eq_(feature['name'],u'Antigua and Barbuda')
eq_(feature['area'],44)
eq_(feature['pop2005'],83039)
eq_(feature['region'],19)
eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078)
# TODO:
# select * from world_merc fails
# as rowid is dropped
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select *,rowid from world_merc)',
table='(select * from world_merc)',
)
fs = ds.featureset()
feature = fs.next()
eq_(feature['OGC_FID'],1)
eq_(feature['fips'],u'AC')
eq_(feature['iso2'],u'AG')
eq_(feature['iso3'],u'ATG')
eq_(feature['un'],28)
eq_(feature['name'],u'Antigua and Barbuda')
eq_(feature['area'],44)
eq_(feature['pop2005'],83039)
eq_(feature['region'],19)
eq_(feature['subregion'],29)
eq_(feature['lon'],-61.783)
eq_(feature['lat'],17.078)
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select OGC_FID,GEOMETRY as geom from world_merc)',
)
fs = ds.featureset()
feature = fs.next()
eq_(feature['OGC_FID'],1)
eq_(len(feature),1)
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select GEOMETRY,OGC_FID,fips from world_merc)',
)
fs = ds.featureset()
feature = fs.next()
print feature
eq_(feature['OGC_FID'],1)
eq_(feature['fips'],u'AC')
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select GEOMETRY,OGC_FID as rowid,fips from world_merc)',
table='(select GEOMETRY,rowid as aliased_id,fips from world_merc)',
key_field='aliased_id'
)
fs = ds.featureset()
feature = fs.next()
eq_(feature['aliased_id'],1)
eq_(feature['fips'],u'AC')
ds = mapnik2.SQLite(file='../data/sqlite/world.sqlite',
table='(select GEOMETRY,OGC_FID,OGC_FID as rowid,fips from world_merc)',
)
fs = ds.featureset()
feature = fs.next()
print feature
eq_(feature['rowid'],1)
eq_(feature['fips'],u'AC')

View file

@ -38,12 +38,8 @@ headers = ['#plugins/input/shape'] + env['CPPPATH']
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
boost_filesystem = 'boost_filesystem%s' % env['BOOST_APPEND']
libraries = [boost_program_options, boost_filesystem]
boost_system = 'boost_system%s' % env['BOOST_APPEND']
if env['HAS_BOOST_SYSTEM']:
libraries.append(boost_system)
libraries = [boost_program_options, boost_filesystem, boost_system]
shapeindex = program_env.Program('shapeindex', source, CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])