Skip to content

Commit

Permalink
Add new angled-point marker placement mode for lines
Browse files Browse the repository at this point in the history
This adds a new mode called 'angled-point' to the marker-placement modes.
The full list of modes is then:
  point, angled-point, interior, line, vertex-first, vertex-last

Angled point is identical to point, except that when placing a marker on
a line, the marker's angle is taken from the angle of the line segment.

There is another possible use of the "angled-point" concept for polygons,
and that is for placing labels on stand (aka erf) polygons. By computing
a dominant angle for a mostly rectangular polygon, this can produce quite
good results. I'm not sure whether I should implement that now, or if I
could do that later.
  • Loading branch information
bmharper committed Oct 26, 2017
1 parent f02a259 commit 05849f0
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 5 deletions.
12 changes: 11 additions & 1 deletion include/mapnik/geom_util.hpp 100644 → 100755
Expand Up @@ -35,6 +35,12 @@
#include <vector>
#include <algorithm>

// boost
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/optional.hpp>
#pragma GCC diagnostic pop

namespace mapnik
{
template <typename T>
Expand Down Expand Up @@ -298,7 +304,7 @@ bool hit_test_first(PathType & path, double x, double y)
namespace label {

template <typename PathType>
bool middle_point(PathType & path, double & x, double & y)
bool middle_point(PathType & path, double & x, double & y, boost::optional<double&> angle = boost::none)
{
double x0 = 0;
double y0 = 0;
Expand All @@ -319,6 +325,10 @@ bool middle_point(PathType & path, double & x, double & y)
double r = (mid_length - dist)/seg_length;
x = x0 + (x1 - x0) * r;
y = y0 + (y1 - y0) * r;
if (angle)
{
*angle = atan2(y1 - y0, x1 - x0);
}
break;
}
dist += seg_length;
Expand Down
6 changes: 6 additions & 0 deletions include/mapnik/markers_placement.hpp
Expand Up @@ -49,6 +49,10 @@ class markers_placement_finder : util::noncopyable
case MARKER_POINT_PLACEMENT:
construct(&point_, locator, detector, params);
break;
case MARKER_ANGLED_POINT_PLACEMENT:
construct(&point_, locator, detector, params);
point_.use_angle(true);
break;
case MARKER_INTERIOR_PLACEMENT:
construct(&interior_, locator, detector, params);
break;
Expand All @@ -70,6 +74,7 @@ class markers_placement_finder : util::noncopyable
{
default:
case MARKER_POINT_PLACEMENT:
case MARKER_ANGLED_POINT_PLACEMENT:
destroy(&point_);
break;
case MARKER_INTERIOR_PLACEMENT:
Expand All @@ -94,6 +99,7 @@ class markers_placement_finder : util::noncopyable
{
default:
case MARKER_POINT_PLACEMENT:
case MARKER_ANGLED_POINT_PLACEMENT:
return point_.get_point(x, y, angle, ignore_placement);
case MARKER_INTERIOR_PLACEMENT:
return interior_.get_point(x, y, angle, ignore_placement);
Expand Down
16 changes: 12 additions & 4 deletions include/mapnik/markers_placements/point.hpp 100644 → 100755
Expand Up @@ -38,11 +38,18 @@ class markers_point_placement : public markers_basic_placement
: markers_basic_placement(params),
locator_(locator),
detector_(detector),
done_(false)
done_(false),
use_angle_(false)
{
locator_.rewind(0);
}

// Use angle of line
void use_angle(bool enable)
{
use_angle_ = enable;
}

// Start again at first marker. Returns the same list of markers only works when they were NOT added to the detector.
void rewind()
{
Expand All @@ -58,9 +65,11 @@ class markers_point_placement : public markers_basic_placement
return false;
}

angle = 0;

if (this->locator_.type() == geometry::geometry_types::LineString)
{
if (!label::middle_point(this->locator_, x, y))
if (!label::middle_point(this->locator_, x, y, use_angle_ ? boost::optional<double&>(angle) : boost::none))
{
this->done_ = true;
return false;
Expand All @@ -75,8 +84,6 @@ class markers_point_placement : public markers_basic_placement
}
}

angle = 0;

if (!this->push_to_detector(x, y, angle, ignore_placement))
{
return false;
Expand All @@ -90,6 +97,7 @@ class markers_point_placement : public markers_basic_placement
Locator & locator_;
Detector & detector_;
bool done_;
bool use_angle_;

// Checks transformed box placement with collision detector.
// returns false if the box:
Expand Down
1 change: 1 addition & 0 deletions include/mapnik/symbolizer_enumerations.hpp
Expand Up @@ -105,6 +105,7 @@ enum marker_placement_enum : std::uint8_t
MARKER_LINE_PLACEMENT,
MARKER_VERTEX_FIRST_PLACEMENT,
MARKER_VERTEX_LAST_PLACEMENT,
MARKER_ANGLED_POINT_PLACEMENT,
marker_placement_enum_MAX
};

Expand Down
1 change: 1 addition & 0 deletions src/symbolizer_enumerations.cpp
Expand Up @@ -67,6 +67,7 @@ static const char * marker_placement_strings[] = {
"line",
"vertex-first",
"vertex-last",
"angled-point",
""
};

Expand Down

0 comments on commit 05849f0

Please sign in to comment.