diff --git a/CHANGELOG.md b/CHANGELOG.md index 33f5109e8..176fc51f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ For a complete change history, see the git log. ## Future +- Added ability to access style list from map by (name,obj) in python (#1725) + +- Added `is_solid` method to python mapnik.Image and mapnik.ImageView classes (#1728) + - Changed scale_denominator C++ interface to take scale as first argument rather than map. - Added support for `background-image` in cairo_renderer (#1724) diff --git a/SConstruct b/SConstruct index 0af8866db..3e04d565b 100644 --- a/SConstruct +++ b/SConstruct @@ -370,6 +370,8 @@ PathVariable.PathAccept), ('JOBS', 'Set the number of parallel compilations', "1", lambda key, value, env: int(value), int), BoolVariable('DEMO', 'Compile demo c++ application', 'True'), BoolVariable('PGSQL2SQLITE', 'Compile and install a utility to convert postgres tables to sqlite', 'False'), + BoolVariable('SHAPEINDEX', 'Compile and install a utility to generate shapefile indexes in the custom format (.index) Mapnik supports', 'True'), + BoolVariable('SVG2PNG', 'Compile and install a utility to generate render an svg file to a png on the command line', 'False'), BoolVariable('COLOR_PRINT', 'Print build status information in color', 'True'), BoolVariable('SAMPLE_INPUT_PLUGINS', 'Compile and install sample plugins', 'False'), BoolVariable('BIGINT', 'Compile support for 64-bit integers in mapnik::value', 'True'), @@ -1805,13 +1807,15 @@ if not HELP_REQUESTED: # Build shapeindex and remove its dependency from the LIBS if 'boost_program_options%s' % env['BOOST_APPEND'] in env['LIBS']: - SConscript('utils/shapeindex/build.py') + if env['SHAPEINDEX']: + SConscript('utils/shapeindex/build.py') # Build the pgsql2psqlite app if requested if env['PGSQL2SQLITE']: SConscript('utils/pgsql2sqlite/build.py') - SConscript('utils/svg2png/build.py') + if env['SVG2PNG']: + SConscript('utils/svg2png/build.py') # devtools not ready for public #SConscript('utils/ogrindex/build.py') diff --git a/bindings/python/mapnik_datasource.cpp b/bindings/python/mapnik_datasource.cpp index 6da2cb0fd..95c495aec 100644 --- a/bindings/python/mapnik_datasource.cpp +++ b/bindings/python/mapnik_datasource.cpp @@ -138,6 +138,9 @@ boost::python::list field_types(boost::shared_ptr const& ds) return fld_types; }} +mapnik::parameters const& (mapnik::datasource::*params_const)() const = &mapnik::datasource::params; + + void export_datasource() { using namespace boost::python; @@ -164,7 +167,7 @@ void export_datasource() .def("fields",&fields) .def("field_types",&field_types) .def("features_at_point",&datasource::features_at_point, (arg("coord"),arg("tolerance")=0)) - .def("params",&datasource::params,return_value_policy(), + .def("params",make_function(params_const,return_value_policy()), "The configuration parameters of the data source. " "These vary depending on the type of data source.") ; diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 9c7c1fd1e..32384a034 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -107,6 +107,28 @@ bool painted(mapnik::image_32 const& im) return im.painted(); } +bool is_solid(mapnik::image_32 const& im) +{ + if (im.width() > 0 && im.height() > 0) + { + mapnik::image_data_32 const & data = im.data(); + mapnik::image_data_32::pixel_type const* first_row = data.getRow(0); + mapnik::image_data_32::pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < im.height(); ++y) + { + mapnik::image_data_32::pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < im.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; +} + unsigned get_pixel(mapnik::image_32 const& im, int x, int y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) @@ -206,6 +228,7 @@ void export_image() .def("height",&image_32::height) .def("view",&image_32::get_view) .def("painted",&painted) + .def("is_solid",&is_solid) .add_property("background",make_function (&image_32::get_background,return_value_policy()), &image_32::set_background, "The background color of the image.") diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 18a0831b6..63bb61578 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -76,6 +76,27 @@ PyObject* view_tostring3(image_view const & view, std::string con (s.data(),s.size()); } +bool is_solid(image_view const& view) +{ + if (view.width() > 0 && view.height() > 0) + { + mapnik::image_view::pixel_type const* first_row = view.getRow(0); + mapnik::image_view::pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < view.height(); ++y) + { + mapnik::image_view::pixel_type const * row = view.getRow(y); + for (unsigned x = 0; x < view.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; +} + void save_view1(image_view const& view, std::string const& filename) { @@ -104,6 +125,7 @@ void export_image_view() class_ >("ImageView","A view into an image.",no_init) .def("width",&image_view::width) .def("height",&image_view::height) + .def("is_solid",&is_solid) .def("tostring",&view_tostring1) .def("tostring",&view_tostring2) .def("tostring",&view_tostring3) diff --git a/bindings/python/mapnik_map.cpp b/bindings/python/mapnik_map.cpp index eecedf6d6..dcd5ee575 100644 --- a/bindings/python/mapnik_map.cpp +++ b/bindings/python/mapnik_map.cpp @@ -116,10 +116,10 @@ void set_maximum_extent(mapnik::Map & m, boost::optional > struct extract_style { - typedef mapnik::feature_type_style result_type; + typedef boost::python::tuple result_type; result_type operator() (std::map::value_type const& val) const { - return val.second; + return boost::python::make_tuple(val.first,val.second); } }; diff --git a/bindings/python/mapnik_style.cpp b/bindings/python/mapnik_style.cpp index 9b1945fcd..7eb9e449b 100644 --- a/bindings/python/mapnik_style.cpp +++ b/bindings/python/mapnik_style.cpp @@ -28,7 +28,6 @@ #include #include "mapnik_enumeration.hpp" #include -#include // image_filter_grammar #include // generate_image_filters using mapnik::feature_type_style; @@ -45,18 +44,12 @@ std::string get_image_filters(feature_type_style & style) void set_image_filters(feature_type_style & style, std::string const& filters) { - std::string::const_iterator itr = filters.begin(); - std::string::const_iterator end = filters.end(); - mapnik::image_filter_grammar > filter_grammar; std::vector new_filters; - bool result = boost::spirit::qi::phrase_parse(itr,end, - filter_grammar, - boost::spirit::qi::ascii::space, - new_filters); - if (!result || itr!=end) + + bool result = parse_image_filters(filters, new_filters); + if (!result) { - throw mapnik::value_error("failed to parse image-filters: '" + std::string(itr,end) + "'"); + throw mapnik::value_error("failed to parse image-filters: '" + filters + "'"); } style.image_filters().swap(new_filters); } diff --git a/bindings/python/python_grid_utils.cpp b/bindings/python/python_grid_utils.cpp index ee6e46236..952f5ce36 100644 --- a/bindings/python/python_grid_utils.cpp +++ b/bindings/python/python_grid_utils.cpp @@ -45,7 +45,7 @@ namespace mapnik { template void grid2utf(T const& grid_type, boost::python::list& l, - std::vector& key_order) + std::vector& key_order) { typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; typedef typename keys_type::const_iterator keys_iterator; diff --git a/deps/agg/include/agg_conv_clipper.h b/deps/agg/include/agg_conv_clipper.h index 3ac9d951e..e5f390646 100755 --- a/deps/agg/include/agg_conv_clipper.h +++ b/deps/agg/include/agg_conv_clipper.h @@ -23,287 +23,301 @@ namespace agg { enum clipper_op_e { clipper_or, - clipper_and, clipper_xor, clipper_a_minus_b, clipper_b_minus_a }; + clipper_and, clipper_xor, clipper_a_minus_b, clipper_b_minus_a }; enum clipper_PolyFillType {clipper_even_odd, clipper_non_zero, clipper_positive, clipper_negative}; template class conv_clipper { - enum status { status_move_to, status_line_to, status_stop }; - typedef VSA source_a_type; - typedef VSB source_b_type; - typedef conv_clipper self_type; + enum status { status_move_to, status_line_to, status_stop }; + typedef VSA source_a_type; + typedef VSB source_b_type; + typedef conv_clipper self_type; private: - source_a_type* m_src_a; - source_b_type* m_src_b; - status m_status; - int m_vertex; - int m_contour; - int m_scaling_factor; - clipper_op_e m_operation; - pod_bvector m_vertex_accumulator; - ClipperLib::Polygons m_poly_a; - ClipperLib::Polygons m_poly_b; - ClipperLib::Polygons m_result; - ClipperLib::Clipper m_clipper; - clipper_PolyFillType m_subjFillType; - clipper_PolyFillType m_clipFillType; + source_a_type* m_src_a; + source_b_type* m_src_b; + status m_status; + int m_vertex; + int m_contour; + int m_scaling_factor; + clipper_op_e m_operation; + pod_bvector m_vertex_accumulator; + ClipperLib::Polygons m_poly_a; + ClipperLib::Polygons m_poly_b; + ClipperLib::Polygons m_result; + ClipperLib::Clipper m_clipper; + clipper_PolyFillType m_subjFillType; + clipper_PolyFillType m_clipFillType; + double start_x_; + double start_y_; - int Round(double val) - { - if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5); - } + int Round(double val) + { + if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5); + } public: conv_clipper(source_a_type &a, source_b_type &b, - clipper_op_e op = clipper_or, - clipper_PolyFillType subjFillType = clipper_even_odd, - clipper_PolyFillType clipFillType = clipper_even_odd, - int scaling_factor = 2) : - m_src_a(&a), - m_src_b(&b), - m_status(status_move_to), - m_vertex(-1), - m_contour(-1), - m_operation(op), - m_subjFillType(subjFillType), - m_clipFillType(clipFillType) - { - m_scaling_factor = std::max(std::min(scaling_factor, 6),0); - m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); - } + clipper_op_e op = clipper_or, + clipper_PolyFillType subjFillType = clipper_even_odd, + clipper_PolyFillType clipFillType = clipper_even_odd, + int scaling_factor = 2) : + m_src_a(&a), + m_src_b(&b), + m_status(status_move_to), + m_vertex(-1), + m_contour(-1), + m_operation(op), + m_subjFillType(subjFillType), + m_clipFillType(clipFillType), + start_x_(0), + start_y_(0) + { + m_scaling_factor = std::max(std::min(scaling_factor, 6),0); + m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); + } conv_clipper(source_a_type &a, - clipper_op_e op = clipper_and, - clipper_PolyFillType subjFillType = clipper_non_zero, - clipper_PolyFillType clipFillType = clipper_non_zero, - int scaling_factor = 6) : - m_src_a(&a), - m_status(status_move_to), - m_vertex(-1), - m_contour(-1), - m_operation(op), - m_subjFillType(subjFillType), - m_clipFillType(clipFillType) - { - m_scaling_factor = std::max(std::min(scaling_factor, 6),0); - m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); - } + clipper_op_e op = clipper_and, + clipper_PolyFillType subjFillType = clipper_non_zero, + clipper_PolyFillType clipFillType = clipper_non_zero, + int scaling_factor = 6) : + m_src_a(&a), + m_status(status_move_to), + m_vertex(-1), + m_contour(-1), + m_operation(op), + m_subjFillType(subjFillType), + m_clipFillType(clipFillType), + start_x_(0), + start_y_(0) + { + m_scaling_factor = std::max(std::min(scaling_factor, 6),0); + m_scaling_factor = Round(std::pow((double)10, m_scaling_factor)); + } - ~conv_clipper() - { - } - unsigned type() const { return m_src_a->type(); } - void attach1(VSA &source, clipper_PolyFillType subjFillType = clipper_even_odd) - { m_src_a = &source; m_subjFillType = subjFillType; } - void attach2(VSB &source, clipper_PolyFillType clipFillType = clipper_even_odd) - { m_src_b = &source; m_clipFillType = clipFillType; } + ~conv_clipper() + { + } + unsigned type() const { return m_src_a->type(); } + void attach1(VSA &source, clipper_PolyFillType subjFillType = clipper_even_odd) + { m_src_a = &source; m_subjFillType = subjFillType; } + void attach2(VSB &source, clipper_PolyFillType clipFillType = clipper_even_odd) + { m_src_b = &source; m_clipFillType = clipFillType; } - void operation(clipper_op_e v) { m_operation = v; } + void operation(clipper_op_e v) { m_operation = v; } - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); - bool next_contour(); - bool next_vertex(double* x, double* y); - void start_extracting(); - void add_vertex_(double &x, double &y); - void end_contour(ClipperLib::Polygons &p); + bool next_contour(); + bool next_vertex(double* x, double* y); + void start_extracting(); + void add_vertex_(double &x, double &y); + void end_contour(ClipperLib::Polygons &p); - template void add(VS &src, ClipperLib::Polygons &p){ - unsigned cmd; - double x; double y; double start_x; double start_y; - bool starting_first_line; + template void add(VS &src, ClipperLib::Polygons &p){ + unsigned cmd; + double x; double y; double start_x; double start_y; + bool starting_first_line; - start_x = 0.0; - start_y = 0.0; - starting_first_line = true; - p.resize(0); + start_x = 0.0; + start_y = 0.0; + starting_first_line = true; + p.resize(0); - cmd = src->vertex( &x , &y ); - while(!is_stop(cmd)) - { - if(is_vertex(cmd)) - { - if(is_move_to(cmd)) - { - if(!starting_first_line ) end_contour(p); - start_x = x; - start_y = y; - } - add_vertex_( x, y ); - starting_first_line = false; - } - else if(is_end_poly(cmd)) - { - if(!starting_first_line && is_closed(cmd)) - add_vertex_( start_x, start_y ); - } - cmd = src->vertex( &x, &y ); - } - end_contour(p); - } + cmd = src->vertex( &x , &y ); + while(!is_stop(cmd)) + { + if(is_vertex(cmd)) + { + if(is_move_to(cmd)) + { + if(!starting_first_line ) end_contour(p); + start_x = x; + start_y = y; + } + add_vertex_( x, y ); + starting_first_line = false; + } + else if(is_end_poly(cmd)) + { + if(!starting_first_line && is_closed(cmd)) + add_vertex_( start_x, start_y ); + } + cmd = src->vertex( &x, &y ); + } + end_contour(p); + } }; //------------------------------------------------------------------------ template - void conv_clipper::start_extracting() + void conv_clipper::start_extracting() { - m_status = status_move_to; - m_contour = -1; - m_vertex = -1; + m_status = status_move_to; + m_contour = -1; + m_vertex = -1; } //------------------------------------------------------------------------------ template - void conv_clipper::rewind(unsigned path_id) + void conv_clipper::rewind(unsigned path_id) { - m_src_a->rewind( path_id ); - m_src_b->rewind( path_id ); + m_src_a->rewind( path_id ); + m_src_b->rewind( path_id ); - add( m_src_a , m_poly_a ); - add( m_src_b , m_poly_b ); - m_result.resize(0); + add( m_src_a , m_poly_a ); + add( m_src_b , m_poly_b ); + m_result.resize(0); - ClipperLib::PolyFillType pftSubj, pftClip; - switch (m_subjFillType) - { - case clipper_even_odd: pftSubj = ClipperLib::pftEvenOdd; break; - case clipper_non_zero: pftSubj = ClipperLib::pftNonZero; break; - case clipper_positive: pftSubj = ClipperLib::pftPositive; break; - default: pftSubj = ClipperLib::pftNegative; - } - switch (m_clipFillType) - { - case clipper_even_odd: pftClip = ClipperLib::pftEvenOdd; break; - case clipper_non_zero: pftClip = ClipperLib::pftNonZero; break; - case clipper_positive: pftClip = ClipperLib::pftPositive; break; - default: pftClip = ClipperLib::pftNegative; - } + ClipperLib::PolyFillType pftSubj, pftClip; + switch (m_subjFillType) + { + case clipper_even_odd: pftSubj = ClipperLib::pftEvenOdd; break; + case clipper_non_zero: pftSubj = ClipperLib::pftNonZero; break; + case clipper_positive: pftSubj = ClipperLib::pftPositive; break; + default: pftSubj = ClipperLib::pftNegative; + } + switch (m_clipFillType) + { + case clipper_even_odd: pftClip = ClipperLib::pftEvenOdd; break; + case clipper_non_zero: pftClip = ClipperLib::pftNonZero; break; + case clipper_positive: pftClip = ClipperLib::pftPositive; break; + default: pftClip = ClipperLib::pftNegative; + } - m_clipper.Clear(); - switch( m_operation ) { - case clipper_or: - { - m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); - m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); - m_clipper.Execute( ClipperLib::ctUnion , m_result , pftSubj, pftClip); - break; - } - case clipper_and: - { - m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); - m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); - m_clipper.Execute( ClipperLib::ctIntersection , m_result, pftSubj, pftClip ); - break; - } - case clipper_xor: - { - m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); - m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); - m_clipper.Execute( ClipperLib::ctXor , m_result, pftSubj, pftClip ); - break; - } - case clipper_a_minus_b: - { - m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); - m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); - m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); - break; - } - case clipper_b_minus_a: - { - m_clipper.AddPolygons( m_poly_b , ClipperLib::ptSubject ); - m_clipper.AddPolygons( m_poly_a , ClipperLib::ptClip ); - m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); - break; - } - } - start_extracting(); + m_clipper.Clear(); + switch( m_operation ) { + case clipper_or: + { + m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); + m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); + m_clipper.Execute( ClipperLib::ctUnion , m_result , pftSubj, pftClip); + break; + } + case clipper_and: + { + m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); + m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); + m_clipper.Execute( ClipperLib::ctIntersection , m_result, pftSubj, pftClip ); + break; + } + case clipper_xor: + { + m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); + m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); + m_clipper.Execute( ClipperLib::ctXor , m_result, pftSubj, pftClip ); + break; + } + case clipper_a_minus_b: + { + m_clipper.AddPolygons( m_poly_a , ClipperLib::ptSubject ); + m_clipper.AddPolygons( m_poly_b , ClipperLib::ptClip ); + m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); + break; + } + case clipper_b_minus_a: + { + m_clipper.AddPolygons( m_poly_b , ClipperLib::ptSubject ); + m_clipper.AddPolygons( m_poly_a , ClipperLib::ptClip ); + m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip ); + break; + } + } + start_extracting(); } //------------------------------------------------------------------------------ template - void conv_clipper::end_contour( ClipperLib::Polygons &p) + void conv_clipper::end_contour( ClipperLib::Polygons &p) { - unsigned i, len; + unsigned i, len; - if( m_vertex_accumulator.size() < 3 ) return; - len = p.size(); - p.resize(len+1); - p[len].resize(m_vertex_accumulator.size()); - for( i = 0 ; i < m_vertex_accumulator.size() ; i++ ) - p[len][i] = m_vertex_accumulator[i]; - m_vertex_accumulator.remove_all(); + if( m_vertex_accumulator.size() < 3 ) return; + len = p.size(); + p.resize(len+1); + p[len].resize(m_vertex_accumulator.size()); + for( i = 0 ; i < m_vertex_accumulator.size() ; i++ ) + p[len][i] = m_vertex_accumulator[i]; + m_vertex_accumulator.remove_all(); } //------------------------------------------------------------------------------ template - void conv_clipper::add_vertex_(double &x, double &y) + void conv_clipper::add_vertex_(double &x, double &y) { - ClipperLib::IntPoint v; + ClipperLib::IntPoint v; - v.X = Round(x * m_scaling_factor); - v.Y = Round(y * m_scaling_factor); - m_vertex_accumulator.add( v ); + v.X = Round(x * m_scaling_factor); + v.Y = Round(y * m_scaling_factor); + m_vertex_accumulator.add( v ); } //------------------------------------------------------------------------------ template - bool conv_clipper::next_contour() + bool conv_clipper::next_contour() { - m_contour++; - if(m_contour >= (int)m_result.size()) return false; - m_vertex =-1; - return true; + m_contour++; + if(m_contour >= (int)m_result.size()) return false; + m_vertex =-1; + return true; } //------------------------------------------------------------------------------ template - bool conv_clipper::next_vertex(double *x, double *y) + bool conv_clipper::next_vertex(double *x, double *y) { - m_vertex++; - if(m_vertex >= (int)m_result[m_contour].size()) return false; - *x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor; - *y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor; - return true; + m_vertex++; + if(m_vertex >= (int)m_result[m_contour].size()) return false; + *x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor; + *y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor; + return true; } //------------------------------------------------------------------------------ + //------------------------------------------------------------------------------ + template - unsigned conv_clipper::vertex(double *x, double *y) + unsigned conv_clipper::vertex(double *x, double *y) { - if( m_status == status_move_to ) - { - if( next_contour() ) - { - if( next_vertex( x, y ) ) - { - m_status =status_line_to; - return path_cmd_move_to; - } - else - { - m_status = status_stop; - return path_cmd_end_poly | path_flags_close; - } - } - else - return path_cmd_stop; - } - else - { - if( next_vertex( x, y ) ) - { - return path_cmd_line_to; - } - else - { - m_status = status_move_to; - return path_cmd_end_poly | path_flags_close; - } - } + if( m_status == status_move_to ) + { + if( next_contour() ) + { + if( next_vertex( x, y ) ) + { + m_status =status_line_to; + start_x_ = *x; + start_y_ = *y; + return path_cmd_move_to; + } + else + { + *x = start_x_; + *y = start_y_; + m_status = status_stop; + return path_cmd_end_poly | path_flags_close; + } + } + else + return path_cmd_stop; + } + else + { + if( next_vertex( x, y ) ) + { + return path_cmd_line_to; + } + else + { + m_status = status_move_to; + *x = start_x_; + *y = start_y_; + return path_cmd_end_poly | path_flags_close; + } + } } //------------------------------------------------------------------------------ diff --git a/include/mapnik/datasource.hpp b/include/mapnik/datasource.hpp index 009c3729a..f9a6e0d41 100644 --- a/include/mapnik/datasource.hpp +++ b/include/mapnik/datasource.hpp @@ -99,6 +99,11 @@ public: return params_; } + parameters & params() + { + return params_; + } + /*! * @brief Get the type of the datasource * @return The type of the datasource (Vector or Raster) diff --git a/include/mapnik/enumeration.hpp b/include/mapnik/enumeration.hpp index 229bc0906..9b61c7e3e 100644 --- a/include/mapnik/enumeration.hpp +++ b/include/mapnik/enumeration.hpp @@ -320,8 +320,14 @@ operator>>(std::istream & is, mapnik::enumeration & e) /** Helper macro. Creates a typedef. * @relates mapnik::enumeration */ +#ifdef _MSC_VER +#define DEFINE_ENUM( name, e) \ + template enumeration; \ + typedef enumeration name +#else #define DEFINE_ENUM( name, e) \ typedef enumeration name +#endif /** Helper macro. Runs the verify_mapnik_enum() method during static initialization. * @relates mapnik::enumeration diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index c8f5ea11b..d651e9c68 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -23,6 +23,9 @@ #ifndef MAPNIK_IMAGE_FILTER_TYPES_HPP #define MAPNIK_IMAGE_FILTER_TYPES_HPP +// mapnik +#include + // boost #include @@ -125,7 +128,9 @@ inline std::ostream& operator<< (std::ostream& os, invert) inline std::ostream& operator<< (std::ostream& os, filter_type const& filter); -bool generate_image_filters(std::back_insert_iterator & sink, std::vector const& v); +MAPNIK_DECL bool generate_image_filters(std::back_insert_iterator & sink, std::vector const& v); + +MAPNIK_DECL bool parse_image_filters(std::string const& filters, std::vector& image_filters); }} diff --git a/include/mapnik/util/geometry_to_wkt.hpp b/include/mapnik/util/geometry_to_wkt.hpp index e49423ece..5f6ca4bc6 100644 --- a/include/mapnik/util/geometry_to_wkt.hpp +++ b/include/mapnik/util/geometry_to_wkt.hpp @@ -24,34 +24,14 @@ #define MAPNIK_GEOMETRY_TO_WKT_HPP // mapnik -#include +#include #include -#include - -// boost -#include namespace mapnik { namespace util { -namespace karma = boost::spirit::karma; +MAPNIK_DECL bool to_wkt(std::string & wkt, mapnik::geometry_type const& geom); -bool to_wkt(std::string & wkt, mapnik::geometry_type const& geom) -{ - typedef std::back_insert_iterator sink_type; - sink_type sink(wkt); - wkt_generator generator(true); - bool result = karma::generate(sink, generator, geom); - return result; -} - -bool to_wkt(std::string & wkt, mapnik::geometry_container const& geom) -{ - typedef std::back_insert_iterator sink_type; - sink_type sink(wkt); - wkt_multi_generator generator; - bool result = karma::generate(sink, generator, geom); - return result; -} +MAPNIK_DECL bool to_wkt(std::string & wkt, mapnik::geometry_container const& geom); }} diff --git a/src/build.py b/src/build.py index c00eeac1e..43ab29ff1 100644 --- a/src/build.py +++ b/src/build.py @@ -56,11 +56,20 @@ 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','proj',env['ICU_LIB_NAME'],filesystem,system,regex,'harfbuzz'] +lib_env['LIBS'] = ['freetype','ltdl','z',env['ICU_LIB_NAME'],filesystem,system,regex,'harfbuzz'] + +if env['PROJ']: + lib_env['LIBS'].append('proj') + +if env['PNG']: + lib_env['LIBS'].append('png') if env['JPEG']: lib_env['LIBS'].append('jpeg') +if env['TIFF']: + lib_env['LIBS'].append('tiff') + if len(env['EXTRA_FREETYPE_LIBS']): lib_env['LIBS'].extend(copy(env['EXTRA_FREETYPE_LIBS'])) @@ -141,7 +150,6 @@ source = Split( palette.cpp path_expression_grammar.cpp plugin.cpp - png_reader.cpp point_symbolizer.cpp polygon_pattern_symbolizer.cpp polygon_symbolizer.cpp @@ -149,7 +157,6 @@ source = Split( save_map.cpp shield_symbolizer.cpp text_symbolizer.cpp - tiff_reader.cpp wkb.cpp projection.cpp proj_transform.cpp @@ -219,6 +226,18 @@ if env['JPEG']: jpeg_reader.cpp """) +if env['TIFF']: + source += Split( + """ + tiff_reader.cpp + """) + +if env['PNG']: + source += Split( + """ + png_reader.cpp + """) + # agg backend source += Split( """ diff --git a/src/gradient.cpp b/src/gradient.cpp index d8f6276f3..3af55050b 100644 --- a/src/gradient.cpp +++ b/src/gradient.cpp @@ -34,6 +34,14 @@ static const char * gradient_strings[] = { IMPLEMENT_ENUM( gradient_e, gradient_strings ) +static const char * gradient_unit_strings[] = { + "user-space-on-use", + "user-space-on-use-bounding-box", + "object-bounding-box", + "" +}; + +IMPLEMENT_ENUM( gradient_unit_e, gradient_unit_strings ) gradient::gradient() : gradient_type_(NO_GRADIENT), diff --git a/src/image_filter_types.cpp b/src/image_filter_types.cpp index cfb8cc0dc..a9bc4c3ce 100644 --- a/src/image_filter_types.cpp +++ b/src/image_filter_types.cpp @@ -21,6 +21,7 @@ *****************************************************************************/ // mapnik #include +#include // image_filter_grammar // boost #include @@ -63,4 +64,17 @@ bool generate_image_filters(std::back_insert_iterator& sink, std::v return r; } +bool parse_image_filters(std::string const& filters, std::vector& image_filters) +{ + std::string::const_iterator itr = filters.begin(); + std::string::const_iterator end = filters.end(); + mapnik::image_filter_grammar > filter_grammar; + bool r = boost::spirit::qi::phrase_parse(itr,end, + filter_grammar, + boost::spirit::qi::ascii::space, + image_filters); + return r && itr==end; +} + }} diff --git a/src/load_map.cpp b/src/load_map.cpp index 6d5e35c0d..18ea89ad3 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -425,15 +425,10 @@ void map_parser::parse_style(Map & map, xml_node const& sty) if (filters) { std::string filter_str = *filters; - std::string::const_iterator itr = filter_str.begin(); - std::string::const_iterator end = filter_str.end(); - bool result = boost::spirit::qi::phrase_parse(itr,end, - sty.get_tree().image_filters_grammar, - boost::spirit::qi::ascii::space, - style.image_filters()); - if (!result || itr!=end) + bool result = filter::parse_image_filters(filter_str, style.image_filters()); + if (!result) { - throw config_error("failed to parse image-filters: '" + std::string(itr,end) + "'"); + throw config_error("failed to parse image-filters: '" + filter_str + "'"); } } diff --git a/src/wkt/wkt_generator.cpp b/src/wkt/wkt_generator.cpp index 03900ee4e..67ca61295 100644 --- a/src/wkt/wkt_generator.cpp +++ b/src/wkt/wkt_generator.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -156,6 +157,23 @@ wkt_multi_generator::wkt_multi_generator() template struct mapnik::util::wkt_generator, mapnik::geometry_type>; template struct mapnik::util::wkt_multi_generator, mapnik::geometry_container >; +bool to_wkt(std::string & wkt, mapnik::geometry_type const& geom) +{ + typedef std::back_insert_iterator sink_type; + sink_type sink(wkt); + wkt_generator generator(true); + bool result = karma::generate(sink, generator, geom); + return result; +} + +bool to_wkt(std::string & wkt, mapnik::geometry_container const& geom) +{ + typedef std::back_insert_iterator sink_type; + sink_type sink(wkt); + wkt_multi_generator generator; + bool result = karma::generate(sink, generator, geom); + return result; +} }} diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp index ffa7fe883..5c7cf7a98 100644 --- a/src/xml_tree.cpp +++ b/src/xml_tree.cpp @@ -182,9 +182,13 @@ std::string xml_node::xml_text = ""; std::string const& xml_node::name() const { if (!is_text_) + { return name_; + } else + { return xml_text; + } } std::string const& xml_node::text() const @@ -193,7 +197,8 @@ std::string const& xml_node::text() const { processed_ = true; return name_; - } else + } + else { throw config_error("text() called on non-text node", *this); } @@ -336,7 +341,8 @@ std::string xml_node::get_text() const if (is_text_) { return name_; - } else + } + else { return ""; } diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index b0c022de9..6a630d1d8 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -335,6 +335,16 @@ def test_map_init(): m = mapnik.Map(256, 256, '+proj=latlong') eq_(m.srs, '+proj=latlong') +def test_map_style_access(): + m = mapnik.Map(256, 256) + sty = mapnik.Style() + m.append_style("style",sty) + styles = list(m.styles) + eq_(len(styles),1) + eq_(styles[0][0],'style') + # returns a copy so let's just check it is the right instance + eq_(isinstance(styles[0][1],mapnik.Style),True) + def test_map_maximum_extent_modification(): m = mapnik.Map(256, 256) eq_(m.maximum_extent, None) diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index d3cc4f1e2..7f052308b 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -12,56 +12,76 @@ def setup(): # from another directory we need to chdir() os.chdir(execution_path('.')) - def test_simplest_render(): m = mapnik.Map(256, 256) - i = mapnik.Image(m.width, m.height) - - mapnik.render(m, i) - - s = i.tostring() - + im = mapnik.Image(m.width, m.height) + eq_(im.painted(),False) + eq_(im.is_solid(),True) + mapnik.render(m, im) + eq_(im.painted(),False) + eq_(im.is_solid(),True) + s = im.tostring() eq_(s, 256 * 256 * '\x00\x00\x00\x00') def test_render_image_to_string(): - i = mapnik.Image(256, 256) - - i.background = mapnik.Color('black') - - s = i.tostring() - + im = mapnik.Image(256, 256) + im.background = mapnik.Color('black') + eq_(im.painted(),False) + eq_(im.is_solid(),True) + s = im.tostring() eq_(s, 256 * 256 * '\x00\x00\x00\xff') + s = im.tostring('png') - s = i.tostring('png') +def test_non_solid_image(): + im = mapnik.Image(256, 256) + im.background = mapnik.Color('black') + eq_(im.painted(),False) + eq_(im.is_solid(),True) + # set one pixel to a different color + im.set_pixel(0,0,mapnik.Color('white')) + eq_(im.painted(),False) + eq_(im.is_solid(),False) + +def test_non_solid_image_view(): + im = mapnik.Image(256, 256) + im.background = mapnik.Color('black') + view = im.view(0,0,256,256) + eq_(view.is_solid(),True) + # set one pixel to a different color + im.set_pixel(0,0,mapnik.Color('white')) + eq_(im.is_solid(),False) + # view, since it is the exact dimensions of the image + # should also be non-solid + eq_(view.is_solid(),False) + # but not a view that excludes the single diff pixel + view2 = im.view(1,1,256,256) + eq_(view2.is_solid(),True) def test_setting_alpha(): w,h = 256,256 im1 = mapnik.Image(w,h) # white, half transparent im1.background = mapnik.Color('rgba(255,255,255,.5)') - + eq_(im1.painted(),False) + eq_(im1.is_solid(),True) # pure white im2 = mapnik.Image(w,h) im2.background = mapnik.Color('rgba(255,255,255,1)') im2.set_alpha(.5) - + eq_(im2.painted(),False) + eq_(im2.is_solid(),True) eq_(len(im1.tostring()), len(im2.tostring())) - def test_render_image_to_file(): - i = mapnik.Image(256, 256) - - i.background = mapnik.Color('black') - + im = mapnik.Image(256, 256) + im.background = mapnik.Color('black') if mapnik.has_jpeg(): - i.save('test.jpg') - i.save('test.png', 'png') - + im.save('test.jpg') + im.save('test.png', 'png') if os.path.exists('test.jpg'): os.remove('test.jpg') else: return False - if os.path.exists('test.png'): os.remove('test.png') else: @@ -71,34 +91,32 @@ def get_paired_images(w,h,mapfile): tmp_map = 'tmp_map.xml' m = mapnik.Map(w,h) mapnik.load_map(m,mapfile) - i = mapnik.Image(w,h) + im = mapnik.Image(w,h) m.zoom_all() - mapnik.render(m,i) + mapnik.render(m,im) mapnik.save_map(m,tmp_map) m2 = mapnik.Map(w,h) mapnik.load_map(m2,tmp_map) - i2 = mapnik.Image(w,h) + im2 = mapnik.Image(w,h) m2.zoom_all() - mapnik.render(m2,i2) + mapnik.render(m2,im2) os.remove(tmp_map) - return i,i2 + return im,im2 def test_render_from_serialization(): try: - i,i2 = get_paired_images(100,100,'../data/good_maps/building_symbolizer.xml') - eq_(i.tostring(),i2.tostring()) + im,im2 = get_paired_images(100,100,'../data/good_maps/building_symbolizer.xml') + eq_(im.tostring(),im2.tostring()) - i,i2 = get_paired_images(100,100,'../data/good_maps/polygon_symbolizer.xml') - eq_(i.tostring(),i2.tostring()) + im,im2 = get_paired_images(100,100,'../data/good_maps/polygon_symbolizer.xml') + eq_(im.tostring(),im2.tostring()) except RuntimeError, e: # only test datasources that we have installed if not 'Could not create datasource' in str(e): raise RuntimeError(e) def test_render_points(): - if not mapnik.has_cairo(): return - # create and populate point datasource (WGS84 lat-lon coordinates) ds = mapnik.MemoryDatasource() context = mapnik.Context() @@ -163,6 +181,14 @@ def test_render_with_scale_factor(): for size in sizes: im = mapnik.Image(256, 256) mapnik.render(m,im,size) + expected_file = './images/support/marker-text-line-scale-factor-%s.png' % size + actual_file = '/tmp/' + os.path.basename(expected_file) + im.save(actual_file,'png8') + #im.save(expected_file,'png8') + # we save and re-open here so both png8 images are ready as full color png + actual = mapnik.Image.open(expected_file) + expected = mapnik.Image.open(expected_file) + eq_(actual.tostring(),expected.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual_file,expected_file)) im.save('./images/support/marker-text-line-scale-factor-%s.png' % size,'png8') if __name__ == "__main__": diff --git a/tests/run_tests.py b/tests/run_tests.py index b2406129f..e9ebae81d 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -72,8 +72,8 @@ def main(): argv.append('-v') argv.append('-v') - dirname = os.path.dirname(sys.argv[0]) - argv.extend(['-w', dirname+'/python_tests']) + dirname = os.path.dirname(sys.argv[0]) + argv.extend(['-w', os.path.join(dirname,'python_tests')]) if not nose.run(argv=argv, plugins=[TodoPlugin(), Doctest()]): sys.exit(1)