diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index c888d67da5..d256ea0951 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -1,6 +1,7 @@ goog.provide('ol.geom.Polygon'); goog.require('goog.asserts'); +goog.require('ol.extent'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryType'); goog.require('ol.geom.LinearRing'); @@ -35,6 +36,12 @@ ol.geom.Polygon = function(coordinates, opt_shared) { vertices = new ol.geom.SharedVertices({dimension: dimension}); } + /** + * @private + * @type {ol.Coordinate} + */ + this.labelPoint_ = null; + /** * @type {ol.geom.SharedVertices} */ @@ -126,3 +133,48 @@ ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) { } return containsCoordinate; }; + + +/** + * Calculates a label point that is guaranteed to be inside the polygon. + * @return {ol.Coordinate} The label point. + */ +ol.geom.Polygon.prototype.getLabelPoint = function() { + if (goog.isNull(this.labelPoint_)) { + var center = ol.extent.getCenter(this.getBounds()), + resultY = center[1], + vertices = this.rings[0].getCoordinates(), + intersections = [], + maxLength = 0, + i, vertex1, vertex2, x, segmentLength, resultX; + + // Calculate intersections with the horizontal bounding box center line + for (i = vertices.length - 1; i >= 1; --i) { + vertex1 = vertices[i]; + vertex2 = vertices[i - 1]; + if ((vertex1[1] >= resultY && vertex2[1] <= resultY) || + (vertex1[1] <= resultY && vertex2[1] >= resultY)) { + x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) * + (vertex2[0] - vertex1[0]) + vertex1[0]; + intersections.push(x); + } + } + + // Find the longest segment of the horizontal bounding box center line that + // has its center point inside the polygon + intersections.sort(); + for (i = intersections.length - 1; i >= 1; --i) { + segmentLength = Math.abs(intersections[i] - intersections[i - 1]); + if (segmentLength > maxLength) { + x = (intersections[i] + intersections[i - 1]) / 2; + if (this.containsCoordinate([x, resultY])) { + maxLength = segmentLength; + resultX = x; + } + } + } + this.labelPoint_ = [resultX, resultY]; + } + + return this.labelPoint_; +}; diff --git a/src/ol/renderer/canvas/canvasvectorrenderer.js b/src/ol/renderer/canvas/canvasvectorrenderer.js index 183412b679..25bde2f6ad 100644 --- a/src/ol/renderer/canvas/canvasvectorrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorrenderer.js @@ -8,7 +8,6 @@ goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.vec.Mat4'); goog.require('ol.Feature'); -goog.require('ol.extent'); goog.require('ol.geom.AbstractCollection'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryType'); @@ -446,8 +445,7 @@ ol.renderer.canvas.VectorRenderer.getLabelVectors = function(geometry) { return [[geometry.get(0), geometry.get(1), 0]]; } if (type == ol.geom.GeometryType.POLYGON) { - // TODO: better label placement - var coordinates = ol.extent.getCenter(geometry.getBounds()); + var coordinates = geometry.getLabelPoint(); return [[coordinates[0], coordinates[1], 0]]; } throw new Error('Label rendering not implemented for geometry type: ' +