From 54b86221140ee22dcfdfaf00e5b8c96a58615af1 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 20 Dec 2017 08:44:01 -0800 Subject: [PATCH 1/4] Replace ol/Sphere with ol/sphere --- changelog/upgrade-notes.md | 27 +++ examples/measure.html | 4 +- examples/measure.js | 6 +- examples/tissot.js | 5 +- src/ol/Geolocation.js | 11 +- src/ol/geom/Polygon.js | 8 +- src/ol/proj.js | 15 +- src/ol/{Sphere.js => sphere.js} | 345 ++++++++++++++------------------ test/spec/ol/sphere.test.js | 311 +++++++++++++--------------- 9 files changed, 330 insertions(+), 402 deletions(-) rename src/ol/{Sphere.js => sphere.js} (67%) diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index f6f55644b1..d032dc71c2 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -35,6 +35,33 @@ register(proj4); The map and sources no longer accept a `logo` option. Instead, if you wish to append a logo to your map, add the desired markup directly in your HTML. In addition, you can use the `attributions` property of a source to display arbitrary markup per-source with the attribution control. +#### Replacement of `ol/Sphere` constructor with `ol/sphere` functions + +The `ol/Sphere` constructor has been removed. If you were using the `getGeodesicArea` method, use the `getArea` function instead. If you were using the `haversineDistance` method, use the `getDistance` function instead. The `circular` method in `ol/Polygon` no longer takes a sphere as the first argument. + +Examples before: +```js +// using ol@4 +import Polygon from 'ol/Polygon'; +import Sphere from 'ol/Sphere'; + +var sphere = new Sphere(Sphere.DEFAULT_RADIUS); +var area = sphere.getGeodesicArea(polygon); +var distance = sphere.haversineDistance(g1, g2); +var circle = Polygon.circular(sphere, center, radius); +``` + +Examples after: +```js +// using ol@5 +import {circular as circularPolygon} from 'ol/Polygon'; +import {getArea, getDistance} from 'ol/sphere'; // note the lowercase + +var area = getArea(polygon); +var distance = getDistance(g1, g2); +var circle = circularPolygon(center, radius); +``` + #### Removal of optional this arguments. The following methods did get the optional this (i.e. opt_this) arguments removed. Please use closures, the es6 arrow function or the bind method to achieve this effect (Bind is explained here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). diff --git a/examples/measure.html b/examples/measure.html index 1d997edeff..b5a4f60a40 100644 --- a/examples/measure.html +++ b/examples/measure.html @@ -3,7 +3,7 @@ layout: example.html title: Measure shortdesc: Using a draw interaction to measure lengths and areas. docs: > -

The ol.Sphere.getLength() and ol.Sphere.getArea() +

The getLength() and getArea() functions calculate spherical lengths and areas for geometries. Lengths are calculated by assuming great circle segments between geometry coordinates. Areas are calculated as if edges of polygons were great circle segments.

@@ -11,7 +11,7 @@ docs: > methods return measures of projected (planar) geometries. These can be very different than on-the-ground measures in certain situations — in northern and southern latitudes using Web Mercator for example. For better results, - use the functions on ol.Sphere.

+ use the functions in the ol/sphere module.

