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.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
|
||||
|
|
|
@ -11,6 +11,10 @@ For a complete change history, see the git log.
|
|||
|
||||
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`,
|
||||
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;
|
||||
|
||||
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()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -196,6 +208,27 @@ void export_layer()
|
|||
"<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",
|
||||
&layer::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")
|
||||
.add_property("stroke",make_function
|
||||
(&line_symbolizer::get_stroke,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
return_value_policy<reference_existing_object>()),
|
||||
&line_symbolizer::set_stroke)
|
||||
.add_property("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> const& (Map::*layers_const)() const = &Map::layers;
|
||||
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)
|
||||
{
|
||||
|
@ -192,7 +192,6 @@ mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo)
|
|||
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)
|
||||
{
|
||||
if (box)
|
||||
|
@ -201,7 +200,7 @@ void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> >
|
|||
}
|
||||
else
|
||||
{
|
||||
m.maximum_extent().reset();
|
||||
m.reset_maximum_extent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,7 +561,7 @@ void export_map()
|
|||
)
|
||||
|
||||
.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,
|
||||
"The maximum extent of the map.\n"
|
||||
"\n"
|
||||
|
|
|
@ -86,13 +86,13 @@ struct markers_symbolizer_pickle_suite : boost::python::pickle_suite
|
|||
|
||||
};
|
||||
|
||||
|
||||
void export_markers_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
mapnik::enumeration_<mapnik::marker_placement_e>("marker_placement")
|
||||
.value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT)
|
||||
.value("INTERIOR_PLACEMENT",mapnik::MARKER_INTERIOR_PLACEMENT)
|
||||
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
|
||||
;
|
||||
|
||||
|
@ -115,7 +115,11 @@ void export_markers_symbolizer()
|
|||
.add_property("opacity",
|
||||
&markers_symbolizer::get_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",
|
||||
&markers_symbolizer::get_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_pycairo", &has_pycairo, "Get pycairo module status");
|
||||
|
||||
python_optional<mapnik::stroke>();
|
||||
python_optional<mapnik::color>();
|
||||
python_optional<mapnik::box2d<double> >();
|
||||
python_optional<mapnik::datasource::geometry_t>();
|
||||
python_optional<std::string>();
|
||||
python_optional<unsigned>();
|
||||
python_optional<double>();
|
||||
python_optional<float>();
|
||||
python_optional<bool>();
|
||||
python_optional<mapnik::text_transform_e>();
|
||||
register_ptr_to_python<mapnik::expression_ptr>();
|
||||
|
|
|
@ -36,52 +36,59 @@ int main( int argc, char **argv )
|
|||
using mapnik::datasource_cache;
|
||||
using mapnik::freetype_engine;
|
||||
|
||||
QCoreApplication::setOrganizationName("Mapnik");
|
||||
QCoreApplication::setOrganizationDomain("mapnik.org");
|
||||
QCoreApplication::setApplicationName("Viewer");
|
||||
|
||||
QSettings settings("viewer.ini",QSettings::IniFormat);
|
||||
|
||||
// register input plug-ins
|
||||
QString plugins_dir = settings.value("mapnik/plugins_dir",
|
||||
QVariant("/usr/local/lib/mapnik/input/")).toString();
|
||||
datasource_cache::instance()->register_datasources(plugins_dir.toStdString());
|
||||
// register fonts
|
||||
int count = settings.beginReadArray("mapnik/fonts");
|
||||
for (int index=0; index < count; ++index)
|
||||
try
|
||||
{
|
||||
settings.setArrayIndex(index);
|
||||
QString font_dir = settings.value("dir").toString();
|
||||
freetype_engine::register_fonts(font_dir.toStdString());
|
||||
}
|
||||
settings.endArray();
|
||||
QCoreApplication::setOrganizationName("Mapnik");
|
||||
QCoreApplication::setOrganizationDomain("mapnik.org");
|
||||
QCoreApplication::setApplicationName("Viewer");
|
||||
QSettings settings("viewer.ini",QSettings::IniFormat);
|
||||
|
||||
QApplication app( argc, argv );
|
||||
MainWindow window;
|
||||
window.show();
|
||||
if (argc > 1) window.open(argv[1]);
|
||||
if (argc >= 3)
|
||||
{
|
||||
QStringList list = QString(argv[2]).split(",");
|
||||
if (list.size()==4)
|
||||
// register input plug-ins
|
||||
QString plugins_dir = settings.value("mapnik/plugins_dir",
|
||||
QVariant("/usr/local/lib/mapnik/input/")).toString();
|
||||
datasource_cache::instance()->register_datasources(plugins_dir.toStdString());
|
||||
// register fonts
|
||||
int count = settings.beginReadArray("mapnik/fonts");
|
||||
for (int index=0; index < count; ++index)
|
||||
{
|
||||
settings.setArrayIndex(index);
|
||||
QString font_dir = settings.value("dir").toString();
|
||||
freetype_engine::register_fonts(font_dir.toStdString());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
QApplication app( argc, argv );
|
||||
MainWindow window;
|
||||
window.show();
|
||||
if (argc > 1) window.open(argv[1]);
|
||||
if (argc >= 3)
|
||||
{
|
||||
QStringList list = QString(argv[2]).split(",");
|
||||
if (list.size()==4)
|
||||
{
|
||||
bool ok;
|
||||
double x0 = list[0].toDouble(&ok);
|
||||
double y0 = list[1].toDouble(&ok);
|
||||
double x1 = list[2].toDouble(&ok);
|
||||
double y1 = list[3].toDouble(&ok);
|
||||
if (ok) window.set_default_extent(x0,y0,x1,y1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window.zoom_all();
|
||||
}
|
||||
if (argc == 4)
|
||||
{
|
||||
bool ok;
|
||||
double x0 = list[0].toDouble(&ok);
|
||||
double y0 = list[1].toDouble(&ok);
|
||||
double x1 = list[2].toDouble(&ok);
|
||||
double y1 = list[3].toDouble(&ok);
|
||||
if (ok) window.set_default_extent(x0,y0,x1,y1);
|
||||
double scaling_factor = QString(argv[3]).toDouble(&ok);
|
||||
if (ok) window.set_scaling_factor(scaling_factor);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
else
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
window.zoom_all();
|
||||
std::cerr << "Could not start viewer: '" << ex.what() << "'\n";
|
||||
return 1;
|
||||
}
|
||||
if (argc == 4)
|
||||
{
|
||||
bool ok;
|
||||
double scaling_factor = QString(argv[3]).toDouble(&ok);
|
||||
if (ok) window.set_scaling_factor(scaling_factor);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
|
|
65
deps/agg/include/agg_pixfmt_rgba.h
vendored
65
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)
|
||||
//
|
||||
// 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,
|
||||
unsigned sr, unsigned sg, unsigned sb,
|
||||
unsigned sa, unsigned cover)
|
||||
{
|
||||
if(cover < 255)
|
||||
if (cover < 255)
|
||||
{
|
||||
sr = (sr * cover + 255) >> 8;
|
||||
sg = (sg * cover + 255) >> 8;
|
||||
sb = (sb * cover + 255) >> 8;
|
||||
sa = (sa * cover + 255) >> 8;
|
||||
}
|
||||
if(sa)
|
||||
|
||||
if (sa)
|
||||
{
|
||||
calc_type d1a = base_mask - p[Order::A];
|
||||
calc_type s1a = base_mask - sa;
|
||||
|
@ -1042,15 +1058,15 @@ namespace agg
|
|||
long_type sbda = sb * 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 :
|
||||
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 :
|
||||
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 :
|
||||
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 sa, unsigned cover)
|
||||
{
|
||||
if (cover < 255)
|
||||
{
|
||||
sr = (sr * cover + 255) >> 8;
|
||||
sg = (sg * cover + 255) >> 8;
|
||||
sb = (sb * cover + 255) >> 8;
|
||||
sa = (sa * cover + 255) >> 8;
|
||||
}
|
||||
if (sa > 0)
|
||||
{
|
||||
calc_type da = p[Order::A];
|
||||
int dr = p[Order::R] - sr + 128;
|
||||
int dg = p[Order::G] - sg + 128;
|
||||
int db = p[Order::B] - sb + 128;
|
||||
calc_type da = (p[Order::A] * sa + 255) >> 8;
|
||||
|
||||
p[Order::R] = dr < 0 ? 0 : (dr > 255 ? 255 : dr);
|
||||
p[Order::G] = dg < 0 ? 0 : (dg > 255 ? 255 : dg);
|
||||
p[Order::B] = db < 0 ? 0 : (db > 255 ? 255 : db);
|
||||
p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
|
||||
int dr = p[Order::R] - sr + 128;
|
||||
int dg = p[Order::G] - sg + 128;
|
||||
int db = p[Order::B] - sb + 128;
|
||||
|
||||
dr = dr < 0 ? 0 : (dr > 255 ? 255 : dr);
|
||||
dg = dg < 0 ? 0 : (dg > 255 ? 255 : dg);
|
||||
db = db < 0 ? 0 : (db > 255 ? 255 : db);
|
||||
|
||||
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);
|
||||
void debug_draw_box(box2d<double> const& extent,
|
||||
double x, double y, double angle = 0.0);
|
||||
void draw_geo_extent(box2d<double> const& extent,mapnik::color const& color);
|
||||
|
||||
private:
|
||||
buffer_type & pixmap_;
|
||||
|
|
|
@ -249,7 +249,7 @@ public:
|
|||
|
||||
struct directive_collector : public boost::static_visitor<>
|
||||
{
|
||||
directive_collector(double * filter_factor)
|
||||
directive_collector(double & filter_factor)
|
||||
: filter_factor_(filter_factor) {}
|
||||
|
||||
template <typename T>
|
||||
|
@ -257,10 +257,10 @@ struct directive_collector : public boost::static_visitor<>
|
|||
|
||||
void operator () (raster_symbolizer const& sym)
|
||||
{
|
||||
*filter_factor_ = sym.calculate_filter_factor();
|
||||
filter_factor_ = sym.calculate_filter_factor();
|
||||
}
|
||||
private:
|
||||
double * filter_factor_;
|
||||
double & filter_factor_;
|
||||
};
|
||||
|
||||
} // namespace mapnik
|
||||
|
|
|
@ -110,7 +110,7 @@ operator << (std::basic_ostream<charT,traits>& out,
|
|||
std::basic_ostringstream<charT,traits> s;
|
||||
s.copyfmt(out);
|
||||
s.width(0);
|
||||
s << "box2d(" << std::setprecision(16)
|
||||
s << "box2d(" << std::fixed << std::setprecision(16)
|
||||
<< e.minx() << ',' << e.miny() << ','
|
||||
<< e.maxx() << ',' << e.maxy() << ')';
|
||||
out << s.str();
|
||||
|
|
|
@ -52,34 +52,25 @@ struct MAPNIK_DECL coord_transform
|
|||
: t_(0),
|
||||
geom_(geom),
|
||||
prj_trans_(0) {}
|
||||
|
||||
|
||||
void set_proj_trans(proj_transform const& prj_trans)
|
||||
{
|
||||
prj_trans_ = &prj_trans;
|
||||
}
|
||||
|
||||
|
||||
void set_trans(Transform const& t)
|
||||
{
|
||||
t_ = &t;
|
||||
}
|
||||
|
||||
|
||||
unsigned vertex(double *x, double *y) const
|
||||
{
|
||||
unsigned command = SEG_MOVETO;
|
||||
bool ok = false;
|
||||
bool skipped_points = false;
|
||||
double z = 0;
|
||||
while (!ok && command != SEG_END)
|
||||
unsigned command = geom_.vertex(x, y);
|
||||
if ( command != 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;
|
||||
double z = 0;
|
||||
if (!prj_trans_->backward(*x, *y, z))
|
||||
return SEG_END;
|
||||
}
|
||||
t_->forward(x, y);
|
||||
return command;
|
||||
|
|
|
@ -241,6 +241,8 @@ double path_length(PathType & path)
|
|||
return length;
|
||||
}
|
||||
|
||||
namespace label {
|
||||
|
||||
template <typename PathType>
|
||||
bool middle_point(PathType & path, double & x, double & y)
|
||||
{
|
||||
|
@ -271,8 +273,6 @@ bool middle_point(PathType & path, double & x, double & y)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace label {
|
||||
|
||||
template <typename PathType>
|
||||
bool centroid(PathType & path, double & x, double & y)
|
||||
{
|
||||
|
|
|
@ -118,9 +118,10 @@ private:
|
|||
CoordTransform t_;
|
||||
freetype_engine font_engine_;
|
||||
face_manager<freetype_engine> font_manager_;
|
||||
label_collision_detector4 detector_;
|
||||
boost::shared_ptr<label_collision_detector4> detector_;
|
||||
boost::scoped_ptr<grid_rasterizer> ras_ptr;
|
||||
box2d<double> query_extent_;
|
||||
void setup(Map const& m);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ namespace mapnik
|
|||
class MAPNIK_DECL layer
|
||||
{
|
||||
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& operator=(layer const& l);
|
||||
bool operator==(layer const& other) const;
|
||||
|
@ -57,7 +59,7 @@ public:
|
|||
* @return the name of the layer.
|
||||
*/
|
||||
|
||||
const std::string& name() const;
|
||||
std::string const& name() const;
|
||||
|
||||
/*!
|
||||
* @brief Set the SRS of the layer.
|
||||
|
@ -188,6 +190,11 @@ public:
|
|||
*/
|
||||
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();
|
||||
private:
|
||||
void swap(const layer& other);
|
||||
|
@ -204,6 +211,8 @@ private:
|
|||
std::string group_by_;
|
||||
std::vector<std::string> styles_;
|
||||
datasource_ptr ds_;
|
||||
int buffer_size_;
|
||||
boost::optional<box2d<double> > maximum_extent_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -332,15 +332,13 @@ public:
|
|||
/*! \brief Set the map 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>
|
||||
*/
|
||||
boost::optional<box2d<double> > const& maximum_extent() const;
|
||||
|
||||
/*! \brief Get the non-const map maximum extent as box2d<double>
|
||||
*/
|
||||
boost::optional<box2d<double> > & maximum_extent();
|
||||
void reset_maximum_extent();
|
||||
|
||||
/*! \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 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;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class marker
|
||||
class marker: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
marker()
|
||||
|
@ -65,20 +65,21 @@ public:
|
|||
(*bitmap_data_)->set(0xff000000);
|
||||
}
|
||||
|
||||
marker(const boost::optional<mapnik::image_ptr> &data)
|
||||
marker(boost::optional<mapnik::image_ptr> const& data)
|
||||
: bitmap_data_(data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
marker(const boost::optional<mapnik::path_ptr> &data)
|
||||
marker(boost::optional<mapnik::svg_path_ptr> const& data)
|
||||
: vector_data_(data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
marker(const marker& rhs)
|
||||
: bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_)
|
||||
marker(marker const& rhs)
|
||||
: bitmap_data_(rhs.bitmap_data_),
|
||||
vector_data_(rhs.vector_data_)
|
||||
{}
|
||||
|
||||
box2d<double> bounding_box() const
|
||||
|
@ -128,17 +129,14 @@ public:
|
|||
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_;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
marker& operator=(const marker&);
|
||||
|
||||
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/expression_evaluator.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
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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>
|
||||
bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym)
|
||||
{
|
||||
boost::optional<stroke> const& strk = sym.get_stroke();
|
||||
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)
|
||||
{
|
||||
mapnik::svg::path_attributes attr = src[i];
|
||||
|
||||
if (strk && attr.stroke_flag)
|
||||
success = true;
|
||||
dst.push_back(src[i]);
|
||||
mapnik::svg::path_attributes & attr = dst.last();
|
||||
if (attr.stroke_flag)
|
||||
{
|
||||
attr.stroke_width = strk->get_width();
|
||||
color const& s_color = strk->get_color();
|
||||
attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0,
|
||||
s_color.blue()/255.0,(s_color.alpha()*strk->get_opacity())/255.0);
|
||||
// TODO - stroke attributes need to be boost::optional
|
||||
// for this to work properly
|
||||
if (strk)
|
||||
{
|
||||
attr.stroke_width = strk->get_width();
|
||||
color const& s_color = strk->get_color();
|
||||
attr.stroke_color = agg::rgba(s_color.red()/255.0,
|
||||
s_color.green()/255.0,
|
||||
s_color.blue()/255.0,
|
||||
s_color.alpha()/255.0);
|
||||
}
|
||||
if (opacity)
|
||||
{
|
||||
attr.stroke_opacity = *opacity;
|
||||
}
|
||||
else if (strk)
|
||||
{
|
||||
attr.stroke_opacity = strk->get_opacity();
|
||||
}
|
||||
}
|
||||
if (fill && attr.fill_flag)
|
||||
if (attr.fill_flag)
|
||||
{
|
||||
color const& f_color = *fill;
|
||||
attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0,
|
||||
f_color.blue()/255.0,(f_color.alpha()*sym.get_opacity())/255.0);
|
||||
if (fill)
|
||||
{
|
||||
color const& f_color = *fill;
|
||||
attr.fill_color = agg::rgba(f_color.red()/255.0,
|
||||
f_color.green()/255.0,
|
||||
f_color.blue()/255.0,
|
||||
f_color.alpha()/255.0);
|
||||
}
|
||||
if (opacity)
|
||||
{
|
||||
attr.fill_opacity = *opacity;
|
||||
}
|
||||
else if (fill_opacity)
|
||||
{
|
||||
attr.fill_opacity = *fill_opacity;
|
||||
}
|
||||
}
|
||||
dst.push_back(attr);
|
||||
}
|
||||
return true;
|
||||
return success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,26 @@
|
|||
#define MAPNIK_MARKERS_PLACEMENT_HPP
|
||||
|
||||
// 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>
|
||||
|
||||
// boost
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
// 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_smooth_poly1.h"
|
||||
|
||||
// stl
|
||||
#include <cmath>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
@ -47,12 +60,40 @@ public:
|
|||
* converted to a positive value with similar magnitude, but
|
||||
* 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.
|
||||
* \note Returns the same list of markers only works when they were NOT added
|
||||
* 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.
|
||||
* Each time this function is called a new point is returned.
|
||||
* \param x Return value for x position
|
||||
|
@ -61,7 +102,115 @@ public:
|
|||
* \param add_to_detector Add selected position to detector
|
||||
* \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:
|
||||
Locator &locator_;
|
||||
box2d<double> size_;
|
||||
|
@ -82,11 +231,69 @@ private:
|
|||
unsigned marker_nr_;
|
||||
|
||||
/** 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. */
|
||||
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. */
|
||||
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
|
||||
enum marker_placement_enum {
|
||||
MARKER_POINT_PLACEMENT,
|
||||
MARKER_INTERIOR_PLACEMENT,
|
||||
MARKER_LINE_PLACEMENT,
|
||||
marker_placement_enum_MAX
|
||||
};
|
||||
|
@ -65,8 +66,12 @@ public:
|
|||
double get_spacing() const;
|
||||
void set_max_error(double max_error);
|
||||
double get_max_error() const;
|
||||
void set_opacity(float opacity);
|
||||
boost::optional<float> get_opacity() const;
|
||||
void set_fill(color const& fill);
|
||||
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);
|
||||
boost::optional<stroke> get_stroke() const;
|
||||
void set_marker_placement(marker_placement_e marker_p);
|
||||
|
@ -79,6 +84,8 @@ private:
|
|||
double spacing_;
|
||||
double max_error_;
|
||||
boost::optional<color> fill_;
|
||||
boost::optional<float> fill_opacity_;
|
||||
boost::optional<float> opacity_;
|
||||
boost::optional<stroke> stroke_;
|
||||
marker_placement_e marker_p_;
|
||||
};
|
||||
|
|
|
@ -66,10 +66,10 @@ public:
|
|||
{
|
||||
throw std::runtime_error("end_path : The path was not begun");
|
||||
}
|
||||
path_attributes attr = cur_attr();
|
||||
unsigned idx = attributes_[attributes_.size() - 1].index;
|
||||
path_attributes& attr = attributes_[attributes_.size() - 1];
|
||||
unsigned idx = attr.index;
|
||||
attr = cur_attr();
|
||||
attr.index = idx;
|
||||
attributes_[attributes_.size() - 1] = attr;
|
||||
}
|
||||
|
||||
void move_to(double x, double y, bool rel=false) // M, m
|
||||
|
|
|
@ -102,14 +102,14 @@ private:
|
|||
template <typename VertexSource, typename AttributeSource, typename ScanlineRenderer, typename PixelFormat>
|
||||
class svg_renderer : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef agg::conv_curve<VertexSource> curved_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_type> curved_trans_type;
|
||||
typedef agg::conv_contour<curved_trans_type> curved_trans_contour_type;
|
||||
typedef agg::renderer_base<PixelFormat> renderer_base;
|
||||
|
||||
public:
|
||||
|
||||
svg_renderer(VertexSource & source, AttributeSource const& attributes)
|
||||
: source_(source),
|
||||
curved_(source_),
|
||||
|
|
|
@ -21,12 +21,14 @@
|
|||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/agg_rasterizer.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_cache.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
|
@ -36,6 +38,7 @@
|
|||
#include <mapnik/svg/svg_converter.hpp>
|
||||
#include <mapnik/svg/svg_renderer.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
|
||||
#include <mapnik/image_compositing.hpp>
|
||||
#include <mapnik/image_filter.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();
|
||||
}
|
||||
|
||||
|
@ -166,7 +173,6 @@ template <typename T>
|
|||
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();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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>
|
||||
|
@ -362,15 +385,18 @@ void agg_renderer<T>::render_marker(pixel_position const& pos, marker const& mar
|
|||
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::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);
|
||||
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);
|
||||
}
|
||||
|
||||
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 void agg_renderer<image_32>::debug_draw_box<agg::rendering_buffer>(
|
||||
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> roof(new geometry_type(Polygon));
|
||||
std::deque<segment_t> face_segments;
|
||||
double x0(0);
|
||||
double y0(0);
|
||||
|
||||
double x0 = 0;
|
||||
double y0 = 0;
|
||||
double x,y;
|
||||
geom.rewind(0);
|
||||
unsigned cm = geom.vertex(&x0,&y0);
|
||||
for (unsigned j=1;j<geom.size();++j)
|
||||
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||
cm = geom.vertex(&x, &y))
|
||||
{
|
||||
double x(0);
|
||||
double y(0);
|
||||
cm = geom.vertex(&x,&y);
|
||||
if (cm == SEG_MOVETO)
|
||||
{
|
||||
frame->move_to(x,y);
|
||||
}
|
||||
else if (cm == SEG_LINETO)
|
||||
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||
{
|
||||
frame->line_to(x,y);
|
||||
face_segments.push_back(segment_t(x0,y0,x,y));
|
||||
}
|
||||
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
}
|
||||
|
||||
std::sort(face_segments.begin(),face_segments.end(), y_order);
|
||||
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));
|
||||
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())));
|
||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||
ras_ptr->reset();
|
||||
|
||||
//
|
||||
frame->move_to(itr->get<0>(),itr->get<1>());
|
||||
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
frame->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);
|
||||
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);
|
||||
ren.color(agg::rgba8(r, g, b, int(a * sym.get_opacity())));
|
||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
|||
{
|
||||
typedef agg::rgba8 color;
|
||||
typedef agg::order_rgba order;
|
||||
typedef agg::pixel32_type pixel_type;
|
||||
typedef agg::pixel32_type pixel_type;
|
||||
typedef agg::comp_op_adaptor_rgba_pre<color, order> blender_type;
|
||||
typedef agg::pattern_filter_bilinear_rgba8 pattern_filter_type;
|
||||
typedef agg::line_image_pattern<pattern_filter_type> pattern_type;
|
||||
|
@ -64,7 +64,7 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
|||
typedef agg::renderer_base<pixfmt_type> renderer_base;
|
||||
typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type;
|
||||
typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
|
||||
|
||||
|
||||
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
||||
|
||||
boost::optional<marker_ptr> mark = marker_cache::instance()->find(filename,true);
|
||||
|
@ -81,8 +81,6 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
|||
|
||||
if (!pat) return;
|
||||
|
||||
box2d<double> ext = query_extent_ * 1.0;
|
||||
|
||||
agg::rendering_buffer buf(current_buffer_->raw_data(),width_,height_, width_ * 4);
|
||||
pixfmt_type pixf(buf);
|
||||
pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
|
||||
|
@ -91,26 +89,40 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
|||
|
||||
pattern_source source(*(*pat));
|
||||
pattern_type pattern (filter,source);
|
||||
renderer_type ren(ren_base, pattern);
|
||||
renderer_type ren(ren_base, pattern);
|
||||
rasterizer_type ras(ren);
|
||||
|
||||
|
||||
agg::trans_affine tr;
|
||||
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;
|
||||
vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer,
|
||||
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)
|
||||
converter.set<transform_tag>(); //always transform
|
||||
converter.set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
||||
|
||||
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
if (geom.size() > 1)
|
||||
{
|
||||
converter.apply(geom);
|
||||
converter.apply(geom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
|
||||
namespace mapnik {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void agg_renderer<T>::process(line_symbolizer const& sym,
|
||||
mapnik::feature_impl & feature,
|
||||
|
@ -60,7 +59,7 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
|||
unsigned g=col.green();
|
||||
unsigned b=col.blue();
|
||||
unsigned a=col.alpha();
|
||||
|
||||
|
||||
ras_ptr->reset();
|
||||
set_gamma_method(stroke_, ras_ptr);
|
||||
|
||||
|
@ -76,11 +75,28 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
|||
pixfmt_comp_type pixf(buf);
|
||||
pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
|
||||
renderer_base renb(pixf);
|
||||
|
||||
|
||||
agg::trans_affine tr;
|
||||
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)
|
||||
{
|
||||
|
@ -94,11 +110,12 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
|
|||
rasterizer_type ras(ren);
|
||||
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,
|
||||
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)
|
||||
converter.set<transform_tag>(); // always transform
|
||||
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
|
||||
{
|
||||
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,
|
||||
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)
|
||||
converter.set<transform_tag>(); // always transform
|
||||
|
|
|
@ -21,23 +21,27 @@
|
|||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/agg_rasterizer.hpp>
|
||||
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/vertex_converters.hpp>
|
||||
#include <mapnik/marker_helpers.hpp>
|
||||
#include <mapnik/marker.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
#include <mapnik/marker_helpers.hpp>
|
||||
#include <mapnik/svg/svg_renderer.hpp>
|
||||
#include <mapnik/svg/svg_storage.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>
|
||||
|
||||
// agg
|
||||
#include "agg_basics.h"
|
||||
#include "agg_renderer_base.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
|
@ -45,234 +49,13 @@
|
|||
#include "agg_path_storage.h"
|
||||
#include "agg_conv_clip_polyline.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
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
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>
|
||||
void agg_renderer<T>::process(markers_symbolizer const& sym,
|
||||
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::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;
|
||||
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);
|
||||
|
||||
|
@ -297,67 +79,124 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
{
|
||||
ras_ptr->reset();
|
||||
ras_ptr->gamma(agg::gamma_power());
|
||||
|
||||
agg::trans_affine geom_tr;
|
||||
evaluate_transform(geom_tr, feature, sym.get_transform());
|
||||
|
||||
box2d<double> const& bbox = (*mark)->bounding_box();
|
||||
agg::trans_affine tr;
|
||||
setup_label_transform(tr, bbox, feature, sym);
|
||||
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;
|
||||
tr *= agg::trans_affine_scaling(scale_factor_);
|
||||
|
||||
if ((*mark)->is_vector())
|
||||
{
|
||||
using namespace mapnik::svg;
|
||||
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
|
||||
|
||||
|
||||
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 agg::renderer_scanline_aa_solid<renderer_base> renderer_type;
|
||||
typedef agg::pod_bvector<path_attributes> svg_attribute_type;
|
||||
typedef svg_renderer<svg_path_adapter,
|
||||
agg::pod_bvector<path_attributes>,
|
||||
svg_attribute_type,
|
||||
renderer_type,
|
||||
agg::pixfmt_rgba32 > svg_renderer_type;
|
||||
typedef vector_markers_rasterizer_dispatch<buffer_type, svg_renderer_type, rasterizer, detector_type> dispatch_type;
|
||||
pixfmt_comp_type > svg_renderer_type;
|
||||
typedef vector_markers_rasterizer_dispatch<buffer_type,
|
||||
svg_renderer_type,
|
||||
rasterizer,
|
||||
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();
|
||||
|
||||
|
||||
svg_renderer_type svg_renderer(svg_path, result ? attributes : (*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_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);
|
||||
|
||||
if (sym.clip()) converter.template set<clip_line_tag>(); //optional clip (default: true)
|
||||
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())
|
||||
// special case for simple ellipse markers
|
||||
// to allow for full control over rx/ry dimensions
|
||||
if (filename == "shape://ellipse"
|
||||
&& (width_expr || height_expr))
|
||||
{
|
||||
converter.apply(geom);
|
||||
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,
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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();
|
||||
typedef raster_markers_rasterizer_dispatch<buffer_type,rasterizer, detector_type> dispatch_type;
|
||||
dispatch_type rasterizer_dispatch(*current_buffer_,*ras_ptr, **marker,
|
||||
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_* 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
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
|
||||
|
|
|
@ -23,19 +23,16 @@
|
|||
// mapnik
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/agg_rasterizer.hpp>
|
||||
#include <mapnik/geom_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_cache.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
|
||||
// agg
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
// stl
|
||||
#include <string>
|
||||
|
@ -89,7 +86,6 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
|
|||
prj_trans.backward(x,y,z);
|
||||
t_.forward(&x,&y);
|
||||
label_ext.re_center(x,y);
|
||||
|
||||
if (sym.get_allow_overlap() ||
|
||||
detector_->has_placement(label_ext))
|
||||
{
|
||||
|
@ -106,8 +102,8 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
|
|||
|
||||
if (!sym.get_ignore_placement())
|
||||
detector_->insert(label_ext);
|
||||
metawriter_with_properties writer = sym.get_metawriter();
|
||||
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
|
||||
//metawriter_with_properties writer = sym.get_metawriter();
|
||||
//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;
|
||||
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;
|
||||
vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
|
||||
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)
|
||||
converter.set<transform_tag>(); //always transform
|
||||
|
|
|
@ -48,15 +48,13 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
|
|||
ras_ptr->reset();
|
||||
set_gamma_method(sym,ras_ptr);
|
||||
|
||||
box2d<double> inflated_extent = query_extent_ * 1.0;
|
||||
|
||||
agg::trans_affine tr;
|
||||
evaluate_transform(tr, feature, sym.get_transform());
|
||||
|
||||
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
|
||||
vertex_converter<box2d<double>, rasterizer, polygon_symbolizer,
|
||||
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)
|
||||
converter.set<transform_tag>(); //always transform
|
||||
|
@ -72,7 +70,7 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
|
|||
}
|
||||
|
||||
agg::rendering_buffer buf(current_buffer_->raw_data(),width_,height_, width_ * 4);
|
||||
|
||||
|
||||
color const& fill = sym.get_fill();
|
||||
unsigned r=fill.red();
|
||||
unsigned g=fill.green();
|
||||
|
|
|
@ -171,7 +171,6 @@ source = Split(
|
|||
json/feature_grammar.cpp
|
||||
json/feature_collection_parser.cpp
|
||||
json/geojson_generator.cpp
|
||||
markers_placement.cpp
|
||||
formatting/base.cpp
|
||||
formatting/expression.cpp
|
||||
formatting/list.cpp
|
||||
|
|
|
@ -497,7 +497,6 @@ public:
|
|||
}
|
||||
else if (cm == SEG_CLOSE)
|
||||
{
|
||||
line_to(x, y);
|
||||
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> roof(new geometry_type(Polygon));
|
||||
std::deque<segment_t> face_segments;
|
||||
double x0(0);
|
||||
double y0(0);
|
||||
|
||||
double x0 = 0;
|
||||
double y0 = 0;
|
||||
double x, y;
|
||||
geom.rewind(0);
|
||||
unsigned cm = geom.vertex(&x0, &y0);
|
||||
|
||||
for (unsigned j = 1; j < geom.size(); ++j)
|
||||
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
||||
cm = geom.vertex(&x, &y))
|
||||
{
|
||||
double x=0;
|
||||
double y=0;
|
||||
|
||||
cm = geom.vertex(&x,&y);
|
||||
|
||||
if (cm == SEG_MOVETO)
|
||||
{
|
||||
frame->move_to(x,y);
|
||||
}
|
||||
else if (cm == SEG_LINETO)
|
||||
else if (cm == SEG_LINETO || cm == SEG_CLOSE)
|
||||
{
|
||||
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;
|
||||
y0 = y;
|
||||
}
|
||||
|
||||
std::sort(face_segments.begin(), face_segments.end(), y_order);
|
||||
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));
|
||||
|
||||
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>() + height);
|
||||
|
@ -935,20 +923,18 @@ void cairo_renderer_base::process(building_symbolizer const& sym,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
frame->move_to(x, y + height);
|
||||
roof->move_to(x, y + height);
|
||||
frame->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);
|
||||
roof->line_to(x, y + height);
|
||||
frame->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());
|
||||
|
||||
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,
|
||||
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
||||
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
|
||||
|
||||
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
||||
converter.set<affine_transform_tag>(); // optional affine transform
|
||||
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;
|
||||
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;
|
||||
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
|
||||
for(unsigned i = 0; i < attributes_.size(); ++i)
|
||||
|
@ -1411,7 +1404,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
|
||||
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();
|
||||
double x1 = bbox.minx();
|
||||
double y1 = bbox.miny();
|
||||
|
@ -1443,7 +1436,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
if (sym.get_allow_overlap() ||
|
||||
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())
|
||||
detector_.insert(extent);
|
||||
|
@ -1462,7 +1455,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
while (placement.get_point(x, y, angle))
|
||||
{
|
||||
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();
|
||||
|
|
|
@ -102,35 +102,35 @@ struct feature_style_processor<Processor>::symbol_dispatch : public boost::stati
|
|||
: output_(output),
|
||||
f_(f),
|
||||
prj_trans_(prj_trans) {}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void operator () (T const& sym) const
|
||||
{
|
||||
process_impl<has_process<Processor,T>::value>::process(output_,sym,f_,prj_trans_);
|
||||
}
|
||||
|
||||
|
||||
Processor & output_;
|
||||
mapnik::feature_impl & f_;
|
||||
proj_transform const& prj_trans_;
|
||||
};
|
||||
|
||||
typedef char (&no_tag)[1];
|
||||
typedef char (&yes_tag)[2];
|
||||
typedef char (&no_tag)[1];
|
||||
typedef char (&yes_tag)[2];
|
||||
|
||||
template <typename T0, typename T1, void (T0::*)(T1 const&, mapnik::feature_impl &, proj_transform const&) >
|
||||
struct process_memfun_helper {};
|
||||
|
||||
template <typename T0, typename T1> no_tag has_process_helper(...);
|
||||
struct process_memfun_helper {};
|
||||
|
||||
template <typename T0, typename T1> no_tag has_process_helper(...);
|
||||
template <typename T0, typename T1> yes_tag has_process_helper(process_memfun_helper<T0, T1, &T0::process>* p);
|
||||
|
||||
template<typename T0,typename T1>
|
||||
|
||||
template<typename T0,typename T1>
|
||||
struct has_process
|
||||
{
|
||||
{
|
||||
typedef typename T0::processor_impl_type processor_impl_type;
|
||||
BOOST_STATIC_CONSTANT(bool
|
||||
, value = sizeof(has_process_helper<processor_impl_type,T1>(0)) == sizeof(yes_tag)
|
||||
);
|
||||
};
|
||||
BOOST_STATIC_CONSTANT(bool
|
||||
, value = sizeof(has_process_helper<processor_impl_type,T1>(0)) == sizeof(yes_tag)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
template <typename Processor>
|
||||
|
@ -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
|
||||
// which is used as a bbox for clipping geometries
|
||||
box2d<double> query_ext = m_.get_current_extent(); // unbuffered
|
||||
if (maximum_extent) {
|
||||
if (maximum_extent)
|
||||
{
|
||||
query_ext.clip(*maximum_extent);
|
||||
}
|
||||
|
||||
box2d<double> layer_ext2 = lay.envelope();
|
||||
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());
|
||||
std::vector<feature_type_style*> active_styles;
|
||||
attribute_collector collector(names);
|
||||
double filt_factor = 1;
|
||||
directive_collector d_collector(&filt_factor);
|
||||
double filt_factor = 1.0;
|
||||
directive_collector d_collector(filt_factor);
|
||||
|
||||
// iterate through all named styles collecting active styles and attribute names
|
||||
BOOST_FOREACH(std::string const& style_name, style_names)
|
||||
|
@ -520,7 +522,7 @@ void feature_style_processor<Processor>::render_style(
|
|||
{
|
||||
|
||||
p.start_style_processing(*style);
|
||||
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
std::ostringstream s1;
|
||||
s1 << "rendering style for layer: '" << lay.name()
|
||||
|
@ -662,4 +664,3 @@ template class feature_style_processor<grid_renderer<grid> >;
|
|||
template class feature_style_processor<agg_renderer<image_32> >;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,14 +21,15 @@
|
|||
*****************************************************************************/
|
||||
|
||||
// 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_renderer.hpp>
|
||||
#include <mapnik/grid/grid_pixfmt.hpp>
|
||||
#include <mapnik/grid/grid_pixel.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_cache.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()),
|
||||
height_(pixmap_.height()),
|
||||
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),
|
||||
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)
|
||||
{
|
||||
setup(m);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void grid_renderer<T>::setup(Map const& m)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(grid_renderer) << "grid_renderer: Scale=" << m.scale();
|
||||
// nothing to do for grids yet on setup
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
detector_.clear();
|
||||
detector_->clear();
|
||||
}
|
||||
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>
|
||||
|
@ -144,21 +170,27 @@ void grid_renderer<T>::render_marker(mapnik::feature_impl & feature, unsigned in
|
|||
else
|
||||
{
|
||||
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,
|
||||
boost::math::iround(pos.x),
|
||||
boost::math::iround(pos.y));
|
||||
boost::math::iround(pos.x - cx),
|
||||
boost::math::iround(pos.y - cy));
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO - remove support for step != or add support for agg scaling with opacity
|
||||
double ratio = (1.0/step);
|
||||
image_data_32 target(ratio * data.width(), ratio * data.height());
|
||||
mapnik::scale_image_agg<image_data_32>(target,data, SCALING_NEAR,
|
||||
scale_factor_, 0.0, 0.0, 1.0, ratio);
|
||||
pixmap_.set_rectangle(feature.id(), target,
|
||||
boost::math::iround(pos.x),
|
||||
boost::math::iround(pos.y));
|
||||
boost::math::iround(pos.x - cx),
|
||||
boost::math::iround(pos.y - cy));
|
||||
}
|
||||
}
|
||||
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
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/grid/grid_rasterizer.hpp>
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
#include <mapnik/grid/grid_pixfmt.hpp>
|
||||
#include <mapnik/grid/grid_pixel.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_cache.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_storage.hpp>
|
||||
#include <mapnik/svg/svg_path_adapter.hpp>
|
||||
#include <mapnik/svg/svg_path_attributes.hpp>
|
||||
#include <mapnik/markers_placement.hpp>
|
||||
#include <mapnik/markers_symbolizer.hpp>
|
||||
|
||||
// agg
|
||||
#include "agg_basics.h"
|
||||
|
@ -46,6 +79,11 @@
|
|||
#include "agg_path_storage.h"
|
||||
#include "agg_conv_clip_polyline.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
|
||||
#include <boost/optional.hpp>
|
||||
|
@ -87,7 +125,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
agg::trans_affine geom_tr;
|
||||
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();
|
||||
|
||||
agg::trans_affine tr;
|
||||
|
@ -137,12 +175,12 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
box2d<double> transformed_bbox = bbox * matrix;
|
||||
|
||||
if (sym.get_allow_overlap() ||
|
||||
detector_.has_placement(transformed_bbox))
|
||||
detector_->has_placement(transformed_bbox))
|
||||
{
|
||||
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())
|
||||
detector_.insert(transformed_bbox);
|
||||
detector_->insert(transformed_bbox);
|
||||
}
|
||||
}
|
||||
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());
|
||||
path_type path(t_,clipped,prj_trans);
|
||||
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_max_error(),
|
||||
sym.get_allow_overlap());
|
||||
|
@ -166,7 +204,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
agg::trans_affine matrix = marker_trans;
|
||||
matrix.rotate(angle);
|
||||
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
|
||||
|
@ -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;
|
||||
path_type path(t_,geom,prj_trans);
|
||||
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_max_error(),
|
||||
sym.get_allow_overlap());
|
||||
|
@ -186,7 +224,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
agg::trans_affine matrix = marker_trans;
|
||||
matrix.rotate(angle);
|
||||
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_pixel.hpp>
|
||||
#include <mapnik/grid/grid.hpp>
|
||||
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/point_symbolizer.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/marker.hpp>
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
|
||||
// agg
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
// stl
|
||||
#include <string>
|
||||
|
||||
// boost
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
template <typename T>
|
||||
|
@ -57,14 +64,14 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
|
|||
if (marker)
|
||||
{
|
||||
box2d<double> const& bbox = (*marker)->bounding_box();
|
||||
coord2d const center = bbox.center();
|
||||
coord2d center = bbox.center();
|
||||
|
||||
agg::trans_affine tr;
|
||||
evaluate_transform(tr, feature, sym.get_image_transform());
|
||||
tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
||||
|
||||
agg::trans_affine_translation const recenter(-center.x, -center.y);
|
||||
agg::trans_affine const recenter_tr = recenter * tr;
|
||||
agg::trans_affine_translation recenter(-center.x, -center.y);
|
||||
agg::trans_affine recenter_tr = recenter * tr;
|
||||
box2d<double> label_ext = bbox * recenter_tr;
|
||||
|
||||
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);
|
||||
label_ext.re_center(x,y);
|
||||
if (sym.get_allow_overlap() ||
|
||||
detector_.has_placement(label_ext))
|
||||
detector_->has_placement(label_ext))
|
||||
{
|
||||
|
||||
render_marker(feature,
|
||||
|
@ -94,7 +101,7 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
|
|||
sym.comp_op());
|
||||
|
||||
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,
|
||||
width_, height_,
|
||||
scale_factor_,
|
||||
t_, font_manager_, detector_,
|
||||
t_, font_manager_, *detector_,
|
||||
query_extent_);
|
||||
bool placement_found = false;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
|
|||
sym, feature, prj_trans,
|
||||
width_, height_,
|
||||
scale_factor_ * (1.0/pixmap_.get_resolution()),
|
||||
t_, font_manager_, detector_,
|
||||
t_, font_manager_, *detector_,
|
||||
query_extent_);
|
||||
bool placement_found = false;
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ layer::layer(std::string const& name, std::string const& srs)
|
|||
clear_label_cache_(false),
|
||||
cache_features_(false),
|
||||
group_by_(""),
|
||||
ds_() {}
|
||||
ds_(),
|
||||
buffer_size_(0) {}
|
||||
|
||||
layer::layer(const layer& rhs)
|
||||
: name_(rhs.name_),
|
||||
|
@ -55,7 +56,9 @@ layer::layer(const layer& rhs)
|
|||
cache_features_(rhs.cache_features_),
|
||||
group_by_(rhs.group_by_),
|
||||
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)
|
||||
{
|
||||
|
@ -82,6 +85,8 @@ void layer::swap(const layer& rhs)
|
|||
group_by_ = rhs.group_by_;
|
||||
styles_=rhs.styles_;
|
||||
ds_=rhs.ds_;
|
||||
buffer_size_ = rhs.buffer_size_;
|
||||
maximum_extent_ = rhs.maximum_extent_;
|
||||
}
|
||||
|
||||
layer::~layer() {}
|
||||
|
@ -176,6 +181,31 @@ void layer::set_datasource(datasource_ptr const& 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
|
||||
{
|
||||
if (ds_) return ds_->envelope();
|
||||
|
|
|
@ -575,66 +575,95 @@ bool map_parser::parse_font(font_set &fset, xml_node const& f)
|
|||
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;
|
||||
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]
|
||||
std::string srs = lay.get_attr("srs", map.srs());
|
||||
std::string srs = node.get_attr("srs", map.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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
lyr.set_queryable(* queryable);
|
||||
}
|
||||
|
||||
optional<boolean> clear_cache =
|
||||
lay.get_opt_attr<boolean>("clear-label-cache");
|
||||
node.get_opt_attr<boolean>("clear-label-cache");
|
||||
if (clear_cache)
|
||||
{
|
||||
lyr.set_clear_label_cache(* clear_cache);
|
||||
}
|
||||
|
||||
optional<boolean> cache_features =
|
||||
lay.get_opt_attr<boolean>("cache-features");
|
||||
node.get_opt_attr<boolean>("cache-features");
|
||||
if (cache_features)
|
||||
{
|
||||
lyr.set_cache_features(* cache_features);
|
||||
}
|
||||
|
||||
optional<std::string> group_by =
|
||||
lay.get_opt_attr<std::string>("group-by");
|
||||
node.get_opt_attr<std::string>("group-by");
|
||||
if (group_by)
|
||||
{
|
||||
lyr.set_group_by(* group_by);
|
||||
}
|
||||
|
||||
xml_node::const_iterator child = lay.begin();
|
||||
xml_node::const_iterator end = lay.end();
|
||||
optional<unsigned> buffer_size = node.get_opt_attr<unsigned>("buffer-size");
|
||||
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)
|
||||
{
|
||||
|
@ -719,7 +748,7 @@ void map_parser::parse_layer(Map & map, xml_node const& lay)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
@ -894,7 +923,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
|
|||
symbol.set_ignore_placement(* ignore_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);
|
||||
|
||||
if (file && !file->empty())
|
||||
|
@ -1018,9 +1047,13 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
|
|||
sym.set_filename(expr);
|
||||
}
|
||||
|
||||
// overall opacity - impacts both fill and stroke, like svg
|
||||
optional<float> opacity = node.get_opt_attr<float>("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");
|
||||
if (image_transform_wkt)
|
||||
{
|
||||
|
@ -1065,7 +1098,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
|
|||
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);
|
||||
parse_symbolizer_base(sym, node);
|
||||
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)
|
||||
{
|
||||
maximum_extent_ = box;
|
||||
maximum_extent_.reset(box);
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -144,7 +144,7 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri,
|
|||
}
|
||||
std::string known_svg_string = mark_itr->second;
|
||||
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());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
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))
|
||||
{
|
||||
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());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
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[] = {
|
||||
"point",
|
||||
"interior",
|
||||
"line",
|
||||
""
|
||||
};
|
||||
|
@ -45,10 +46,7 @@ markers_symbolizer::markers_symbolizer()
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) {
|
||||
// override the default for clipping in symbolizer base
|
||||
this->set_clip(false);
|
||||
}
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
||||
: symbolizer_with_image(filename),
|
||||
|
@ -59,10 +57,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) {
|
||||
// override the default for clipping in symbolizer base
|
||||
this->set_clip(false);
|
||||
}
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
||||
: symbolizer_with_image(rhs),
|
||||
|
@ -74,6 +69,8 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
|||
spacing_(rhs.spacing_),
|
||||
max_error_(rhs.max_error_),
|
||||
fill_(rhs.fill_),
|
||||
fill_opacity_(rhs.fill_opacity_),
|
||||
opacity_(rhs.opacity_),
|
||||
stroke_(rhs.stroke_),
|
||||
marker_p_(rhs.marker_p_) {}
|
||||
|
||||
|
@ -117,6 +114,16 @@ double markers_symbolizer::get_max_error() const
|
|||
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)
|
||||
{
|
||||
fill_ = fill;
|
||||
|
@ -127,6 +134,16 @@ boost::optional<color> markers_symbolizer::get_fill() const
|
|||
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)
|
||||
{
|
||||
width_ = width;
|
||||
|
|
|
@ -78,6 +78,11 @@ public:
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -218,6 +223,11 @@ public:
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -249,7 +259,6 @@ public:
|
|||
{
|
||||
set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) );
|
||||
}
|
||||
|
||||
serialize_symbolizer_base(sym_node, sym);
|
||||
}
|
||||
|
||||
|
@ -283,6 +292,10 @@ public:
|
|||
{
|
||||
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_)
|
||||
{
|
||||
set_attr( sym_node, "opacity", sym.get_opacity() );
|
||||
|
@ -454,7 +467,7 @@ private:
|
|||
}
|
||||
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() )
|
||||
{
|
||||
|
@ -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() );
|
||||
}
|
||||
|
||||
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();
|
||||
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 );
|
||||
}
|
||||
|
||||
unsigned buffer_size = map.buffer_size();
|
||||
int buffer_size = map.buffer_size();
|
||||
if ( buffer_size || explicit_defaults)
|
||||
{
|
||||
set_attr( map_node, "buffer-size", buffer_size );
|
||||
|
|
|
@ -221,7 +221,11 @@ void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
|
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">
|
||||
<Rule>
|
||||
<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>
|
||||
</Style>
|
||||
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
<Map background-color="white" srs="+init=epsg:4326" minimum-version="0.7.2">
|
||||
<Style name="1">
|
||||
<Rule>
|
||||
<LineSymbolizer stroke-width=".2" stroke="grey"/>
|
||||
<MarkersSymbolizer file="../svg/crosshair16x16.svg"/>
|
||||
<LineSymbolizer offset="-2" stroke-width="2" stroke="red"/>
|
||||
<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>
|
||||
</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()
|
||||
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
|
||||
def test_shieldsymbolizer_init():
|
||||
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():
|
||||
p = mapnik.MarkersSymbolizer()
|
||||
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.placement,mapnik.marker_placement.POINT_PLACEMENT)
|
||||
eq_(p.fill,None)
|
||||
|
@ -154,9 +164,11 @@ def test_markersymbolizer_init():
|
|||
p.fill = mapnik.Color('white')
|
||||
p.allow_overlap = True
|
||||
p.opacity = 0.5
|
||||
p.fill_opacity = .01
|
||||
|
||||
eq_(p.allow_overlap, True)
|
||||
eq_(p.opacity, 0.5)
|
||||
eq_(p.fill_opacity, 0.5)
|
||||
|
||||
|
||||
# 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": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]}
|
||||
|
||||
# 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
|
||||
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
|
||||
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):
|
||||
""" 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)
|
||||
return val
|
||||
|
||||
def test_render_grid():
|
||||
def test_render_grid_old():
|
||||
""" test old method """
|
||||
width,height = 256,256
|
||||
m = create_grid_map(width,height)
|
||||
|
@ -117,7 +117,7 @@ def test_render_grid():
|
|||
lr_lonlat = mapnik.Coord(143.40,-38.80)
|
||||
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat))
|
||||
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)
|
||||
|
||||
# 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,11),expected)
|
||||
|
||||
def test_render_grid2():
|
||||
def test_render_grid_new():
|
||||
""" test old against new"""
|
||||
width,height = 256,256
|
||||
m = create_grid_map(width,height)
|
||||
|
@ -140,7 +140,7 @@ def test_render_grid2():
|
|||
grid = mapnik.Grid(m.width,m.height,key='Name')
|
||||
mapnik.render_layer(m,grid,layer=0,fields=['Name'])
|
||||
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
|
||||
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_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():
|
||||
""" test using feature id"""
|
||||
|
@ -177,7 +177,7 @@ def test_render_grid3():
|
|||
grid = mapnik.Grid(m.width,m.height,key='__id__')
|
||||
mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
|
||||
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
|
||||
grid_view = grid.view(0,0,width,height)
|
||||
# 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))
|
||||
#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():
|
||||
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";
|
||||
}
|
||||
mapnik::image_32 im(w,h);
|
||||
agg::rendering_buffer buf(im.raw_data(), w, h, w * 4);
|
||||
// 10 pixel buffer to avoid edge clipping of 100% svg's
|
||||
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);
|
||||
renderer_base renb(pixf);
|
||||
|
||||
|
@ -165,7 +166,7 @@ int main (int argc,char** argv)
|
|||
// center the svg marker on '0,0'
|
||||
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
|
||||
// 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::svg_path_adapter svg_path(stl_storage);
|
||||
|
|
Loading…
Reference in a new issue