Merge branch 'master' into geometry_cleanup

This commit is contained in:
Artem Pavlenko 2011-12-14 14:04:30 +00:00
commit ed7abc5c51
16 changed files with 123 additions and 70 deletions

View file

@ -41,8 +41,10 @@ def is_py3():
prefix = env['PREFIX'] prefix = env['PREFIX']
target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik') target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik')
target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2')
libraries = ['mapnik','png'] libraries = ['mapnik']
libraries.append('png')
if env['JPEG']: if env['JPEG']:
libraries.append('jpeg') libraries.append('jpeg')
@ -121,22 +123,24 @@ else:
paths = ''' paths = '''
"""Configuration paths of Mapnik fonts and input plugins (auto-generated by SCons).""" """Configuration paths of Mapnik fonts and input plugins (auto-generated by SCons)."""
import os from os.path import normpath,join,dirname
mapniklibpath = '%s' mapniklibpath = '%s'
mapniklibpath = normpath(join(dirname(__file__),mapniklibpath))
''' '''
paths += "inputpluginspath = os.path.normpath(mapniklibpath + '/input')\n" paths += "inputpluginspath = join(mapniklibpath,'input')\n"
if env['SYSTEM_FONTS']: if env['SYSTEM_FONTS']:
paths += "fontscollectionpath = os.path.normpath('%s')" % env['SYSTEM_FONTS'] paths += "fontscollectionpath = normpath('%s')\n" % env['SYSTEM_FONTS']
else: else:
paths += "fontscollectionpath = os.path.normpath(mapniklibpath + '/fonts')" paths += "fontscollectionpath = join(mapniklibpath,'fonts')\n"
paths += "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n"
if not os.path.exists('mapnik'): if not os.path.exists('mapnik'):
os.mkdir('mapnik') os.mkdir('mapnik')
file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR'])) file('mapnik/paths.py','w').write(paths % (os.path.relpath(env['MAPNIK_LIB_DIR'],target_path)))
# force open perms temporarily so that `sudo scons install` # force open perms temporarily so that `sudo scons install`
# does not later break simple non-install non-sudo rebuild # does not later break simple non-install non-sudo rebuild
@ -152,8 +156,7 @@ if 'install' in COMMAND_LINE_TARGETS:
init_module = env.Install(target_path, init_files) init_module = env.Install(target_path, init_files)
env.Alias(target='install', source=init_module) env.Alias(target='install', source=init_module)
# install mapnik2 module which redirects to mapnik and issues DeprecatedWarning # install mapnik2 module which redirects to mapnik and issues DeprecatedWarning
path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2') init_mapnik2 = env.Install(target_path_deprecated, 'mapnik2/__init__.py')
init_mapnik2 = env.Install(path, 'mapnik2/__init__.py')
env.Alias(target='install', source=init_mapnik2) env.Alias(target='install', source=init_mapnik2)
# fix perms and install the custom generated 'paths.py' # fix perms and install the custom generated 'paths.py'
@ -204,4 +207,5 @@ if 'uninstall' not in COMMAND_LINE_TARGETS:
env['create_uninstall_target'](env, target_path) env['create_uninstall_target'](env, target_path)
env['create_uninstall_target'](env, target_path_deprecated)

View file

@ -1,3 +0,0 @@
mapniklibpath = '@PACKAGE_LIB_DIR@'
inputpluginspath = mapniklibpath + '/input'
fontscollectionpath = '@SYSTEM_FONTS_DIR@/truetype/ttf-dejavu'

View file

@ -213,6 +213,12 @@ struct symbolizer_attributes : public boost::static_visitor<>
void operator () (building_symbolizer const& sym) void operator () (building_symbolizer const& sym)
{ {
expression_ptr const& height_expr = sym.height();
if (height_expr)
{
expression_attributes f_attr(names_);
boost::apply_visitor(f_attr,*height_expr);
}
collect_metawriter(sym); collect_metawriter(sym);
} }
// TODO - support remaining syms // TODO - support remaining syms

View file

