Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

+ add VertexSource based implementations of label position algos

  • Loading branch information...
commit f6fa57da2641488f444b277199a08ded5f675eae 1 parent 710b7eb
@artemp artemp authored
Showing with 201 additions and 0 deletions.
  1. +201 −0 include/mapnik/geom_util.hpp
View
201 include/mapnik/geom_util.hpp
@@ -32,6 +32,7 @@
// stl
#include <cmath>
+#include <vector>
namespace mapnik
{
@@ -216,6 +217,206 @@ struct filter_at_point
return extent.contains(pt_);
}
};
+
+////////////////////////////////////////////////////////////////////////////
+template <typename PathType>
+double path_length(PathType & path)
+{
+ double x0,y0,x1,y1;
+ path.rewind(0);
+ unsigned command = path.vertex(&x0,&y0);
+ if (command == SEG_END) return 0;
+ double length = 0;
+ while (SEG_END != (command = path.vertex(&x1, &y1)))
+ {
+ length += distance(x0,y0,x1,y1);
+ x0 = x1;
+ y0 = y1;
+ }
+ return length;
+}
+
+template <typename PathType>
+bool middle_point(PathType & path, double & x, double & y)
+{
+ double x0,y0,x1,y1;
+ double mid_length = 0.5 * path_length(path);
+ path.rewind(0);
+ unsigned command = path.vertex(&x0,&y0);
+ if (command == SEG_END) return false;
+ double dist = 0.0;
+ while (SEG_END != (command = path.vertex(&x1, &y1)))
+ {
+ double seg_length = distance(x0, y0, x1, y1);
+
+ if ( dist + seg_length >= mid_length)
+ {
+ double r = (mid_length - dist)/seg_length;
+ x = x0 + (x1 - x0) * r;
+ y = y0 + (y1 - y0) * r;
+ break;
+ }
+ dist += seg_length;
+ x0 = x1;
+ y0 = y1;
+ }
+ return true;
+}
+
+template <typename PathType>
+bool centroid(PathType & path, double & x, double & y)
+{
+ double x0;
+ double y0;
+ double x1;
+ double y1;
+ double start_x;
+ double start_y;
+
+ path.rewind(0);
+ unsigned command = path.vertex(&x0, &y0);
+ if (command == SEG_END) return false;
+
+ start_x = x0;
+ start_y = y0;
+
+ double atmp = 0;
+ double xtmp = 0;
+ double ytmp = 0;
+
+ 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;
+ }
+
+ 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)
+{
+ bool inside=false;
+ double x0, y0, x1, y1;
+ path.rewind(0);
+ unsigned command = path.vertex(&x0, &y0);
+ if (command == SEG_END) return false;
+ unsigned count = 0;
+ while (SEG_END != (command = path.vertex(&x1, &y1)))
+ {
+ ++count;
+ if (command == SEG_MOVETO)
+ {
+ x0 = x1;
+ y0 = y1;
+ continue;
+ }
+ if ((((y1 <= y) && (y < y0)) ||
+ ((y0 <= y) && (y < y1))) &&
+ (x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1))
+ inside=!inside;
+
+ x0 = x1;
+ y0 = y1;
+ }
+
+ if (count == 0) // one vertex
+ {
+ return distance(x, y, x0, y0) <= fabs(tol);
+ }
+ return inside;
+}
+
+template <typename PathType>
+void label_interior_position(PathType & path, double & x, double & y)
+{
+ // start with the centroid
+ centroid(path, x,y);
+
+ // if we are not a polygon, or the default is within the polygon we are done
+ if (hit_test(path,x,y,0.001))
+ return;
+
+ // otherwise we find a horizontal line across the polygon and then return the
+ // center of the widest intersection between the polygon and the line.
+
+ std::vector<double> intersections; // only need to store the X as we know the y
+
+ double x0;
+ double y0;
+ path.rewind(0);
+ unsigned command = path.vertex(&x0, &y0);
+ double x1,y1;
+ while (SEG_END != (command = path.vertex(&x1, &y1)))
+ {
+ if (command != SEG_MOVETO)
+ {
+ // if the segments overlap
+ if (y0==y1)
+ {
+ if (y0==y)
+ {
+ double xi = (x0+x1)/2.0;
+ intersections.push_back(xi);
+ }
+ }
+ // if the path segment crosses the bisector
+ else if ((y0 <= y && y1 >= y) ||
+ (y0 >= y && y1 <= y))
+ {
+ // then calculate the intersection
+ double xi = x0;
+ if (x0 != x1)
+ {
+ double m = (y1-y0)/(x1-x0);
+ double c = y0 - m*x0;
+ xi = (y-c)/m;
+ }
+
+ intersections.push_back(xi);
+ }
+ }
+ x0 = x1;
+ y0 = y1;
+ }
+ // no intersections we just return the default
+ if (intersections.empty())
+ return;
+ x0=intersections[0];
+ double max_width = 0;
+ for (unsigned ii = 1; ii < intersections.size(); ++ii)
+ {
+ double x1=intersections[ii];
+ double xc=(x0+x1)/2.0;
+ double width = std::fabs(x1-x0);
+ if (width > max_width && hit_test(path,xc,y,0))
+ {
+ x=xc;
+ max_width = width;
+ break;
+ }
+ }
+}
+
}
#endif // MAPNIK_GEOM_UTIL_HPP
Please sign in to comment.
Something went wrong with that request. Please try again.