Merge branch 'master' into harfbuzz
Conflicts: src/build.py
This commit is contained in:
commit
ef0aae3733
59 changed files with 1568 additions and 852 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -43,4 +43,11 @@ demo/c++/demo.tif
|
||||||
demo/c++/demo.jpg
|
demo/c++/demo.jpg
|
||||||
demo/c++/demo.png
|
demo/c++/demo.png
|
||||||
demo/c++/demo256.png
|
demo/c++/demo256.png
|
||||||
|
demo/viewer/Makefile
|
||||||
|
demo/viewer/Makefile.Debug
|
||||||
|
demo/viewer/Makefile.Release
|
||||||
|
demo/viewer/release/
|
||||||
|
demo/viewer/ui_about.h
|
||||||
|
demo/viewer/ui_info.h
|
||||||
|
demo/viewer/ui_layer_info.h
|
||||||
tests/cpp_tests/*-bin
|
tests/cpp_tests/*-bin
|
||||||
|
|
|
@ -11,6 +11,10 @@ For a complete change history, see the git log.
|
||||||
|
|
||||||
Not yet released
|
Not yet released
|
||||||
|
|
||||||
|
- Added support for overriding fill, stroke, and opacity for svg markers using marker properties
|
||||||
|
|
||||||
|
- Added support for setting opacity dynamically on images in polygon pattern and markers symbolizers
|
||||||
|
|
||||||
- Added support for filtering on a features geometry type, either `point`, `linestring`, 'polygon`,
|
- Added support for filtering on a features geometry type, either `point`, `linestring`, 'polygon`,
|
||||||
or `collection` using the expression keyword of `[mapnik::geometry_type]` (#546)
|
or `collection` using the expression keyword of `[mapnik::geometry_type]` (#546)
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,18 @@ struct layer_pickle_suite : boost::python::pickle_suite
|
||||||
|
|
||||||
std::vector<std::string> & (mapnik::layer::*_styles_)() = &mapnik::layer::styles;
|
std::vector<std::string> & (mapnik::layer::*_styles_)() = &mapnik::layer::styles;
|
||||||
|
|
||||||
|
void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double> > const& box)
|
||||||
|
{
|
||||||
|
if (box)
|
||||||
|
{
|
||||||
|
l.set_maximum_extent(*box);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l.reset_maximum_extent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void export_layer()
|
void export_layer()
|
||||||
{
|
{
|
||||||
using namespace boost::python;
|
using namespace boost::python;
|
||||||
|
@ -196,6 +208,27 @@ void export_layer()
|
||||||
"<mapnik.Datasource object at 0x65470>\n"
|
"<mapnik.Datasource object at 0x65470>\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
.add_property("buffer_size",
|
||||||
|
&layer::buffer_size,
|
||||||
|
&layer::set_buffer_size,
|
||||||
|
"Get/Set the size of buffer around layer in pixels.\n"
|
||||||
|
"\n"
|
||||||
|
"Usage:\n"
|
||||||
|
">>> l.buffer_size\n"
|
||||||
|
"0 # zero by default\n"
|
||||||
|
">>> l.buffer_size = 2\n"
|
||||||
|
">>> l.buffer_size\n"
|
||||||
|
"2\n"
|
||||||
|
)
|
||||||
|
.add_property("maximum_extent",make_function
|
||||||
|
(&layer::maximum_extent,return_value_policy<copy_const_reference>()),
|
||||||
|
&set_maximum_extent,
|
||||||
|
"The maximum extent of the map.\n"
|
||||||
|
"\n"
|
||||||
|
"Usage:\n"
|
||||||
|
">>> m.maximum_extent = Box2d(-180,-90,180,90)\n"
|
||||||
|
)
|
||||||
|
|
||||||
.add_property("maxzoom",
|
.add_property("maxzoom",
|
||||||
&layer::max_zoom,
|
&layer::max_zoom,
|
||||||
&layer::set_max_zoom,
|
&layer::set_max_zoom,
|
||||||
|
|
|
@ -57,7 +57,7 @@ void export_line_symbolizer()
|
||||||
"Set/get the rasterization method of the line of the point")
|
"Set/get the rasterization method of the line of the point")
|
||||||
.add_property("stroke",make_function
|
.add_property("stroke",make_function
|
||||||
(&line_symbolizer::get_stroke,
|
(&line_symbolizer::get_stroke,
|
||||||
return_value_policy<copy_const_reference>()),
|
return_value_policy<reference_existing_object>()),
|
||||||
&line_symbolizer::set_stroke)
|
&line_symbolizer::set_stroke)
|
||||||
.add_property("smooth",
|
.add_property("smooth",
|
||||||
&line_symbolizer::smooth,
|
&line_symbolizer::smooth,
|
||||||
|
|
|
@ -117,7 +117,7 @@ struct map_pickle_suite : boost::python::pickle_suite
|
||||||
std::vector<layer>& (Map::*layers_nonconst)() = &Map::layers;
|
std::vector<layer>& (Map::*layers_nonconst)() = &Map::layers;
|
||||||
std::vector<layer> const& (Map::*layers_const)() const = &Map::layers;
|
std::vector<layer> const& (Map::*layers_const)() const = &Map::layers;
|
||||||
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
|
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
|
||||||
boost::optional<mapnik::box2d<double> > const& (Map::*maximum_extent_const)() const = &Map::maximum_extent;
|
//boost::optional<mapnik::box2d<double> > const& (Map::*maximum_extent_const)() const = &Map::maximum_extent;
|
||||||
|
|
||||||
mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name)
|
mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,6 @@ mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - find a simplier way to set optional to uninitialized
|
|
||||||
void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> > const& box)
|
void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> > const& box)
|
||||||
{
|
{
|
||||||
if (box)
|
if (box)
|
||||||
|
@ -201,7 +200,7 @@ void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> >
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m.maximum_extent().reset();
|
m.reset_maximum_extent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +561,7 @@ void export_map()
|
||||||
)
|
)
|
||||||
|
|
||||||
.add_property("maximum_extent",make_function
|
.add_property("maximum_extent",make_function
|
||||||
(maximum_extent_const,return_value_policy<copy_const_reference>()),
|
(&Map::maximum_extent,return_value_policy<copy_const_reference>()),
|
||||||
&set_maximum_extent,
|
&set_maximum_extent,
|
||||||
"The maximum extent of the map.\n"
|
"The maximum extent of the map.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
@ -86,13 +86,13 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void export_markers_symbolizer()
|
void export_markers_symbolizer()
|
||||||
{
|
{
|
||||||
using namespace boost::python;
|
using namespace boost::python;
|
||||||
|
|
||||||
mapnik::enumeration_<mapnik::marker_placement_e>("marker_placement")
|
mapnik::enumeration_<mapnik::marker_placement_e>("marker_placement")
|
||||||
.value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT)
|
.value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT)
|
||||||
|
.value("INTERIOR_PLACEMENT",mapnik::MARKER_INTERIOR_PLACEMENT)
|
||||||
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
|
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -115,7 +115,11 @@ void export_markers_symbolizer()
|
||||||
.add_property("opacity",
|
.add_property("opacity",
|
||||||
&markers_symbolizer::get_opacity,
|
&markers_symbolizer::get_opacity,
|
||||||
&markers_symbolizer::set_opacity,
|
&markers_symbolizer::set_opacity,
|
||||||
"Set/get the text opacity")
|
"Set/get the overall opacity")
|
||||||
|
.add_property("fill_opacity",
|
||||||
|
&markers_symbolizer::get_fill_opacity,
|
||||||
|
&markers_symbolizer::set_fill_opacity,
|
||||||
|
"Set/get the fill opacity")
|
||||||
.add_property("ignore_placement",
|
.add_property("ignore_placement",
|
||||||
&markers_symbolizer::get_ignore_placement,
|
&markers_symbolizer::get_ignore_placement,
|
||||||
&markers_symbolizer::set_ignore_placement)
|
&markers_symbolizer::set_ignore_placement)
|
||||||
|
|
|
@ -608,12 +608,14 @@ BOOST_PYTHON_MODULE(_mapnik)
|
||||||
def("has_cairo", &has_cairo, "Get cairo library status");
|
def("has_cairo", &has_cairo, "Get cairo library status");
|
||||||
def("has_pycairo", &has_pycairo, "Get pycairo module status");
|
def("has_pycairo", &has_pycairo, "Get pycairo module status");
|
||||||
|
|
||||||
|
python_optional<mapnik::stroke>();
|
||||||
python_optional<mapnik::color>();
|
python_optional<mapnik::color>();
|
||||||
python_optional<mapnik::box2d<double> >();
|
python_optional<mapnik::box2d<double> >();
|
||||||
python_optional<mapnik::datasource::geometry_t>();
|
python_optional<mapnik::datasource::geometry_t>();
|
||||||
python_optional<std::string>();
|
python_optional<std::string>();
|
||||||
python_optional<unsigned>();
|
python_optional<unsigned>();
|
||||||
python_optional<double>();
|
python_optional<double>();
|
||||||
|
python_optional<float>();
|
||||||
python_optional<bool>();
|
python_optional<bool>();
|
||||||
python_optional<mapnik::text_transform_e>();
|
python_optional<mapnik::text_transform_e>();
|
||||||
register_ptr_to_python<mapnik::expression_ptr>();
|
register_ptr_to_python<mapnik::expression_ptr>();
|
||||||
|
|
|
@ -36,10 +36,11 @@ int main( int argc, char **argv )
|
||||||
using mapnik::datasource_cache;
|
using mapnik::datasource_cache;
|
||||||
using mapnik::freetype_engine;
|
using mapnik::freetype_engine;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
QCoreApplication::setOrganizationName("Mapnik");
|
QCoreApplication::setOrganizationName("Mapnik");
|
||||||
QCoreApplication::setOrganizationDomain("mapnik.org");
|
QCoreApplication::setOrganizationDomain("mapnik.org");
|
||||||
QCoreApplication::setApplicationName("Viewer");
|
QCoreApplication::setApplicationName("Viewer");
|
||||||
|
|
||||||
QSettings settings("viewer.ini",QSettings::IniFormat);
|
QSettings settings("viewer.ini",QSettings::IniFormat);
|
||||||
|
|
||||||
// register input plug-ins
|
// register input plug-ins
|
||||||
|
@ -84,4 +85,10 @@ int main( int argc, char **argv )
|
||||||
if (ok) window.set_scaling_factor(scaling_factor);
|
if (ok) window.set_scaling_factor(scaling_factor);
|
||||||
}
|
}
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
std::cerr << "Could not start viewer: '" << ex.what() << "'\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
59
deps/agg/include/agg_pixfmt_rgba.h
vendored
59
deps/agg/include/agg_pixfmt_rgba.h
vendored
|
@ -1015,18 +1015,34 @@ namespace agg
|
||||||
// Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
|
// Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa)
|
||||||
//
|
//
|
||||||
// Da' = Sa + Da - Sa.Da
|
// Da' = Sa + Da - Sa.Da
|
||||||
|
|
||||||
|
|
||||||
|
// http://www.w3.org/TR/SVGCompositing/
|
||||||
|
// if Sca == 0 and Dca == Da
|
||||||
|
// Dca' = Sa × Da + Sca × (1 - Da) + Dca × (1 - Sa)
|
||||||
|
// = Sa × Da + Dca × (1 - Sa)
|
||||||
|
// = Da = Dca
|
||||||
|
// otherwise if Sca == 0
|
||||||
|
// Dca' = Sca × (1 - Da) + Dca × (1 - Sa)
|
||||||
|
// = Dca × (1 - Sa)
|
||||||
|
// otherwise if Sca > 0
|
||||||
|
// Dca' = Sa × Da - Sa × Da × min(1, (1 - Dca/Da) × Sa/Sca) + Sca × (1 - Da) + Dca × (1 - Sa)
|
||||||
|
// = Sa × Da × (1 - min(1, (1 - Dca/Da) × Sa/Sca)) + Sca × (1 - Da) + Dca × (1 - Sa)
|
||||||
|
|
||||||
|
// sa * da * (255 - std::min(255, (255 - p[0]/da)*(sa/(sc*sa)) +
|
||||||
static AGG_INLINE void blend_pix(value_type* p,
|
static AGG_INLINE void blend_pix(value_type* p,
|
||||||
unsigned sr, unsigned sg, unsigned sb,
|
unsigned sr, unsigned sg, unsigned sb,
|
||||||
unsigned sa, unsigned cover)
|
unsigned sa, unsigned cover)
|
||||||
{
|
{
|
||||||
if(cover < 255)
|
if (cover < 255)
|
||||||
{
|
{
|
||||||
sr = (sr * cover + 255) >> 8;
|
sr = (sr * cover + 255) >> 8;
|
||||||
sg = (sg * cover + 255) >> 8;
|
sg = (sg * cover + 255) >> 8;
|
||||||
sb = (sb * cover + 255) >> 8;
|
sb = (sb * cover + 255) >> 8;
|
||||||
sa = (sa * cover + 255) >> 8;
|
sa = (sa * cover + 255) >> 8;
|
||||||
}
|
}
|
||||||
if(sa)
|
|
||||||
|
if (sa)
|
||||||
{
|
{
|
||||||
calc_type d1a = base_mask - p[Order::A];
|
calc_type d1a = base_mask - p[Order::A];
|
||||||
calc_type s1a = base_mask - sa;
|
calc_type s1a = base_mask - sa;
|
||||||
|
@ -1042,15 +1058,15 @@ namespace agg
|
||||||
long_type sbda = sb * da;
|
long_type sbda = sb * da;
|
||||||
long_type sada = sa * da;
|
long_type sada = sa * da;
|
||||||
|
|
||||||
p[Order::R] = (value_type)(((srda + drsa <= sada) ?
|
if ( sr > 0) p[Order::R] = (value_type)(((srda + drsa <= sada) ?
|
||||||
sr * d1a + dr * s1a :
|
sr * d1a + dr * s1a :
|
||||||
sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask) >> base_shift);
|
sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask) >> base_shift);
|
||||||
|
|
||||||
p[Order::G] = (value_type)(((sgda + dgsa <= sada) ?
|
if ( sg > 0 ) p[Order::G] = (value_type)(((sgda + dgsa <= sada) ?
|
||||||
sg * d1a + dg * s1a :
|
sg * d1a + dg * s1a :
|
||||||
sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask) >> base_shift);
|
sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask) >> base_shift);
|
||||||
|
|
||||||
p[Order::B] = (value_type)(((sbda + dbsa <= sada) ?
|
if ( sb > 0) p[Order::B] = (value_type)(((sbda + dbsa <= sada) ?
|
||||||
sb * d1a + db * s1a :
|
sb * d1a + db * s1a :
|
||||||
sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask) >> base_shift);
|
sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask) >> base_shift);
|
||||||
|
|
||||||
|
@ -1502,24 +1518,29 @@ namespace agg
|
||||||
unsigned sr, unsigned sg, unsigned sb,
|
unsigned sr, unsigned sg, unsigned sb,
|
||||||
unsigned sa, unsigned cover)
|
unsigned sa, unsigned cover)
|
||||||
{
|
{
|
||||||
if (cover < 255)
|
calc_type da = (p[Order::A] * sa + 255) >> 8;
|
||||||
{
|
|
||||||
sr = (sr * cover + 255) >> 8;
|
|
||||||
sg = (sg * cover + 255) >> 8;
|
|
||||||
sb = (sb * cover + 255) >> 8;
|
|
||||||
sa = (sa * cover + 255) >> 8;
|
|
||||||
}
|
|
||||||
if (sa > 0)
|
|
||||||
{
|
|
||||||
calc_type da = p[Order::A];
|
|
||||||
int dr = p[Order::R] - sr + 128;
|
int dr = p[Order::R] - sr + 128;
|
||||||
int dg = p[Order::G] - sg + 128;
|
int dg = p[Order::G] - sg + 128;
|
||||||
int db = p[Order::B] - sb + 128;
|
int db = p[Order::B] - sb + 128;
|
||||||
|
|
||||||
p[Order::R] = dr < 0 ? 0 : (dr > 255 ? 255 : dr);
|
dr = dr < 0 ? 0 : (dr > 255 ? 255 : dr);
|
||||||
p[Order::G] = dg < 0 ? 0 : (dg > 255 ? 255 : dg);
|
dg = dg < 0 ? 0 : (dg > 255 ? 255 : dg);
|
||||||
p[Order::B] = db < 0 ? 0 : (db > 255 ? 255 : db);
|
db = db < 0 ? 0 : (db > 255 ? 255 : db);
|
||||||
p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
|
|
||||||
|
p[Order::A] = da;
|
||||||
|
|
||||||
|
if (da < 255)
|
||||||
|
{
|
||||||
|
p[Order::R] = (dr * da + 255) >> 8;
|
||||||
|
p[Order::G] = (dg * da + 255) >> 8;
|
||||||
|
p[Order::B] = (db * da + 255) >> 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p[Order::R] = dr;
|
||||||
|
p[Order::G] = dg;
|
||||||
|
p[Order::B] = db;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -127,6 +127,7 @@ protected:
|
||||||
double x, double y, double angle = 0.0);
|
double x, double y, double angle = 0.0);
|
||||||
void debug_draw_box(box2d<double> const& extent,
|
void debug_draw_box(box2d<double> const& extent,
|
||||||
double x, double y, double angle = 0.0);
|
double x, double y, double angle = 0.0);
|
||||||
|
void draw_geo_extent(box2d<double> const& extent,mapnik::color const& color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
buffer_type & pixmap_;
|
buffer_type & pixmap_;
|
||||||
|
|
|
@ -249,7 +249,7 @@ public:
|
||||||
|
|
||||||
struct directive_collector : public boost::static_visitor<>
|
struct directive_collector : public boost::static_visitor<>
|
||||||
{
|
{
|
||||||
directive_collector(double * filter_factor)
|
directive_collector(double & filter_factor)
|
||||||
: filter_factor_(filter_factor) {}
|
: filter_factor_(filter_factor) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -257,10 +257,10 @@ struct directive_collector : public boost::static_visitor<>
|
||||||
|
|
||||||
void operator () (raster_symbolizer const& sym)
|
void operator () (raster_symbolizer const& sym)
|
||||||
{
|
{
|
||||||
*filter_factor_ = sym.calculate_filter_factor();
|
filter_factor_ = sym.calculate_filter_factor();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
double * filter_factor_;
|
double & filter_factor_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mapnik
|
} // namespace mapnik
|
||||||
|
|
|
@ -110,7 +110,7 @@ operator << (std::basic_ostream<charT,traits>& out,
|
||||||
std::basic_ostringstream<charT,traits> s;
|
std::basic_ostringstream<charT,traits> s;
|
||||||
s.copyfmt(out);
|
s.copyfmt(out);
|
||||||
s.width(0);
|
s.width(0);
|
||||||
s << "box2d(" << std::setprecision(16)
|
s << "box2d(" << std::fixed << std::setprecision(16)
|
||||||
<< e.minx() << ',' << e.miny() << ','
|
<< e.minx() << ',' << e.miny() << ','
|
||||||
<< e.maxx() << ',' << e.maxy() << ')';
|
<< e.maxx() << ',' << e.maxy() << ')';
|
||||||
out << s.str();
|
out << s.str();
|
||||||
|
|
|
@ -65,21 +65,12 @@ struct MAPNIK_DECL coord_transform
|
||||||
|
|
||||||
unsigned vertex(double *x, double *y) const
|
unsigned vertex(double *x, double *y) const
|
||||||
{
|
{
|
||||||
unsigned command = SEG_MOVETO;
|
unsigned command = geom_.vertex(x, y);
|
||||||
bool ok = false;
|
if ( command != SEG_END)
|
||||||
bool skipped_points = false;
|
{
|
||||||
double z = 0;
|
double z = 0;
|
||||||
while (!ok && command != SEG_END)
|
if (!prj_trans_->backward(*x, *y, z))
|
||||||
{
|
return SEG_END;
|
||||||
command = geom_.vertex(x, y);
|
|
||||||
ok = prj_trans_->backward(*x, *y, z);
|
|
||||||
if (!ok) {
|
|
||||||
skipped_points = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (skipped_points && (command == SEG_LINETO))
|
|
||||||
{
|
|
||||||
command = SEG_MOVETO;
|
|
||||||
}
|
}
|
||||||
t_->forward(x, y);
|
t_->forward(x, y);
|
||||||
return command;
|
return command;
|
||||||
|
|
|
@ -241,6 +241,8 @@ double path_length(PathType & path)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace label {
|
||||||
|
|
||||||
template <typename PathType>
|
template <typename PathType>
|
||||||
bool middle_point(PathType & path, double & x, double & y)
|
bool middle_point(PathType & path, double & x, double & y)
|
||||||
{
|
{
|
||||||
|
@ -271,8 +273,6 @@ bool middle_point(PathType & path, double & x, double & y)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace label {
|
|
||||||
|
|
||||||
template <typename PathType>
|
template <typename PathType>
|
||||||
bool centroid(PathType & path, double & x, double & y)
|
bool centroid(PathType & path, double & x, double & y)
|
||||||
{
|
{
|
||||||
|
|
|
@ -118,9 +118,10 @@ private:
|
||||||
CoordTransform t_;
|
CoordTransform t_;
|
||||||
freetype_engine font_engine_;
|
freetype_engine font_engine_;
|
||||||
face_manager<freetype_engine> font_manager_;
|
face_manager<freetype_engine> font_manager_;
|
||||||
label_collision_detector4 detector_;
|
boost::shared_ptr<label_collision_detector4> detector_;
|
||||||
boost::scoped_ptr<grid_rasterizer> ras_ptr;
|
boost::scoped_ptr<grid_rasterizer> ras_ptr;
|
||||||
box2d<double> query_extent_;
|
box2d<double> query_extent_;
|
||||||
|
void setup(Map const& m);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,9 @@ namespace mapnik
|
||||||
class MAPNIK_DECL layer
|
class MAPNIK_DECL layer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit layer(std::string const& name, std::string const& srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
|
layer(std::string const& name,
|
||||||
|
std::string const& srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
|
||||||
|
|
||||||
layer(layer const& l);
|
layer(layer const& l);
|
||||||
layer& operator=(layer const& l);
|
layer& operator=(layer const& l);
|
||||||
bool operator==(layer const& other) const;
|
bool operator==(layer const& other) const;
|
||||||
|
@ -57,7 +59,7 @@ public:
|
||||||
* @return the name of the layer.
|
* @return the name of the layer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const std::string& name() const;
|
std::string const& name() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Set the SRS of the layer.
|
* @brief Set the SRS of the layer.
|
||||||
|
@ -188,6 +190,11 @@ public:
|
||||||
*/
|
*/
|
||||||
box2d<double> envelope() const;
|
box2d<double> envelope() const;
|
||||||
|
|
||||||
|
void set_maximum_extent(box2d<double> const& box);
|
||||||
|
boost::optional<box2d<double> > const& maximum_extent() const;
|
||||||
|
void reset_maximum_extent();
|
||||||
|
void set_buffer_size(int size);
|
||||||
|
int buffer_size() const;
|
||||||
~layer();
|
~layer();
|
||||||
private:
|
private:
|
||||||
void swap(const layer& other);
|
void swap(const layer& other);
|
||||||
|
@ -204,6 +211,8 @@ private:
|
||||||
std::string group_by_;
|
std::string group_by_;
|
||||||
std::vector<std::string> styles_;
|
std::vector<std::string> styles_;
|
||||||
datasource_ptr ds_;
|
datasource_ptr ds_;
|
||||||
|
int buffer_size_;
|
||||||
|
boost::optional<box2d<double> > maximum_extent_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -332,15 +332,13 @@ public:
|
||||||
/*! \brief Set the map maximum extent.
|
/*! \brief Set the map maximum extent.
|
||||||
* @param box The bounding box for the maximum extent.
|
* @param box The bounding box for the maximum extent.
|
||||||
*/
|
*/
|
||||||
void set_maximum_extent(box2d<double>const& box);
|
void set_maximum_extent(box2d<double> const& box);
|
||||||
|
|
||||||
/*! \brief Get the map maximum extent as box2d<double>
|
/*! \brief Get the map maximum extent as box2d<double>
|
||||||
*/
|
*/
|
||||||
boost::optional<box2d<double> > const& maximum_extent() const;
|
boost::optional<box2d<double> > const& maximum_extent() const;
|
||||||
|
|
||||||
/*! \brief Get the non-const map maximum extent as box2d<double>
|
void reset_maximum_extent();
|
||||||
*/
|
|
||||||
boost::optional<box2d<double> > & maximum_extent();
|
|
||||||
|
|
||||||
/*! \brief Get the map base path where paths should be relative to.
|
/*! \brief Get the map base path where paths should be relative to.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -49,13 +49,13 @@ namespace mapnik
|
||||||
|
|
||||||
typedef agg::pod_bvector<mapnik::svg::path_attributes> attr_storage;
|
typedef agg::pod_bvector<mapnik::svg::path_attributes> attr_storage;
|
||||||
typedef mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage> svg_storage_type;
|
typedef mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage> svg_storage_type;
|
||||||
typedef boost::shared_ptr<svg_storage_type> path_ptr;
|
typedef boost::shared_ptr<svg_storage_type> svg_path_ptr;
|
||||||
typedef boost::shared_ptr<image_data_32> image_ptr;
|
typedef boost::shared_ptr<image_data_32> image_ptr;
|
||||||
/**
|
/**
|
||||||
* A class to hold either vector or bitmap marker data. This allows these to be treated equally
|
* A class to hold either vector or bitmap marker data. This allows these to be treated equally
|
||||||
* in the image caches and most of the render paths.
|
* in the image caches and most of the render paths.
|
||||||
*/
|
*/
|
||||||
class marker
|
class marker: private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
marker()
|
marker()
|
||||||
|
@ -65,20 +65,21 @@ public:
|
||||||
(*bitmap_data_)->set(0xff000000);
|
(*bitmap_data_)->set(0xff000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
marker(const boost::optional<mapnik::image_ptr> &data)
|
marker(boost::optional<mapnik::image_ptr> const& data)
|
||||||
: bitmap_data_(data)
|
: bitmap_data_(data)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
marker(const boost::optional<mapnik::path_ptr> &data)
|
marker(boost::optional<mapnik::svg_path_ptr> const& data)
|
||||||
: vector_data_(data)
|
: vector_data_(data)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
marker(const marker& rhs)
|
marker(marker const& rhs)
|
||||||
: bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_)
|
: bitmap_data_(rhs.bitmap_data_),
|
||||||
|
vector_data_(rhs.vector_data_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
box2d<double> bounding_box() const
|
box2d<double> bounding_box() const
|
||||||
|
@ -128,17 +129,14 @@ public:
|
||||||
return bitmap_data_;
|
return bitmap_data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<mapnik::path_ptr> get_vector_data() const
|
boost::optional<mapnik::svg_path_ptr> get_vector_data() const
|
||||||
{
|
{
|
||||||
return vector_data_;
|
return vector_data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
marker& operator=(const marker&);
|
|
||||||
|
|
||||||
boost::optional<mapnik::image_ptr> bitmap_data_;
|
boost::optional<mapnik::image_ptr> bitmap_data_;
|
||||||
boost::optional<mapnik::path_ptr> vector_data_;
|
boost::optional<mapnik::svg_path_ptr> vector_data_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,39 +27,359 @@
|
||||||
#include <mapnik/markers_symbolizer.hpp>
|
#include <mapnik/markers_symbolizer.hpp>
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||||
|
#include <mapnik/svg/svg_converter.hpp>
|
||||||
|
#include <mapnik/marker.hpp> // for svg_storage_type
|
||||||
|
#include <mapnik/svg/svg_storage.hpp>
|
||||||
|
#include <mapnik/markers_placement.hpp>
|
||||||
|
|
||||||
|
// agg
|
||||||
|
#include "agg_ellipse.h"
|
||||||
|
#include "agg_basics.h"
|
||||||
|
#include "agg_renderer_base.h"
|
||||||
|
#include "agg_renderer_scanline.h"
|
||||||
|
#include "agg_rendering_buffer.h"
|
||||||
|
#include "agg_scanline_u.h"
|
||||||
|
#include "agg_image_filters.h"
|
||||||
|
#include "agg_trans_bilinear.h"
|
||||||
|
#include "agg_span_allocator.h"
|
||||||
|
#include "agg_image_accessors.h"
|
||||||
|
#include "agg_pixfmt_rgba.h"
|
||||||
|
#include "agg_span_image_filter_rgba.h"
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
|
||||||
|
template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
|
||||||
|
struct vector_markers_rasterizer_dispatch
|
||||||
|
{
|
||||||
|
typedef typename SvgRenderer::renderer_base renderer_base;
|
||||||
|
typedef typename renderer_base::pixfmt_type pixfmt_type;
|
||||||
|
|
||||||
|
vector_markers_rasterizer_dispatch(BufferType & image_buffer,
|
||||||
|
SvgRenderer & svg_renderer,
|
||||||
|
Rasterizer & ras,
|
||||||
|
box2d<double> const& bbox,
|
||||||
|
agg::trans_affine const& marker_trans,
|
||||||
|
markers_symbolizer const& sym,
|
||||||
|
Detector & detector,
|
||||||
|
double scale_factor)
|
||||||
|
: buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4),
|
||||||
|
pixf_(buf_),
|
||||||
|
renb_(pixf_),
|
||||||
|
svg_renderer_(svg_renderer),
|
||||||
|
ras_(ras),
|
||||||
|
bbox_(bbox),
|
||||||
|
marker_trans_(marker_trans),
|
||||||
|
sym_(sym),
|
||||||
|
detector_(detector),
|
||||||
|
scale_factor_(scale_factor)
|
||||||
|
{
|
||||||
|
pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_path(T & path)
|
||||||
|
{
|
||||||
|
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||||
|
|
||||||
|
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||||
|
{
|
||||||
|
double x,y;
|
||||||
|
path.rewind(0);
|
||||||
|
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||||
|
{
|
||||||
|
label::interior_position(path, x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label::centroid(path, x, y);
|
||||||
|
}
|
||||||
|
agg::trans_affine matrix = marker_trans_;
|
||||||
|
matrix.translate(x,y);
|
||||||
|
box2d<double> transformed_bbox = bbox_ * matrix;
|
||||||
|
|
||||||
|
if (sym_.get_allow_overlap() ||
|
||||||
|
detector_.has_placement(transformed_bbox))
|
||||||
|
{
|
||||||
|
svg_renderer_.render(ras_, sl_, renb_, matrix, 1, bbox_);
|
||||||
|
|
||||||
|
if (!sym_.get_ignore_placement())
|
||||||
|
detector_.insert(transformed_bbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
||||||
|
sym_.get_spacing() * scale_factor_,
|
||||||
|
sym_.get_max_error(),
|
||||||
|
sym_.get_allow_overlap());
|
||||||
|
double x, y, angle;
|
||||||
|
while (placement.get_point(x, y, angle))
|
||||||
|
{
|
||||||
|
agg::trans_affine matrix = marker_trans_;
|
||||||
|
matrix.rotate(angle);
|
||||||
|
matrix.translate(x, y);
|
||||||
|
svg_renderer_.render(ras_, sl_, renb_, matrix, 1, bbox_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
agg::scanline_u8 sl_;
|
||||||
|
agg::rendering_buffer buf_;
|
||||||
|
pixfmt_type pixf_;
|
||||||
|
renderer_base renb_;
|
||||||
|
SvgRenderer & svg_renderer_;
|
||||||
|
Rasterizer & ras_;
|
||||||
|
box2d<double> const& bbox_;
|
||||||
|
agg::trans_affine const& marker_trans_;
|
||||||
|
markers_symbolizer const& sym_;
|
||||||
|
Detector & detector_;
|
||||||
|
double scale_factor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Rasterizer, typename RendererBuffer>
|
||||||
|
void render_raster_marker(Rasterizer & ras, RendererBuffer & renb,
|
||||||
|
agg::scanline_u8 & sl, image_data_32 const& src,
|
||||||
|
agg::trans_affine const& marker_tr, double opacity)
|
||||||
|
{
|
||||||
|
double width = src.width();
|
||||||
|
double height = src.height();
|
||||||
|
double p[8];
|
||||||
|
p[0] = 0; p[1] = 0;
|
||||||
|
p[2] = width; p[3] = 0;
|
||||||
|
p[4] = width; p[5] = height;
|
||||||
|
p[6] = 0; p[7] = height;
|
||||||
|
|
||||||
|
marker_tr.transform(&p[0], &p[1]);
|
||||||
|
marker_tr.transform(&p[2], &p[3]);
|
||||||
|
marker_tr.transform(&p[4], &p[5]);
|
||||||
|
marker_tr.transform(&p[6], &p[7]);
|
||||||
|
|
||||||
|
ras.move_to_d(p[0],p[1]);
|
||||||
|
ras.line_to_d(p[2],p[3]);
|
||||||
|
ras.line_to_d(p[4],p[5]);
|
||||||
|
ras.line_to_d(p[6],p[7]);
|
||||||
|
|
||||||
|
typedef agg::rgba8 color_type;
|
||||||
|
agg::span_allocator<color_type> sa;
|
||||||
|
agg::image_filter_bilinear filter_kernel;
|
||||||
|
agg::image_filter_lut filter(filter_kernel, false);
|
||||||
|
|
||||||
|
agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(),
|
||||||
|
src.width(),
|
||||||
|
src.height(),
|
||||||
|
src.width()*4);
|
||||||
|
agg::pixfmt_rgba32_pre pixf(marker_buf);
|
||||||
|
|
||||||
|
typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
|
||||||
|
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
|
||||||
|
typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
|
||||||
|
interpolator_type> span_gen_type;
|
||||||
|
typedef agg::order_rgba order_type;
|
||||||
|
typedef agg::pixel32_type pixel_type;
|
||||||
|
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
||||||
|
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
||||||
|
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
||||||
|
typedef agg::renderer_scanline_aa_alpha<renderer_base,
|
||||||
|
agg::span_allocator<agg::rgba8>,
|
||||||
|
span_gen_type> renderer_type;
|
||||||
|
img_accessor_type ia(pixf);
|
||||||
|
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
|
||||||
|
span_gen_type sg(ia, interpolator, filter);
|
||||||
|
renderer_type rp(renb,sa, sg, unsigned(opacity*255));
|
||||||
|
agg::render_scanlines(ras, sl, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BufferType, typename Rasterizer, typename Detector>
|
||||||
|
struct raster_markers_rasterizer_dispatch
|
||||||
|
{
|
||||||
|
typedef agg::rgba8 color_type;
|
||||||
|
typedef agg::order_rgba order_type;
|
||||||
|
typedef agg::pixel32_type pixel_type;
|
||||||
|
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
||||||
|
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
||||||
|
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
||||||
|
|
||||||
|
raster_markers_rasterizer_dispatch(BufferType & image_buffer,
|
||||||
|
Rasterizer & ras,
|
||||||
|
image_data_32 const& src,
|
||||||
|
agg::trans_affine const& marker_trans,
|
||||||
|
markers_symbolizer const& sym,
|
||||||
|
Detector & detector,
|
||||||
|
double scale_factor)
|
||||||
|
: buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4),
|
||||||
|
pixf_(buf_),
|
||||||
|
renb_(pixf_),
|
||||||
|
ras_(ras),
|
||||||
|
src_(src),
|
||||||
|
marker_trans_(marker_trans),
|
||||||
|
sym_(sym),
|
||||||
|
detector_(detector),
|
||||||
|
scale_factor_(scale_factor)
|
||||||
|
{
|
||||||
|
pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_path(T & path)
|
||||||
|
{
|
||||||
|
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||||
|
box2d<double> bbox_(0,0, src_.width(),src_.height());
|
||||||
|
|
||||||
|
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||||
|
{
|
||||||
|
double x,y;
|
||||||
|
path.rewind(0);
|
||||||
|
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||||
|
{
|
||||||
|
label::interior_position(path, x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label::centroid(path, x, y);
|
||||||
|
}
|
||||||
|
agg::trans_affine matrix = marker_trans_;
|
||||||
|
matrix.translate(x,y);
|
||||||
|
box2d<double> transformed_bbox = bbox_ * matrix;
|
||||||
|
|
||||||
|
if (sym_.get_allow_overlap() ||
|
||||||
|
detector_.has_placement(transformed_bbox))
|
||||||
|
{
|
||||||
|
|
||||||
|
float opacity = sym_.get_opacity() ? *sym_.get_opacity() : 1;
|
||||||
|
render_raster_marker(ras_, renb_, sl_, src_,
|
||||||
|
matrix, opacity);
|
||||||
|
if (!sym_.get_ignore_placement())
|
||||||
|
detector_.insert(transformed_bbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
||||||
|
sym_.get_spacing() * scale_factor_,
|
||||||
|
sym_.get_max_error(),
|
||||||
|
sym_.get_allow_overlap());
|
||||||
|
double x, y, angle;
|
||||||
|
while (placement.get_point(x, y, angle))
|
||||||
|
{
|
||||||
|
agg::trans_affine matrix = marker_trans_;
|
||||||
|
matrix.rotate(angle);
|
||||||
|
matrix.translate(x,y);
|
||||||
|
float opacity = sym_.get_opacity() ? *sym_.get_opacity() : 1;
|
||||||
|
render_raster_marker(ras_, renb_, sl_, src_,
|
||||||
|
matrix, opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
agg::scanline_u8 sl_;
|
||||||
|
agg::rendering_buffer buf_;
|
||||||
|
pixfmt_comp_type pixf_;
|
||||||
|
renderer_base renb_;
|
||||||
|
Rasterizer & ras_;
|
||||||
|
image_data_32 const& src_;
|
||||||
|
agg::trans_affine const& marker_trans_;
|
||||||
|
markers_symbolizer const& sym_;
|
||||||
|
Detector & detector_;
|
||||||
|
double scale_factor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void build_ellipse(T const& sym, mapnik::feature_impl const& feature, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path)
|
||||||
|
{
|
||||||
|
expression_ptr const& width_expr = sym.get_width();
|
||||||
|
expression_ptr const& height_expr = sym.get_height();
|
||||||
|
double width = 0;
|
||||||
|
double height = 0;
|
||||||
|
if (width_expr && height_expr)
|
||||||
|
{
|
||||||
|
width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
|
||||||
|
height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
|
||||||
|
}
|
||||||
|
else if (width_expr)
|
||||||
|
{
|
||||||
|
width = boost::apply_visitor(evaluate<Feature,value_type>(feature), *width_expr).to_double();
|
||||||
|
height = width;
|
||||||
|
}
|
||||||
|
else if (height_expr)
|
||||||
|
{
|
||||||
|
height = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr).to_double();
|
||||||
|
width = height;
|
||||||
|
}
|
||||||
|
svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes());
|
||||||
|
styled_svg.push_attr();
|
||||||
|
styled_svg.begin_path();
|
||||||
|
agg::ellipse c(0, 0, width/2.0, height/2.0);
|
||||||
|
styled_svg.storage().concat_path(c);
|
||||||
|
styled_svg.end_path();
|
||||||
|
styled_svg.pop_attr();
|
||||||
|
double lox,loy,hix,hiy;
|
||||||
|
styled_svg.bounding_rect(&lox, &loy, &hix, &hiy);
|
||||||
|
marker_ellipse.set_bounding_box(lox,loy,hix,hiy);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Attr>
|
template <typename Attr>
|
||||||
bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym)
|
bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym)
|
||||||
{
|
{
|
||||||
boost::optional<stroke> const& strk = sym.get_stroke();
|
boost::optional<stroke> const& strk = sym.get_stroke();
|
||||||
boost::optional<color> const& fill = sym.get_fill();
|
boost::optional<color> const& fill = sym.get_fill();
|
||||||
if (strk || fill)
|
boost::optional<float> const& opacity = sym.get_opacity();
|
||||||
|
boost::optional<float> const& fill_opacity = sym.get_fill_opacity();
|
||||||
|
if (strk || fill || opacity || fill_opacity)
|
||||||
{
|
{
|
||||||
|
bool success = false;
|
||||||
for(unsigned i = 0; i < src.size(); ++i)
|
for(unsigned i = 0; i < src.size(); ++i)
|
||||||
{
|
{
|
||||||
mapnik::svg::path_attributes attr = src[i];
|
success = true;
|
||||||
|
dst.push_back(src[i]);
|
||||||
if (strk && attr.stroke_flag)
|
mapnik::svg::path_attributes & attr = dst.last();
|
||||||
|
if (attr.stroke_flag)
|
||||||
|
{
|
||||||
|
// TODO - stroke attributes need to be boost::optional
|
||||||
|
// for this to work properly
|
||||||
|
if (strk)
|
||||||
{
|
{
|
||||||
attr.stroke_width = strk->get_width();
|
attr.stroke_width = strk->get_width();
|
||||||
color const& s_color = strk->get_color();
|
color const& s_color = strk->get_color();
|
||||||
attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0,
|
attr.stroke_color = agg::rgba(s_color.red()/255.0,
|
||||||
s_color.blue()/255.0,(s_color.alpha()*strk->get_opacity())/255.0);
|
s_color.green()/255.0,
|
||||||
|
s_color.blue()/255.0,
|
||||||
|
s_color.alpha()/255.0);
|
||||||
}
|
}
|
||||||
if (fill && attr.fill_flag)
|
if (opacity)
|
||||||
|
{
|
||||||
|
attr.stroke_opacity = *opacity;
|
||||||
|
}
|
||||||
|
else if (strk)
|
||||||
|
{
|
||||||
|
attr.stroke_opacity = strk->get_opacity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attr.fill_flag)
|
||||||
|
{
|
||||||
|
if (fill)
|
||||||
{
|
{
|
||||||
color const& f_color = *fill;
|
color const& f_color = *fill;
|
||||||
attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0,
|
attr.fill_color = agg::rgba(f_color.red()/255.0,
|
||||||
f_color.blue()/255.0,(f_color.alpha()*sym.get_opacity())/255.0);
|
f_color.green()/255.0,
|
||||||
|
f_color.blue()/255.0,
|
||||||
|
f_color.alpha()/255.0);
|
||||||
}
|
}
|
||||||
dst.push_back(attr);
|
if (opacity)
|
||||||
|
{
|
||||||
|
attr.fill_opacity = *opacity;
|
||||||
}
|
}
|
||||||
return true;
|
else if (fill_opacity)
|
||||||
|
{
|
||||||
|
attr.fill_opacity = *fill_opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,26 @@
|
||||||
#define MAPNIK_MARKERS_PLACEMENT_HPP
|
#define MAPNIK_MARKERS_PLACEMENT_HPP
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
|
#include <mapnik/markers_placement.hpp>
|
||||||
|
#include <mapnik/geometry.hpp>
|
||||||
|
#include <mapnik/ctrans.hpp>
|
||||||
|
#include <mapnik/label_collision_detector.hpp>
|
||||||
|
#include <mapnik/global.hpp> //round
|
||||||
#include <mapnik/box2d.hpp>
|
#include <mapnik/box2d.hpp>
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
|
#include "agg_basics.h"
|
||||||
|
#include "agg_conv_clip_polygon.h"
|
||||||
|
#include "agg_conv_clip_polyline.h"
|
||||||
|
#include "agg_trans_affine.h"
|
||||||
#include "agg_conv_transform.h"
|
#include "agg_conv_transform.h"
|
||||||
|
#include "agg_conv_smooth_poly1.h"
|
||||||
|
|
||||||
|
// stl
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
@ -47,12 +60,40 @@ public:
|
||||||
* converted to a positive value with similar magnitude, but
|
* converted to a positive value with similar magnitude, but
|
||||||
* choosen to optimize marker placement. 0 = no markers
|
* choosen to optimize marker placement. 0 = no markers
|
||||||
*/
|
*/
|
||||||
markers_placement(Locator &locator, box2d<double> const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap);
|
markers_placement(Locator &locator, box2d<double> const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap)
|
||||||
|
: locator_(locator),
|
||||||
|
size_(size),
|
||||||
|
tr_(tr),
|
||||||
|
detector_(detector),
|
||||||
|
max_error_(max_error),
|
||||||
|
allow_overlap_(allow_overlap)
|
||||||
|
{
|
||||||
|
marker_width_ = (size_ * tr_).width();
|
||||||
|
if (spacing >= 0)
|
||||||
|
{
|
||||||
|
spacing_ = spacing;
|
||||||
|
} else if (spacing < 0)
|
||||||
|
{
|
||||||
|
spacing_ = find_optimal_spacing(-spacing);
|
||||||
|
}
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
|
||||||
/** Start again at first marker.
|
/** Start again at first marker.
|
||||||
* \note Returns the same list of markers only works when they were NOT added
|
* \note Returns the same list of markers only works when they were NOT added
|
||||||
* to the detector.
|
* to the detector.
|
||||||
*/
|
*/
|
||||||
void rewind();
|
void rewind()
|
||||||
|
{
|
||||||
|
locator_.rewind(0);
|
||||||
|
//Get first point
|
||||||
|
done_ = agg::is_stop(locator_.vertex(&next_x, &next_y)) || spacing_ < marker_width_;
|
||||||
|
last_x = next_x;
|
||||||
|
last_y = next_y; // Force request of new segment
|
||||||
|
error_ = 0;
|
||||||
|
marker_nr_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Get a point where the marker should be placed.
|
/** Get a point where the marker should be placed.
|
||||||
* Each time this function is called a new point is returned.
|
* Each time this function is called a new point is returned.
|
||||||
* \param x Return value for x position
|
* \param x Return value for x position
|
||||||
|
@ -61,7 +102,115 @@ public:
|
||||||
* \param add_to_detector Add selected position to detector
|
* \param add_to_detector Add selected position to detector
|
||||||
* \return True if a place is found, false if none is found.
|
* \return True if a place is found, false if none is found.
|
||||||
*/
|
*/
|
||||||
bool get_point(double & x, double & y, double & angle, bool add_to_detector = true);
|
bool get_point(double & x, double & y, double & angle, bool add_to_detector = true)
|
||||||
|
{
|
||||||
|
if (done_) return false;
|
||||||
|
unsigned cmd;
|
||||||
|
/* This functions starts at the position of the previous marker,
|
||||||
|
walks along the path, counting how far it has to go in spacing_left.
|
||||||
|
If one marker can't be placed at the position it should go to it is
|
||||||
|
moved a bit. The error is compensated for in the next call to this
|
||||||
|
function.
|
||||||
|
|
||||||
|
error > 0: Marker too near to the end of the path.
|
||||||
|
error = 0: Perfect position.
|
||||||
|
error < 0: Marker too near to the beginning of the path.
|
||||||
|
*/
|
||||||
|
if (marker_nr_++ == 0)
|
||||||
|
{
|
||||||
|
//First marker
|
||||||
|
spacing_left_ = spacing_ / 2;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
spacing_left_ = spacing_;
|
||||||
|
}
|
||||||
|
spacing_left_ -= error_;
|
||||||
|
error_ = 0;
|
||||||
|
//Loop exits when a position is found or when no more segments are available
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
//Do not place markers too close to the beginning of a segment
|
||||||
|
if (spacing_left_ < marker_width_/2)
|
||||||
|
{
|
||||||
|
set_spacing_left(marker_width_/2); //Only moves forward
|
||||||
|
}
|
||||||
|
//Error for this marker is too large. Skip to the next position.
|
||||||
|
if (abs(error_) > max_error_ * spacing_)
|
||||||
|
{
|
||||||
|
if (error_ > spacing_)
|
||||||
|
{
|
||||||
|
error_ = 0; //Avoid moving backwards
|
||||||
|
MAPNIK_LOG_WARN(markers_placement) << "Extremely large error in markers_placement. Please file a bug report.";
|
||||||
|
}
|
||||||
|
spacing_left_ += spacing_ - error_;
|
||||||
|
error_ = 0;
|
||||||
|
}
|
||||||
|
double dx = next_x - last_x;
|
||||||
|
double dy = next_y - last_y;
|
||||||
|
double segment_length = std::sqrt(dx * dx + dy * dy);
|
||||||
|
if (segment_length <= spacing_left_)
|
||||||
|
{
|
||||||
|
//Segment is to short to place marker. Find next segment
|
||||||
|
spacing_left_ -= segment_length;
|
||||||
|
last_x = next_x;
|
||||||
|
last_y = next_y;
|
||||||
|
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
||||||
|
{
|
||||||
|
//Skip over "move" commands
|
||||||
|
last_x = next_x;
|
||||||
|
last_y = next_y;
|
||||||
|
}
|
||||||
|
if (agg::is_stop(cmd))
|
||||||
|
{
|
||||||
|
done_ = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue; //Try again
|
||||||
|
}
|
||||||
|
/* At this point we know the following things:
|
||||||
|
- segment_length > spacing_left
|
||||||
|
- error is small enough
|
||||||
|
- at least half a marker fits into this segment
|
||||||
|
*/
|
||||||
|
//Check if marker really fits in this segment
|
||||||
|
if (segment_length < marker_width_)
|
||||||
|
{
|
||||||
|
//Segment to short => Skip this segment
|
||||||
|
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
||||||
|
continue;
|
||||||
|
} else if (segment_length - spacing_left_ < marker_width_/2)
|
||||||
|
{
|
||||||
|
//Segment is long enough, but we are to close to the end
|
||||||
|
//Note: This function moves backwards. This could lead to an infinite
|
||||||
|
// loop when another function adds a positive offset. Therefore we
|
||||||
|
// only move backwards when there is no offset
|
||||||
|
if (error_ == 0)
|
||||||
|
{
|
||||||
|
set_spacing_left(segment_length - marker_width_/2, true);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
//Skip this segment
|
||||||
|
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
||||||
|
}
|
||||||
|
continue; //Force checking of max_error constraint
|
||||||
|
}
|
||||||
|
angle = atan2(dy, dx);
|
||||||
|
x = last_x + dx * (spacing_left_ / segment_length);
|
||||||
|
y = last_y + dy * (spacing_left_ / segment_length);
|
||||||
|
box2d<double> box = perform_transform(angle, x, y);
|
||||||
|
if (!allow_overlap_ && !detector_.has_placement(box))
|
||||||
|
{
|
||||||
|
//10.0 is the approxmiate number of positions tried and choosen arbitrarily
|
||||||
|
set_spacing_left(spacing_left_ + spacing_ * max_error_ / 10.0); //Only moves forward
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (add_to_detector) detector_.insert(box);
|
||||||
|
last_x = x;
|
||||||
|
last_y = y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Locator &locator_;
|
Locator &locator_;
|
||||||
box2d<double> size_;
|
box2d<double> size_;
|
||||||
|
@ -82,11 +231,69 @@ private:
|
||||||
unsigned marker_nr_;
|
unsigned marker_nr_;
|
||||||
|
|
||||||
/** Rotates the size_ box and translates the position. */
|
/** Rotates the size_ box and translates the position. */
|
||||||
box2d<double> perform_transform(double angle, double dx, double dy);
|
box2d<double> perform_transform(double angle, double dx, double dy)
|
||||||
|
{
|
||||||
|
double x1 = size_.minx();
|
||||||
|
double x2 = size_.maxx();
|
||||||
|
double y1 = size_.miny();
|
||||||
|
double y2 = size_.maxy();
|
||||||
|
agg::trans_affine tr = tr_ * agg::trans_affine_rotation(angle).translate(dx, dy);
|
||||||
|
double xA = x1, yA = y1, xB = x2, yB = y1, xC = x2, yC = y2, xD = x1, yD = y2;
|
||||||
|
tr.transform(&xA, &yA);
|
||||||
|
tr.transform(&xB, &yB);
|
||||||
|
tr.transform(&xC, &yC);
|
||||||
|
tr.transform(&xD, &yD);
|
||||||
|
box2d<double> result(xA, yA, xC, yC);
|
||||||
|
result.expand_to_include(xB, yB);
|
||||||
|
result.expand_to_include(xD, yD);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** Automatically chooses spacing. */
|
/** Automatically chooses spacing. */
|
||||||
double find_optimal_spacing(double s);
|
double find_optimal_spacing(double s)
|
||||||
|
{
|
||||||
|
rewind();
|
||||||
|
//Calculate total path length
|
||||||
|
unsigned cmd = agg::path_cmd_move_to;
|
||||||
|
double length = 0;
|
||||||
|
while (!agg::is_stop(cmd))
|
||||||
|
{
|
||||||
|
double dx = next_x - last_x;
|
||||||
|
double dy = next_y - last_y;
|
||||||
|
length += std::sqrt(dx * dx + dy * dy);
|
||||||
|
last_x = next_x;
|
||||||
|
last_y = next_y;
|
||||||
|
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
||||||
|
{
|
||||||
|
//Skip over "move" commands
|
||||||
|
last_x = next_x;
|
||||||
|
last_y = next_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned points = round(length / s);
|
||||||
|
if (points == 0) return 0.0; //Path to short
|
||||||
|
return length / points;
|
||||||
|
}
|
||||||
|
|
||||||
/** Set spacing_left_, adjusts error_ and performs sanity checks. */
|
/** Set spacing_left_, adjusts error_ and performs sanity checks. */
|
||||||
void set_spacing_left(double sl, bool allow_negative=false);
|
void set_spacing_left(double sl, bool allow_negative=false)
|
||||||
|
{
|
||||||
|
double delta_error = sl - spacing_left_;
|
||||||
|
if (!allow_negative && delta_error < 0)
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_WARN(markers_placement) << "Unexpected negative error in markers_placement. Please file a bug report.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef MAPNIK_DEBUG
|
||||||
|
if (delta_error == 0.0)
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_WARN(markers_placement) << "Not moving at all in set_spacing_left()! Please file a bug report.";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
error_ += delta_error;
|
||||||
|
spacing_left_ = sl;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace mapnik {
|
||||||
// TODO - consider merging with text_symbolizer label_placement_e
|
// TODO - consider merging with text_symbolizer label_placement_e
|
||||||
enum marker_placement_enum {
|
enum marker_placement_enum {
|
||||||
MARKER_POINT_PLACEMENT,
|
MARKER_POINT_PLACEMENT,
|
||||||
|
MARKER_INTERIOR_PLACEMENT,
|
||||||
MARKER_LINE_PLACEMENT,
|
MARKER_LINE_PLACEMENT,
|
||||||
marker_placement_enum_MAX
|
marker_placement_enum_MAX
|
||||||
};
|
};
|
||||||
|
@ -65,8 +66,12 @@ public:
|
||||||
double get_spacing() const;
|
double get_spacing() const;
|
||||||
void set_max_error(double max_error);
|
void set_max_error(double max_error);
|
||||||
double get_max_error() const;
|
double get_max_error() const;
|
||||||
|
void set_opacity(float opacity);
|
||||||
|
boost::optional<float> get_opacity() const;
|
||||||
void set_fill(color const& fill);
|
void set_fill(color const& fill);
|
||||||
boost::optional<color> get_fill() const;
|
boost::optional<color> get_fill() const;
|
||||||
|
void set_fill_opacity(float opacity);
|
||||||
|
boost::optional<float> get_fill_opacity() const;
|
||||||
void set_stroke(stroke const& stroke);
|
void set_stroke(stroke const& stroke);
|
||||||
boost::optional<stroke> get_stroke() const;
|
boost::optional<stroke> get_stroke() const;
|
||||||
void set_marker_placement(marker_placement_e marker_p);
|
void set_marker_placement(marker_placement_e marker_p);
|
||||||
|
@ -79,6 +84,8 @@ private:
|
||||||
double spacing_;
|
double spacing_;
|
||||||
double max_error_;
|
double max_error_;
|
||||||
boost::optional<color> fill_;
|
boost::optional<color> fill_;
|
||||||
|
boost::optional<float> fill_opacity_;
|
||||||
|
boost::optional<float> opacity_;
|
||||||
boost::optional<stroke> stroke_;
|
boost::optional<stroke> stroke_;
|
||||||
marker_placement_e marker_p_;
|
marker_placement_e marker_p_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,10 +66,10 @@ public:
|
||||||
{
|
{
|
||||||
throw std::runtime_error("end_path : The path was not begun");
|
throw std::runtime_error("end_path : The path was not begun");
|
||||||
}
|
}
|
||||||
path_attributes attr = cur_attr();
|
path_attributes& attr = attributes_[attributes_.size() - 1];
|
||||||
unsigned idx = attributes_[attributes_.size() - 1].index;
|
unsigned idx = attr.index;
|
||||||
|
attr = cur_attr();
|
||||||
attr.index = idx;
|
attr.index = idx;
|
||||||
attributes_[attributes_.size() - 1] = attr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void move_to(double x, double y, bool rel=false) // M, m
|
void move_to(double x, double y, bool rel=false) // M, m
|
||||||
|
|
|
@ -102,6 +102,7 @@ private:
|
||||||
template <typename VertexSource, typename AttributeSource, typename ScanlineRenderer, typename PixelFormat>
|
template <typename VertexSource, typename AttributeSource, typename ScanlineRenderer, typename PixelFormat>
|
||||||
class svg_renderer : boost::noncopyable
|
class svg_renderer : boost::noncopyable
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
typedef agg::conv_curve<VertexSource> curved_type;
|
typedef agg::conv_curve<VertexSource> curved_type;
|
||||||
typedef agg::conv_stroke<curved_type> curved_stroked_type;
|
typedef agg::conv_stroke<curved_type> curved_stroked_type;
|
||||||
typedef agg::conv_transform<curved_stroked_type> curved_stroked_trans_type;
|
typedef agg::conv_transform<curved_stroked_type> curved_stroked_trans_type;
|
||||||
|
@ -109,7 +110,6 @@ class svg_renderer : boost::noncopyable
|
||||||
typedef agg::conv_contour<curved_trans_type> curved_trans_contour_type;
|
typedef agg::conv_contour<curved_trans_type> curved_trans_contour_type;
|
||||||
typedef agg::renderer_base<PixelFormat> renderer_base;
|
typedef agg::renderer_base<PixelFormat> renderer_base;
|
||||||
|
|
||||||
public:
|
|
||||||
svg_renderer(VertexSource & source, AttributeSource const& attributes)
|
svg_renderer(VertexSource & source, AttributeSource const& attributes)
|
||||||
: source_(source),
|
: source_(source),
|
||||||
curved_(source_),
|
curved_(source_),
|
||||||
|
|
|
@ -21,12 +21,14 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/layer.hpp>
|
|
||||||
#include <mapnik/feature_type_style.hpp>
|
|
||||||
#include <mapnik/graphics.hpp>
|
|
||||||
#include <mapnik/agg_renderer.hpp>
|
#include <mapnik/agg_renderer.hpp>
|
||||||
#include <mapnik/agg_rasterizer.hpp>
|
#include <mapnik/agg_rasterizer.hpp>
|
||||||
#include <mapnik/agg_helpers.hpp>
|
#include <mapnik/agg_helpers.hpp>
|
||||||
|
#include <mapnik/graphics.hpp>
|
||||||
|
|
||||||
|
#include <mapnik/debug.hpp>
|
||||||
|
#include <mapnik/layer.hpp>
|
||||||
|
#include <mapnik/feature_type_style.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
#include <mapnik/unicode.hpp>
|
#include <mapnik/unicode.hpp>
|
||||||
|
@ -36,6 +38,7 @@
|
||||||
#include <mapnik/svg/svg_converter.hpp>
|
#include <mapnik/svg/svg_converter.hpp>
|
||||||
#include <mapnik/svg/svg_renderer.hpp>
|
#include <mapnik/svg/svg_renderer.hpp>
|
||||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||||
|
|
||||||
#include <mapnik/image_compositing.hpp>
|
#include <mapnik/image_compositing.hpp>
|
||||||
#include <mapnik/image_filter.hpp>
|
#include <mapnik/image_filter.hpp>
|
||||||
#include <mapnik/image_util.hpp>
|
#include <mapnik/image_util.hpp>
|
||||||
|
@ -156,6 +159,10 @@ void agg_renderer<T>::setup(Map const &m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
|
||||||
|
agg::pixfmt_rgba32 pixf(buf);
|
||||||
|
pixf.premultiply();
|
||||||
|
|
||||||
MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Scale=" << m.scale();
|
MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Scale=" << m.scale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +173,6 @@ template <typename T>
|
||||||
void agg_renderer<T>::start_map_processing(Map const& map)
|
void agg_renderer<T>::start_map_processing(Map const& map)
|
||||||
{
|
{
|
||||||
MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Start map processing bbox=" << map.get_current_extent();
|
MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Start map processing bbox=" << map.get_current_extent();
|
||||||
|
|
||||||
ras_ptr->clip_box(0,0,width_,height_);
|
ras_ptr->clip_box(0,0,width_,height_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +197,24 @@ void agg_renderer<T>::start_layer_processing(layer const& lay, box2d<double> con
|
||||||
{
|
{
|
||||||
detector_->clear();
|
detector_->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
query_extent_ = query_extent;
|
query_extent_ = query_extent;
|
||||||
|
int buffer_size = lay.buffer_size();
|
||||||
|
if (buffer_size != 0 )
|
||||||
|
{
|
||||||
|
double padding = buffer_size * (double)(query_extent.width()/pixmap_.width());
|
||||||
|
double x0 = query_extent_.minx();
|
||||||
|
double y0 = query_extent_.miny();
|
||||||
|
double x1 = query_extent_.maxx();
|
||||||
|
double y1 = query_extent_.maxy();
|
||||||
|
query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<box2d<double> > const& maximum_extent = lay.maximum_extent();
|
||||||
|
if (maximum_extent)
|
||||||
|
{
|
||||||
|
query_extent_.clip(*maximum_extent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -362,15 +385,18 @@ void agg_renderer<T>::render_marker(pixel_position const& pos, marker const& mar
|
||||||
src.height(),
|
src.height(),
|
||||||
src.width()*4);
|
src.width()*4);
|
||||||
agg::pixfmt_rgba32_pre pixf(marker_buf);
|
agg::pixfmt_rgba32_pre pixf(marker_buf);
|
||||||
|
|
||||||
typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
|
typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
|
||||||
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
|
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
|
||||||
typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
|
typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
|
||||||
interpolator_type> span_gen_type;
|
interpolator_type> span_gen_type;
|
||||||
|
typedef agg::renderer_scanline_aa_alpha<renderer_base,
|
||||||
|
agg::span_allocator<agg::rgba8>,
|
||||||
|
span_gen_type> renderer_type;
|
||||||
img_accessor_type ia(pixf);
|
img_accessor_type ia(pixf);
|
||||||
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
|
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
|
||||||
span_gen_type sg(ia, interpolator, filter);
|
span_gen_type sg(ia, interpolator, filter);
|
||||||
agg::render_scanlines_aa(*ras_ptr, sl, renb, sa, sg);
|
renderer_type rp(renb,sa, sg, unsigned(opacity*255));
|
||||||
|
agg::render_scanlines(*ras_ptr, sl, rp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,6 +453,27 @@ void agg_renderer<T>::debug_draw_box(R& buf, box2d<double> const& box,
|
||||||
agg::render_scanlines(*ras_ptr, sl_line, ren);
|
agg::render_scanlines(*ras_ptr, sl_line, ren);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void agg_renderer<T>::draw_geo_extent(box2d<double> const& extent, mapnik::color const& color)
|
||||||
|
{
|
||||||
|
box2d<double> box = t_.forward(extent);
|
||||||
|
double x0 = box.minx();
|
||||||
|
double x1 = box.maxx();
|
||||||
|
double y0 = box.miny();
|
||||||
|
double y1 = box.maxy();
|
||||||
|
unsigned rgba = color.rgba();
|
||||||
|
for (double x=x0; x<x1; x++)
|
||||||
|
{
|
||||||
|
pixmap_.setPixel(x, y0, rgba);
|
||||||
|
pixmap_.setPixel(x, y1, rgba);
|
||||||
|
}
|
||||||
|
for (double y=y0; y<y1; y++)
|
||||||
|
{
|
||||||
|
pixmap_.setPixel(x0, y, rgba);
|
||||||
|
pixmap_.setPixel(x1, y, rgba);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template class agg_renderer<image_32>;
|
template class agg_renderer<image_32>;
|
||||||
template void agg_renderer<image_32>::debug_draw_box<agg::rendering_buffer>(
|
template void agg_renderer<image_32>::debug_draw_box<agg::rendering_buffer>(
|
||||||
agg::rendering_buffer& buf,
|
agg::rendering_buffer& buf,
|
||||||
|
|
|
@ -82,32 +82,31 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
|
||||||
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
|
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
|
||||||
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
|
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
|
||||||
std::deque<segment_t> face_segments;
|
std::deque<segment_t> face_segments;
|
||||||
double x0(0);
|
double x0 = 0;
|
||||||
double y0(0);
|
double y0 = 0;
|
||||||
|
double x,y;
|
||||||
geom.rewind(0);
|
geom.rewind(0);
|
||||||
unsigned cm = geom.vertex(&x0,&y0);
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||||
for (unsigned j=1;j<geom.size();++j)
|
cm = geom.vertex(&x, &y))
|
||||||
{
|
{
|
||||||
double x(0);
|
|
||||||
double y(0);
|
|
||||||
cm = geom.vertex(&x,&y);
|
|
||||||
if (cm == SEG_MOVETO)
|
if (cm == SEG_MOVETO)
|
||||||
{
|
{
|
||||||
frame->move_to(x,y);
|
frame->move_to(x,y);
|
||||||
}
|
}
|
||||||
else if (cm == SEG_LINETO)
|
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||||
{
|
{
|
||||||
frame->line_to(x,y);
|
frame->line_to(x,y);
|
||||||
face_segments.push_back(segment_t(x0,y0,x,y));
|
face_segments.push_back(segment_t(x0,y0,x,y));
|
||||||
}
|
}
|
||||||
|
|
||||||
x0 = x;
|
x0 = x;
|
||||||
y0 = y;
|
y0 = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(face_segments.begin(),face_segments.end(), y_order);
|
std::sort(face_segments.begin(),face_segments.end(), y_order);
|
||||||
std::deque<segment_t>::const_iterator itr=face_segments.begin();
|
std::deque<segment_t>::const_iterator itr=face_segments.begin();
|
||||||
for (;itr!=face_segments.end();++itr)
|
std::deque<segment_t>::const_iterator end=face_segments.end();
|
||||||
|
|
||||||
|
for (; itr!=end; ++itr)
|
||||||
{
|
{
|
||||||
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
||||||
faces->move_to(itr->get<0>(),itr->get<1>());
|
faces->move_to(itr->get<0>(),itr->get<1>());
|
||||||
|
@ -120,22 +119,22 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
|
||||||
ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
|
ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(a * sym.get_opacity())));
|
||||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||||
ras_ptr->reset();
|
ras_ptr->reset();
|
||||||
|
//
|
||||||
frame->move_to(itr->get<0>(),itr->get<1>());
|
frame->move_to(itr->get<0>(),itr->get<1>());
|
||||||
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geom.rewind(0);
|
geom.rewind(0);
|
||||||
for (unsigned j=0;j<geom.size();++j)
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||||
|
cm = geom.vertex(&x, &y))
|
||||||
{
|
{
|
||||||
double x,y;
|
|
||||||
unsigned cm = geom.vertex(&x,&y);
|
|
||||||
if (cm == SEG_MOVETO)
|
if (cm == SEG_MOVETO)
|
||||||
{
|
{
|
||||||
frame->move_to(x,y+height);
|
frame->move_to(x,y+height);
|
||||||
roof->move_to(x,y+height);
|
roof->move_to(x,y+height);
|
||||||
}
|
}
|
||||||
else if (cm == SEG_LINETO)
|
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||||
{
|
{
|
||||||
frame->line_to(x,y+height);
|
frame->line_to(x,y+height);
|
||||||
roof->line_to(x,y+height);
|
roof->line_to(x,y+height);
|
||||||
|
@ -153,6 +152,7 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
|
||||||
ras_ptr->add_path(roof_path);
|
ras_ptr->add_path(roof_path);
|
||||||
ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
|
ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
|
||||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,6 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
||||||
|
|
||||||
if (!pat) return;
|
if (!pat) return;
|
||||||
|
|
||||||
box2d<double> ext = query_extent_ * 1.0;
|
|
||||||
|
|
||||||
agg::rendering_buffer buf(current_buffer_->raw_data(),width_,height_, width_ * 4);
|
agg::rendering_buffer buf(current_buffer_->raw_data(),width_,height_, width_ * 4);
|
||||||
pixfmt_type pixf(buf);
|
pixfmt_type pixf(buf);
|
||||||
pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
|
pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
|
||||||
|
@ -97,10 +95,24 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
evaluate_transform(tr, feature, sym.get_transform());
|
evaluate_transform(tr, feature, sym.get_transform());
|
||||||
|
|
||||||
|
box2d<double> clipping_extent = query_extent_;
|
||||||
|
if (sym.clip())
|
||||||
|
{
|
||||||
|
double padding = (double)(query_extent_.width()/pixmap_.width());
|
||||||
|
float half_stroke = (*mark)->width()/2.0;
|
||||||
|
if (half_stroke > 1)
|
||||||
|
padding *= half_stroke;
|
||||||
|
double x0 = query_extent_.minx();
|
||||||
|
double y0 = query_extent_.miny();
|
||||||
|
double x1 = query_extent_.maxx();
|
||||||
|
double y1 = query_extent_.maxy();
|
||||||
|
clipping_extent.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
|
||||||
|
}
|
||||||
|
|
||||||
typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;
|
typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;
|
||||||
vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer,
|
vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(ext,ras,sym,t_,prj_trans,tr,scale_factor_);
|
converter(clipping_extent,ras,sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_line_tag>(); //optional clip (default: true)
|
if (sym.clip()) converter.set<clip_line_tag>(); //optional clip (default: true)
|
||||||
converter.set<transform_tag>(); //always transform
|
converter.set<transform_tag>(); //always transform
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void agg_renderer<T>::process(line_symbolizer const& sym,
|
void agg_renderer<T>::process(line_symbolizer const& sym,
|
||||||
mapnik::feature_impl & feature,
|
mapnik::feature_impl & feature,
|
||||||
|
@ -80,7 +79,24 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
evaluate_transform(tr, feature, sym.get_transform());
|
evaluate_transform(tr, feature, sym.get_transform());
|
||||||
|
|
||||||
box2d<double> ext = query_extent_ * 1.1;
|
box2d<double> clipping_extent = query_extent_;
|
||||||
|
if (sym.clip())
|
||||||
|
{
|
||||||
|
double padding = (double)(query_extent_.width()/pixmap_.width());
|
||||||
|
float half_stroke = stroke_.get_width()/2.0;
|
||||||
|
if (half_stroke > 1)
|
||||||
|
padding *= half_stroke;
|
||||||
|
if (fabs(sym.offset()) > 0)
|
||||||
|
padding *= fabs(sym.offset()) * 1.2;
|
||||||
|
double x0 = query_extent_.minx();
|
||||||
|
double y0 = query_extent_.miny();
|
||||||
|
double x1 = query_extent_.maxx();
|
||||||
|
double y1 = query_extent_.maxy();
|
||||||
|
clipping_extent.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
|
||||||
|
// debugging
|
||||||
|
//box2d<double> inverse(x0 + padding, y0 + padding, x1 - padding , y1 - padding);
|
||||||
|
//draw_geo_extent(inverse,mapnik::color("red"));
|
||||||
|
}
|
||||||
|
|
||||||
if (sym.get_rasterizer() == RASTERIZER_FAST)
|
if (sym.get_rasterizer() == RASTERIZER_FAST)
|
||||||
{
|
{
|
||||||
|
@ -94,11 +110,12 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
||||||
rasterizer_type ras(ren);
|
rasterizer_type ras(ren);
|
||||||
set_join_caps_aa(stroke_,ras);
|
set_join_caps_aa(stroke_,ras);
|
||||||
|
|
||||||
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
|
typedef boost::mpl::vector<clip_line_tag, transform_tag,
|
||||||
|
offset_transform_tag, affine_transform_tag,
|
||||||
|
smooth_tag, dash_tag, stroke_tag> conv_types;
|
||||||
vertex_converter<box2d<double>, rasterizer_type, line_symbolizer,
|
vertex_converter<box2d<double>, rasterizer_type, line_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(ext,ras,sym,t_,prj_trans,tr,scaled);
|
converter(clipping_extent,ras,sym,t_,prj_trans,tr,scaled);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
||||||
converter.set<transform_tag>(); // always transform
|
converter.set<transform_tag>(); // always transform
|
||||||
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
||||||
|
@ -117,10 +134,12 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
|
typedef boost::mpl::vector<clip_line_tag, transform_tag, offset_transform_tag,
|
||||||
|
affine_transform_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
|
||||||
|
|
||||||
vertex_converter<box2d<double>, rasterizer, line_symbolizer,
|
vertex_converter<box2d<double>, rasterizer, line_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(ext,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
converter(clipping_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
||||||
converter.set<transform_tag>(); // always transform
|
converter.set<transform_tag>(); // always transform
|
||||||
|
|
|
@ -21,23 +21,27 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/debug.hpp>
|
|
||||||
#include <mapnik/graphics.hpp>
|
#include <mapnik/graphics.hpp>
|
||||||
#include <mapnik/geom_util.hpp>
|
|
||||||
#include <mapnik/agg_renderer.hpp>
|
#include <mapnik/agg_renderer.hpp>
|
||||||
#include <mapnik/agg_rasterizer.hpp>
|
#include <mapnik/agg_rasterizer.hpp>
|
||||||
|
|
||||||
|
#include <mapnik/debug.hpp>
|
||||||
|
#include <mapnik/geom_util.hpp>
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
#include <mapnik/vertex_converters.hpp>
|
#include <mapnik/vertex_converters.hpp>
|
||||||
|
#include <mapnik/marker_helpers.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
#include <mapnik/marker_helpers.hpp>
|
|
||||||
#include <mapnik/svg/svg_renderer.hpp>
|
#include <mapnik/svg/svg_renderer.hpp>
|
||||||
|
#include <mapnik/svg/svg_storage.hpp>
|
||||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||||
#include <mapnik/markers_placement.hpp>
|
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||||
#include <mapnik/markers_symbolizer.hpp>
|
#include <mapnik/markers_symbolizer.hpp>
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
#include "agg_basics.h"
|
#include "agg_basics.h"
|
||||||
|
#include "agg_renderer_base.h"
|
||||||
|
#include "agg_renderer_scanline.h"
|
||||||
#include "agg_rendering_buffer.h"
|
#include "agg_rendering_buffer.h"
|
||||||
#include "agg_pixfmt_rgba.h"
|
#include "agg_pixfmt_rgba.h"
|
||||||
#include "agg_rasterizer_scanline_aa.h"
|
#include "agg_rasterizer_scanline_aa.h"
|
||||||
|
@ -45,234 +49,13 @@
|
||||||
#include "agg_path_storage.h"
|
#include "agg_path_storage.h"
|
||||||
#include "agg_conv_clip_polyline.h"
|
#include "agg_conv_clip_polyline.h"
|
||||||
#include "agg_conv_transform.h"
|
#include "agg_conv_transform.h"
|
||||||
#include "agg_image_filters.h"
|
|
||||||
#include "agg_trans_bilinear.h"
|
|
||||||
#include "agg_span_allocator.h"
|
|
||||||
#include "agg_image_accessors.h"
|
|
||||||
#include "agg_span_image_filter_rgba.h"
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
|
|
||||||
struct vector_markers_rasterizer_dispatch
|
|
||||||
{
|
|
||||||
typedef agg::rgba8 color_type;
|
|
||||||
typedef agg::order_rgba order_type;
|
|
||||||
typedef agg::pixel32_type pixel_type;
|
|
||||||
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
|
||||||
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
|
||||||
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
|
||||||
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
|
|
||||||
|
|
||||||
vector_markers_rasterizer_dispatch(BufferType & image_buffer,
|
|
||||||
SvgRenderer & svg_renderer,
|
|
||||||
Rasterizer & ras,
|
|
||||||
box2d<double> const& bbox,
|
|
||||||
agg::trans_affine const& marker_trans,
|
|
||||||
markers_symbolizer const& sym,
|
|
||||||
Detector & detector,
|
|
||||||
double scale_factor)
|
|
||||||
: buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4),
|
|
||||||
pixf_(buf_),
|
|
||||||
renb_(pixf_),
|
|
||||||
svg_renderer_(svg_renderer),
|
|
||||||
ras_(ras),
|
|
||||||
bbox_(bbox),
|
|
||||||
marker_trans_(marker_trans),
|
|
||||||
sym_(sym),
|
|
||||||
detector_(detector),
|
|
||||||
scale_factor_(scale_factor)
|
|
||||||
{
|
|
||||||
pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void add_path(T & path)
|
|
||||||
{
|
|
||||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
|
||||||
|
|
||||||
if (placement_method == MARKER_POINT_PLACEMENT)
|
|
||||||
{
|
|
||||||
double x,y;
|
|
||||||
path.rewind(0);
|
|
||||||
label::interior_position(path, x, y);
|
|
||||||
agg::trans_affine matrix = marker_trans_;
|
|
||||||
matrix.translate(x,y);
|
|
||||||
box2d<double> transformed_bbox = bbox_ * matrix;
|
|
||||||
|
|
||||||
if (sym_.get_allow_overlap() ||
|
|
||||||
detector_.has_placement(transformed_bbox))
|
|
||||||
{
|
|
||||||
svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
|
|
||||||
|
|
||||||
if (!sym_.get_ignore_placement())
|
|
||||||
detector_.insert(transformed_bbox);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
|
||||||
sym_.get_spacing() * scale_factor_,
|
|
||||||
sym_.get_max_error(),
|
|
||||||
sym_.get_allow_overlap());
|
|
||||||
double x, y, angle;
|
|
||||||
while (placement.get_point(x, y, angle))
|
|
||||||
{
|
|
||||||
agg::trans_affine matrix = marker_trans_;
|
|
||||||
matrix.rotate(angle);
|
|
||||||
matrix.translate(x, y);
|
|
||||||
svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
agg::scanline_u8 sl_;
|
|
||||||
agg::rendering_buffer buf_;
|
|
||||||
pixfmt_comp_type pixf_;
|
|
||||||
renderer_base renb_;
|
|
||||||
SvgRenderer & svg_renderer_;
|
|
||||||
Rasterizer & ras_;
|
|
||||||
box2d<double> const& bbox_;
|
|
||||||
agg::trans_affine const& marker_trans_;
|
|
||||||
markers_symbolizer const& sym_;
|
|
||||||
Detector & detector_;
|
|
||||||
double scale_factor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Rasterizer, typename RendererBuffer>
|
|
||||||
void render_raster_marker(Rasterizer & ras, RendererBuffer & renb,
|
|
||||||
agg::scanline_u8 & sl, image_data_32 const& src,
|
|
||||||
agg::trans_affine const& marker_tr, double opacity)
|
|
||||||
{
|
|
||||||
|
|
||||||
double width = src.width();
|
|
||||||
double height = src.height();
|
|
||||||
double p[8];
|
|
||||||
p[0] = 0; p[1] = 0;
|
|
||||||
p[2] = width; p[3] = 0;
|
|
||||||
p[4] = width; p[5] = height;
|
|
||||||
p[6] = 0; p[7] = height;
|
|
||||||
|
|
||||||
marker_tr.transform(&p[0], &p[1]);
|
|
||||||
marker_tr.transform(&p[2], &p[3]);
|
|
||||||
marker_tr.transform(&p[4], &p[5]);
|
|
||||||
marker_tr.transform(&p[6], &p[7]);
|
|
||||||
|
|
||||||
ras.move_to_d(p[0],p[1]);
|
|
||||||
ras.line_to_d(p[2],p[3]);
|
|
||||||
ras.line_to_d(p[4],p[5]);
|
|
||||||
ras.line_to_d(p[6],p[7]);
|
|
||||||
|
|
||||||
typedef agg::rgba8 color_type;
|
|
||||||
agg::span_allocator<color_type> sa;
|
|
||||||
agg::image_filter_bilinear filter_kernel;
|
|
||||||
agg::image_filter_lut filter(filter_kernel, false);
|
|
||||||
|
|
||||||
agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(),
|
|
||||||
src.width(),
|
|
||||||
src.height(),
|
|
||||||
src.width()*4);
|
|
||||||
agg::pixfmt_rgba32_pre pixf(marker_buf);
|
|
||||||
|
|
||||||
typedef agg::image_accessor_clone<agg::pixfmt_rgba32_pre> img_accessor_type;
|
|
||||||
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
|
|
||||||
typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
|
|
||||||
interpolator_type> span_gen_type;
|
|
||||||
img_accessor_type ia(pixf);
|
|
||||||
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );
|
|
||||||
span_gen_type sg(ia, interpolator, filter);
|
|
||||||
agg::render_scanlines_aa(ras, sl, renb, sa, sg);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename BufferType, typename Rasterizer, typename Detector>
|
|
||||||
struct raster_markers_rasterizer_dispatch
|
|
||||||
{
|
|
||||||
typedef agg::rgba8 color_type;
|
|
||||||
typedef agg::order_rgba order_type;
|
|
||||||
typedef agg::pixel32_type pixel_type;
|
|
||||||
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
|
||||||
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
|
||||||
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
|
||||||
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
|
|
||||||
|
|
||||||
raster_markers_rasterizer_dispatch(BufferType & image_buffer,
|
|
||||||
Rasterizer & ras,
|
|
||||||
image_data_32 const& src,
|
|
||||||
agg::trans_affine const& marker_trans,
|
|
||||||
markers_symbolizer const& sym,
|
|
||||||
Detector & detector,
|
|
||||||
double scale_factor)
|
|
||||||
: buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4),
|
|
||||||
pixf_(buf_),
|
|
||||||
renb_(pixf_),
|
|
||||||
ras_(ras),
|
|
||||||
src_(src),
|
|
||||||
marker_trans_(marker_trans),
|
|
||||||
sym_(sym),
|
|
||||||
detector_(detector),
|
|
||||||
scale_factor_(scale_factor)
|
|
||||||
{
|
|
||||||
pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void add_path(T & path)
|
|
||||||
{
|
|
||||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
|
||||||
box2d<double> bbox_(0,0, src_.width(),src_.height());
|
|
||||||
|
|
||||||
if (placement_method == MARKER_POINT_PLACEMENT)
|
|
||||||
{
|
|
||||||
double x,y;
|
|
||||||
path.rewind(0);
|
|
||||||
label::interior_position(path, x, y);
|
|
||||||
agg::trans_affine matrix = marker_trans_;
|
|
||||||
matrix.translate(x,y);
|
|
||||||
box2d<double> transformed_bbox = bbox_ * matrix;
|
|
||||||
|
|
||||||
if (sym_.get_allow_overlap() ||
|
|
||||||
detector_.has_placement(transformed_bbox))
|
|
||||||
{
|
|
||||||
|
|
||||||
render_raster_marker(ras_, renb_, sl_, src_,
|
|
||||||
matrix, sym_.get_opacity());
|
|
||||||
if (!sym_.get_ignore_placement())
|
|
||||||
detector_.insert(transformed_bbox);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
|
||||||
sym_.get_spacing() * scale_factor_,
|
|
||||||
sym_.get_max_error(),
|
|
||||||
sym_.get_allow_overlap());
|
|
||||||
double x, y, angle;
|
|
||||||
while (placement.get_point(x, y, angle))
|
|
||||||
{
|
|
||||||
agg::trans_affine matrix = marker_trans_;
|
|
||||||
matrix.rotate(angle);
|
|
||||||
matrix.translate(x,y);
|
|
||||||
render_raster_marker(ras_, renb_, sl_, src_,
|
|
||||||
matrix, sym_.get_opacity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
agg::scanline_u8 sl_;
|
|
||||||
agg::rendering_buffer buf_;
|
|
||||||
pixfmt_comp_type pixf_;
|
|
||||||
renderer_base renb_;
|
|
||||||
Rasterizer & ras_;
|
|
||||||
image_data_32 const& src_;
|
|
||||||
agg::trans_affine const& marker_trans_;
|
|
||||||
markers_symbolizer const& sym_;
|
|
||||||
Detector & detector_;
|
|
||||||
double scale_factor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void agg_renderer<T>::process(markers_symbolizer const& sym,
|
void agg_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
feature_impl & feature,
|
feature_impl & feature,
|
||||||
|
@ -284,9 +67,8 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
|
||||||
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
|
||||||
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
|
||||||
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
|
|
||||||
typedef label_collision_detector4 detector_type;
|
typedef label_collision_detector4 detector_type;
|
||||||
typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;
|
typedef boost::mpl::vector<clip_line_tag,clip_poly_tag,transform_tag,smooth_tag> conv_types;
|
||||||
|
|
||||||
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
|
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
|
||||||
|
|
||||||
|
@ -297,67 +79,124 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
{
|
{
|
||||||
ras_ptr->reset();
|
ras_ptr->reset();
|
||||||
ras_ptr->gamma(agg::gamma_power());
|
ras_ptr->gamma(agg::gamma_power());
|
||||||
|
|
||||||
agg::trans_affine geom_tr;
|
agg::trans_affine geom_tr;
|
||||||
evaluate_transform(geom_tr, feature, sym.get_transform());
|
evaluate_transform(geom_tr, feature, sym.get_transform());
|
||||||
|
|
||||||
box2d<double> const& bbox = (*mark)->bounding_box();
|
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
setup_label_transform(tr, bbox, feature, sym);
|
tr *= agg::trans_affine_scaling(scale_factor_);
|
||||||
tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
|
||||||
coord2d center = bbox.center();
|
|
||||||
agg::trans_affine_translation recenter(-center.x, -center.y);
|
|
||||||
agg::trans_affine marker_trans = recenter * tr;
|
|
||||||
|
|
||||||
if ((*mark)->is_vector())
|
if ((*mark)->is_vector())
|
||||||
{
|
{
|
||||||
using namespace mapnik::svg;
|
using namespace mapnik::svg;
|
||||||
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
|
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
|
||||||
|
typedef agg::pod_bvector<path_attributes> svg_attribute_type;
|
||||||
|
|
||||||
vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source());
|
|
||||||
svg_path_adapter svg_path(stl_storage);
|
|
||||||
|
|
||||||
agg::pod_bvector<path_attributes> attributes;
|
|
||||||
bool result = push_explicit_style( (*marker)->attributes(), attributes, sym);
|
|
||||||
|
|
||||||
typedef svg_renderer<svg_path_adapter,
|
typedef svg_renderer<svg_path_adapter,
|
||||||
agg::pod_bvector<path_attributes>,
|
svg_attribute_type,
|
||||||
renderer_type,
|
renderer_type,
|
||||||
agg::pixfmt_rgba32 > svg_renderer_type;
|
pixfmt_comp_type > svg_renderer_type;
|
||||||
typedef vector_markers_rasterizer_dispatch<buffer_type, svg_renderer_type, rasterizer, detector_type> dispatch_type;
|
typedef vector_markers_rasterizer_dispatch<buffer_type,
|
||||||
|
svg_renderer_type,
|
||||||
|
rasterizer,
|
||||||
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*marker)->attributes());
|
detector_type > dispatch_type;
|
||||||
|
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
|
||||||
|
expression_ptr const& width_expr = sym.get_width();
|
||||||
|
expression_ptr const& height_expr = sym.get_height();
|
||||||
|
|
||||||
|
// special case for simple ellipse markers
|
||||||
|
// to allow for full control over rx/ry dimensions
|
||||||
|
if (filename == "shape://ellipse"
|
||||||
|
&& (width_expr || height_expr))
|
||||||
|
{
|
||||||
|
svg_storage_type marker_ellipse;
|
||||||
|
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source());
|
||||||
|
svg_path_adapter svg_path(stl_storage);
|
||||||
|
build_ellipse(sym, feature, marker_ellipse, svg_path);
|
||||||
|
svg_attribute_type attributes;
|
||||||
|
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
|
||||||
|
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes());
|
||||||
|
evaluate_transform(tr, feature, sym.get_image_transform());
|
||||||
|
box2d<double> bbox = marker_ellipse.bounding_box();
|
||||||
|
coord2d center = bbox.center();
|
||||||
|
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||||
|
agg::trans_affine marker_trans = recenter * tr;
|
||||||
dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr,
|
dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr,
|
||||||
bbox, marker_trans, sym, *detector_, scale_factor_);
|
bbox, marker_trans, sym, *detector_, scale_factor_);
|
||||||
|
|
||||||
|
|
||||||
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
||||||
if (sym.clip()) converter.template set<clip_line_tag>(); //optional clip (default: true)
|
{
|
||||||
|
eGeomType type = feature.paths()[0].type();
|
||||||
|
if (type == Polygon)
|
||||||
|
converter.template set<clip_poly_tag>();
|
||||||
|
else if (type == LineString)
|
||||||
|
converter.template set<clip_line_tag>();
|
||||||
|
// don't clip if type==Point
|
||||||
|
}
|
||||||
converter.template set<transform_tag>(); //always transform
|
converter.template set<transform_tag>(); //always transform
|
||||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||||
|
|
||||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||||
{
|
{
|
||||||
converter.apply(geom);
|
converter.apply(geom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
box2d<double> const& bbox = (*mark)->bounding_box();
|
||||||
|
setup_label_transform(tr, bbox, feature, sym);
|
||||||
|
coord2d center = bbox.center();
|
||||||
|
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||||
|
agg::trans_affine marker_trans = recenter * tr;
|
||||||
|
vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
|
||||||
|
svg_path_adapter svg_path(stl_storage);
|
||||||
|
svg_attribute_type attributes;
|
||||||
|
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
|
||||||
|
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes());
|
||||||
|
dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr,
|
||||||
|
bbox, marker_trans, sym, *detector_, scale_factor_);
|
||||||
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
||||||
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
|
converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
||||||
|
{
|
||||||
|
eGeomType type = feature.paths()[0].type();
|
||||||
|
if (type == Polygon)
|
||||||
|
converter.template set<clip_poly_tag>();
|
||||||
|
else if (type == LineString)
|
||||||
|
converter.template set<clip_line_tag>();
|
||||||
|
// don't clip if type==Point
|
||||||
|
}
|
||||||
|
converter.template set<transform_tag>(); //always transform
|
||||||
|
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||||
|
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||||
|
{
|
||||||
|
converter.apply(geom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else // raster markers
|
else // raster markers
|
||||||
{
|
{
|
||||||
|
box2d<double> const& bbox = (*mark)->bounding_box();
|
||||||
|
setup_label_transform(tr, bbox, feature, sym);
|
||||||
|
coord2d center = bbox.center();
|
||||||
|
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||||
|
agg::trans_affine marker_trans = recenter * tr;
|
||||||
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
|
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
|
||||||
typedef raster_markers_rasterizer_dispatch<buffer_type,rasterizer, detector_type> dispatch_type;
|
typedef raster_markers_rasterizer_dispatch<buffer_type,rasterizer, detector_type> dispatch_type;
|
||||||
dispatch_type rasterizer_dispatch(*current_buffer_,*ras_ptr, **marker,
|
dispatch_type rasterizer_dispatch(*current_buffer_,*ras_ptr, **marker,
|
||||||
marker_trans, sym, *detector_, scale_factor_);
|
marker_trans, sym, *detector_, scale_factor_);
|
||||||
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(query_extent_* 1.1, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
converter(query_extent_, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.template set<clip_line_tag>(); //optional clip (default: true)
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
||||||
|
{
|
||||||
|
eGeomType type = feature.paths()[0].type();
|
||||||
|
if (type == Polygon)
|
||||||
|
converter.template set<clip_poly_tag>();
|
||||||
|
else if (type == LineString)
|
||||||
|
converter.template set<clip_line_tag>();
|
||||||
|
// don't clip if type==Point
|
||||||
|
}
|
||||||
converter.template set<transform_tag>(); //always transform
|
converter.template set<transform_tag>(); //always transform
|
||||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,16 @@
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/agg_renderer.hpp>
|
#include <mapnik/agg_renderer.hpp>
|
||||||
#include <mapnik/agg_rasterizer.hpp>
|
#include <mapnik/agg_rasterizer.hpp>
|
||||||
#include <mapnik/geom_util.hpp>
|
|
||||||
#include <mapnik/image_util.hpp>
|
#include <mapnik/image_util.hpp>
|
||||||
#include <mapnik/metawriter.hpp>
|
|
||||||
|
#include <mapnik/geom_util.hpp>
|
||||||
|
#include <mapnik/point_symbolizer.hpp>
|
||||||
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
#include "agg_basics.h"
|
#include "agg_trans_affine.h"
|
||||||
#include "agg_rendering_buffer.h"
|
|
||||||
#include "agg_pixfmt_rgba.h"
|
|
||||||
#include "agg_rasterizer_scanline_aa.h"
|
|
||||||
#include "agg_scanline_u.h"
|
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -89,7 +86,6 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
|
||||||
prj_trans.backward(x,y,z);
|
prj_trans.backward(x,y,z);
|
||||||
t_.forward(&x,&y);
|
t_.forward(&x,&y);
|
||||||
label_ext.re_center(x,y);
|
label_ext.re_center(x,y);
|
||||||
|
|
||||||
if (sym.get_allow_overlap() ||
|
if (sym.get_allow_overlap() ||
|
||||||
detector_->has_placement(label_ext))
|
detector_->has_placement(label_ext))
|
||||||
{
|
{
|
||||||
|
@ -106,8 +102,8 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
|
||||||
|
|
||||||
if (!sym.get_ignore_placement())
|
if (!sym.get_ignore_placement())
|
||||||
detector_->insert(label_ext);
|
detector_->insert(label_ext);
|
||||||
metawriter_with_properties writer = sym.get_metawriter();
|
//metawriter_with_properties writer = sym.get_metawriter();
|
||||||
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
|
//if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,11 +139,10 @@ void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
evaluate_transform(tr, feature, sym.get_transform());
|
evaluate_transform(tr, feature, sym.get_transform());
|
||||||
|
|
||||||
box2d<double> inflated_extent = query_extent_ * 1.0;
|
|
||||||
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
|
||||||
vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
|
vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
||||||
converter.set<transform_tag>(); //always transform
|
converter.set<transform_tag>(); //always transform
|
||||||
|
|
|
@ -48,15 +48,13 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
|
||||||
ras_ptr->reset();
|
ras_ptr->reset();
|
||||||
set_gamma_method(sym,ras_ptr);
|
set_gamma_method(sym,ras_ptr);
|
||||||
|
|
||||||
box2d<double> inflated_extent = query_extent_ * 1.0;
|
|
||||||
|
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
evaluate_transform(tr, feature, sym.get_transform());
|
evaluate_transform(tr, feature, sym.get_transform());
|
||||||
|
|
||||||
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
|
||||||
vertex_converter<box2d<double>, rasterizer, polygon_symbolizer,
|
vertex_converter<box2d<double>, rasterizer, polygon_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
||||||
converter.set<transform_tag>(); //always transform
|
converter.set<transform_tag>(); //always transform
|
||||||
|
|
|
@ -171,7 +171,6 @@ source = Split(
|
||||||
json/feature_grammar.cpp
|
json/feature_grammar.cpp
|
||||||
json/feature_collection_parser.cpp
|
json/feature_collection_parser.cpp
|
||||||
json/geojson_generator.cpp
|
json/geojson_generator.cpp
|
||||||
markers_placement.cpp
|
|
||||||
formatting/base.cpp
|
formatting/base.cpp
|
||||||
formatting/expression.cpp
|
formatting/expression.cpp
|
||||||
formatting/list.cpp
|
formatting/list.cpp
|
||||||
|
|
|
@ -497,7 +497,6 @@ public:
|
||||||
}
|
}
|
||||||
else if (cm == SEG_CLOSE)
|
else if (cm == SEG_CLOSE)
|
||||||
{
|
{
|
||||||
line_to(x, y);
|
|
||||||
close_path();
|
close_path();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -882,43 +881,32 @@ void cairo_renderer_base::process(building_symbolizer const& sym,
|
||||||
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
|
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
|
||||||
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
|
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
|
||||||
std::deque<segment_t> face_segments;
|
std::deque<segment_t> face_segments;
|
||||||
double x0(0);
|
double x0 = 0;
|
||||||
double y0(0);
|
double y0 = 0;
|
||||||
|
double x, y;
|
||||||
geom.rewind(0);
|
geom.rewind(0);
|
||||||
unsigned cm = geom.vertex(&x0, &y0);
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||||
|
cm = geom.vertex(&x, &y))
|
||||||
for (unsigned j = 1; j < geom.size(); ++j)
|
|
||||||
{
|
{
|
||||||
double x=0;
|
|
||||||
double y=0;
|
|
||||||
|
|
||||||
cm = geom.vertex(&x,&y);
|
|
||||||
|
|
||||||
if (cm == SEG_MOVETO)
|
if (cm == SEG_MOVETO)
|
||||||
{
|
{
|
||||||
frame->move_to(x,y);
|
frame->move_to(x,y);
|
||||||
}
|
}
|
||||||
else if (cm == SEG_LINETO)
|
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||||
{
|
{
|
||||||
frame->line_to(x,y);
|
frame->line_to(x,y);
|
||||||
|
face_segments.push_back(segment_t(x0,y0,x,y));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j != 0)
|
|
||||||
{
|
|
||||||
face_segments.push_back(segment_t(x0, y0, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
x0 = x;
|
x0 = x;
|
||||||
y0 = y;
|
y0 = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(face_segments.begin(), face_segments.end(), y_order);
|
std::sort(face_segments.begin(), face_segments.end(), y_order);
|
||||||
std::deque<segment_t>::const_iterator itr = face_segments.begin();
|
std::deque<segment_t>::const_iterator itr = face_segments.begin();
|
||||||
for (; itr != face_segments.end(); ++itr)
|
std::deque<segment_t>::const_iterator end=face_segments.end();
|
||||||
|
for (; itr != end; ++itr)
|
||||||
{
|
{
|
||||||
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
||||||
|
|
||||||
faces->move_to(itr->get<0>(), itr->get<1>());
|
faces->move_to(itr->get<0>(), itr->get<1>());
|
||||||
faces->line_to(itr->get<2>(), itr->get<3>());
|
faces->line_to(itr->get<2>(), itr->get<3>());
|
||||||
faces->line_to(itr->get<2>(), itr->get<3>() + height);
|
faces->line_to(itr->get<2>(), itr->get<3>() + height);
|
||||||
|
@ -935,20 +923,18 @@ void cairo_renderer_base::process(building_symbolizer const& sym,
|
||||||
}
|
}
|
||||||
|
|
||||||
geom.rewind(0);
|
geom.rewind(0);
|
||||||
for (unsigned j = 0; j < geom.size(); ++j)
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||||
|
cm = geom.vertex(&x, &y))
|
||||||
{
|
{
|
||||||
double x, y;
|
|
||||||
unsigned cm = geom.vertex(&x, &y);
|
|
||||||
|
|
||||||
if (cm == SEG_MOVETO)
|
if (cm == SEG_MOVETO)
|
||||||
{
|
{
|
||||||
frame->move_to(x, y + height);
|
frame->move_to(x,y+height);
|
||||||
roof->move_to(x, y + height);
|
roof->move_to(x,y+height);
|
||||||
}
|
}
|
||||||
else if (cm == SEG_LINETO)
|
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||||
{
|
{
|
||||||
frame->line_to(x, y + height);
|
frame->line_to(x,y+height);
|
||||||
roof->line_to(x, y + height);
|
roof->line_to(x,y+height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,14 +973,21 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
|
||||||
evaluate_transform(tr, feature, sym.get_transform());
|
evaluate_transform(tr, feature, sym.get_transform());
|
||||||
|
|
||||||
box2d<double> ext = query_extent_ * 1.1;
|
box2d<double> ext = query_extent_ * 1.1;
|
||||||
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag> conv_types;
|
typedef boost::mpl::vector<clip_line_tag, clip_poly_tag, transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag> conv_types;
|
||||||
vertex_converter<box2d<double>, cairo_context, line_symbolizer,
|
vertex_converter<box2d<double>, cairo_context, line_symbolizer,
|
||||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||||
converter(ext,context,sym,t_,prj_trans,tr,scale_factor_);
|
converter(ext,context,sym,t_,prj_trans,tr,scale_factor_);
|
||||||
|
|
||||||
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
||||||
|
{
|
||||||
|
eGeomType type = feature.paths()[0].type();
|
||||||
|
if (type == Polygon)
|
||||||
|
converter.set<clip_poly_tag>();
|
||||||
|
else if (type == LineString)
|
||||||
|
converter.set<clip_line_tag>();
|
||||||
|
// don't clip if type==Point
|
||||||
|
}
|
||||||
converter.set<transform_tag>(); // always transform
|
converter.set<transform_tag>(); // always transform
|
||||||
|
|
||||||
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
||||||
converter.set<affine_transform_tag>(); // optional affine transform
|
converter.set<affine_transform_tag>(); // optional affine transform
|
||||||
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
||||||
|
@ -1035,7 +1028,7 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const&
|
||||||
|
|
||||||
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
||||||
agg::trans_affine transform;
|
agg::trans_affine transform;
|
||||||
mapnik::path_ptr vmarker = *marker.get_vector_data();
|
mapnik::svg_path_ptr vmarker = *marker.get_vector_data();
|
||||||
using namespace mapnik::svg;
|
using namespace mapnik::svg;
|
||||||
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
|
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
|
||||||
for(unsigned i = 0; i < attributes_.size(); ++i)
|
for(unsigned i = 0; i < attributes_.size(); ++i)
|
||||||
|
@ -1411,7 +1404,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
|
boost::optional<svg_path_ptr> marker = (*mark)->get_vector_data();
|
||||||
box2d<double> const& bbox = (*marker)->bounding_box();
|
box2d<double> const& bbox = (*marker)->bounding_box();
|
||||||
double x1 = bbox.minx();
|
double x1 = bbox.minx();
|
||||||
double y1 = bbox.miny();
|
double y1 = bbox.miny();
|
||||||
|
@ -1443,7 +1436,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
||||||
if (sym.get_allow_overlap() ||
|
if (sym.get_allow_overlap() ||
|
||||||
detector_.has_placement(extent))
|
detector_.has_placement(extent))
|
||||||
{
|
{
|
||||||
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity());
|
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, 1);
|
||||||
|
|
||||||
if (!sym.get_ignore_placement())
|
if (!sym.get_ignore_placement())
|
||||||
detector_.insert(extent);
|
detector_.insert(extent);
|
||||||
|
@ -1462,7 +1455,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
||||||
while (placement.get_point(x, y, angle))
|
while (placement.get_point(x, y, angle))
|
||||||
{
|
{
|
||||||
agg::trans_affine matrix = recenter * tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
|
agg::trans_affine matrix = recenter * tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
|
||||||
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h), **mark, matrix, sym.get_opacity(),false);
|
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h), **mark, matrix, 1,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.fill();
|
context.fill();
|
||||||
|
|
|
@ -321,9 +321,11 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
||||||
// if we've got this far, now prepare the unbuffered extent
|
// if we've got this far, now prepare the unbuffered extent
|
||||||
// which is used as a bbox for clipping geometries
|
// which is used as a bbox for clipping geometries
|
||||||
box2d<double> query_ext = m_.get_current_extent(); // unbuffered
|
box2d<double> query_ext = m_.get_current_extent(); // unbuffered
|
||||||
if (maximum_extent) {
|
if (maximum_extent)
|
||||||
|
{
|
||||||
query_ext.clip(*maximum_extent);
|
query_ext.clip(*maximum_extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
box2d<double> layer_ext2 = lay.envelope();
|
box2d<double> layer_ext2 = lay.envelope();
|
||||||
if (fw_success)
|
if (fw_success)
|
||||||
{
|
{
|
||||||
|
@ -351,8 +353,8 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
||||||
query q(layer_ext,res,scale_denom,m_.get_current_extent());
|
query q(layer_ext,res,scale_denom,m_.get_current_extent());
|
||||||
std::vector<feature_type_style*> active_styles;
|
std::vector<feature_type_style*> active_styles;
|
||||||
attribute_collector collector(names);
|
attribute_collector collector(names);
|
||||||
double filt_factor = 1;
|
double filt_factor = 1.0;
|
||||||
directive_collector d_collector(&filt_factor);
|
directive_collector d_collector(filt_factor);
|
||||||
|
|
||||||
// iterate through all named styles collecting active styles and attribute names
|
// iterate through all named styles collecting active styles and attribute names
|
||||||
BOOST_FOREACH(std::string const& style_name, style_names)
|
BOOST_FOREACH(std::string const& style_name, style_names)
|
||||||
|
@ -662,4 +664,3 @@ template class feature_style_processor<grid_renderer<grid> >;
|
||||||
template class feature_style_processor<agg_renderer<image_32> >;
|
template class feature_style_processor<agg_renderer<image_32> >;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,15 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/layer.hpp>
|
|
||||||
#include <mapnik/feature_type_style.hpp>
|
|
||||||
#include <mapnik/debug.hpp>
|
|
||||||
#include <mapnik/grid/grid_rasterizer.hpp>
|
#include <mapnik/grid/grid_rasterizer.hpp>
|
||||||
#include <mapnik/grid/grid_renderer.hpp>
|
#include <mapnik/grid/grid_renderer.hpp>
|
||||||
#include <mapnik/grid/grid_pixfmt.hpp>
|
#include <mapnik/grid/grid_pixfmt.hpp>
|
||||||
#include <mapnik/grid/grid_pixel.hpp>
|
#include <mapnik/grid/grid_pixel.hpp>
|
||||||
#include <mapnik/grid/grid.hpp>
|
#include <mapnik/grid/grid.hpp>
|
||||||
|
|
||||||
|
#include <mapnik/debug.hpp>
|
||||||
|
#include <mapnik/layer.hpp>
|
||||||
|
#include <mapnik/feature_type_style.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
#include <mapnik/unicode.hpp>
|
#include <mapnik/unicode.hpp>
|
||||||
|
@ -56,13 +57,22 @@ grid_renderer<T>::grid_renderer(Map const& m, T & pixmap, double scale_factor, u
|
||||||
width_(pixmap_.width()),
|
width_(pixmap_.width()),
|
||||||
height_(pixmap_.height()),
|
height_(pixmap_.height()),
|
||||||
scale_factor_(scale_factor),
|
scale_factor_(scale_factor),
|
||||||
|
// NOTE: can change this to m dims instead of pixmap_ if render-time
|
||||||
|
// resolution support is dropped from grid_renderer python interface
|
||||||
t_(pixmap_.width(),pixmap_.height(),m.get_current_extent(),offset_x,offset_y),
|
t_(pixmap_.width(),pixmap_.height(),m.get_current_extent(),offset_x,offset_y),
|
||||||
font_engine_(),
|
font_engine_(),
|
||||||
font_manager_(font_engine_),
|
font_manager_(font_engine_),
|
||||||
detector_(box2d<double>(-m.buffer_size(), -m.buffer_size(), pixmap_.width() + m.buffer_size(), pixmap_.height() + m.buffer_size())),
|
detector_(boost::make_shared<label_collision_detector4>(box2d<double>(-m.buffer_size(), -m.buffer_size(), m.width() + m.buffer_size() ,m.height() + m.buffer_size()))),
|
||||||
ras_ptr(new grid_rasterizer)
|
ras_ptr(new grid_rasterizer)
|
||||||
|
{
|
||||||
|
setup(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void grid_renderer<T>::setup(Map const& m)
|
||||||
{
|
{
|
||||||
MAPNIK_LOG_DEBUG(grid_renderer) << "grid_renderer: Scale=" << m.scale();
|
MAPNIK_LOG_DEBUG(grid_renderer) << "grid_renderer: Scale=" << m.scale();
|
||||||
|
// nothing to do for grids yet on setup
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -91,9 +101,25 @@ void grid_renderer<T>::start_layer_processing(layer const& lay, box2d<double> co
|
||||||
|
|
||||||
if (lay.clear_label_cache())
|
if (lay.clear_label_cache())
|
||||||
{
|
{
|
||||||
detector_.clear();
|
detector_->clear();
|
||||||
}
|
}
|
||||||
query_extent_ = query_extent;
|
query_extent_ = query_extent;
|
||||||
|
int buffer_size = lay.buffer_size();
|
||||||
|
if (buffer_size != 0 )
|
||||||
|
{
|
||||||
|
double padding = buffer_size * (double)(query_extent.width()/pixmap_.width());
|
||||||
|
double x0 = query_extent_.minx();
|
||||||
|
double y0 = query_extent_.miny();
|
||||||
|
double x1 = query_extent_.maxx();
|
||||||
|
double y1 = query_extent_.maxy();
|
||||||
|
query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<box2d<double> > const& maximum_extent = lay.maximum_extent();
|
||||||
|
if (maximum_extent)
|
||||||
|
{
|
||||||
|
query_extent_.clip(*maximum_extent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -144,21 +170,27 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl & feature, unsigned in
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
image_data_32 const& data = **marker.get_bitmap_data();
|
image_data_32 const& data = **marker.get_bitmap_data();
|
||||||
if (step == 1 && scale_factor_ == 1.0)
|
double width = data.width();
|
||||||
|
double height = data.height();
|
||||||
|
double cx = 0.5 * width;
|
||||||
|
double cy = 0.5 * height;
|
||||||
|
if (step == 1 && (std::fabs(1.0 - scale_factor_) < 0.001 && tr.is_identity()))
|
||||||
{
|
{
|
||||||
|
// TODO - support opacity
|
||||||
pixmap_.set_rectangle(feature.id(), data,
|
pixmap_.set_rectangle(feature.id(), data,
|
||||||
boost::math::iround(pos.x),
|
boost::math::iround(pos.x - cx),
|
||||||
boost::math::iround(pos.y));
|
boost::math::iround(pos.y - cy));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// TODO - remove support for step != or add support for agg scaling with opacity
|
||||||
double ratio = (1.0/step);
|
double ratio = (1.0/step);
|
||||||
image_data_32 target(ratio * data.width(), ratio * data.height());
|
image_data_32 target(ratio * data.width(), ratio * data.height());
|
||||||
mapnik::scale_image_agg<image_data_32>(target,data, SCALING_NEAR,
|
mapnik::scale_image_agg<image_data_32>(target,data, SCALING_NEAR,
|
||||||
scale_factor_, 0.0, 0.0, 1.0, ratio);
|
scale_factor_, 0.0, 0.0, 1.0, ratio);
|
||||||
pixmap_.set_rectangle(feature.id(), target,
|
pixmap_.set_rectangle(feature.id(), target,
|
||||||
boost::math::iround(pos.x),
|
boost::math::iround(pos.x - cx),
|
||||||
boost::math::iround(pos.y));
|
boost::math::iround(pos.y - cy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pixmap_.add_feature(feature);
|
pixmap_.add_feature(feature);
|
||||||
|
|
|
@ -20,22 +20,55 @@
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
porting notes -->
|
||||||
|
|
||||||
|
- grid includes
|
||||||
|
- detector
|
||||||
|
- no gamma
|
||||||
|
- mapnik::pixfmt_gray32
|
||||||
|
- agg::scanline_bin sl
|
||||||
|
- grid_rendering_buffer
|
||||||
|
- agg::renderer_scanline_bin_solid
|
||||||
|
- clamping:
|
||||||
|
// - clamp sizes to > 4 pixels of interactivity
|
||||||
|
if (tr.scale() < 0.5)
|
||||||
|
{
|
||||||
|
agg::trans_affine tr2;
|
||||||
|
tr2 *= agg::trans_affine_scaling(0.5);
|
||||||
|
tr = tr2;
|
||||||
|
}
|
||||||
|
tr *= agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution()));
|
||||||
|
- svg_renderer.render_id
|
||||||
|
- only encode feature if placements are found:
|
||||||
|
if (placed)
|
||||||
|
{
|
||||||
|
pixmap_.add_feature(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/debug.hpp>
|
|
||||||
#include <mapnik/grid/grid_rasterizer.hpp>
|
#include <mapnik/grid/grid_rasterizer.hpp>
|
||||||
#include <mapnik/grid/grid_renderer.hpp>
|
#include <mapnik/grid/grid_renderer.hpp>
|
||||||
#include <mapnik/grid/grid_pixfmt.hpp>
|
#include <mapnik/grid/grid_pixfmt.hpp>
|
||||||
#include <mapnik/grid/grid_pixel.hpp>
|
#include <mapnik/grid/grid_pixel.hpp>
|
||||||
#include <mapnik/grid/grid.hpp>
|
#include <mapnik/grid/grid.hpp>
|
||||||
|
|
||||||
|
#include <mapnik/debug.hpp>
|
||||||
|
#include <mapnik/geom_util.hpp>
|
||||||
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
|
#include <mapnik/vertex_converters.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
#include <mapnik/marker_helpers.hpp>
|
#include <mapnik/marker_helpers.hpp>
|
||||||
#include <mapnik/markers_symbolizer.hpp>
|
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
|
||||||
#include <mapnik/marker_cache.hpp>
|
|
||||||
#include <mapnik/svg/svg_renderer.hpp>
|
#include <mapnik/svg/svg_renderer.hpp>
|
||||||
|
#include <mapnik/svg/svg_storage.hpp>
|
||||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||||
|
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||||
#include <mapnik/markers_placement.hpp>
|
#include <mapnik/markers_placement.hpp>
|
||||||
|
#include <mapnik/markers_symbolizer.hpp>
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
#include "agg_basics.h"
|
#include "agg_basics.h"
|
||||||
|
@ -46,6 +79,11 @@
|
||||||
#include "agg_path_storage.h"
|
#include "agg_path_storage.h"
|
||||||
#include "agg_conv_clip_polyline.h"
|
#include "agg_conv_clip_polyline.h"
|
||||||
#include "agg_conv_transform.h"
|
#include "agg_conv_transform.h"
|
||||||
|
#include "agg_image_filters.h"
|
||||||
|
#include "agg_trans_bilinear.h"
|
||||||
|
#include "agg_span_allocator.h"
|
||||||
|
#include "agg_image_accessors.h"
|
||||||
|
#include "agg_span_image_filter_rgba.h"
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
@ -87,7 +125,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
agg::trans_affine geom_tr;
|
agg::trans_affine geom_tr;
|
||||||
evaluate_transform(geom_tr, feature, sym.get_transform());
|
evaluate_transform(geom_tr, feature, sym.get_transform());
|
||||||
|
|
||||||
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
|
boost::optional<svg_path_ptr> marker = (*mark)->get_vector_data();
|
||||||
box2d<double> const& bbox = (*marker)->bounding_box();
|
box2d<double> const& bbox = (*marker)->bounding_box();
|
||||||
|
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
|
@ -137,12 +175,12 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
box2d<double> transformed_bbox = bbox * matrix;
|
box2d<double> transformed_bbox = bbox * matrix;
|
||||||
|
|
||||||
if (sym.get_allow_overlap() ||
|
if (sym.get_allow_overlap() ||
|
||||||
detector_.has_placement(transformed_bbox))
|
detector_->has_placement(transformed_bbox))
|
||||||
{
|
{
|
||||||
placed = true;
|
placed = true;
|
||||||
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox);
|
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, 1, bbox);
|
||||||
if (!sym.get_ignore_placement())
|
if (!sym.get_ignore_placement())
|
||||||
detector_.insert(transformed_bbox);
|
detector_->insert(transformed_bbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sym.clip())
|
else if (sym.clip())
|
||||||
|
@ -155,7 +193,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
||||||
path_type path(t_,clipped,prj_trans);
|
path_type path(t_,clipped,prj_trans);
|
||||||
transformed_path_type path_transformed(path,geom_tr);
|
transformed_path_type path_transformed(path,geom_tr);
|
||||||
markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, detector_,
|
markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, *detector_,
|
||||||
sym.get_spacing() * scale_factor_,
|
sym.get_spacing() * scale_factor_,
|
||||||
sym.get_max_error(),
|
sym.get_max_error(),
|
||||||
sym.get_allow_overlap());
|
sym.get_allow_overlap());
|
||||||
|
@ -166,7 +204,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
agg::trans_affine matrix = marker_trans;
|
agg::trans_affine matrix = marker_trans;
|
||||||
matrix.rotate(angle);
|
matrix.rotate(angle);
|
||||||
matrix.translate(x, y);
|
matrix.translate(x, y);
|
||||||
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox);
|
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, 1, bbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -175,7 +213,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
typedef agg::conv_transform<path_type, agg::trans_affine> transformed_path_type;
|
typedef agg::conv_transform<path_type, agg::trans_affine> transformed_path_type;
|
||||||
path_type path(t_,geom,prj_trans);
|
path_type path(t_,geom,prj_trans);
|
||||||
transformed_path_type path_transformed(path,geom_tr);
|
transformed_path_type path_transformed(path,geom_tr);
|
||||||
markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, detector_,
|
markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, *detector_,
|
||||||
sym.get_spacing() * scale_factor_,
|
sym.get_spacing() * scale_factor_,
|
||||||
sym.get_max_error(),
|
sym.get_max_error(),
|
||||||
sym.get_allow_overlap());
|
sym.get_allow_overlap());
|
||||||
|
@ -186,7 +224,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
||||||
agg::trans_affine matrix = marker_trans;
|
agg::trans_affine matrix = marker_trans;
|
||||||
matrix.rotate(angle);
|
matrix.rotate(angle);
|
||||||
matrix.translate(x, y);
|
matrix.translate(x, y);
|
||||||
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox);
|
svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, 1, bbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,22 @@
|
||||||
#include <mapnik/grid/grid_pixfmt.hpp>
|
#include <mapnik/grid/grid_pixfmt.hpp>
|
||||||
#include <mapnik/grid/grid_pixel.hpp>
|
#include <mapnik/grid/grid_pixel.hpp>
|
||||||
#include <mapnik/grid/grid.hpp>
|
#include <mapnik/grid/grid.hpp>
|
||||||
|
|
||||||
#include <mapnik/geom_util.hpp>
|
#include <mapnik/geom_util.hpp>
|
||||||
#include <mapnik/point_symbolizer.hpp>
|
#include <mapnik/point_symbolizer.hpp>
|
||||||
#include <mapnik/expression_evaluator.hpp>
|
#include <mapnik/expression_evaluator.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
#include <mapnik/marker_cache.hpp>
|
#include <mapnik/marker_cache.hpp>
|
||||||
|
|
||||||
|
// agg
|
||||||
|
#include "agg_trans_affine.h"
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
// boost
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -57,14 +64,14 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
|
||||||
if (marker)
|
if (marker)
|
||||||
{
|
{
|
||||||
box2d<double> const& bbox = (*marker)->bounding_box();
|
box2d<double> const& bbox = (*marker)->bounding_box();
|
||||||
coord2d const center = bbox.center();
|
coord2d center = bbox.center();
|
||||||
|
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
evaluate_transform(tr, feature, sym.get_image_transform());
|
evaluate_transform(tr, feature, sym.get_image_transform());
|
||||||
tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
||||||
|
|
||||||
agg::trans_affine_translation const recenter(-center.x, -center.y);
|
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||||
agg::trans_affine const recenter_tr = recenter * tr;
|
agg::trans_affine recenter_tr = recenter * tr;
|
||||||
box2d<double> label_ext = bbox * recenter_tr;
|
box2d<double> label_ext = bbox * recenter_tr;
|
||||||
|
|
||||||
for (unsigned i=0; i<feature.num_geometries(); ++i)
|
for (unsigned i=0; i<feature.num_geometries(); ++i)
|
||||||
|
@ -82,7 +89,7 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
|
||||||
t_.forward(&x,&y);
|
t_.forward(&x,&y);
|
||||||
label_ext.re_center(x,y);
|
label_ext.re_center(x,y);
|
||||||
if (sym.get_allow_overlap() ||
|
if (sym.get_allow_overlap() ||
|
||||||
detector_.has_placement(label_ext))
|
detector_->has_placement(label_ext))
|
||||||
{
|
{
|
||||||
|
|
||||||
render_marker(feature,
|
render_marker(feature,
|
||||||
|
@ -94,7 +101,7 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
|
||||||
sym.comp_op());
|
sym.comp_op());
|
||||||
|
|
||||||
if (!sym.get_ignore_placement())
|
if (!sym.get_ignore_placement())
|
||||||
detector_.insert(label_ext);
|
detector_->insert(label_ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
|
||||||
sym, feature, prj_trans,
|
sym, feature, prj_trans,
|
||||||
width_, height_,
|
width_, height_,
|
||||||
scale_factor_,
|
scale_factor_,
|
||||||
t_, font_manager_, detector_,
|
t_, font_manager_, *detector_,
|
||||||
query_extent_);
|
query_extent_);
|
||||||
bool placement_found = false;
|
bool placement_found = false;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
|
||||||
sym, feature, prj_trans,
|
sym, feature, prj_trans,
|
||||||
width_, height_,
|
width_, height_,
|
||||||
scale_factor_ * (1.0/pixmap_.get_resolution()),
|
scale_factor_ * (1.0/pixmap_.get_resolution()),
|
||||||
t_, font_manager_, detector_,
|
t_, font_manager_, *detector_,
|
||||||
query_extent_);
|
query_extent_);
|
||||||
bool placement_found = false;
|
bool placement_found = false;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ layer::layer(std::string const& name, std::string const& srs)
|
||||||
clear_label_cache_(false),
|
clear_label_cache_(false),
|
||||||
cache_features_(false),
|
cache_features_(false),
|
||||||
group_by_(""),
|
group_by_(""),
|
||||||
ds_() {}
|
ds_(),
|
||||||
|
buffer_size_(0) {}
|
||||||
|
|
||||||
layer::layer(const layer& rhs)
|
layer::layer(const layer& rhs)
|
||||||
: name_(rhs.name_),
|
: name_(rhs.name_),
|
||||||
|
@ -55,7 +56,9 @@ layer::layer(const layer& rhs)
|
||||||
cache_features_(rhs.cache_features_),
|
cache_features_(rhs.cache_features_),
|
||||||
group_by_(rhs.group_by_),
|
group_by_(rhs.group_by_),
|
||||||
styles_(rhs.styles_),
|
styles_(rhs.styles_),
|
||||||
ds_(rhs.ds_) {}
|
ds_(rhs.ds_),
|
||||||
|
buffer_size_(rhs.buffer_size_),
|
||||||
|
maximum_extent_(rhs.maximum_extent_) {}
|
||||||
|
|
||||||
layer& layer::operator=(const layer& rhs)
|
layer& layer::operator=(const layer& rhs)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +85,8 @@ void layer::swap(const layer& rhs)
|
||||||
group_by_ = rhs.group_by_;
|
group_by_ = rhs.group_by_;
|
||||||
styles_=rhs.styles_;
|
styles_=rhs.styles_;
|
||||||
ds_=rhs.ds_;
|
ds_=rhs.ds_;
|
||||||
|
buffer_size_ = rhs.buffer_size_;
|
||||||
|
maximum_extent_ = rhs.maximum_extent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer::~layer() {}
|
layer::~layer() {}
|
||||||
|
@ -176,6 +181,31 @@ void layer::set_datasource(datasource_ptr const& ds)
|
||||||
ds_ = ds;
|
ds_ = ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void layer::set_maximum_extent(box2d<double> const& box)
|
||||||
|
{
|
||||||
|
maximum_extent_.reset(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<box2d<double> > const& layer::maximum_extent() const
|
||||||
|
{
|
||||||
|
return maximum_extent_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer::reset_maximum_extent()
|
||||||
|
{
|
||||||
|
maximum_extent_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer::set_buffer_size(int size)
|
||||||
|
{
|
||||||
|
buffer_size_ = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer::buffer_size() const
|
||||||
|
{
|
||||||
|
return buffer_size_;
|
||||||
|
}
|
||||||
|
|
||||||
box2d<double> layer::envelope() const
|
box2d<double> layer::envelope() const
|
||||||
{
|
{
|
||||||
if (ds_) return ds_->envelope();
|
if (ds_) return ds_->envelope();
|
||||||
|
|
|
@ -575,66 +575,95 @@ bool map_parser::parse_font(font_set &fset, xml_node const& f)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_parser::parse_layer(Map & map, xml_node const& lay)
|
void map_parser::parse_layer(Map & map, xml_node const& node)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
name = lay.get_attr("name", std::string("Unnamed"));
|
name = node.get_attr("name", std::string("Unnamed"));
|
||||||
|
|
||||||
// XXX if no projection is given inherit from map? [DS]
|
// XXX if no projection is given inherit from map? [DS]
|
||||||
std::string srs = lay.get_attr("srs", map.srs());
|
std::string srs = node.get_attr("srs", map.srs());
|
||||||
|
|
||||||
layer lyr(name, srs);
|
layer lyr(name, srs);
|
||||||
|
|
||||||
optional<boolean> status = lay.get_opt_attr<boolean>("status");
|
optional<boolean> status = node.get_opt_attr<boolean>("status");
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
lyr.set_active(* status);
|
lyr.set_active(* status);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<double> min_zoom = lay.get_opt_attr<double>("minzoom");
|
optional<double> min_zoom = node.get_opt_attr<double>("minzoom");
|
||||||
if (min_zoom)
|
if (min_zoom)
|
||||||
{
|
{
|
||||||
lyr.set_min_zoom(* min_zoom);
|
lyr.set_min_zoom(* min_zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
optional<double> max_zoom = lay.get_opt_attr<double>("maxzoom");
|
optional<double> max_zoom = node.get_opt_attr<double>("maxzoom");
|
||||||
if (max_zoom)
|
if (max_zoom)
|
||||||
{
|
{
|
||||||
lyr.set_max_zoom(* max_zoom);
|
lyr.set_max_zoom(* max_zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<boolean> queryable = lay.get_opt_attr<boolean>("queryable");
|
optional<boolean> queryable = node.get_opt_attr<boolean>("queryable");
|
||||||
if (queryable)
|
if (queryable)
|
||||||
{
|
{
|
||||||
lyr.set_queryable(* queryable);
|
lyr.set_queryable(* queryable);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<boolean> clear_cache =
|
optional<boolean> clear_cache =
|
||||||
lay.get_opt_attr<boolean>("clear-label-cache");
|
node.get_opt_attr<boolean>("clear-label-cache");
|
||||||
if (clear_cache)
|
if (clear_cache)
|
||||||
{
|
{
|
||||||
lyr.set_clear_label_cache(* clear_cache);
|
lyr.set_clear_label_cache(* clear_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<boolean> cache_features =
|
optional<boolean> cache_features =
|
||||||
lay.get_opt_attr<boolean>("cache-features");
|
node.get_opt_attr<boolean>("cache-features");
|
||||||
if (cache_features)
|
if (cache_features)
|
||||||
{
|
{
|
||||||
lyr.set_cache_features(* cache_features);
|
lyr.set_cache_features(* cache_features);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::string> group_by =
|
optional<std::string> group_by =
|
||||||
lay.get_opt_attr<std::string>("group-by");
|
node.get_opt_attr<std::string>("group-by");
|
||||||
if (group_by)
|
if (group_by)
|
||||||
{
|
{
|
||||||
lyr.set_group_by(* group_by);
|
lyr.set_group_by(* group_by);
|
||||||
}
|
}
|
||||||
|
|
||||||
xml_node::const_iterator child = lay.begin();
|
optional<unsigned> buffer_size = node.get_opt_attr<unsigned>("buffer-size");
|
||||||
xml_node::const_iterator end = lay.end();
|
if (buffer_size)
|
||||||
|
{
|
||||||
|
lyr.set_buffer_size(*buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<std::string> maximum_extent = node.get_opt_attr<std::string>("maximum-extent");
|
||||||
|
if (maximum_extent)
|
||||||
|
{
|
||||||
|
box2d<double> box;
|
||||||
|
if (box.from_string(*maximum_extent))
|
||||||
|
{
|
||||||
|
lyr.set_maximum_extent(box);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::ostringstream s_err;
|
||||||
|
s_err << "failed to parse 'maximum-extent' in layer " << name;
|
||||||
|
if (strict_)
|
||||||
|
{
|
||||||
|
throw config_error(s_err.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_WARN(load_map) << "map_parser: " << s_err.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_node::const_iterator child = node.begin();
|
||||||
|
xml_node::const_iterator end = node.end();
|
||||||
|
|
||||||
for(; child != end; ++child)
|
for(; child != end; ++child)
|
||||||
{
|
{
|
||||||
|
@ -719,7 +748,7 @@ void map_parser::parse_layer(Map & map, xml_node const& lay)
|
||||||
{
|
{
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
ex.append_context(std::string(" encountered during parsing of layer '") + name + "'", lay);
|
ex.append_context(std::string(" encountered during parsing of layer '") + name + "'", node);
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -894,7 +923,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
|
||||||
symbol.set_ignore_placement(* ignore_placement);
|
symbol.set_ignore_placement(* ignore_placement);
|
||||||
}
|
}
|
||||||
point_placement_e placement =
|
point_placement_e placement =
|
||||||
sym.get_attr<point_placement_e>("placement", CENTROID_POINT_PLACEMENT);
|
sym.get_attr<point_placement_e>("placement", symbol.get_point_placement());
|
||||||
symbol.set_point_placement(placement);
|
symbol.set_point_placement(placement);
|
||||||
|
|
||||||
if (file && !file->empty())
|
if (file && !file->empty())
|
||||||
|
@ -1018,9 +1047,13 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
|
||||||
sym.set_filename(expr);
|
sym.set_filename(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// overall opacity - impacts both fill and stroke, like svg
|
||||||
optional<float> opacity = node.get_opt_attr<float>("opacity");
|
optional<float> opacity = node.get_opt_attr<float>("opacity");
|
||||||
if (opacity) sym.set_opacity(*opacity);
|
if (opacity) sym.set_opacity(*opacity);
|
||||||
|
|
||||||
|
optional<float> fill_opacity = node.get_opt_attr<float>("fill-opacity");
|
||||||
|
if (fill_opacity) sym.set_fill_opacity(*fill_opacity);
|
||||||
|
|
||||||
optional<std::string> image_transform_wkt = node.get_opt_attr<std::string>("transform");
|
optional<std::string> image_transform_wkt = node.get_opt_attr<std::string>("transform");
|
||||||
if (image_transform_wkt)
|
if (image_transform_wkt)
|
||||||
{
|
{
|
||||||
|
@ -1065,7 +1098,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
|
||||||
sym.set_stroke(strk);
|
sym.set_stroke(strk);
|
||||||
}
|
}
|
||||||
|
|
||||||
marker_placement_e placement = node.get_attr<marker_placement_e>("placement", MARKER_POINT_PLACEMENT);
|
marker_placement_e placement = node.get_attr<marker_placement_e>("placement",sym.get_marker_placement());
|
||||||
sym.set_marker_placement(placement);
|
sym.set_marker_placement(placement);
|
||||||
parse_symbolizer_base(sym, node);
|
parse_symbolizer_base(sym, node);
|
||||||
rule.append(sym);
|
rule.append(sym);
|
||||||
|
|
|
@ -352,7 +352,7 @@ void Map::set_background_image(std::string const& image_filename)
|
||||||
|
|
||||||
void Map::set_maximum_extent(box2d<double> const& box)
|
void Map::set_maximum_extent(box2d<double> const& box)
|
||||||
{
|
{
|
||||||
maximum_extent_ = box;
|
maximum_extent_.reset(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<box2d<double> > const& Map::maximum_extent() const
|
boost::optional<box2d<double> > const& Map::maximum_extent() const
|
||||||
|
@ -360,9 +360,9 @@ boost::optional<box2d<double> > const& Map::maximum_extent() const
|
||||||
return maximum_extent_;
|
return maximum_extent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<box2d<double> > & Map::maximum_extent()
|
void Map::reset_maximum_extent()
|
||||||
{
|
{
|
||||||
return maximum_extent_;
|
maximum_extent_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& Map::base_path() const
|
std::string const& Map::base_path() const
|
||||||
|
|
|
@ -144,7 +144,7 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri,
|
||||||
}
|
}
|
||||||
std::string known_svg_string = mark_itr->second;
|
std::string known_svg_string = mark_itr->second;
|
||||||
using namespace mapnik::svg;
|
using namespace mapnik::svg;
|
||||||
path_ptr marker_path(boost::make_shared<svg_storage_type>());
|
svg_path_ptr marker_path(boost::make_shared<svg_storage_type>());
|
||||||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||||
svg_path_adapter svg_path(stl_storage);
|
svg_path_adapter svg_path(stl_storage);
|
||||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||||
|
@ -173,7 +173,7 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri,
|
||||||
if (is_svg(uri))
|
if (is_svg(uri))
|
||||||
{
|
{
|
||||||
using namespace mapnik::svg;
|
using namespace mapnik::svg;
|
||||||
path_ptr marker_path(boost::make_shared<svg_storage_type>());
|
svg_path_ptr marker_path(boost::make_shared<svg_storage_type>());
|
||||||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||||
svg_path_adapter svg_path(stl_storage);
|
svg_path_adapter svg_path(stl_storage);
|
||||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||||
|
|
|
@ -1,253 +0,0 @@
|
||||||
// mapnik
|
|
||||||
#include <mapnik/markers_placement.hpp>
|
|
||||||
#include <mapnik/geometry.hpp>
|
|
||||||
#include <mapnik/ctrans.hpp>
|
|
||||||
#include <mapnik/label_collision_detector.hpp>
|
|
||||||
#include <mapnik/global.hpp> //round
|
|
||||||
// agg
|
|
||||||
#include "agg_basics.h"
|
|
||||||
#include "agg_conv_clip_polyline.h"
|
|
||||||
#include "agg_trans_affine.h"
|
|
||||||
#include "agg_conv_transform.h"
|
|
||||||
#include "agg_conv_smooth_poly1.h"
|
|
||||||
// stl
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace mapnik
|
|
||||||
{
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
markers_placement<Locator, Detector>::markers_placement(
|
|
||||||
Locator &locator, box2d<double> const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap)
|
|
||||||
: locator_(locator), size_(size), tr_(tr), detector_(detector), max_error_(max_error), allow_overlap_(allow_overlap)
|
|
||||||
{
|
|
||||||
marker_width_ = (size_ * tr_).width();
|
|
||||||
if (spacing >= 0)
|
|
||||||
{
|
|
||||||
spacing_ = spacing;
|
|
||||||
} else if (spacing < 0)
|
|
||||||
{
|
|
||||||
spacing_ = find_optimal_spacing(-spacing);
|
|
||||||
}
|
|
||||||
rewind();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
double markers_placement<Locator, Detector>::find_optimal_spacing(double s)
|
|
||||||
{
|
|
||||||
rewind();
|
|
||||||
//Calculate total path length
|
|
||||||
unsigned cmd = agg::path_cmd_move_to;
|
|
||||||
double length = 0;
|
|
||||||
while (!agg::is_stop(cmd))
|
|
||||||
{
|
|
||||||
double dx = next_x - last_x;
|
|
||||||
double dy = next_y - last_y;
|
|
||||||
length += std::sqrt(dx * dx + dy * dy);
|
|
||||||
last_x = next_x;
|
|
||||||
last_y = next_y;
|
|
||||||
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
|
||||||
{
|
|
||||||
//Skip over "move" commands
|
|
||||||
last_x = next_x;
|
|
||||||
last_y = next_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned points = round(length / s);
|
|
||||||
if (points == 0) return 0.0; //Path to short
|
|
||||||
return length / points;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
void markers_placement<Locator, Detector>::rewind()
|
|
||||||
{
|
|
||||||
locator_.rewind(0);
|
|
||||||
//Get first point
|
|
||||||
done_ = agg::is_stop(locator_.vertex(&next_x, &next_y)) || spacing_ < marker_width_;
|
|
||||||
last_x = next_x;
|
|
||||||
last_y = next_y; // Force request of new segment
|
|
||||||
error_ = 0;
|
|
||||||
marker_nr_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
bool markers_placement<Locator, Detector>::get_point(
|
|
||||||
double & x, double & y, double & angle, bool add_to_detector)
|
|
||||||
{
|
|
||||||
if (done_) return false;
|
|
||||||
|
|
||||||
unsigned cmd;
|
|
||||||
|
|
||||||
/* This functions starts at the position of the previous marker,
|
|
||||||
walks along the path, counting how far it has to go in spacing_left.
|
|
||||||
If one marker can't be placed at the position it should go to it is
|
|
||||||
moved a bit. The error is compensated for in the next call to this
|
|
||||||
function.
|
|
||||||
|
|
||||||
error > 0: Marker too near to the end of the path.
|
|
||||||
error = 0: Perfect position.
|
|
||||||
error < 0: Marker too near to the beginning of the path.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (marker_nr_++ == 0)
|
|
||||||
{
|
|
||||||
//First marker
|
|
||||||
spacing_left_ = spacing_ / 2;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
spacing_left_ = spacing_;
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing_left_ -= error_;
|
|
||||||
error_ = 0;
|
|
||||||
|
|
||||||
//Loop exits when a position is found or when no more segments are available
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
//Do not place markers too close to the beginning of a segment
|
|
||||||
if (spacing_left_ < marker_width_/2)
|
|
||||||
{
|
|
||||||
set_spacing_left(marker_width_/2); //Only moves forward
|
|
||||||
}
|
|
||||||
//Error for this marker is too large. Skip to the next position.
|
|
||||||
if (abs(error_) > max_error_ * spacing_)
|
|
||||||
{
|
|
||||||
if (error_ > spacing_)
|
|
||||||
{
|
|
||||||
error_ = 0; //Avoid moving backwards
|
|
||||||
|
|
||||||
MAPNIK_LOG_WARN(markers_placement) << "Extremely large error in markers_placement. Please file a bug report.";
|
|
||||||
}
|
|
||||||
spacing_left_ += spacing_ - error_;
|
|
||||||
error_ = 0;
|
|
||||||
}
|
|
||||||
double dx = next_x - last_x;
|
|
||||||
double dy = next_y - last_y;
|
|
||||||
double segment_length = std::sqrt(dx * dx + dy * dy);
|
|
||||||
if (segment_length <= spacing_left_)
|
|
||||||
{
|
|
||||||
//Segment is to short to place marker. Find next segment
|
|
||||||
spacing_left_ -= segment_length;
|
|
||||||
last_x = next_x;
|
|
||||||
last_y = next_y;
|
|
||||||
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
|
||||||
{
|
|
||||||
//Skip over "move" commands
|
|
||||||
last_x = next_x;
|
|
||||||
last_y = next_y;
|
|
||||||
}
|
|
||||||
if (agg::is_stop(cmd))
|
|
||||||
{
|
|
||||||
done_ = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue; //Try again
|
|
||||||
}
|
|
||||||
|
|
||||||
/* At this point we know the following things:
|
|
||||||
- segment_length > spacing_left
|
|
||||||
- error is small enough
|
|
||||||
- at least half a marker fits into this segment
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Check if marker really fits in this segment
|
|
||||||
if (segment_length < marker_width_)
|
|
||||||
{
|
|
||||||
//Segment to short => Skip this segment
|
|
||||||
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
|
||||||
continue;
|
|
||||||
} else if (segment_length - spacing_left_ < marker_width_/2)
|
|
||||||
{
|
|
||||||
//Segment is long enough, but we are to close to the end
|
|
||||||
|
|
||||||
//Note: This function moves backwards. This could lead to an infinite
|
|
||||||
// loop when another function adds a positive offset. Therefore we
|
|
||||||
// only move backwards when there is no offset
|
|
||||||
if (error_ == 0)
|
|
||||||
{
|
|
||||||
set_spacing_left(segment_length - marker_width_/2, true);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
//Skip this segment
|
|
||||||
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
|
||||||
}
|
|
||||||
continue; //Force checking of max_error constraint
|
|
||||||
}
|
|
||||||
angle = atan2(dy, dx);
|
|
||||||
x = last_x + dx * (spacing_left_ / segment_length);
|
|
||||||
y = last_y + dy * (spacing_left_ / segment_length);
|
|
||||||
|
|
||||||
box2d<double> box = perform_transform(angle, x, y);
|
|
||||||
|
|
||||||
if (!allow_overlap_ && !detector_.has_placement(box))
|
|
||||||
{
|
|
||||||
//10.0 is the approxmiate number of positions tried and choosen arbitrarily
|
|
||||||
set_spacing_left(spacing_left_ + spacing_ * max_error_ / 10.0); //Only moves forward
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (add_to_detector) detector_.insert(box);
|
|
||||||
last_x = x;
|
|
||||||
last_y = y;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
box2d<double> markers_placement<Locator, Detector>::perform_transform(double angle, double dx, double dy)
|
|
||||||
{
|
|
||||||
double x1 = size_.minx();
|
|
||||||
double x2 = size_.maxx();
|
|
||||||
double y1 = size_.miny();
|
|
||||||
double y2 = size_.maxy();
|
|
||||||
|
|
||||||
agg::trans_affine tr = tr_ * agg::trans_affine_rotation(angle).translate(dx, dy);
|
|
||||||
|
|
||||||
double xA = x1, yA = y1, xB = x2, yB = y1, xC = x2, yC = y2, xD = x1, yD = y2;
|
|
||||||
tr.transform(&xA, &yA);
|
|
||||||
tr.transform(&xB, &yB);
|
|
||||||
tr.transform(&xC, &yC);
|
|
||||||
tr.transform(&xD, &yD);
|
|
||||||
|
|
||||||
box2d<double> result(xA, yA, xC, yC);
|
|
||||||
result.expand_to_include(xB, yB);
|
|
||||||
result.expand_to_include(xD, yD);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Locator, typename Detector>
|
|
||||||
void markers_placement<Locator, Detector>::set_spacing_left(double sl, bool allow_negative)
|
|
||||||
{
|
|
||||||
double delta_error = sl - spacing_left_;
|
|
||||||
if (!allow_negative && delta_error < 0)
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_WARN(markers_placement) << "Unexpected negative error in markers_placement. Please file a bug report.";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef MAPNIK_DEBUG
|
|
||||||
if (delta_error == 0.0)
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_WARN(markers_placement) << "Not moving at all in set_spacing_left()! Please file a bug report.";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
error_ += delta_error;
|
|
||||||
spacing_left_ = sl;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
|
|
||||||
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
|
||||||
typedef coord_transform<CoordTransform,clipped_geometry_type> clipped_path_type;
|
|
||||||
typedef agg::conv_transform<path_type, agg::trans_affine> transformed_path_type;
|
|
||||||
|
|
||||||
template class markers_placement<geometry_type, label_collision_detector4>;
|
|
||||||
template class markers_placement<path_type, label_collision_detector4>;
|
|
||||||
template class markers_placement<clipped_geometry_type, label_collision_detector4>;
|
|
||||||
template class markers_placement<transformed_path_type, label_collision_detector4>;
|
|
||||||
template class markers_placement<clipped_path_type, label_collision_detector4>;
|
|
||||||
template class markers_placement<agg::conv_transform<clipped_path_type,agg::trans_affine>, label_collision_detector4>;
|
|
||||||
template class markers_placement<agg::conv_smooth_poly1_curve<clipped_path_type>, label_collision_detector4>;
|
|
||||||
template class markers_placement<agg::conv_smooth_poly1_curve<geometry_type>, label_collision_detector4>;
|
|
||||||
template class markers_placement<agg::conv_smooth_poly1_curve<path_type>, label_collision_detector4>;
|
|
||||||
template class markers_placement<agg::conv_smooth_poly1_curve<clipped_geometry_type>, label_collision_detector4>;
|
|
||||||
} //ns mapnik
|
|
|
@ -30,6 +30,7 @@ namespace mapnik {
|
||||||
|
|
||||||
static const char * marker_placement_strings[] = {
|
static const char * marker_placement_strings[] = {
|
||||||
"point",
|
"point",
|
||||||
|
"interior",
|
||||||
"line",
|
"line",
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
@ -45,10 +46,7 @@ markers_symbolizer::markers_symbolizer()
|
||||||
allow_overlap_(false),
|
allow_overlap_(false),
|
||||||
spacing_(100.0),
|
spacing_(100.0),
|
||||||
max_error_(0.2),
|
max_error_(0.2),
|
||||||
marker_p_(MARKER_POINT_PLACEMENT) {
|
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||||
// override the default for clipping in symbolizer base
|
|
||||||
this->set_clip(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
||||||
: symbolizer_with_image(filename),
|
: symbolizer_with_image(filename),
|
||||||
|
@ -59,10 +57,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
||||||
allow_overlap_(false),
|
allow_overlap_(false),
|
||||||
spacing_(100.0),
|
spacing_(100.0),
|
||||||
max_error_(0.2),
|
max_error_(0.2),
|
||||||
marker_p_(MARKER_POINT_PLACEMENT) {
|
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||||
// override the default for clipping in symbolizer base
|
|
||||||
this->set_clip(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
||||||
: symbolizer_with_image(rhs),
|
: symbolizer_with_image(rhs),
|
||||||
|
@ -74,6 +69,8 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
||||||
spacing_(rhs.spacing_),
|
spacing_(rhs.spacing_),
|
||||||
max_error_(rhs.max_error_),
|
max_error_(rhs.max_error_),
|
||||||
fill_(rhs.fill_),
|
fill_(rhs.fill_),
|
||||||
|
fill_opacity_(rhs.fill_opacity_),
|
||||||
|
opacity_(rhs.opacity_),
|
||||||
stroke_(rhs.stroke_),
|
stroke_(rhs.stroke_),
|
||||||
marker_p_(rhs.marker_p_) {}
|
marker_p_(rhs.marker_p_) {}
|
||||||
|
|
||||||
|
@ -117,6 +114,16 @@ double markers_symbolizer::get_max_error() const
|
||||||
return max_error_;
|
return max_error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markers_symbolizer::set_opacity(float opacity)
|
||||||
|
{
|
||||||
|
opacity_ = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<float> markers_symbolizer::get_opacity() const
|
||||||
|
{
|
||||||
|
return opacity_;
|
||||||
|
}
|
||||||
|
|
||||||
void markers_symbolizer::set_fill(color const& fill)
|
void markers_symbolizer::set_fill(color const& fill)
|
||||||
{
|
{
|
||||||
fill_ = fill;
|
fill_ = fill;
|
||||||
|
@ -127,6 +134,16 @@ boost::optional<color> markers_symbolizer::get_fill() const
|
||||||
return fill_;
|
return fill_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markers_symbolizer::set_fill_opacity(float opacity)
|
||||||
|
{
|
||||||
|
fill_opacity_ = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<float> markers_symbolizer::get_fill_opacity() const
|
||||||
|
{
|
||||||
|
return fill_opacity_;
|
||||||
|
}
|
||||||
|
|
||||||
void markers_symbolizer::set_width(expression_ptr const& width)
|
void markers_symbolizer::set_width(expression_ptr const& width)
|
||||||
{
|
{
|
||||||
width_ = width;
|
width_ = width;
|
||||||
|
|
|
@ -78,6 +78,11 @@ public:
|
||||||
{
|
{
|
||||||
set_attr( sym_node, "placement", sym.get_point_placement() );
|
set_attr( sym_node, "placement", sym.get_point_placement() );
|
||||||
}
|
}
|
||||||
|
if (sym.get_image_transform())
|
||||||
|
{
|
||||||
|
std::string tr_str = sym.get_image_transform_string();
|
||||||
|
set_attr( sym_node, "transform", tr_str );
|
||||||
|
}
|
||||||
serialize_symbolizer_base(sym_node, sym);
|
serialize_symbolizer_base(sym_node, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +223,11 @@ public:
|
||||||
{
|
{
|
||||||
set_attr(sym_node, "shield-dy", displacement.y);
|
set_attr(sym_node, "shield-dy", displacement.y);
|
||||||
}
|
}
|
||||||
|
if (sym.get_image_transform())
|
||||||
|
{
|
||||||
|
std::string tr_str = sym.get_image_transform_string();
|
||||||
|
set_attr( sym_node, "transform", tr_str );
|
||||||
|
}
|
||||||
serialize_symbolizer_base(sym_node, sym);
|
serialize_symbolizer_base(sym_node, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +259,6 @@ public:
|
||||||
{
|
{
|
||||||
set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) );
|
set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize_symbolizer_base(sym_node, sym);
|
serialize_symbolizer_base(sym_node, sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +292,10 @@ public:
|
||||||
{
|
{
|
||||||
set_attr( sym_node, "fill", sym.get_fill() );
|
set_attr( sym_node, "fill", sym.get_fill() );
|
||||||
}
|
}
|
||||||
|
if (sym.get_fill_opacity() != dfl.get_fill_opacity() || explicit_defaults_)
|
||||||
|
{
|
||||||
|
set_attr( sym_node, "fill-opacity", sym.get_fill_opacity() );
|
||||||
|
}
|
||||||
if (sym.get_opacity() != dfl.get_opacity() || explicit_defaults_)
|
if (sym.get_opacity() != dfl.get_opacity() || explicit_defaults_)
|
||||||
{
|
{
|
||||||
set_attr( sym_node, "opacity", sym.get_opacity() );
|
set_attr( sym_node, "opacity", sym.get_opacity() );
|
||||||
|
@ -454,7 +467,7 @@ private:
|
||||||
}
|
}
|
||||||
if ( strk.dash_offset() != dfl.dash_offset() || explicit_defaults_ )
|
if ( strk.dash_offset() != dfl.dash_offset() || explicit_defaults_ )
|
||||||
{
|
{
|
||||||
set_attr( node, "stroke-dash-offset", strk.dash_offset());
|
set_attr( node, "stroke-dashoffset", strk.dash_offset());
|
||||||
}
|
}
|
||||||
if ( ! strk.get_dash_array().empty() )
|
if ( ! strk.get_dash_array().empty() )
|
||||||
{
|
{
|
||||||
|
@ -728,6 +741,22 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau
|
||||||
set_attr( layer_node, "group-by", layer.group_by() );
|
set_attr( layer_node, "group-by", layer.group_by() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int buffer_size = layer.buffer_size();
|
||||||
|
if ( buffer_size || explicit_defaults)
|
||||||
|
{
|
||||||
|
set_attr( layer_node, "buffer-size", buffer_size );
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<box2d<double> > const& maximum_extent = layer.maximum_extent();
|
||||||
|
if ( maximum_extent)
|
||||||
|
{
|
||||||
|
std::ostringstream s;
|
||||||
|
s << std::setprecision(16)
|
||||||
|
<< maximum_extent->minx() << "," << maximum_extent->miny() << ","
|
||||||
|
<< maximum_extent->maxx() << "," << maximum_extent->maxy();
|
||||||
|
set_attr( layer_node, "maximum-extent", s.str() );
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> const& style_names = layer.styles();
|
std::vector<std::string> const& style_names = layer.styles();
|
||||||
for (unsigned i = 0; i < style_names.size(); ++i)
|
for (unsigned i = 0; i < style_names.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -775,7 +804,7 @@ void serialize_map(ptree & pt, Map const & map, bool explicit_defaults)
|
||||||
set_attr( map_node, "background-image", *image_filename );
|
set_attr( map_node, "background-image", *image_filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned buffer_size = map.buffer_size();
|
int buffer_size = map.buffer_size();
|
||||||
if ( buffer_size || explicit_defaults)
|
if ( buffer_size || explicit_defaults)
|
||||||
{
|
{
|
||||||
set_attr( map_node, "buffer-size", buffer_size );
|
set_attr( map_node, "buffer-size", buffer_size );
|
||||||
|
|
|
@ -221,7 +221,11 @@ void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (how_placed == POINT_PLACEMENT)
|
if (geom.type() == LineString)
|
||||||
|
{
|
||||||
|
label::middle_point(geom, label_x,label_y);
|
||||||
|
}
|
||||||
|
else if (how_placed == POINT_PLACEMENT)
|
||||||
{
|
{
|
||||||
label::centroid(geom, label_x, label_y);
|
label::centroid(geom, label_x, label_y);
|
||||||
}
|
}
|
||||||
|
|
66
tests/data/good_maps/marker_ellipse_transform.xml
Normal file
66
tests/data/good_maps/marker_ellipse_transform.xml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<Map srs="+init=epsg:4326" background-color="rgba(255,255,255,.5)">
|
||||||
|
|
||||||
|
<Style name="ellipse">
|
||||||
|
<Rule>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="240"
|
||||||
|
height="240"
|
||||||
|
fill="steelblue"
|
||||||
|
fill-opacity=".7"
|
||||||
|
stroke="yellow"
|
||||||
|
stroke-width="16"
|
||||||
|
stroke-opacity=".3"
|
||||||
|
/>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="100"
|
||||||
|
opacity=".5"
|
||||||
|
fill="darkorange"
|
||||||
|
comp-op="multiply"
|
||||||
|
transform="skewX(50)"
|
||||||
|
allow-overlap="true"
|
||||||
|
/>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="100"
|
||||||
|
opacity=".5"
|
||||||
|
fill="darkred"
|
||||||
|
comp-op="color-burn"
|
||||||
|
transform="skewX(-50)"
|
||||||
|
allow-overlap="true"
|
||||||
|
/>
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="layer" srs="+init=epsg:4326">
|
||||||
|
<StyleName>ellipse</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
2.5,2.5
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<!-- points to frame data view -->
|
||||||
|
|
||||||
|
<Style name="frame">
|
||||||
|
<Rule>
|
||||||
|
<PointSymbolizer />
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="frame" srs="+init=epsg:4326">
|
||||||
|
<StyleName>frame</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
0,0
|
||||||
|
5,0
|
||||||
|
0,5
|
||||||
|
5,5
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
</Map>
|
66
tests/data/good_maps/marker_ellipse_transform2.xml
Normal file
66
tests/data/good_maps/marker_ellipse_transform2.xml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<Map srs="+init=epsg:4326" background-color="rgba(255,255,255,.5)">
|
||||||
|
|
||||||
|
<Style name="ellipse">
|
||||||
|
<Rule>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="240"
|
||||||
|
height="240"
|
||||||
|
fill="steelblue"
|
||||||
|
fill-opacity=".7"
|
||||||
|
stroke="yellow"
|
||||||
|
stroke-width="16"
|
||||||
|
stroke-opacity=".3"
|
||||||
|
/>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="100"
|
||||||
|
opacity=".5"
|
||||||
|
fill="darkorange"
|
||||||
|
comp-op="grain-extract"
|
||||||
|
transform="skewX(50)"
|
||||||
|
allow-overlap="true"
|
||||||
|
/>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
width="100"
|
||||||
|
opacity=".5"
|
||||||
|
fill="darkred"
|
||||||
|
comp-op="color-burn"
|
||||||
|
transform="skewX(-50)"
|
||||||
|
allow-overlap="true"
|
||||||
|
/>
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="layer" srs="+init=epsg:4326">
|
||||||
|
<StyleName>ellipse</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
2.5,2.5
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<!-- points to frame data view -->
|
||||||
|
|
||||||
|
<Style name="frame">
|
||||||
|
<Rule>
|
||||||
|
<PointSymbolizer />
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="frame" srs="+init=epsg:4326">
|
||||||
|
<StyleName>frame</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
0,0
|
||||||
|
5,0
|
||||||
|
0,5
|
||||||
|
5,5
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
</Map>
|
|
@ -3,7 +3,14 @@
|
||||||
<Style name="1">
|
<Style name="1">
|
||||||
<Rule>
|
<Rule>
|
||||||
<LineSymbolizer stroke-width=".2" stroke="grey"/>
|
<LineSymbolizer stroke-width=".2" stroke="grey"/>
|
||||||
<MarkersSymbolizer stroke="green" stroke-width="1.3" fill="yellow"/>
|
<MarkersSymbolizer
|
||||||
|
file="shape://arrow"
|
||||||
|
transform="scale(.8,.5)"
|
||||||
|
stroke="green"
|
||||||
|
stroke-width="1.3"
|
||||||
|
fill="yellow"
|
||||||
|
placement="line"
|
||||||
|
/>
|
||||||
</Rule>
|
</Rule>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
<Map background-color="white" srs="+init=epsg:4326" minimum-version="0.7.2">
|
<Map background-color="white" srs="+init=epsg:4326" minimum-version="0.7.2">
|
||||||
<Style name="1">
|
<Style name="1">
|
||||||
<Rule>
|
<Rule>
|
||||||
<LineSymbolizer stroke-width=".2" stroke="grey"/>
|
<LineSymbolizer offset="-2" stroke-width="2" stroke="red"/>
|
||||||
<MarkersSymbolizer file="../svg/crosshair16x16.svg"/>
|
<LineSymbolizer stroke-width="2" stroke="orange"/>
|
||||||
|
<LineSymbolizer offset="2" stroke-width="2" stroke="yellow"/>
|
||||||
|
<LineSymbolizer offset="4" stroke-width="2" stroke="green"/>
|
||||||
|
<MarkersSymbolizer
|
||||||
|
file="../svg/octocat.svg"
|
||||||
|
transform="scale(.13)"
|
||||||
|
placement="line"
|
||||||
|
/>
|
||||||
</Rule>
|
</Rule>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
|
52
tests/data/good_maps/text_halo_and_collision.xml
Normal file
52
tests/data/good_maps/text_halo_and_collision.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<Map srs="+init=epsg:4326" background-color="steelblue">
|
||||||
|
<!-- test case for https://github.com/mapnik/mapnik/issues/1354 -->
|
||||||
|
|
||||||
|
<Style name="labels">
|
||||||
|
<Rule>
|
||||||
|
<TextSymbolizer
|
||||||
|
face-name="DejaVu Sans Book"
|
||||||
|
size="22"
|
||||||
|
halo-radius="10"
|
||||||
|
placement="point"
|
||||||
|
allow-overlap="false">
|
||||||
|
'this text halos should not overlap vertically'
|
||||||
|
</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
<Layer name="points" srs="+init=epsg:4326">
|
||||||
|
<StyleName>labels</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
2,2
|
||||||
|
2,2.3
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<!-- points to frame data view -->
|
||||||
|
|
||||||
|
<Style name="frame">
|
||||||
|
<Rule>
|
||||||
|
<PointSymbolizer />
|
||||||
|
</Rule>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Layer name="frame" srs="+init=epsg:4326">
|
||||||
|
<StyleName>frame</StyleName>
|
||||||
|
<Datasource>
|
||||||
|
<Parameter name="type">csv</Parameter>
|
||||||
|
<Parameter name="inline">
|
||||||
|
x,y
|
||||||
|
0,0
|
||||||
|
5,0
|
||||||
|
0,5
|
||||||
|
5,5
|
||||||
|
</Parameter>
|
||||||
|
</Datasource>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
</Map>
|
17
tests/data/svg/octocat.svg
Normal file
17
tests/data/svg/octocat.svg
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.2 -1 379 334">
|
||||||
|
<path id="puddle" fill="#9CDAF1" d="m296.94 295.43c0 20.533-47.56 37.176-106.22 37.176-58.67 0-106.23-16.643-106.23-37.176s47.558-37.18 106.23-37.18c58.66 0 106.22 16.65 106.22 37.18z"/>
|
||||||
|
<g id="shadow-legs" fill="#7DBBE6">
|
||||||
|
<path d="m161.85 331.22v-26.5c0-3.422-.619-6.284-1.653-8.701 6.853 5.322 7.316 18.695 7.316 18.695v17.004c6.166.481 12.534.773 19.053.861l-.172-16.92c-.944-23.13-20.769-25.961-20.769-25.961-7.245-1.645-7.137 1.991-6.409 4.34-7.108-12.122-26.158-10.556-26.158-10.556-6.611 2.357-.475 6.607-.475 6.607 10.387 3.775 11.33 15.105 11.33 15.105v23.622c5.72.98 11.71 1.79 17.94 2.4z"/>
|
||||||
|
<path d="m245.4 283.48s-19.053-1.566-26.16 10.559c.728-2.35.839-5.989-6.408-4.343 0 0-19.824 2.832-20.768 25.961l-.174 16.946c6.509-.025 12.876-.254 19.054-.671v-17.219s.465-13.373 7.316-18.695c-1.034 2.417-1.653 5.278-1.653 8.701v26.775c6.214-.544 12.211-1.279 17.937-2.188v-24.113s.944-11.33 11.33-15.105c0-.01 6.13-4.26-.48-6.62z"/>
|
||||||
|
</g>
|
||||||
|
<path id="cat" d="m378.18 141.32l.28-1.389c-31.162-6.231-63.141-6.294-82.487-5.49 3.178-11.451 4.134-24.627 4.134-39.32 0-21.073-7.917-37.931-20.77-50.759 2.246-7.25 5.246-23.351-2.996-43.963 0 0-14.541-4.617-47.431 17.396-12.884-3.22-26.596-4.81-40.328-4.81-15.109 0-30.376 1.924-44.615 5.83-33.94-23.154-48.923-18.411-48.923-18.411-9.78 24.457-3.733 42.566-1.896 47.063-11.495 12.406-18.513 28.243-18.513 47.659 0 14.658 1.669 27.808 5.745 39.237-19.511-.71-50.323-.437-80.373 5.572l.276 1.389c30.231-6.046 61.237-6.256 80.629-5.522.898 2.366 1.899 4.661 3.021 6.879-19.177.618-51.922 3.062-83.303 11.915l.387 1.36c31.629-8.918 64.658-11.301 83.649-11.882 11.458 21.358 34.048 35.152 74.236 39.484-5.704 3.833-11.523 10.349-13.881 21.374-7.773 3.718-32.379 12.793-47.142-12.599 0 0-8.264-15.109-24.082-16.292 0 0-15.344-.235-1.059 9.562 0 0 10.267 4.838 17.351 23.019 0 0 9.241 31.01 53.835 21.061v32.032s-.943 11.33-11.33 15.105c0 0-6.137 4.249.475 6.606 0 0 28.792 2.361 28.792-21.238v-34.929s-1.142-13.852 5.663-18.667v57.371s-.47 13.688-7.551 18.881c0 0-4.723 8.494 5.663 6.137 0 0 19.824-2.832 20.769-25.961l.449-58.06h4.765l.453 58.06c.943 23.129 20.768 25.961 20.768 25.961 10.383 2.357 5.663-6.137 5.663-6.137-7.08-5.193-7.551-18.881-7.551-18.881v-56.876c6.801 5.296 5.663 18.171 5.663 18.171v34.929c0 23.6 28.793 21.238 28.793 21.238 6.606-2.357.474-6.606.474-6.606-10.386-3.775-11.33-15.105-11.33-15.105v-45.786c0-17.854-7.518-27.309-14.87-32.3 42.859-4.25 63.426-18.089 72.903-39.591 18.773.516 52.557 2.803 84.873 11.919l.384-1.36c-32.131-9.063-65.692-11.408-84.655-11.96.898-2.172 1.682-4.431 2.378-6.755 19.25-.80 51.38-.79 82.66 5.46z"/>
|
||||||
|
<path id="face" fill="#F4CBB2" d="m258.19 94.132c9.231 8.363 14.631 18.462 14.631 29.343 0 50.804-37.872 52.181-84.585 52.181-46.721 0-84.589-7.035-84.589-52.181 0-10.809 5.324-20.845 14.441-29.174 15.208-13.881 40.946-6.531 70.147-6.531 29.07-.004 54.72-7.429 69.95 6.357z"/>
|
||||||
|
<path id="eyes" fill="#FFF" d="m160.1 126.06 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z m94.43 0 c0 13.994-7.88 25.336-17.6 25.336-9.72 0-17.6-11.342-17.6-25.336 0-13.992 7.88-25.33 17.6-25.33 9.72.01 17.6 11.34 17.6 25.33z"/>
|
||||||
|
<g fill="#AD5C51">
|
||||||
|
<path id="pupils" d="m154.46 126.38 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z m94.42 0 c0 9.328-5.26 16.887-11.734 16.887s-11.733-7.559-11.733-16.887c0-9.331 5.255-16.894 11.733-16.894 6.47 0 11.73 7.56 11.73 16.89z"/>
|
||||||
|
<circle id="nose" cx="188.5" cy="148.56" r="4.401"/>
|
||||||
|
<path id="mouth" d="m178.23 159.69c-.26-.738.128-1.545.861-1.805.737-.26 1.546.128 1.805.861 1.134 3.198 4.167 5.346 7.551 5.346s6.417-2.147 7.551-5.346c.26-.738 1.067-1.121 1.805-.861s1.121 1.067.862 1.805c-1.529 4.324-5.639 7.229-10.218 7.229s-8.68-2.89-10.21-7.22z"/>
|
||||||
|
</g>
|
||||||
|
<path id="octo" fill="#C3E4D8" d="m80.641 179.82 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m8.5 4.72 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.193 6.14 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m4.72 7.08 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m5.188 6.61 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m7.09 5.66 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.91 3.78 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m9.87 0 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z m10.01 -1.64 c0 1.174-1.376 2.122-3.07 2.122-1.693 0-3.07-.948-3.07-2.122 0-1.175 1.377-2.127 3.07-2.127 1.694 0 3.07.95 3.07 2.13z"/>
|
||||||
|
<path id="drop" fill="#9CDAF1" d="m69.369 186.12l-3.066 10.683s-.8 3.861 2.84 4.546c3.8-.074 3.486-3.627 3.223-4.781z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
39
tests/python_tests/markers_complex_rendering_test.py
Normal file
39
tests/python_tests/markers_complex_rendering_test.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#coding=utf8
|
||||||
|
import os
|
||||||
|
import mapnik
|
||||||
|
from utilities import execution_path
|
||||||
|
from nose.tools import *
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
# All of the paths used are relative, if we run the tests
|
||||||
|
# from another directory we need to chdir()
|
||||||
|
os.chdir(execution_path('.'))
|
||||||
|
|
||||||
|
def test_marker_ellipse_render1():
|
||||||
|
m = mapnik.Map(256,256)
|
||||||
|
mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform.xml')
|
||||||
|
m.zoom_all()
|
||||||
|
im = mapnik.Image(m.width,m.height)
|
||||||
|
mapnik.render(m,im)
|
||||||
|
actual = '/tmp/mapnik-marker-ellipse-render1.png'
|
||||||
|
expected = 'images/support/mapnik-marker-ellipse-render1.png'
|
||||||
|
im.save(actual)
|
||||||
|
expected_im = mapnik.Image.open(expected)
|
||||||
|
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
|
||||||
|
|
||||||
|
#def test_marker_ellipse_render2():
|
||||||
|
# # currently crashes https://github.com/mapnik/mapnik/issues/1365
|
||||||
|
# m = mapnik.Map(256,256)
|
||||||
|
# mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform2.xml')
|
||||||
|
# m.zoom_all()
|
||||||
|
# im = mapnik.Image(m.width,m.height)
|
||||||
|
# mapnik.render(m,im)
|
||||||
|
# actual = '/tmp/mapnik-marker-ellipse-render2.png'
|
||||||
|
# expected = 'images/support/mapnik-marker-ellipse-render2.png'
|
||||||
|
# im.save(actual)
|
||||||
|
# expected_im = mapnik.Image.open(expected)
|
||||||
|
# eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
setup()
|
||||||
|
[eval(run)() for run in dir() if 'test_' in run]
|
|
@ -21,6 +21,15 @@ def test_line_symbolizer_init():
|
||||||
s = mapnik.LineSymbolizer()
|
s = mapnik.LineSymbolizer()
|
||||||
eq_(s.rasterizer, mapnik.line_rasterizer.FULL)
|
eq_(s.rasterizer, mapnik.line_rasterizer.FULL)
|
||||||
|
|
||||||
|
def test_line_symbolizer_stroke_reference():
|
||||||
|
l = mapnik.LineSymbolizer(mapnik.Color('green'),0.1)
|
||||||
|
l.stroke.add_dash(.1,.1)
|
||||||
|
l.stroke.add_dash(.1,.1)
|
||||||
|
eq_(l.stroke.get_dashes(), [(.1,.1),(.1,.1)])
|
||||||
|
eq_(l.stroke.color,mapnik.Color('green'))
|
||||||
|
eq_(l.stroke.opacity,1.0)
|
||||||
|
assert_almost_equal(l.stroke.width,0.1)
|
||||||
|
|
||||||
# ShieldSymbolizer initialization
|
# ShieldSymbolizer initialization
|
||||||
def test_shieldsymbolizer_init():
|
def test_shieldsymbolizer_init():
|
||||||
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
|
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
|
||||||
|
@ -126,7 +135,8 @@ def test_pointsymbolizer_init():
|
||||||
def test_markersymbolizer_init():
|
def test_markersymbolizer_init():
|
||||||
p = mapnik.MarkersSymbolizer()
|
p = mapnik.MarkersSymbolizer()
|
||||||
eq_(p.allow_overlap, False)
|
eq_(p.allow_overlap, False)
|
||||||
eq_(p.opacity,1)
|
eq_(p.opacity,None)
|
||||||
|
eq_(p.fill_opacity,None)
|
||||||
eq_(p.filename,'shape://ellipse')
|
eq_(p.filename,'shape://ellipse')
|
||||||
eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT)
|
eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT)
|
||||||
eq_(p.fill,None)
|
eq_(p.fill,None)
|
||||||
|
@ -154,9 +164,11 @@ def test_markersymbolizer_init():
|
||||||
p.fill = mapnik.Color('white')
|
p.fill = mapnik.Color('white')
|
||||||
p.allow_overlap = True
|
p.allow_overlap = True
|
||||||
p.opacity = 0.5
|
p.opacity = 0.5
|
||||||
|
p.fill_opacity = .01
|
||||||
|
|
||||||
eq_(p.allow_overlap, True)
|
eq_(p.allow_overlap, True)
|
||||||
eq_(p.opacity, 0.5)
|
eq_(p.opacity, 0.5)
|
||||||
|
eq_(p.fill_opacity, 0.5)
|
||||||
|
|
||||||
|
|
||||||
# PointSymbolizer missing image file
|
# PointSymbolizer missing image file
|
||||||
|
|
|
@ -20,13 +20,13 @@ def setup():
|
||||||
grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]}
|
grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]}
|
||||||
|
|
||||||
# now using svg rendering
|
# now using svg rendering
|
||||||
grid_correct_old2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!! ### ", " !!! ### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %%% ", " $$$ %%% ", " $$$ %%% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
grid_correct_old2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!! ### ", " !!! ### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %%% ", " $$$ %%% ", " $$$ %%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
||||||
|
|
||||||
# previous rendering using agg ellipse directly
|
# previous rendering using agg ellipse directly
|
||||||
grid_correct_new = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %% ", " $$$ %%% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]}
|
grid_correct_new = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
||||||
|
|
||||||
# newer rendering using svg
|
# newer rendering using svg
|
||||||
grid_correct_new2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
grid_correct_new2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]}
|
||||||
|
|
||||||
def resolve(grid,row,col):
|
def resolve(grid,row,col):
|
||||||
""" Resolve the attributes for a given pixel in a grid.
|
""" Resolve the attributes for a given pixel in a grid.
|
||||||
|
@ -108,7 +108,7 @@ def show_grids(name,g1,g2):
|
||||||
val += '\n\t%s\n\t%s' % (g1_file,g2_file)
|
val += '\n\t%s\n\t%s' % (g1_file,g2_file)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def test_render_grid():
|
def test_render_grid_old():
|
||||||
""" test old method """
|
""" test old method """
|
||||||
width,height = 256,256
|
width,height = 256,256
|
||||||
m = create_grid_map(width,height)
|
m = create_grid_map(width,height)
|
||||||
|
@ -117,7 +117,7 @@ def test_render_grid():
|
||||||
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
||||||
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
||||||
grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
|
grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name'])
|
||||||
eq_(grid,grid_correct_old2,show_grids('old',grid,grid_correct_old2))
|
eq_(grid,grid_correct_old2,show_grids('old-markers',grid,grid_correct_old2))
|
||||||
eq_(resolve(grid,0,0),None)
|
eq_(resolve(grid,0,0),None)
|
||||||
|
|
||||||
# check every pixel of the nw symbol
|
# check every pixel of the nw symbol
|
||||||
|
@ -128,7 +128,7 @@ def test_render_grid():
|
||||||
eq_(resolve(grid,23,10),expected)
|
eq_(resolve(grid,23,10),expected)
|
||||||
eq_(resolve(grid,23,11),expected)
|
eq_(resolve(grid,23,11),expected)
|
||||||
|
|
||||||
def test_render_grid2():
|
def test_render_grid_new():
|
||||||
""" test old against new"""
|
""" test old against new"""
|
||||||
width,height = 256,256
|
width,height = 256,256
|
||||||
m = create_grid_map(width,height)
|
m = create_grid_map(width,height)
|
||||||
|
@ -140,7 +140,7 @@ def test_render_grid2():
|
||||||
grid = mapnik.Grid(m.width,m.height,key='Name')
|
grid = mapnik.Grid(m.width,m.height,key='Name')
|
||||||
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
||||||
utf1 = grid.encode('utf',resolution=4)
|
utf1 = grid.encode('utf',resolution=4)
|
||||||
eq_(utf1,grid_correct_new2,show_grids('new',utf1,grid_correct_new2))
|
eq_(utf1,grid_correct_new2,show_grids('new-markers',utf1,grid_correct_new2))
|
||||||
|
|
||||||
# check a full view is the same as a full image
|
# check a full view is the same as a full image
|
||||||
grid_view = grid.view(0,0,width,height)
|
grid_view = grid.view(0,0,width,height)
|
||||||
|
@ -164,7 +164,7 @@ def test_render_grid2():
|
||||||
|
|
||||||
grid_feat_id = {'keys': ['', '3', '4', '2', '1'], 'data': {'1': {'Name': 'South East'}, '3': {'Name': u'North West'}, '2': {'Name': 'South West'}, '4': {'Name': 'North East'}}, 'grid': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' !! ## ', ' !!! ### ', ' !! ## ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' $$$ %% ', ' $$$ %%% ', ' $$ %% ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']}
|
grid_feat_id = {'keys': ['', '3', '4', '2', '1'], 'data': {'1': {'Name': 'South East'}, '3': {'Name': u'North West'}, '2': {'Name': 'South West'}, '4': {'Name': 'North East'}}, 'grid': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' !! ## ', ' !!! ### ', ' !! ## ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' $$$ %% ', ' $$$ %%% ', ' $$ %% ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']}
|
||||||
|
|
||||||
grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$$ %% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
||||||
|
|
||||||
def test_render_grid3():
|
def test_render_grid3():
|
||||||
""" test using feature id"""
|
""" test using feature id"""
|
||||||
|
@ -177,7 +177,7 @@ def test_render_grid3():
|
||||||
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
||||||
mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
|
mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
|
||||||
utf1 = grid.encode('utf',resolution=4)
|
utf1 = grid.encode('utf',resolution=4)
|
||||||
eq_(utf1,grid_feat_id2,show_grids('id',utf1,grid_feat_id2))
|
eq_(utf1,grid_feat_id2,show_grids('id-markers',utf1,grid_feat_id2))
|
||||||
# check a full view is the same as a full image
|
# check a full view is the same as a full image
|
||||||
grid_view = grid.view(0,0,width,height)
|
grid_view = grid.view(0,0,width,height)
|
||||||
# for kicks check at full res too
|
# for kicks check at full res too
|
||||||
|
@ -282,7 +282,7 @@ def test_line_rendering():
|
||||||
eq_(utf1,line_expected,show_grids('line',utf1,line_expected))
|
eq_(utf1,line_expected,show_grids('line',utf1,line_expected))
|
||||||
#open('test.json','w').write(json.dumps(grid.encode()))
|
#open('test.json','w').write(json.dumps(grid.encode()))
|
||||||
|
|
||||||
point_expected = {"keys": ["", "3", "4", "2", "1"], "data": {"1": {"Name": "South East"}, "3": {"Name": "North West"}, "2": {"Name": "South West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]}
|
point_expected = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]}
|
||||||
|
|
||||||
def test_point_symbolizer_grid():
|
def test_point_symbolizer_grid():
|
||||||
width,height = 256,256
|
width,height = 256,256
|
||||||
|
|
|
@ -155,8 +155,9 @@ int main (int argc,char** argv)
|
||||||
{
|
{
|
||||||
std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
|
std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
|
||||||
}
|
}
|
||||||
mapnik::image_32 im(w,h);
|
// 10 pixel buffer to avoid edge clipping of 100% svg's
|
||||||
agg::rendering_buffer buf(im.raw_data(), w, h, w * 4);
|
mapnik::image_32 im(w+10,h+10);
|
||||||
|
agg::rendering_buffer buf(im.raw_data(), im.width(), im.height(), im.width() * 4);
|
||||||
pixfmt pixf(buf);
|
pixfmt pixf(buf);
|
||||||
renderer_base renb(pixf);
|
renderer_base renb(pixf);
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ int main (int argc,char** argv)
|
||||||
// center the svg marker on '0,0'
|
// center the svg marker on '0,0'
|
||||||
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
|
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
|
||||||
// render the marker at the center of the marker box
|
// render the marker at the center of the marker box
|
||||||
mtx.translate(0.5 * w, 0.5 * h);
|
mtx.translate(0.5 * im.width(), 0.5 * im.height());
|
||||||
|
|
||||||
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage((*marker.get_vector_data())->source());
|
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage((*marker.get_vector_data())->source());
|
||||||
mapnik::svg::svg_path_adapter svg_path(stl_storage);
|
mapnik::svg::svg_path_adapter svg_path(stl_storage);
|
||||||
|
|
Loading…
Reference in a new issue