Permalink
Browse files

Merge pull request #1587 from strk/2.1.x-multi_policy

Add marker-multi-policy parameter (backport to 2.1.x from master) - refs #1573, #1555 and #1586
  • Loading branch information...
2 parents 219c5f5 + 4a0933e commit 0b2f2f8ee0e7d14f3d3ea7bd17efd8f6a0da7251 Dane Springmeyer committed Nov 21, 2012
View
@@ -9,6 +9,8 @@ For a complete change history, see the git log.
## Unreleased
+- Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573)
+
- Add DebugSymbolizer (#1366)
@@ -89,6 +89,12 @@ void export_markers_symbolizer()
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
;
+ mapnik::enumeration_<mapnik::marker_multi_policy_e>("marker_multi_policy")
+ .value("EACH",mapnik::MARKER_EACH_MULTI)
+ .value("WHOLE",mapnik::MARKER_WHOLE_MULTI)
+ .value("LARGEST",mapnik::MARKER_LARGEST_MULTI)
+ ;
+
class_<markers_symbolizer>("MarkersSymbolizer",
init<>("Default Markers Symbolizer - circle"))
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
@@ -143,6 +149,10 @@ void export_markers_symbolizer()
&markers_symbolizer::get_marker_placement,
&markers_symbolizer::set_marker_placement,
"Set/get the marker placement")
+ .add_property("multi_policy",
+ &markers_symbolizer::get_marker_multi_policy,
+ &markers_symbolizer::set_marker_multi_policy,
+ "Set/get the marker multi geometry rendering policy")
.add_property("comp_op",
&markers_symbolizer::comp_op,
&markers_symbolizer::set_comp_op,
@@ -329,6 +329,70 @@ bool centroid(PathType & path, double & x, double & y)
return true;
}
+// Compute centroid over a set of paths
+template <typename Iter>
+bool centroid_geoms(Iter start, Iter end, double & x, double & y)
+{
+ double x0 = 0.0;
+ double y0 = 0.0;
+ double x1 = 0.0;
+ double y1 = 0.0;
+ double start_x = x0;
+ double start_y = y0;
+
+ bool empty = true;
+
+ double atmp = 0.0;
+ double xtmp = 0.0;
+ double ytmp = 0.0;
+ unsigned count = 1;
+
+ while (start!=end)
+ {
+ typename Iter::value_type & path = *start++;
+ path.rewind(0);
+ unsigned command = path.vertex(&x0, &y0);
+ if (command == SEG_END) continue;
+ empty = false;
+
+ while (SEG_END != (command = path.vertex(&x1, &y1)))
+ {
+ double dx0 = x0 - start_x;
+ double dy0 = y0 - start_y;
+ double dx1 = x1 - start_x;
+ double dy1 = y1 - start_y;
+ double ai = dx0 * dy1 - dx1 * dy0;
+ atmp += ai;
+ xtmp += (dx1 + dx0) * ai;
+ ytmp += (dy1 + dy0) * ai;
+ x0 = x1;
+ y0 = y1;
+ ++count;
+ }
+ }
+
+ if ( empty ) return false;
+
+ if (count <= 2) {
+ x = (start_x + x0) * 0.5;
+ y = (start_y + y0) * 0.5;
+ return true;
+ }
+
+ if (atmp != 0)
+ {
+ x = (xtmp/(3*atmp)) + start_x;
+ y = (ytmp/(3*atmp)) + start_y;
+ }
+ else
+ {
+ x = x0;
+ y = y0;
+ }
+
+ return true;
+}
+
template <typename PathType>
bool hit_test(PathType & path, double x, double y, double tol)
{
@@ -398,6 +398,68 @@ void setup_transform_scaling(agg::trans_affine & tr, box2d<double> const& bbox,
}
}
+// Apply markers to a feature with multiple geometries
+template <typename Converter>
+void apply_markers_multi(feature_impl & feature, Converter& converter, markers_symbolizer const& sym)
+{
+ std::size_t geom_count = feature.paths().size();
+ if (geom_count == 1)
+ {
+ converter.apply(feature.paths()[0]);
+ }
+ else if (geom_count > 1)
+ {
+ marker_multi_policy_e multi_policy = sym.get_marker_multi_policy();
+ marker_placement_e placement = sym.get_marker_placement();
+ if (placement == MARKER_POINT_PLACEMENT &&
+ multi_policy == MARKER_WHOLE_MULTI)
+ {
+ double x, y;
+ if (label::centroid_geoms(feature.paths().begin(), feature.paths().end(), x, y))
+ {
+ geometry_type pt(Point);
+ pt.move_to(x, y);
+ // unset any clipping since we're now dealing with a point
+ converter.template unset<clip_poly_tag>();
+ converter.apply(pt);
+ }
+ }
+ else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
+ multi_policy == MARKER_LARGEST_MULTI)
+ {
+ // Only apply to path with largest envelope area
+ // TODO: consider using true area for polygon types
+ double maxarea = 0;
+ geometry_type* largest = 0;
+ BOOST_FOREACH(geometry_type & geom, feature.paths())
+ {
+ const box2d<double>& env = geom.envelope();
+ double area = env.width() * env.height();
+ if (area > maxarea)
+ {
+ maxarea = area;
+ largest = &geom;
+ }
+ }
+ if (largest)
+ {
+ converter.apply(*largest);
+ }
+ }
+ else
+ {
+ if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
+ {
+ MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
+ }
+ BOOST_FOREACH(geometry_type & path, feature.paths())
+ {
+ converter.apply(path);
+ }
+ }
+ }
+}
+
}
#endif //MAPNIK_MARKER_HELPERS_HPP
@@ -46,6 +46,15 @@ enum marker_placement_enum {
DEFINE_ENUM( marker_placement_e, marker_placement_enum );
+enum marker_multi_policy_enum {
+ MARKER_EACH_MULTI, // each component in a multi gets its marker
+ MARKER_WHOLE_MULTI, // consider all components of a multi as a whole
+ MARKER_LARGEST_MULTI, // only the largest component of a multi gets a marker
+ marker_multi_policy_enum_MAX
+};
+
+DEFINE_ENUM( marker_multi_policy_e, marker_multi_policy_enum );
+
struct MAPNIK_DECL markers_symbolizer :
public symbolizer_with_image, public symbolizer_base
{
@@ -74,6 +83,8 @@ struct MAPNIK_DECL markers_symbolizer :
boost::optional<stroke> get_stroke() const;
void set_marker_placement(marker_placement_e marker_p);
marker_placement_e get_marker_placement() const;
+ void set_marker_multi_policy(marker_multi_policy_e marker_p);
+ marker_multi_policy_e get_marker_multi_policy() const;
private:
expression_ptr width_;
expression_ptr height_;
@@ -86,6 +97,7 @@ struct MAPNIK_DECL markers_symbolizer :
boost::optional<float> opacity_;
boost::optional<stroke> stroke_;
marker_placement_e marker_p_;
+ marker_multi_policy_e marker_mp_;
};
}
@@ -347,6 +347,16 @@ struct vertex_converter : private boost::noncopyable
disp_.vec_[index]=1;
}
+ template <typename Conv>
+ void unset()
+ {
+ typedef typename boost::mpl::find<conv_types,Conv>::type iter;
+ typedef typename boost::mpl::end<conv_types>::type end;
+ std::size_t index = boost::mpl::distance<iter,end>::value - 1;
+ if (index < disp_.vec_.size())
+ disp_.vec_[index]=0;
+ }
+
detail::dispatcher<args_type,conv_types> disp_;
};
@@ -26,6 +26,7 @@
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/debug.hpp>
+#include <mapnik/feature.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/vertex_converters.hpp>
@@ -136,10 +137,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
else
{
@@ -172,10 +170,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@@ -207,11 +202,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
}
View
@@ -1706,10 +1706,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
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())
- {
- converter.apply(geom);
- }
+ apply_markers_multi(feature, converter, sym);
}
else
{
@@ -1734,10 +1731,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
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())
- {
- converter.apply(geom);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@@ -1767,10 +1761,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
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())
- {
- converter.apply(geom);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
}
@@ -163,10 +163,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
else
{
@@ -208,10 +205,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@@ -256,10 +250,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
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);
- }
+ apply_markers_multi(feature, converter, sym);
}
}
}
View
@@ -1027,6 +1027,10 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
marker_placement_e placement = node.get_attr<marker_placement_e>("placement",sym.get_marker_placement());
sym.set_marker_placement(placement);
+
+ marker_multi_policy_e mpolicy = node.get_attr<marker_multi_policy_e>("multi-policy",sym.get_marker_multi_policy());
+ sym.set_marker_multi_policy(mpolicy);
+
parse_symbolizer_base(sym, node);
rule.append(sym);
}
Oops, something went wrong.

0 comments on commit 0b2f2f8

Please sign in to comment.