tags: "draw, edit, measure, vector" ---
diff --git a/examples/measure.js b/examples/measure.js index e2e6779d8a..07717f8aa0 100644 --- a/examples/measure.js +++ b/examples/measure.js @@ -1,7 +1,7 @@ import _ol_Map_ from '../src/ol/Map.js'; import _ol_Observable_ from '../src/ol/Observable.js'; import _ol_Overlay_ from '../src/ol/Overlay.js'; -import _ol_Sphere_ from '../src/ol/Sphere.js'; +import {getArea, getLength} from '../src/ol/sphere.js'; import _ol_View_ from '../src/ol/View.js'; import LineString from '../src/ol/geom/LineString.js'; import Polygon from '../src/ol/geom/Polygon.js'; @@ -144,7 +144,7 @@ var draw; // global so we can remove it later * @return {string} The formatted length. */ var formatLength = function(line) { - var length = _ol_Sphere_.getLength(line); + var length = getLength(line); var output; if (length > 100) { output = (Math.round(length / 1000 * 100) / 100) + @@ -163,7 +163,7 @@ var formatLength = function(line) { * @return {string} Formatted area. */ var formatArea = function(polygon) { - var area = _ol_Sphere_.getArea(polygon); + var area = getArea(polygon); var output; if (area > 10000) { output = (Math.round(area / 1000000 * 100) / 100) + diff --git a/examples/tissot.js b/examples/tissot.js index 772d2aae0c..03230af4e5 100644 --- a/examples/tissot.js +++ b/examples/tissot.js @@ -1,6 +1,5 @@ import _ol_Feature_ from '../src/ol/Feature.js'; import _ol_Map_ from '../src/ol/Map.js'; -import _ol_Sphere_ from '../src/ol/Sphere.js'; import _ol_View_ from '../src/ol/View.js'; import Polygon from '../src/ol/geom/Polygon.js'; import TileLayer from '../src/ol/layer/Tile.js'; @@ -57,13 +56,11 @@ var map3857 = new _ol_Map_({ }) }); -var wgs84Sphere = new _ol_Sphere_(6378137); - var radius = 800000; var x, y; for (x = -180; x < 180; x += 30) { for (y = -90; y < 90; y += 30) { - var circle4326 = Polygon.circular(wgs84Sphere, [x, y], radius, 64); + var circle4326 = Polygon.circular([x, y], radius, 64); var circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857'); vectorLayer4326.getSource().addFeature(new _ol_Feature_(circle4326)); vectorLayer3857.getSource().addFeature(new _ol_Feature_(circle3857)); diff --git a/src/ol/Geolocation.js b/src/ol/Geolocation.js index 80150ef85a..ae3f696817 100644 --- a/src/ol/Geolocation.js +++ b/src/ol/Geolocation.js @@ -4,14 +4,12 @@ import {inherits} from './index.js'; import _ol_GeolocationProperty_ from './GeolocationProperty.js'; import _ol_Object_ from './Object.js'; -import _ol_Sphere_ from './Sphere.js'; import _ol_events_ from './events.js'; import EventType from './events/EventType.js'; import Polygon from './geom/Polygon.js'; import _ol_has_ from './has.js'; import {toRadians} from './math.js'; import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js'; -import _ol_proj_EPSG4326_ from './proj/EPSG4326.js'; /** @@ -74,12 +72,6 @@ var Geolocation = function(opt_options) { */ this.transform_ = identityTransform; - /** - * @private - * @type {ol.Sphere} - */ - this.sphere_ = new _ol_Sphere_(_ol_proj_EPSG4326_.RADIUS); - /** * @private * @type {number|undefined} @@ -175,8 +167,7 @@ Geolocation.prototype.positionChange_ = function(position) { this.set(_ol_GeolocationProperty_.POSITION, projectedPosition); this.set(_ol_GeolocationProperty_.SPEED, coords.speed === null ? undefined : coords.speed); - var geometry = Polygon.circular( - this.sphere_, this.position_, coords.accuracy); + var geometry = Polygon.circular(this.position_, coords.accuracy); geometry.applyTransform(this.transform_); this.set(_ol_GeolocationProperty_.ACCURACY_GEOMETRY, geometry); this.changed(); diff --git a/src/ol/geom/Polygon.js b/src/ol/geom/Polygon.js index caa064f731..269e1dc0c7 100644 --- a/src/ol/geom/Polygon.js +++ b/src/ol/geom/Polygon.js @@ -9,6 +9,7 @@ import GeometryType from '../geom/GeometryType.js'; import LinearRing from '../geom/LinearRing.js'; import Point from '../geom/Point.js'; import SimpleGeometry from '../geom/SimpleGeometry.js'; +import {offset as sphereOffset} from '../sphere.js'; import _ol_geom_flat_area_ from '../geom/flat/area.js'; import _ol_geom_flat_closest_ from '../geom/flat/closest.js'; import _ol_geom_flat_contains_ from '../geom/flat/contains.js'; @@ -369,22 +370,23 @@ Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) { /** * Create an approximation of a circle on the surface of a sphere. - * @param {ol.Sphere} sphere The sphere. * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees). * @param {number} radius The great-circle distance from the center to * the polygon vertices. * @param {number=} opt_n Optional number of vertices for the resulting * polygon. Default is `32`. + * @param {number=} opt_sphereRadius Optional radius for the sphere (defaults to + * the Earth's mean radius using the WGS84 ellipsoid). * @return {ol.geom.Polygon} The "circular" polygon. * @api */ -Polygon.circular = function(sphere, center, radius, opt_n) { +Polygon.circular = function(center, radius, opt_n, opt_sphereRadius) { var n = opt_n ? opt_n : 32; /** @type {Array.} */ var flatCoordinates = []; var i; for (i = 0; i < n; ++i) { - extend(flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n)); + extend(flatCoordinates, sphereOffset(center, radius, 2 * Math.PI * i / n, opt_sphereRadius)); } flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); var polygon = new Polygon(null); diff --git a/src/ol/proj.js b/src/ol/proj.js index 7dfc123ca1..79ca1ddd9a 100644 --- a/src/ol/proj.js +++ b/src/ol/proj.js @@ -1,7 +1,7 @@ /** * @module ol/proj */ -import Sphere from './Sphere.js'; +import {getDistance} from './sphere.js'; import {applyTransform} from './extent.js'; import {modulo} from './math.js'; import EPSG3857 from './proj/EPSG3857.js'; @@ -21,13 +21,6 @@ import {add as addTransformFunc, clear as clearTransformFuncs, get as getTransfo export var METERS_PER_UNIT = Units.METERS_PER_UNIT; -/** - * A place to store the mean radius of the Earth. - * @type {ol.Sphere} - */ -var SPHERE = new Sphere(Sphere.DEFAULT_RADIUS); - - /** * @param {Array.} input Input coordinate array. * @param {Array.=} opt_output Output array of coordinate values. @@ -150,10 +143,8 @@ export function getPointResolution(projection, resolution, point, opt_units) { point[0], point[1] + resolution / 2 ]; vertices = toEPSG4326(vertices, vertices, 2); - var width = SPHERE.haversineDistance( - vertices.slice(0, 2), vertices.slice(2, 4)); - var height = SPHERE.haversineDistance( - vertices.slice(4, 6), vertices.slice(6, 8)); + var width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4)); + var height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8)); pointResolution = (width + height) / 2; var metersPerUnit = opt_units ? Units.METERS_PER_UNIT[opt_units] : diff --git a/src/ol/Sphere.js b/src/ol/sphere.js similarity index 67% rename from src/ol/Sphere.js rename to src/ol/sphere.js index c10d602f8a..538cf256e2 100644 --- a/src/ol/Sphere.js +++ b/src/ol/sphere.js @@ -1,113 +1,69 @@ /** - * @module ol/Sphere - */ +* @license +* Latitude/longitude spherical geodesy formulae taken from +* http://www.movable-type.co.uk/scripts/latlong.html +* Licensed under CC-BY-3.0. +*/ /** - * @license - * Latitude/longitude spherical geodesy formulae taken from - * http://www.movable-type.co.uk/scripts/latlong.html - * Licensed under CC-BY-3.0. + * @module ol/Sphere */ import {toRadians, toDegrees} from './math.js'; import GeometryType from './geom/GeometryType.js'; /** - * Object literal with options for the {@link ol.Sphere.getLength} or - * {@link ol.Sphere.getArea} functions. + * Object literal with options for the {@link getLength} or + * {@link getArea} functions. * @typedef {{projection: (ol.ProjectionLike|undefined), * radius: (number|undefined)}} */ export var SphereMetricOptions; -/** - * @classdesc - * Class to create objects that can be used with {@link - * ol.geom.Polygon.circular}. - * - * For example to create a sphere whose radius is equal to the semi-major - * axis of the WGS84 ellipsoid: - * - * ```js - * var wgs84Sphere= new ol.Sphere(6378137); - * ``` - * - * @constructor - * @param {number} radius Radius. - * @api - */ -var _ol_Sphere_ = function(radius) { - - /** - * @type {number} - */ - this.radius = radius; - -}; - - -/** - * Returns the geodesic area for a list of coordinates. - * - * [Reference](https://trs-new.jpl.nasa.gov/handle/2014/40409) - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 - * - * @param {Array.} coordinates List of coordinates of a linear - * ring. If the ring is oriented clockwise, the area will be positive, - * otherwise it will be negative. - * @return {number} Area. - * @api - */ -_ol_Sphere_.prototype.geodesicArea = function(coordinates) { - return _ol_Sphere_.getArea_(coordinates, this.radius); -}; - - -/** - * Returns the distance from c1 to c2 using the haversine formula. - * - * @param {ol.Coordinate} c1 Coordinate 1. - * @param {ol.Coordinate} c2 Coordinate 2. - * @return {number} Haversine distance. - * @api - */ -_ol_Sphere_.prototype.haversineDistance = function(c1, c2) { - return _ol_Sphere_.getDistance_(c1, c2, this.radius); -}; - - -/** - * Returns the coordinate at the given distance and bearing from `c1`. - * - * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees). - * @param {number} distance The great-circle distance between the origin - * point and the target point. - * @param {number} bearing The bearing (in radians). - * @return {ol.Coordinate} The target point. - */ -_ol_Sphere_.prototype.offset = function(c1, distance, bearing) { - var lat1 = toRadians(c1[1]); - var lon1 = toRadians(c1[0]); - var dByR = distance / this.radius; - var lat = Math.asin( - Math.sin(lat1) * Math.cos(dByR) + - Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)); - var lon = lon1 + Math.atan2( - Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), - Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)); - return [toDegrees(lon), toDegrees(lat)]; -}; - - /** * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid. * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius * @type {number} */ -_ol_Sphere_.DEFAULT_RADIUS = 6371008.8; +export var DEFAULT_RADIUS = 6371008.8; + + +/** + * Get the great circle distance (in meters) between two geographic coordinates. + * @param {Array} c1 Starting coordinate. + * @param {Array} c2 Ending coordinate. + * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's + * mean radius using the WGS84 ellipsoid. + * @return {number} The great circle distance between the points (in meters). + * @api + */ +export function getDistance(c1, c2, opt_radius) { + var radius = opt_radius || DEFAULT_RADIUS; + var lat1 = toRadians(c1[1]); + var lat2 = toRadians(c2[1]); + var deltaLatBy2 = (lat2 - lat1) / 2; + var deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2; + var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + + Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * + Math.cos(lat1) * Math.cos(lat2); + return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +} + + +/** + * Get the cumulative great circle length of linestring coordinates (geographic). + * @param {Array} coordinates Linestring coordinates. + * @param {number} radius The sphere radius to use. + * @return {number} The length (in meters). + */ +function getLengthInternal(coordinates, radius) { + var length = 0; + for (var i = 0, ii = coordinates.length; i < ii - 1; ++i) { + length += getDistance(coordinates[i], coordinates[i + 1], radius); + } + return length; +} /** @@ -122,17 +78,19 @@ _ol_Sphere_.DEFAULT_RADIUS = 6371008.8; * @param {(ol.ProjectionLike|undefined)} opt_options.projection Projection of * the geometry. By default, the geometry is assumed to be in EPSG:3857 * (Web Mercator). - * @param {(number|undefined)} opt_options.radius Sphere radius. By default, - * the radius of the earth is used (Clarke 1866 Authalic Sphere). + * @param {(number|undefined)} opt_options.radius Sphere radius. Defaults to + * the Earth's mean radius using the WGS84 ellipsoid. * @return {number} The spherical length (in meters). * @api */ -_ol_Sphere_.getLength = function(geometry, opt_options) { +export function getLength(geometry, opt_options) { var options = opt_options || {}; - var radius = options.radius || _ol_Sphere_.DEFAULT_RADIUS; + var radius = options.radius || DEFAULT_RADIUS; var projection = options.projection || 'EPSG:3857'; - geometry = geometry.clone().transform(projection, 'EPSG:4326'); var type = geometry.getType(); + if (type !== GeometryType.GEOMETRY_COLLECTION) { + geometry = geometry.clone().transform(projection, 'EPSG:4326'); + } var length = 0; var coordinates, coords, i, ii, j, jj; switch (type) { @@ -143,14 +101,14 @@ _ol_Sphere_.getLength = function(geometry, opt_options) { case GeometryType.LINE_STRING: case GeometryType.LINEAR_RING: { coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); - length = _ol_Sphere_.getLength_(coordinates, radius); + length = getLengthInternal(coordinates, radius); break; } case GeometryType.MULTI_LINE_STRING: case GeometryType.POLYGON: { coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); for (i = 0, ii = coordinates.length; i < ii; ++i) { - length += _ol_Sphere_.getLength_(coordinates[i], radius); + length += getLengthInternal(coordinates[i], radius); } break; } @@ -159,7 +117,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) { for (i = 0, ii = coordinates.length; i < ii; ++i) { coords = coordinates[i]; for (j = 0, jj = coords.length; j < jj; ++j) { - length += _ol_Sphere_.getLength_(coords[j], radius); + length += getLengthInternal(coords[j], radius); } } break; @@ -167,7 +125,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) { case GeometryType.GEOMETRY_COLLECTION: { var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries(); for (i = 0, ii = geometries.length; i < ii; ++i) { - length += _ol_Sphere_.getLength(geometries[i], opt_options); + length += getLength(geometries[i], opt_options); } break; } @@ -176,101 +134,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) { } } return length; -}; - - -/** - * Get the cumulative great circle length of linestring coordinates (geographic). - * @param {Array} coordinates Linestring coordinates. - * @param {number} radius The sphere radius to use. - * @return {number} The length (in meters). - */ -_ol_Sphere_.getLength_ = function(coordinates, radius) { - var length = 0; - for (var i = 0, ii = coordinates.length; i < ii - 1; ++i) { - length += _ol_Sphere_.getDistance_(coordinates[i], coordinates[i + 1], radius); - } - return length; -}; - - -/** - * Get the great circle distance between two geographic coordinates. - * @param {Array} c1 Starting coordinate. - * @param {Array} c2 Ending coordinate. - * @param {number} radius The sphere radius to use. - * @return {number} The great circle distance between the points (in meters). - */ -_ol_Sphere_.getDistance_ = function(c1, c2, radius) { - var lat1 = toRadians(c1[1]); - var lat2 = toRadians(c2[1]); - var deltaLatBy2 = (lat2 - lat1) / 2; - var deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2; - var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + - Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * - Math.cos(lat1) * Math.cos(lat2); - return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); -}; - - -/** - * Get the spherical area of a geometry. This is the area (in meters) assuming - * that polygon edges are segments of great circles on a sphere. - * @param {ol.geom.Geometry} geometry A geometry. - * @param {SphereMetricOptions=} opt_options Options for the area - * calculation. By default, geometries are assumed to be in 'EPSG:3857'. - * You can change this by providing a `projection` option. - * @return {number} The spherical area (in square meters). - * @api - */ -_ol_Sphere_.getArea = function(geometry, opt_options) { - var options = opt_options || {}; - var radius = options.radius || _ol_Sphere_.DEFAULT_RADIUS; - var projection = options.projection || 'EPSG:3857'; - geometry = geometry.clone().transform(projection, 'EPSG:4326'); - var type = geometry.getType(); - var area = 0; - var coordinates, coords, i, ii, j, jj; - switch (type) { - case GeometryType.POINT: - case GeometryType.MULTI_POINT: - case GeometryType.LINE_STRING: - case GeometryType.MULTI_LINE_STRING: - case GeometryType.LINEAR_RING: { - break; - } - case GeometryType.POLYGON: { - coordinates = /** @type {ol.geom.Polygon} */ (geometry).getCoordinates(); - area = Math.abs(_ol_Sphere_.getArea_(coordinates[0], radius)); - for (i = 1, ii = coordinates.length; i < ii; ++i) { - area -= Math.abs(_ol_Sphere_.getArea_(coordinates[i], radius)); - } - break; - } - case GeometryType.MULTI_POLYGON: { - coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); - for (i = 0, ii = coordinates.length; i < ii; ++i) { - coords = coordinates[i]; - area += Math.abs(_ol_Sphere_.getArea_(coords[0], radius)); - for (j = 1, jj = coords.length; j < jj; ++j) { - area -= Math.abs(_ol_Sphere_.getArea_(coords[j], radius)); - } - } - break; - } - case GeometryType.GEOMETRY_COLLECTION: { - var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries(); - for (i = 0, ii = geometries.length; i < ii; ++i) { - area += _ol_Sphere_.getArea(geometries[i], opt_options); - } - break; - } - default: { - throw new Error('Unsupported geometry type: ' + type); - } - } - return area; -}; +} /** @@ -287,7 +151,7 @@ _ol_Sphere_.getArea = function(geometry, opt_options) { * @param {number} radius The sphere radius. * @return {number} Area (in square meters). */ -_ol_Sphere_.getArea_ = function(coordinates, radius) { +function getAreaInternal(coordinates, radius) { var area = 0, len = coordinates.length; var x1 = coordinates[len - 1][0]; var y1 = coordinates[len - 1][1]; @@ -300,5 +164,92 @@ _ol_Sphere_.getArea_ = function(coordinates, radius) { y1 = y2; } return area * radius * radius / 2.0; -}; -export default _ol_Sphere_; +} + + +/** + * Get the spherical area of a geometry. This is the area (in meters) assuming + * that polygon edges are segments of great circles on a sphere. + * @param {ol.geom.Geometry} geometry A geometry. + * @param {SphereMetricOptions=} opt_options Options for the area + * calculation. By default, geometries are assumed to be in 'EPSG:3857'. + * You can change this by providing a `projection` option. + * @return {number} The spherical area (in square meters). + * @api + */ +export function getArea(geometry, opt_options) { + var options = opt_options || {}; + var radius = options.radius || DEFAULT_RADIUS; + var projection = options.projection || 'EPSG:3857'; + var type = geometry.getType(); + if (type !== GeometryType.GEOMETRY_COLLECTION) { + geometry = geometry.clone().transform(projection, 'EPSG:4326'); + } + var area = 0; + var coordinates, coords, i, ii, j, jj; + switch (type) { + case GeometryType.POINT: + case GeometryType.MULTI_POINT: + case GeometryType.LINE_STRING: + case GeometryType.MULTI_LINE_STRING: + case GeometryType.LINEAR_RING: { + break; + } + case GeometryType.POLYGON: { + coordinates = /** @type {ol.geom.Polygon} */ (geometry).getCoordinates(); + area = Math.abs(getAreaInternal(coordinates[0], radius)); + for (i = 1, ii = coordinates.length; i < ii; ++i) { + area -= Math.abs(getAreaInternal(coordinates[i], radius)); + } + break; + } + case GeometryType.MULTI_POLYGON: { + coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); + for (i = 0, ii = coordinates.length; i < ii; ++i) { + coords = coordinates[i]; + area += Math.abs(getAreaInternal(coords[0], radius)); + for (j = 1, jj = coords.length; j < jj; ++j) { + area -= Math.abs(getAreaInternal(coords[j], radius)); + } + } + break; + } + case GeometryType.GEOMETRY_COLLECTION: { + var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries(); + for (i = 0, ii = geometries.length; i < ii; ++i) { + area += getArea(geometries[i], opt_options); + } + break; + } + default: { + throw new Error('Unsupported geometry type: ' + type); + } + } + return area; +} + + +/** + * Returns the coordinate at the given distance and bearing from `c1`. + * + * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees). + * @param {number} distance The great-circle distance between the origin + * point and the target point. + * @param {number} bearing The bearing (in radians). + * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's + * mean radius using the WGS84 ellipsoid. + * @return {ol.Coordinate} The target point. + */ +export function offset(c1, distance, bearing, opt_radius) { + var radius = opt_radius || DEFAULT_RADIUS; + var lat1 = toRadians(c1[1]); + var lon1 = toRadians(c1[0]); + var dByR = distance / radius; + var lat = Math.asin( + Math.sin(lat1) * Math.cos(dByR) + + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)); + var lon = lon1 + Math.atan2( + Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), + Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)); + return [toDegrees(lon), toDegrees(lat)]; +} diff --git a/test/spec/ol/sphere.test.js b/test/spec/ol/sphere.test.js index 923832ada3..4524124343 100644 --- a/test/spec/ol/sphere.test.js +++ b/test/spec/ol/sphere.test.js @@ -1,96 +1,155 @@ -// See http://www.movable-type.co.uk/scripts/latlong.html -// FIXME add tests for offset - - -import _ol_Sphere_ from '../../../src/ol/Sphere.js'; +import {getArea, getDistance, getLength} from '../../../src/ol/sphere.js'; import WKT from '../../../src/ol/format/WKT.js'; import GeometryCollection from '../../../src/ol/geom/GeometryCollection.js'; import LineString from '../../../src/ol/geom/LineString.js'; import MultiLineString from '../../../src/ol/geom/MultiLineString.js'; import MultiPoint from '../../../src/ol/geom/MultiPoint.js'; import Point from '../../../src/ol/geom/Point.js'; -import _ol_proj_EPSG4326_ from '../../../src/ol/proj/EPSG4326.js'; -describe('ol.Sphere', function() { +describe('ol/sphere', function() { - var sphere = new _ol_Sphere_(6371); - var expected = [{ - c1: [0, 0], - c2: [0, 0], - haversineDistance: 0 - }, { - c1: [0, 0], - c2: [45, 45], - haversineDistance: 6671.695598673525 - }, { - c1: [0, 0], - c2: [-45, 45], - haversineDistance: 6671.695598673525 - }, { - c1: [0, 0], - c2: [-45, -45], - haversineDistance: 6671.695598673525 - }, { - c1: [0, 0], - c2: [45, -45], - haversineDistance: 6671.695598673525 - }, { - c1: [45, 45], - c2: [45, 45], - haversineDistance: 0 - }, { - c1: [45, 45], - c2: [-45, 45], - haversineDistance: 6671.695598673525 - }, { - c1: [45, 45], - c2: [-45, -45], - haversineDistance: 13343.391197347048 - }, { - c1: [45, 45], - c2: [45, -45], - haversineDistance: 10007.543398010286 - }, { - c1: [-45, 45], - c2: [-45, 45], - haversineDistance: 0 - }, { - c1: [-45, 45], - c2: [-45, -45], - haversineDistance: 10007.543398010286 - }, { - c1: [-45, 45], - c2: [45, -45], - haversineDistance: 13343.391197347048 - }, { - c1: [-45, -45], - c2: [-45, -45], - haversineDistance: 0 - }, { - c1: [-45, -45], - c2: [45, -45], - haversineDistance: 6671.695598673525 - }, { - c1: [45, -45], - c2: [45, -45], - haversineDistance: 0 - }]; + describe('getDistance()', function() { - describe('haversineDistance', function() { + var expected = [{ + c1: [0, 0], + c2: [0, 0], + distance: 0 + }, { + c1: [0, 0], + c2: [45, 45], + distance: 6671704.814011975 + }, { + c1: [0, 0], + c2: [-45, 45], + distance: 6671704.814011975 + }, { + c1: [0, 0], + c2: [-45, -45], + distance: 6671704.814011975 + }, { + c1: [0, 0], + c2: [45, -45], + distance: 6671704.814011975 + }, { + c1: [45, 45], + c2: [45, 45], + distance: 0 + }, { + c1: [45, 45], + c2: [-45, 45], + distance: 6671704.814011975 + }, { + c1: [45, 45], + c2: [-45, -45], + distance: 13343409.628023949 + }, { + c1: [45, 45], + c2: [45, -45], + distance: 10007557.221017962 + }, { + c1: [-45, 45], + c2: [-45, 45], + distance: 0 + }, { + c1: [-45, 45], + c2: [-45, -45], + distance: 10007557.221017962 + }, { + c1: [-45, 45], + c2: [45, -45], + distance: 13343409.628023949 + }, { + c1: [-45, -45], + c2: [-45, -45], + distance: 0 + }, { + c1: [-45, -45], + c2: [45, -45], + distance: 6671704.814011975 + }, { + c1: [45, -45], + c2: [45, -45], + distance: 0 + }]; - it('results match Chris Veness\'s reference implementation', function() { - var e, i; - for (i = 0; i < expected.length; ++i) { - e = expected[i]; - expect(sphere.haversineDistance(e.c1, e.c2)).to.roughlyEqual( - e.haversineDistance, 1e-9); - } + expected.forEach(function(e, i) { + it('calculates the distance between two points: ' + i, function() { + expect(getDistance(e.c1, e.c2)).to.roughlyEqual(e.distance, 1e-6); + }); + }); + }); + + describe('getLength()', function() { + var cases = [{ + geometry: new Point([0, 0]), + length: 0 + }, { + geometry: new MultiPoint([[0, 0], [1, 1]]), + length: 0 + }, { + geometry: new LineString([ + [12801741.441226462, -3763310.627144653], + [14582853.293918837, -2511525.2348457114], + [15918687.18343812, -2875744.624352243], + [16697923.618991036, -4028802.0261344076] + ]), + length: 4407939.124914191 + }, { + geometry: new LineString([ + [115, -32], + [131, -22], + [143, -25], + [150, -34] + ]), + options: {projection: 'EPSG:4326'}, + length: 4407939.124914191 + }, { + geometry: new MultiLineString([ + [ + [115, -32], + [131, -22], + [143, -25], + [150, -34] + ], [ + [115, -32], + [131, -22], + [143, -25], + [150, -34] + ] + ]), + options: {projection: 'EPSG:4326'}, + length: 2 * 4407939.124914191 + }, { + geometry: new GeometryCollection([ + new LineString([ + [115, -32], + [131, -22], + [143, -25], + [150, -34] + ]), + new LineString([ + [115, -32], + [131, -22], + [143, -25], + [150, -34] + ]) + ]), + options: {projection: 'EPSG:4326'}, + length: 2 * 4407939.124914191 + }]; + + cases.forEach(function(c, i) { + it('works for case ' + i, function() { + var c = cases[i]; + var length = getLength(c.geometry, c.options); + expect(length).to.roughlyEqual(c.length, 1e-8); + }); }); }); - describe('Vincenty area', function() { + describe('getArea()', function() { var geometry; before(function(done) { afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) { @@ -104,100 +163,10 @@ describe('ol.Sphere', function() { }); }); - it('results match the expected area of Ilinois', function() { - var coords = geometry.getPolygon(0).getLinearRing(0).getCoordinates(); - var sphere = new _ol_Sphere_(_ol_proj_EPSG4326_.RADIUS); - expect(sphere.geodesicArea(coords)).to.equal(145978332359.37125); + it('calculates the area of Ilinois', function() { + var area = getArea(geometry, {projection: 'EPSG:4326'}); + expect(area).to.equal(145652224192.4434); }); }); }); - -describe('ol.Sphere.getLength()', function() { - var cases = [{ - geometry: new Point([0, 0]), - length: 0 - }, { - geometry: new MultiPoint([[0, 0], [1, 1]]), - length: 0 - }, { - geometry: new LineString([ - [12801741.441226462, -3763310.627144653], - [14582853.293918837, -2511525.2348457114], - [15918687.18343812, -2875744.624352243], - [16697923.618991036, -4028802.0261344076] - ]), - length: 4407939.124914191 - }, { - geometry: new LineString([ - [115, -32], - [131, -22], - [143, -25], - [150, -34] - ]), - options: {projection: 'EPSG:4326'}, - length: 4407939.124914191 - }, { - geometry: new MultiLineString([ - [ - [115, -32], - [131, -22], - [143, -25], - [150, -34] - ], [ - [115, -32], - [131, -22], - [143, -25], - [150, -34] - ] - ]), - options: {projection: 'EPSG:4326'}, - length: 2 * 4407939.124914191 - }, { - geometry: new GeometryCollection([ - new LineString([ - [115, -32], - [131, -22], - [143, -25], - [150, -34] - ]), - new LineString([ - [115, -32], - [131, -22], - [143, -25], - [150, -34] - ]) - ]), - options: {projection: 'EPSG:4326'}, - length: 2 * 4407939.124914191 - }]; - - cases.forEach(function(c, i) { - it('works for case ' + i, function() { - var c = cases[i]; - var length = _ol_Sphere_.getLength(c.geometry, c.options); - expect(length).to.roughlyEqual(c.length, 1e-8); - }); - }); - -}); - -describe('ol.Sphere.getArea()', function() { - var geometry; - before(function(done) { - afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) { - try { - var format = new WKT(); - geometry = format.readGeometry(wkt); - } catch (e) { - done(e); - } - done(); - }); - }); - - it('calculates the area of Ilinois', function() { - var area = _ol_Sphere_.getArea(geometry, {projection: 'EPSG:4326'}); - expect(area).to.equal(145652224192.4434); - }); -}); From dae1921533d44a42bbfba6fffd58e2c0b54a38f4 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 20 Dec 2017 14:39:09 -0700 Subject: [PATCH 2/4] Regression test for projected geometry collections --- test/spec/ol/sphere.test.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/test/spec/ol/sphere.test.js b/test/spec/ol/sphere.test.js index 4524124343..b3a0c1a26b 100644 --- a/test/spec/ol/sphere.test.js +++ b/test/spec/ol/sphere.test.js @@ -95,6 +95,22 @@ describe('ol/sphere', function() { [16697923.618991036, -4028802.0261344076] ]), length: 4407939.124914191 + }, { + geometry: new GeometryCollection([ + new LineString([ + [12801741.441226462, -3763310.627144653], + [14582853.293918837, -2511525.2348457114], + [15918687.18343812, -2875744.624352243], + [16697923.618991036, -4028802.0261344076] + ]), + new LineString([ + [12801741.441226462, -3763310.627144653], + [14582853.293918837, -2511525.2348457114], + [15918687.18343812, -2875744.624352243], + [16697923.618991036, -4028802.0261344076] + ]) + ]), + length: 2 * 4407939.124914191 }, { geometry: new LineString([ [115, -32], @@ -151,6 +167,7 @@ describe('ol/sphere', function() { describe('getArea()', function() { var geometry; + var expectedArea = 145652224192.4434; before(function(done) { afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) { try { @@ -165,8 +182,22 @@ describe('ol/sphere', function() { it('calculates the area of Ilinois', function() { var area = getArea(geometry, {projection: 'EPSG:4326'}); - expect(area).to.equal(145652224192.4434); + expect(area).to.equal(expectedArea); }); + + it('calculates the area of a projected geometry', function() { + var projected = geometry.clone().transform('EPSG:4326', 'EPSG:3857'); + var area = getArea(projected); + expect(area).to.roughlyEqual(expectedArea, 1e-3); + }); + + it('calculates the area of a projected geometry collection', function() { + var part = geometry.clone().transform('EPSG:4326', 'EPSG:3857'); + var collection = new GeometryCollection([part, part.clone()]); + var area = getArea(collection); + expect(area).to.roughlyEqual(2 * expectedArea, 1e-3); + }); + }); }); From c89738cadb9f499fbca638a3691146e1b479f42b Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 20 Dec 2017 14:49:56 -0700 Subject: [PATCH 3/4] Named exports instead of static functions from ol/geom/Polygon --- changelog/upgrade-notes.md | 6 +++--- examples/tissot.js | 4 ++-- src/ol/Geolocation.js | 4 ++-- src/ol/View.js | 6 +++--- src/ol/geom/Polygon.js | 22 +++++++++++----------- src/ol/interaction/Draw.js | 6 +++--- src/ol/interaction/Extent.js | 6 +++--- src/ol/interaction/Snap.js | 4 ++-- test/spec/ol/geom/polygon.test.js | 14 +++++++------- test/spec/ol/interaction/dragzoom.test.js | 6 +++--- 10 files changed, 39 insertions(+), 39 deletions(-) diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index d032dc71c2..600eec820f 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -37,12 +37,12 @@ The map and sources no longer accept a `logo` option. Instead, if you wish to a #### Replacement of `ol/Sphere` constructor with `ol/sphere` functions -The `ol/Sphere` constructor has been removed. If you were using the `getGeodesicArea` method, use the `getArea` function instead. If you were using the `haversineDistance` method, use the `getDistance` function instead. The `circular` method in `ol/Polygon` no longer takes a sphere as the first argument. +The `ol/Sphere` constructor has been removed. If you were using the `getGeodesicArea` method, use the `getArea` function instead. If you were using the `haversineDistance` method, use the `getDistance` function instead. The `circular` method in `ol/geom/Polygon` no longer takes a sphere as the first argument. Examples before: ```js // using ol@4 -import Polygon from 'ol/Polygon'; +import Polygon from 'ol/geom/Polygon'; import Sphere from 'ol/Sphere'; var sphere = new Sphere(Sphere.DEFAULT_RADIUS); @@ -54,7 +54,7 @@ var circle = Polygon.circular(sphere, center, radius); Examples after: ```js // using ol@5 -import {circular as circularPolygon} from 'ol/Polygon'; +import {circular as circularPolygon} from 'ol/geom/Polygon'; import {getArea, getDistance} from 'ol/sphere'; // note the lowercase var area = getArea(polygon); diff --git a/examples/tissot.js b/examples/tissot.js index 03230af4e5..43fdd0c13e 100644 --- a/examples/tissot.js +++ b/examples/tissot.js @@ -1,7 +1,7 @@ import _ol_Feature_ from '../src/ol/Feature.js'; import _ol_Map_ from '../src/ol/Map.js'; import _ol_View_ from '../src/ol/View.js'; -import Polygon from '../src/ol/geom/Polygon.js'; +import {circular as circularPolygon} from '../src/ol/geom/Polygon.js'; import TileLayer from '../src/ol/layer/Tile.js'; import _ol_layer_Vector_ from '../src/ol/layer/Vector.js'; import _ol_source_TileWMS_ from '../src/ol/source/TileWMS.js'; @@ -60,7 +60,7 @@ var radius = 800000; var x, y; for (x = -180; x < 180; x += 30) { for (y = -90; y < 90; y += 30) { - var circle4326 = Polygon.circular([x, y], radius, 64); + var circle4326 = circularPolygon([x, y], radius, 64); var circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857'); vectorLayer4326.getSource().addFeature(new _ol_Feature_(circle4326)); vectorLayer3857.getSource().addFeature(new _ol_Feature_(circle3857)); diff --git a/src/ol/Geolocation.js b/src/ol/Geolocation.js index ae3f696817..546c4b22ed 100644 --- a/src/ol/Geolocation.js +++ b/src/ol/Geolocation.js @@ -6,7 +6,7 @@ import _ol_GeolocationProperty_ from './GeolocationProperty.js'; import _ol_Object_ from './Object.js'; import _ol_events_ from './events.js'; import EventType from './events/EventType.js'; -import Polygon from './geom/Polygon.js'; +import {circular as circularPolygon} from './geom/Polygon.js'; import _ol_has_ from './has.js'; import {toRadians} from './math.js'; import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js'; @@ -167,7 +167,7 @@ Geolocation.prototype.positionChange_ = function(position) { this.set(_ol_GeolocationProperty_.POSITION, projectedPosition); this.set(_ol_GeolocationProperty_.SPEED, coords.speed === null ? undefined : coords.speed); - var geometry = Polygon.circular(this.position_, coords.accuracy); + var geometry = circularPolygon(this.position_, coords.accuracy); geometry.applyTransform(this.transform_); this.set(_ol_GeolocationProperty_.ACCURACY_GEOMETRY, geometry); this.changed(); diff --git a/src/ol/View.js b/src/ol/View.js index f2c27a17cc..4e37a0251e 100644 --- a/src/ol/View.js +++ b/src/ol/View.js @@ -15,7 +15,7 @@ import _ol_coordinate_ from './coordinate.js'; import {inAndOut} from './easing.js'; import {getForViewAndSize, getCenter, getHeight, getWidth, isEmpty} from './extent.js'; import GeometryType from './geom/GeometryType.js'; -import Polygon from './geom/Polygon.js'; +import {fromExtent as polygonFromExtent} from './geom/Polygon.js'; import SimpleGeometry from './geom/SimpleGeometry.js'; import {clamp, modulo} from './math.js'; import _ol_obj_ from './obj.js'; @@ -884,10 +884,10 @@ _ol_View_.prototype.fit = function(geometryOrExtent, opt_options) { 24); // Invalid extent or geometry provided as `geometry` assert(!isEmpty(geometryOrExtent), 25); // Cannot fit empty extent provided as `geometry` - geometry = Polygon.fromExtent(geometryOrExtent); + geometry = polygonFromExtent(geometryOrExtent); } else if (geometryOrExtent.getType() === GeometryType.CIRCLE) { geometryOrExtent = geometryOrExtent.getExtent(); - geometry = Polygon.fromExtent(geometryOrExtent); + geometry = polygonFromExtent(geometryOrExtent); geometry.rotate(this.getRotation(), getCenter(geometryOrExtent)); } else { geometry = geometryOrExtent; diff --git a/src/ol/geom/Polygon.js b/src/ol/geom/Polygon.js index 269e1dc0c7..22c8dbf902 100644 --- a/src/ol/geom/Polygon.js +++ b/src/ol/geom/Polygon.js @@ -367,6 +367,8 @@ Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) { this.changed(); }; +export default Polygon; + /** * Create an approximation of a circle on the surface of a sphere. @@ -380,7 +382,7 @@ Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) { * @return {ol.geom.Polygon} The "circular" polygon. * @api */ -Polygon.circular = function(center, radius, opt_n, opt_sphereRadius) { +export function circular(center, radius, opt_n, opt_sphereRadius) { var n = opt_n ? opt_n : 32; /** @type {Array.} */ var flatCoordinates = []; @@ -393,7 +395,7 @@ Polygon.circular = function(center, radius, opt_n, opt_sphereRadius) { polygon.setFlatCoordinates( GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); return polygon; -}; +} /** @@ -402,7 +404,7 @@ Polygon.circular = function(center, radius, opt_n, opt_sphereRadius) { * @return {ol.geom.Polygon} The polygon. * @api */ -Polygon.fromExtent = function(extent) { +export function fromExtent(extent) { var minX = extent[0]; var minY = extent[1]; var maxX = extent[2]; @@ -413,7 +415,7 @@ Polygon.fromExtent = function(extent) { polygon.setFlatCoordinates( GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); return polygon; -}; +} /** @@ -425,7 +427,7 @@ Polygon.fromExtent = function(extent) { * @return {ol.geom.Polygon} Polygon geometry. * @api */ -Polygon.fromCircle = function(circle, opt_sides, opt_angle) { +export function fromCircle(circle, opt_sides, opt_angle) { var sides = opt_sides ? opt_sides : 32; var stride = circle.getStride(); var layout = circle.getLayout(); @@ -437,10 +439,9 @@ Polygon.fromCircle = function(circle, opt_sides, opt_angle) { } var ends = [flatCoordinates.length]; polygon.setFlatCoordinates(layout, flatCoordinates, ends); - Polygon.makeRegular( - polygon, circle.getCenter(), circle.getRadius(), opt_angle); + makeRegular(polygon, circle.getCenter(), circle.getRadius(), opt_angle); return polygon; -}; +} /** @@ -451,7 +452,7 @@ Polygon.fromCircle = function(circle, opt_sides, opt_angle) { * @param {number=} opt_angle Start angle for the first vertex of the polygon in * radians. Default is 0. */ -Polygon.makeRegular = function(polygon, center, radius, opt_angle) { +export function makeRegular(polygon, center, radius, opt_angle) { var flatCoordinates = polygon.getFlatCoordinates(); var layout = polygon.getLayout(); var stride = polygon.getStride(); @@ -466,5 +467,4 @@ Polygon.makeRegular = function(polygon, center, radius, opt_angle) { flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle)); } polygon.setFlatCoordinates(layout, flatCoordinates, ends); -}; -export default Polygon; +} diff --git a/src/ol/interaction/Draw.js b/src/ol/interaction/Draw.js index a7a2d1428c..4c1addd19a 100644 --- a/src/ol/interaction/Draw.js +++ b/src/ol/interaction/Draw.js @@ -18,7 +18,7 @@ import MultiLineString from '../geom/MultiLineString.js'; import MultiPoint from '../geom/MultiPoint.js'; import MultiPolygon from '../geom/MultiPolygon.js'; import Point from '../geom/Point.js'; -import Polygon from '../geom/Polygon.js'; +import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js'; import DrawEventType from '../interaction/DrawEventType.js'; import _ol_interaction_Pointer_ from '../interaction/Pointer.js'; import _ol_interaction_Property_ from '../interaction/Property.js'; @@ -795,10 +795,10 @@ Draw.createRegularPolygon = function(opt_sides, opt_angle) { var radius = Math.sqrt( _ol_coordinate_.squaredDistance(center, end)); var geometry = opt_geometry ? /** @type {ol.geom.Polygon} */ (opt_geometry) : - Polygon.fromCircle(new Circle(center), opt_sides); + fromCircle(new Circle(center), opt_sides); var angle = opt_angle ? opt_angle : Math.atan((end[1] - center[1]) / (end[0] - center[0])); - Polygon.makeRegular(geometry, center, radius, angle); + makeRegular(geometry, center, radius, angle); return geometry; } ); diff --git a/src/ol/interaction/Extent.js b/src/ol/interaction/Extent.js index 1479c1f9fd..bb19804f2c 100644 --- a/src/ol/interaction/Extent.js +++ b/src/ol/interaction/Extent.js @@ -10,7 +10,7 @@ import Event from '../events/Event.js'; import {boundingExtent, getArea} from '../extent.js'; import GeometryType from '../geom/GeometryType.js'; import Point from '../geom/Point.js'; -import Polygon from '../geom/Polygon.js'; +import {fromExtent as polygonFromExtent} from '../geom/Polygon.js'; import _ol_interaction_ExtentEventType_ from '../interaction/ExtentEventType.js'; import _ol_interaction_Pointer_ from '../interaction/Pointer.js'; import _ol_layer_Vector_ from '../layer/Vector.js'; @@ -376,7 +376,7 @@ _ol_interaction_Extent_.prototype.createOrUpdateExtentFeature_ = function(extent if (!extent) { extentFeature = new _ol_Feature_({}); } else { - extentFeature = new _ol_Feature_(Polygon.fromExtent(extent)); + extentFeature = new _ol_Feature_(polygonFromExtent(extent)); } this.extentFeature_ = extentFeature; this.extentOverlay_.getSource().addFeature(extentFeature); @@ -384,7 +384,7 @@ _ol_interaction_Extent_.prototype.createOrUpdateExtentFeature_ = function(extent if (!extent) { extentFeature.setGeometry(undefined); } else { - extentFeature.setGeometry(Polygon.fromExtent(extent)); + extentFeature.setGeometry(polygonFromExtent(extent)); } } return extentFeature; diff --git a/src/ol/interaction/Snap.js b/src/ol/interaction/Snap.js index 02b39e75ee..92a1627952 100644 --- a/src/ol/interaction/Snap.js +++ b/src/ol/interaction/Snap.js @@ -10,7 +10,7 @@ import EventType from '../events/EventType.js'; import {boundingExtent, createEmpty} from '../extent.js'; import {TRUE, FALSE} from '../functions.js'; import GeometryType from '../geom/GeometryType.js'; -import Polygon from '../geom/Polygon.js'; +import {fromCircle} from '../geom/Polygon.js'; import _ol_interaction_Pointer_ from '../interaction/Pointer.js'; import _ol_obj_ from '../obj.js'; import _ol_source_Vector_ from '../source/Vector.js'; @@ -435,7 +435,7 @@ _ol_interaction_Snap_.prototype.updateFeature_ = function(feature) { * @private */ _ol_interaction_Snap_.prototype.writeCircleGeometry_ = function(feature, geometry) { - var polygon = Polygon.fromCircle(geometry); + var polygon = fromCircle(geometry); var coordinates = polygon.getCoordinates()[0]; var i, ii, segment, segmentData; for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { diff --git a/test/spec/ol/geom/polygon.test.js b/test/spec/ol/geom/polygon.test.js index 677841690e..1499b617ab 100644 --- a/test/spec/ol/geom/polygon.test.js +++ b/test/spec/ol/geom/polygon.test.js @@ -1,10 +1,10 @@ import * as _ol_extent_ from '../../../../src/ol/extent.js'; import Circle from '../../../../src/ol/geom/Circle.js'; import LinearRing from '../../../../src/ol/geom/LinearRing.js'; -import Polygon from '../../../../src/ol/geom/Polygon.js'; +import Polygon, {fromCircle, fromExtent} from '../../../../src/ol/geom/Polygon.js'; -describe('ol.geom.Polygon', function() { +describe('ol/geom/Polygon', function() { it('can be constructed with a null geometry', function() { expect(function() { @@ -561,10 +561,10 @@ describe('ol.geom.Polygon', function() { }); }); - describe('ol.geom.Polygon.fromExtent', function() { + describe('fromExtent()', function() { it('creates the correct polygon', function() { var extent = [1, 2, 3, 5]; - var polygon = Polygon.fromExtent(extent); + var polygon = fromExtent(extent); var flatCoordinates = polygon.getFlatCoordinates(); expect(flatCoordinates).to.eql( [1, 2, 1, 5, 3, 5, 3, 2, 1, 2]); @@ -574,11 +574,11 @@ describe('ol.geom.Polygon', function() { }); }); - describe('ol.geom.Polygon.fromCircle', function() { + describe('fromCircle()', function() { it('creates a regular polygon', function() { var circle = new Circle([0, 0, 0], 1, 'XYZ'); - var polygon = Polygon.fromCircle(circle); + var polygon = fromCircle(circle); var coordinates = polygon.getLinearRing(0).getCoordinates(); expect(coordinates[0].length).to.eql(3); expect(coordinates[0][2]).to.eql(0); @@ -599,7 +599,7 @@ describe('ol.geom.Polygon', function() { it('creates a regular polygon with custom sides and angle', function() { var circle = new Circle([0, 0], 1); - var polygon = Polygon.fromCircle(circle, 4, Math.PI / 2); + var polygon = fromCircle(circle, 4, Math.PI / 2); var coordinates = polygon.getLinearRing(0).getCoordinates(); expect(coordinates[4]).to.eql(coordinates[0]); expect(coordinates[0][0]).to.roughlyEqual(0, 1e-9); diff --git a/test/spec/ol/interaction/dragzoom.test.js b/test/spec/ol/interaction/dragzoom.test.js index bdb977af05..5007d28fd1 100644 --- a/test/spec/ol/interaction/dragzoom.test.js +++ b/test/spec/ol/interaction/dragzoom.test.js @@ -1,7 +1,7 @@ import _ol_Map_ from '../../../../src/ol/Map.js'; import _ol_View_ from '../../../../src/ol/View.js'; import * as _ol_extent_ from '../../../../src/ol/extent.js'; -import Polygon from '../../../../src/ol/geom/Polygon.js'; +import {fromExtent as polygonFromExtent} from '../../../../src/ol/geom/Polygon.js'; import DragZoom from '../../../../src/ol/interaction/DragZoom.js'; import _ol_layer_Vector_ from '../../../../src/ol/layer/Vector.js'; import _ol_render_Box_ from '../../../../src/ol/render/Box.js'; @@ -72,7 +72,7 @@ describe('ol.interaction.DragZoom', function() { var box = new _ol_render_Box_(); var extent = [-110, 40, -90, 60]; - box.geometry_ = Polygon.fromExtent(extent); + box.geometry_ = polygonFromExtent(extent); interaction.box_ = box; interaction.onBoxEnd(); @@ -94,7 +94,7 @@ describe('ol.interaction.DragZoom', function() { var box = new _ol_render_Box_(); var extent = [-11.25, -11.25, 11.25, 11.25]; - box.geometry_ = Polygon.fromExtent(extent); + box.geometry_ = polygonFromExtent(extent); interaction.box_ = box; map.getView().setResolution(0.25); From f393252a11b2973f46b77cdf772977d1a89b1998 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 20 Dec 2017 23:39:16 -0700 Subject: [PATCH 4/4] Dedicated section for notes on the circular change --- changelog/upgrade-notes.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index 600eec820f..03c5b1f301 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -37,31 +37,50 @@ The map and sources no longer accept a `logo` option. Instead, if you wish to a #### Replacement of `ol/Sphere` constructor with `ol/sphere` functions -The `ol/Sphere` constructor has been removed. If you were using the `getGeodesicArea` method, use the `getArea` function instead. If you were using the `haversineDistance` method, use the `getDistance` function instead. The `circular` method in `ol/geom/Polygon` no longer takes a sphere as the first argument. +The `ol/Sphere` constructor has been removed. If you were using the `getGeodesicArea` method, use the `getArea` function instead. If you were using the `haversineDistance` method, use the `getDistance` function instead. Examples before: ```js // using ol@4 -import Polygon from 'ol/geom/Polygon'; -import Sphere from 'ol/Sphere'; +import Sphere from 'ol/sphere'; var sphere = new Sphere(Sphere.DEFAULT_RADIUS); var area = sphere.getGeodesicArea(polygon); var distance = sphere.haversineDistance(g1, g2); -var circle = Polygon.circular(sphere, center, radius); ``` Examples after: ```js // using ol@5 import {circular as circularPolygon} from 'ol/geom/Polygon'; -import {getArea, getDistance} from 'ol/sphere'; // note the lowercase +import {getArea, getDistance} from 'ol/sphere'; var area = getArea(polygon); var distance = getDistance(g1, g2); var circle = circularPolygon(center, radius); ``` +#### New signature for the `circular` function for creating polygons + +The `circular` function exported from `ol/geom/Polygon` no longer requires a `Sphere` as the first argument. + +Example before: +```js +// using ol@4 +import Polygon from 'ol/geom/polygon'; +import Sphere from 'ol/sphere'; + +var poly = Polygon.circular(new Sphere(Sphere.DEFAULT_RADIUS), center, radius); +``` + +Example after: +```js +// using ol@5 +import {circular as circularPolygon} from 'ol/geom/Polygon'; + +var poly = circularPolygon(center, radius); +``` + #### Removal of optional this arguments. The following methods did get the optional this (i.e. opt_this) arguments removed. Please use closures, the es6 arrow function or the bind method to achieve this effect (Bind is explained here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).