@ -26,6 +26,7 @@
// mapnik // mapnik
#include <mapnik/color.hpp> #include <mapnik/color.hpp>
#include <mapnik/symbolizer.hpp> #include <mapnik/symbolizer.hpp>
#include <mapnik/filter_factory.hpp>
namespace mapnik namespace mapnik
{ {
@ -79,11 +80,10 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base
explicit building_symbolizer() explicit building_symbolizer()
: symbolizer_base(), : symbolizer_base(),
fill_(color(128,128,128)), fill_(color(128,128,128)),
height_(0.0),
opacity_(1.0) opacity_(1.0)
{} {}
building_symbolizer(color const& fill,double height) building_symbolizer(color const& fill, expression_ptr height)
: symbolizer_base(), : symbolizer_base(),
fill_(fill), fill_(fill),
height_(height), height_(height),
@ -97,11 +97,11 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base
{ {
fill_ = fill; fill_ = fill;
} }
double height() const expression_ptr height() const
{ {
return height_; return height_;
} }
void set_height(double height) void set_height(expression_ptr height)
{ {
height_=height; height_=height;
} }
@ -115,7 +115,7 @@ struct MAPNIK_DECL building_symbolizer : public symbolizer_base
} }
private: private:
color fill_; color fill_;
double height_; expression_ptr height_;
double opacity_; double opacity_;
}; };
} }

View file

@ -489,10 +489,12 @@ void csv_datasource::parse_csv(T& stream,
std::string::const_iterator str_beg = value.begin(); std::string::const_iterator str_beg = value.begin();
std::string::const_iterator str_end = value.end(); std::string::const_iterator str_end = value.end();
bool r = qi::phrase_parse(str_beg,str_end, bool r = qi::phrase_parse(str_beg,str_end,
( (
qi::lit("POINT") >> '(' >> double_[ref(x) = _1] >> double_[ref(y) = _1] >> ')' qi::lit("POINT") >> '('
), >> double_[ref(x) = _1]
ascii::space); >> double_[ref(y) = _1] >> ')'
),
ascii::space);
if (r && (str_beg == str_end)) if (r && (str_beg == str_end))
{ {
@ -615,28 +617,27 @@ void csv_datasource::parse_csv(T& stream,
} }
} }
// add all values as attributes // now, add all values as attributes
// here we detect numbers and treat everything else as pure strings /* First we detect likely strings, then try parsing likely numbers,
// this is intentional since boolean and null types are not common in csv editors finally falling back to string type
if (value.empty()) * We intentionally do not try to detect boolean or null types
{ since they are not common in csv
UnicodeString ustr = tr.transcode(value.c_str()); * Likely strings are either empty values, very long values
boost::put(*feature,fld_name,ustr); or value with leading zeros like 001 (which are not safe
if (feature_count == 1) to assume are numbers)
{ */
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String));
}
}
// only true strings are this long
else if (value_length > 20)
{
UnicodeString ustr = tr.transcode(value.c_str());
boost::put(*feature,fld_name,ustr);
if (feature_count == 1)
{
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String));
}
bool has_dot = value.find(".") != std::string::npos;
if (value.empty() ||
(value_length > 20) ||
(value_length > 1 && !has_dot && value[0] == '0'))
{
UnicodeString ustr = tr.transcode(value.c_str());
boost::put(*feature,fld_name,ustr);
if (feature_count == 1)
{
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String));
}
} }
else if ((value[0] >= '0' && value[0] <= '9') || value[0] == '-') else if ((value[0] >= '0' && value[0] <= '9') || value[0] == '-')
{ {
@ -646,12 +647,14 @@ void csv_datasource::parse_csv(T& stream,
bool r = qi::phrase_parse(str_beg,str_end,qi::double_,ascii::space,float_val); bool r = qi::phrase_parse(str_beg,str_end,qi::double_,ascii::space,float_val);
if (r && (str_beg == str_end)) if (r && (str_beg == str_end))
{ {
if (value.find(".") != std::string::npos) if (has_dot)
{ {
boost::put(*feature,fld_name,float_val); boost::put(*feature,fld_name,float_val);
if (feature_count == 1) if (feature_count == 1)
{ {
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::Double)); desc_.add_descriptor(
mapnik::attribute_descriptor(
fld_name,mapnik::Double));
} }
} }
else else
@ -660,7 +663,9 @@ void csv_datasource::parse_csv(T& stream,
boost::put(*feature,fld_name,val); boost::put(*feature,fld_name,val);
if (feature_count == 1) if (feature_count == 1)
{ {
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::Integer)); desc_.add_descriptor(
mapnik::attribute_descriptor(
fld_name,mapnik::Integer));
} }
} }
} }
@ -671,7 +676,9 @@ void csv_datasource::parse_csv(T& stream,
boost::put(*feature,fld_name,ustr); boost::put(*feature,fld_name,ustr);
if (feature_count == 1) if (feature_count == 1)
{ {
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); desc_.add_descriptor(
mapnik::attribute_descriptor(
fld_name,mapnik::String));
} }
} }
} }
@ -682,7 +689,9 @@ void csv_datasource::parse_csv(T& stream,
boost::put(*feature,fld_name,ustr); boost::put(*feature,fld_name,ustr);
if (feature_count == 1) if (feature_count == 1)
{ {
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String)); desc_.add_descriptor(
mapnik::attribute_descriptor(
fld_name,mapnik::String));
} }
} }
} }

View file

@ -25,6 +25,7 @@
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp> #include <mapnik/agg_rasterizer.hpp>
#include <mapnik/segment.hpp> #include <mapnik/segment.hpp>
#include <mapnik/expression_evaluator.hpp>
// boost // boost
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
@ -66,7 +67,13 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
ras_ptr->reset(); ras_ptr->reset();
ras_ptr->gamma(agg::gamma_linear()); ras_ptr->gamma(agg::gamma_linear());
double height = sym.height() * scale_factor_; double height = 0.0;
expression_ptr height_expr = sym.height();
if (height_expr)
{
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr);
height = result.to_double() * scale_factor_;
}
for (unsigned i=0;i<feature.num_geometries();++i) for (unsigned i=0;i<feature.num_geometries();++i)
{ {

View file

@ -62,7 +62,7 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
renderer ren(renb); renderer ren(renb);
ras_ptr->reset(); ras_ptr->reset();
ras_ptr->gamma(agg::gamma_linear(0.0, sym.get_gamma())); ras_ptr->gamma(agg::gamma_power(sym.get_gamma()));
metawriter_with_properties writer = sym.get_metawriter(); metawriter_with_properties writer = sym.get_metawriter();
for (unsigned i=0;i<feature.num_geometries();++i) for (unsigned i=0;i<feature.num_geometries();++i)
{ {

View file

@ -779,7 +779,13 @@ void cairo_renderer_base::process(building_symbolizer const& sym,
cairo_context context(context_); cairo_context context(context_);
color const& fill = sym.get_fill(); color const& fill = sym.get_fill();
double height = 0.7071 * sym.height(); // height in meters double height = 0.0;
expression_ptr height_expr = sym.height();
if (height_expr)
{
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr);
height = 0.7071 * result.to_double();
}
for (unsigned i = 0; i < feature.num_geometries(); ++i) for (unsigned i = 0; i < feature.num_geometries(); ++i)
{ {

View file

@ -28,6 +28,7 @@
#include <mapnik/grid/grid_pixel.hpp> #include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp> #include <mapnik/grid/grid.hpp>
#include <mapnik/segment.hpp> #include <mapnik/segment.hpp>
#include <mapnik/expression_evaluator.hpp>
// boost // boost
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
@ -59,7 +60,13 @@ void grid_renderer<T>::process(building_symbolizer const& sym,
ras_ptr->reset(); ras_ptr->reset();
double height = sym.height() * scale_factor_; double height = 0.0;
expression_ptr height_expr = sym.height();
if (height_expr)
{
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr);
height = result.to_double() * scale_factor_;
}
for (unsigned i=0;i<feature.num_geometries();++i) for (unsigned i=0;i<feature.num_geometries();++i)
{ {

View file

@ -1906,9 +1906,8 @@ void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym )
optional<double> opacity = get_opt_attr<double>(sym, "fill-opacity"); optional<double> opacity = get_opt_attr<double>(sym, "fill-opacity");
if (opacity) building_sym.set_opacity(*opacity); if (opacity) building_sym.set_opacity(*opacity);
// height // height
// TODO - expression optional<std::string> height = get_opt_attr<std::string>(sym, "height");
optional<double> height = get_opt_attr<double>(sym, "height"); if (height) building_sym.set_height(parse_expression(*height, "utf8"));
if (height) building_sym.set_height(*height);
parse_metawriter_in_symbolizer(building_sym, sym); parse_metawriter_in_symbolizer(building_sym, sym);
rule.append(building_sym); rule.append(building_sym);

View file

@ -241,10 +241,9 @@ public:
{ {
set_attr( sym_node, "fill-opacity", sym.get_opacity() ); set_attr( sym_node, "fill-opacity", sym.get_opacity() );
} }
if ( sym.height() != dfl.height() || explicit_defaults_ )
{ set_attr( sym_node, "height", to_expression_string(*sym.height()) );
set_attr( sym_node, "height", sym.height() );
}
add_metawriter_attributes(sym_node, sym); add_metawriter_attributes(sym_node, sym);
} }

View file

@ -0,0 +1,4 @@
x,y,fips
0,0,001
0,0,003
0,0,005
1 x y fips
2 0 0 001
3 0 0 003
4 0 0 005

View file

@ -7,25 +7,15 @@
</Rule> </Rule>
</Style> </Style>
<!-- layer created by ogr like: ogr2ogr -t_srs EPSG:4326 -f SQLite ../sqlite/world.sqlite world_merc.shp -->
<!-- here we read with the ogr plugin -->
<Layer name="world_borders1" srs="+init=epsg:4326">
<StyleName>world_borders_style1</StyleName>
<Datasource>
<Parameter name="type">ogr</Parameter>
<Parameter name="file">../sqlite/world.sqlite</Parameter>
<Parameter name="layer">world_merc</Parameter>
</Datasource>
</Layer>
<Style name="world_borders_style2"> <Style name="world_borders_style2">
<Rule> <Rule>
<PolygonSymbolizer fill="yellow" gamma="0.5"/> <PolygonSymbolizer fill="yellow" gamma="0.5"/>
</Rule> </Rule>
</Style> </Style>
<!-- here we read with native sqlite plugin --> <!-- layer created by ogr like: ogr2ogr -t_srs EPSG:4326 -f SQLite ../sqlite/world.sqlite world_merc.shp -->
<Layer name="world_borders2" srs="+init=epsg:4326"> <Layer name="world_borders2" srs="+init=epsg:4326">
<StyleName>world_borders_style1</StyleName>
<StyleName>world_borders_style2</StyleName> <StyleName>world_borders_style2</StyleName>
<Datasource> <Datasource>
<Parameter name="type">sqlite</Parameter> <Parameter name="type">sqlite</Parameter>

6
tests/data/svg/README.md Normal file
View file

@ -0,0 +1,6 @@
Other good sources of svg for tests include:
* http://intertwingly.net/svg/
* http://www.w3.org/Graphics/SVG/Test/20110816/
* http://croczilla.com/bits_and_pieces/svg/samples/
* http://www.w3schools.com/svg/svg_examples.asp

View file

@ -227,6 +227,25 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
query.add_property_name('bogus') query.add_property_name('bogus')
fs = ds.features(query) fs = ds.features(query)
def test_that_leading_zeros_mean_strings(**kwargs):
ds = get_csv_ds('leading_zeros.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','fips'])
eq_(ds.field_types(),['int','int','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'001')
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'003')
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'005')
if __name__ == "__main__": if __name__ == "__main__":
setup() setup()
[eval(run)(visual=True) for run in dir() if 'test_' in run] [eval(run)(visual=True) for run in dir() if 'test_' in run]

View file

@ -12,7 +12,7 @@ def usage():
def main(): def main():
try: try:
opts, args = getopt.getopt(sys.argv[1:], "hvqp:", ["help", "prefix="]) opts, args = getopt.getopt(sys.argv[1:], "hvqp:", ["help", "prefix="])
except getopt.GetoptError as err: except getopt.GetoptError,err:
print(str(err)) print(str(err))
usage() usage()
sys.exit(2) sys.exit(2)