Merge pull request #7643 from tschaub/sphere

Replace ol/Sphere with ol/sphere
This commit is contained in:
Tim Schaub
2017-12-21 00:08:46 -07:00
committed by GitHub
15 changed files with 413 additions and 435 deletions
+46
View File
@@ -35,6 +35,52 @@ 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. 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.
Examples before:
```js
// using ol@4
import Sphere from 'ol/sphere';
var sphere = new Sphere(Sphere.DEFAULT_RADIUS);
var area = sphere.getGeodesicArea(polygon);
var distance = sphere.haversineDistance(g1, g2);
```
Examples after:
```js
// using ol@5
import {circular as circularPolygon} from 'ol/geom/Polygon';
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. #### 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). 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).
+2 -2
View File
@@ -3,7 +3,7 @@ layout: example.html
title: Measure title: Measure
shortdesc: Using a draw interaction to measure lengths and areas. shortdesc: Using a draw interaction to measure lengths and areas.
docs: > docs: >
<p>The <code>ol.Sphere.getLength()</code> and <code>ol.Sphere.getArea()</code> <p>The <code>getLength()</code> and <code>getArea()</code>
functions calculate spherical lengths and areas for geometries. Lengths are functions calculate spherical lengths and areas for geometries. Lengths are
calculated by assuming great circle segments between geometry coordinates. calculated by assuming great circle segments between geometry coordinates.
Areas are calculated as if edges of polygons were great circle segments.</p> Areas are calculated as if edges of polygons were great circle segments.</p>
@@ -11,7 +11,7 @@ docs: >
methods return measures of projected (planar) geometries. These can be very methods return measures of projected (planar) geometries. These can be very
different than on-the-ground measures in certain situations — in northern different than on-the-ground measures in certain situations — in northern
and southern latitudes using Web Mercator for example. For better results, and southern latitudes using Web Mercator for example. For better results,
use the functions on <code>ol.Sphere</code>.</p> use the functions in the <code>ol/sphere</code> module.</p>
tags: "draw, edit, measure, vector" tags: "draw, edit, measure, vector"
--- ---
<div id="map" class="map"></div> <div id="map" class="map"></div>
+3 -3
View File
@@ -1,7 +1,7 @@
import _ol_Map_ from '../src/ol/Map.js'; import _ol_Map_ from '../src/ol/Map.js';
import _ol_Observable_ from '../src/ol/Observable.js'; import _ol_Observable_ from '../src/ol/Observable.js';
import _ol_Overlay_ from '../src/ol/Overlay.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 _ol_View_ from '../src/ol/View.js';
import LineString from '../src/ol/geom/LineString.js'; import LineString from '../src/ol/geom/LineString.js';
import Polygon from '../src/ol/geom/Polygon.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. * @return {string} The formatted length.
*/ */
var formatLength = function(line) { var formatLength = function(line) {
var length = _ol_Sphere_.getLength(line); var length = getLength(line);
var output; var output;
if (length > 100) { if (length > 100) {
output = (Math.round(length / 1000 * 100) / 100) + output = (Math.round(length / 1000 * 100) / 100) +
@@ -163,7 +163,7 @@ var formatLength = function(line) {
* @return {string} Formatted area. * @return {string} Formatted area.
*/ */
var formatArea = function(polygon) { var formatArea = function(polygon) {
var area = _ol_Sphere_.getArea(polygon); var area = getArea(polygon);
var output; var output;
if (area > 10000) { if (area > 10000) {
output = (Math.round(area / 1000000 * 100) / 100) + output = (Math.round(area / 1000000 * 100) / 100) +
+2 -5
View File
@@ -1,8 +1,7 @@
import _ol_Feature_ from '../src/ol/Feature.js'; import _ol_Feature_ from '../src/ol/Feature.js';
import _ol_Map_ from '../src/ol/Map.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 _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 TileLayer from '../src/ol/layer/Tile.js';
import _ol_layer_Vector_ from '../src/ol/layer/Vector.js'; import _ol_layer_Vector_ from '../src/ol/layer/Vector.js';
import _ol_source_TileWMS_ from '../src/ol/source/TileWMS.js'; import _ol_source_TileWMS_ from '../src/ol/source/TileWMS.js';
@@ -57,13 +56,11 @@ var map3857 = new _ol_Map_({
}) })
}); });
var wgs84Sphere = new _ol_Sphere_(6378137);
var radius = 800000; var radius = 800000;
var x, y; var x, y;
for (x = -180; x < 180; x += 30) { for (x = -180; x < 180; x += 30) {
for (y = -90; y < 90; y += 30) { for (y = -90; y < 90; y += 30) {
var circle4326 = Polygon.circular(wgs84Sphere, [x, y], radius, 64); var circle4326 = circularPolygon([x, y], radius, 64);
var circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857'); var circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857');
vectorLayer4326.getSource().addFeature(new _ol_Feature_(circle4326)); vectorLayer4326.getSource().addFeature(new _ol_Feature_(circle4326));
vectorLayer3857.getSource().addFeature(new _ol_Feature_(circle3857)); vectorLayer3857.getSource().addFeature(new _ol_Feature_(circle3857));
+2 -11
View File
@@ -4,14 +4,12 @@
import {inherits} from './index.js'; import {inherits} from './index.js';
import _ol_GeolocationProperty_ from './GeolocationProperty.js'; import _ol_GeolocationProperty_ from './GeolocationProperty.js';
import _ol_Object_ from './Object.js'; import _ol_Object_ from './Object.js';
import _ol_Sphere_ from './Sphere.js';
import _ol_events_ from './events.js'; import _ol_events_ from './events.js';
import EventType from './events/EventType.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 _ol_has_ from './has.js';
import {toRadians} from './math.js'; import {toRadians} from './math.js';
import {get as getProjection, getTransformFromProjections, identityTransform} from './proj.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; this.transform_ = identityTransform;
/**
* @private
* @type {ol.Sphere}
*/
this.sphere_ = new _ol_Sphere_(_ol_proj_EPSG4326_.RADIUS);
/** /**
* @private * @private
* @type {number|undefined} * @type {number|undefined}
@@ -175,8 +167,7 @@ Geolocation.prototype.positionChange_ = function(position) {
this.set(_ol_GeolocationProperty_.POSITION, projectedPosition); this.set(_ol_GeolocationProperty_.POSITION, projectedPosition);
this.set(_ol_GeolocationProperty_.SPEED, this.set(_ol_GeolocationProperty_.SPEED,
coords.speed === null ? undefined : coords.speed); coords.speed === null ? undefined : coords.speed);
var geometry = Polygon.circular( var geometry = circularPolygon(this.position_, coords.accuracy);
this.sphere_, this.position_, coords.accuracy);
geometry.applyTransform(this.transform_); geometry.applyTransform(this.transform_);
this.set(_ol_GeolocationProperty_.ACCURACY_GEOMETRY, geometry); this.set(_ol_GeolocationProperty_.ACCURACY_GEOMETRY, geometry);
this.changed(); this.changed();
+3 -3
View File
@@ -15,7 +15,7 @@ import _ol_coordinate_ from './coordinate.js';
import {inAndOut} from './easing.js'; import {inAndOut} from './easing.js';
import {getForViewAndSize, getCenter, getHeight, getWidth, isEmpty} from './extent.js'; import {getForViewAndSize, getCenter, getHeight, getWidth, isEmpty} from './extent.js';
import GeometryType from './geom/GeometryType.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 SimpleGeometry from './geom/SimpleGeometry.js';
import {clamp, modulo} from './math.js'; import {clamp, modulo} from './math.js';
import _ol_obj_ from './obj.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` 24); // Invalid extent or geometry provided as `geometry`
assert(!isEmpty(geometryOrExtent), assert(!isEmpty(geometryOrExtent),
25); // Cannot fit empty extent provided as `geometry` 25); // Cannot fit empty extent provided as `geometry`
geometry = Polygon.fromExtent(geometryOrExtent); geometry = polygonFromExtent(geometryOrExtent);
} else if (geometryOrExtent.getType() === GeometryType.CIRCLE) { } else if (geometryOrExtent.getType() === GeometryType.CIRCLE) {
geometryOrExtent = geometryOrExtent.getExtent(); geometryOrExtent = geometryOrExtent.getExtent();
geometry = Polygon.fromExtent(geometryOrExtent); geometry = polygonFromExtent(geometryOrExtent);
geometry.rotate(this.getRotation(), getCenter(geometryOrExtent)); geometry.rotate(this.getRotation(), getCenter(geometryOrExtent));
} else { } else {
geometry = geometryOrExtent; geometry = geometryOrExtent;
+15 -13
View File
@@ -9,6 +9,7 @@ import GeometryType from '../geom/GeometryType.js';
import LinearRing from '../geom/LinearRing.js'; import LinearRing from '../geom/LinearRing.js';
import Point from '../geom/Point.js'; import Point from '../geom/Point.js';
import SimpleGeometry from '../geom/SimpleGeometry.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_area_ from '../geom/flat/area.js';
import _ol_geom_flat_closest_ from '../geom/flat/closest.js'; import _ol_geom_flat_closest_ from '../geom/flat/closest.js';
import _ol_geom_flat_contains_ from '../geom/flat/contains.js'; import _ol_geom_flat_contains_ from '../geom/flat/contains.js';
@@ -366,32 +367,35 @@ Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {
this.changed(); this.changed();
}; };
export default Polygon;
/** /**
* Create an approximation of a circle on the surface of a sphere. * 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 {ol.Coordinate} center Center (`[lon, lat]` in degrees).
* @param {number} radius The great-circle distance from the center to * @param {number} radius The great-circle distance from the center to
* the polygon vertices. * the polygon vertices.
* @param {number=} opt_n Optional number of vertices for the resulting * @param {number=} opt_n Optional number of vertices for the resulting
* polygon. Default is `32`. * 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. * @return {ol.geom.Polygon} The "circular" polygon.
* @api * @api
*/ */
Polygon.circular = function(sphere, center, radius, opt_n) { export function circular(center, radius, opt_n, opt_sphereRadius) {
var n = opt_n ? opt_n : 32; var n = opt_n ? opt_n : 32;
/** @type {Array.<number>} */ /** @type {Array.<number>} */
var flatCoordinates = []; var flatCoordinates = [];
var i; var i;
for (i = 0; i < n; ++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]); flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
var polygon = new Polygon(null); var polygon = new Polygon(null);
polygon.setFlatCoordinates( polygon.setFlatCoordinates(
GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
return polygon; return polygon;
}; }
/** /**
@@ -400,7 +404,7 @@ Polygon.circular = function(sphere, center, radius, opt_n) {
* @return {ol.geom.Polygon} The polygon. * @return {ol.geom.Polygon} The polygon.
* @api * @api
*/ */
Polygon.fromExtent = function(extent) { export function fromExtent(extent) {
var minX = extent[0]; var minX = extent[0];
var minY = extent[1]; var minY = extent[1];
var maxX = extent[2]; var maxX = extent[2];
@@ -411,7 +415,7 @@ Polygon.fromExtent = function(extent) {
polygon.setFlatCoordinates( polygon.setFlatCoordinates(
GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]); GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
return polygon; return polygon;
}; }
/** /**
@@ -423,7 +427,7 @@ Polygon.fromExtent = function(extent) {
* @return {ol.geom.Polygon} Polygon geometry. * @return {ol.geom.Polygon} Polygon geometry.
* @api * @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 sides = opt_sides ? opt_sides : 32;
var stride = circle.getStride(); var stride = circle.getStride();
var layout = circle.getLayout(); var layout = circle.getLayout();
@@ -435,10 +439,9 @@ Polygon.fromCircle = function(circle, opt_sides, opt_angle) {
} }
var ends = [flatCoordinates.length]; var ends = [flatCoordinates.length];
polygon.setFlatCoordinates(layout, flatCoordinates, ends); polygon.setFlatCoordinates(layout, flatCoordinates, ends);
Polygon.makeRegular( makeRegular(polygon, circle.getCenter(), circle.getRadius(), opt_angle);
polygon, circle.getCenter(), circle.getRadius(), opt_angle);
return polygon; return polygon;
}; }
/** /**
@@ -449,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 * @param {number=} opt_angle Start angle for the first vertex of the polygon in
* radians. Default is 0. * 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 flatCoordinates = polygon.getFlatCoordinates();
var layout = polygon.getLayout(); var layout = polygon.getLayout();
var stride = polygon.getStride(); var stride = polygon.getStride();
@@ -464,5 +467,4 @@ Polygon.makeRegular = function(polygon, center, radius, opt_angle) {
flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle)); flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));
} }
polygon.setFlatCoordinates(layout, flatCoordinates, ends); polygon.setFlatCoordinates(layout, flatCoordinates, ends);
}; }
export default Polygon;
+3 -3
View File
@@ -18,7 +18,7 @@ import MultiLineString from '../geom/MultiLineString.js';
import MultiPoint from '../geom/MultiPoint.js'; import MultiPoint from '../geom/MultiPoint.js';
import MultiPolygon from '../geom/MultiPolygon.js'; import MultiPolygon from '../geom/MultiPolygon.js';
import Point from '../geom/Point.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 DrawEventType from '../interaction/DrawEventType.js';
import _ol_interaction_Pointer_ from '../interaction/Pointer.js'; import _ol_interaction_Pointer_ from '../interaction/Pointer.js';
import _ol_interaction_Property_ from '../interaction/Property.js'; import _ol_interaction_Property_ from '../interaction/Property.js';
@@ -795,10 +795,10 @@ Draw.createRegularPolygon = function(opt_sides, opt_angle) {
var radius = Math.sqrt( var radius = Math.sqrt(
_ol_coordinate_.squaredDistance(center, end)); _ol_coordinate_.squaredDistance(center, end));
var geometry = opt_geometry ? /** @type {ol.geom.Polygon} */ (opt_geometry) : 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 : var angle = opt_angle ? opt_angle :
Math.atan((end[1] - center[1]) / (end[0] - center[0])); Math.atan((end[1] - center[1]) / (end[0] - center[0]));
Polygon.makeRegular(geometry, center, radius, angle); makeRegular(geometry, center, radius, angle);
return geometry; return geometry;
} }
); );
+3 -3
View File
@@ -10,7 +10,7 @@ import Event from '../events/Event.js';
import {boundingExtent, getArea} from '../extent.js'; import {boundingExtent, getArea} from '../extent.js';
import GeometryType from '../geom/GeometryType.js'; import GeometryType from '../geom/GeometryType.js';
import Point from '../geom/Point.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_ExtentEventType_ from '../interaction/ExtentEventType.js';
import _ol_interaction_Pointer_ from '../interaction/Pointer.js'; import _ol_interaction_Pointer_ from '../interaction/Pointer.js';
import _ol_layer_Vector_ from '../layer/Vector.js'; import _ol_layer_Vector_ from '../layer/Vector.js';
@@ -376,7 +376,7 @@ _ol_interaction_Extent_.prototype.createOrUpdateExtentFeature_ = function(extent
if (!extent) { if (!extent) {
extentFeature = new _ol_Feature_({}); extentFeature = new _ol_Feature_({});
} else { } else {
extentFeature = new _ol_Feature_(Polygon.fromExtent(extent)); extentFeature = new _ol_Feature_(polygonFromExtent(extent));
} }
this.extentFeature_ = extentFeature; this.extentFeature_ = extentFeature;
this.extentOverlay_.getSource().addFeature(extentFeature); this.extentOverlay_.getSource().addFeature(extentFeature);
@@ -384,7 +384,7 @@ _ol_interaction_Extent_.prototype.createOrUpdateExtentFeature_ = function(extent
if (!extent) { if (!extent) {
extentFeature.setGeometry(undefined); extentFeature.setGeometry(undefined);
} else { } else {
extentFeature.setGeometry(Polygon.fromExtent(extent)); extentFeature.setGeometry(polygonFromExtent(extent));
} }
} }
return extentFeature; return extentFeature;
+2 -2
View File
@@ -10,7 +10,7 @@ import EventType from '../events/EventType.js';
import {boundingExtent, createEmpty} from '../extent.js'; import {boundingExtent, createEmpty} from '../extent.js';
import {TRUE, FALSE} from '../functions.js'; import {TRUE, FALSE} from '../functions.js';
import GeometryType from '../geom/GeometryType.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_interaction_Pointer_ from '../interaction/Pointer.js';
import _ol_obj_ from '../obj.js'; import _ol_obj_ from '../obj.js';
import _ol_source_Vector_ from '../source/Vector.js'; import _ol_source_Vector_ from '../source/Vector.js';
@@ -435,7 +435,7 @@ _ol_interaction_Snap_.prototype.updateFeature_ = function(feature) {
* @private * @private
*/ */
_ol_interaction_Snap_.prototype.writeCircleGeometry_ = function(feature, geometry) { _ol_interaction_Snap_.prototype.writeCircleGeometry_ = function(feature, geometry) {
var polygon = Polygon.fromCircle(geometry); var polygon = fromCircle(geometry);
var coordinates = polygon.getCoordinates()[0]; var coordinates = polygon.getCoordinates()[0];
var i, ii, segment, segmentData; var i, ii, segment, segmentData;
for (i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+3 -12
View File
@@ -1,7 +1,7 @@
/** /**
* @module ol/proj * @module ol/proj
*/ */
import Sphere from './Sphere.js'; import {getDistance} from './sphere.js';
import {applyTransform} from './extent.js'; import {applyTransform} from './extent.js';
import {modulo} from './math.js'; import {modulo} from './math.js';
import EPSG3857 from './proj/EPSG3857.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; 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.<number>} input Input coordinate array. * @param {Array.<number>} input Input coordinate array.
* @param {Array.<number>=} opt_output Output array of coordinate values. * @param {Array.<number>=} 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 point[0], point[1] + resolution / 2
]; ];
vertices = toEPSG4326(vertices, vertices, 2); vertices = toEPSG4326(vertices, vertices, 2);
var width = SPHERE.haversineDistance( var width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4));
vertices.slice(0, 2), vertices.slice(2, 4)); var height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8));
var height = SPHERE.haversineDistance(
vertices.slice(4, 6), vertices.slice(6, 8));
pointResolution = (width + height) / 2; pointResolution = (width + height) / 2;
var metersPerUnit = opt_units ? var metersPerUnit = opt_units ?
Units.METERS_PER_UNIT[opt_units] : Units.METERS_PER_UNIT[opt_units] :
+148 -197
View File
@@ -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 * @module ol/Sphere
* Latitude/longitude spherical geodesy formulae taken from
* http://www.movable-type.co.uk/scripts/latlong.html
* Licensed under CC-BY-3.0.
*/ */
import {toRadians, toDegrees} from './math.js'; import {toRadians, toDegrees} from './math.js';
import GeometryType from './geom/GeometryType.js'; import GeometryType from './geom/GeometryType.js';
/** /**
* Object literal with options for the {@link ol.Sphere.getLength} or * Object literal with options for the {@link getLength} or
* {@link ol.Sphere.getArea} functions. * {@link getArea} functions.
* @typedef {{projection: (ol.ProjectionLike|undefined), * @typedef {{projection: (ol.ProjectionLike|undefined),
* radius: (number|undefined)}} * radius: (number|undefined)}}
*/ */
export var SphereMetricOptions; 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.<ol.Coordinate>} 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. * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid.
* https://en.wikipedia.org/wiki/Earth_radius#Mean_radius * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius
* @type {number} * @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 * @param {(ol.ProjectionLike|undefined)} opt_options.projection Projection of
* the geometry. By default, the geometry is assumed to be in EPSG:3857 * the geometry. By default, the geometry is assumed to be in EPSG:3857
* (Web Mercator). * (Web Mercator).
* @param {(number|undefined)} opt_options.radius Sphere radius. By default, * @param {(number|undefined)} opt_options.radius Sphere radius. Defaults to
* the radius of the earth is used (Clarke 1866 Authalic Sphere). * the Earth's mean radius using the WGS84 ellipsoid.
* @return {number} The spherical length (in meters). * @return {number} The spherical length (in meters).
* @api * @api
*/ */
_ol_Sphere_.getLength = function(geometry, opt_options) { export function getLength(geometry, opt_options) {
var options = 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'; var projection = options.projection || 'EPSG:3857';
geometry = geometry.clone().transform(projection, 'EPSG:4326');
var type = geometry.getType(); var type = geometry.getType();
if (type !== GeometryType.GEOMETRY_COLLECTION) {
geometry = geometry.clone().transform(projection, 'EPSG:4326');
}
var length = 0; var length = 0;
var coordinates, coords, i, ii, j, jj; var coordinates, coords, i, ii, j, jj;
switch (type) { switch (type) {
@@ -143,14 +101,14 @@ _ol_Sphere_.getLength = function(geometry, opt_options) {
case GeometryType.LINE_STRING: case GeometryType.LINE_STRING:
case GeometryType.LINEAR_RING: { case GeometryType.LINEAR_RING: {
coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
length = _ol_Sphere_.getLength_(coordinates, radius); length = getLengthInternal(coordinates, radius);
break; break;
} }
case GeometryType.MULTI_LINE_STRING: case GeometryType.MULTI_LINE_STRING:
case GeometryType.POLYGON: { case GeometryType.POLYGON: {
coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates(); coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
for (i = 0, ii = coordinates.length; i < ii; ++i) { for (i = 0, ii = coordinates.length; i < ii; ++i) {
length += _ol_Sphere_.getLength_(coordinates[i], radius); length += getLengthInternal(coordinates[i], radius);
} }
break; break;
} }
@@ -159,7 +117,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) {
for (i = 0, ii = coordinates.length; i < ii; ++i) { for (i = 0, ii = coordinates.length; i < ii; ++i) {
coords = coordinates[i]; coords = coordinates[i];
for (j = 0, jj = coords.length; j < jj; ++j) { for (j = 0, jj = coords.length; j < jj; ++j) {
length += _ol_Sphere_.getLength_(coords[j], radius); length += getLengthInternal(coords[j], radius);
} }
} }
break; break;
@@ -167,7 +125,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) {
case GeometryType.GEOMETRY_COLLECTION: { case GeometryType.GEOMETRY_COLLECTION: {
var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries(); var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();
for (i = 0, ii = geometries.length; i < ii; ++i) { for (i = 0, ii = geometries.length; i < ii; ++i) {
length += _ol_Sphere_.getLength(geometries[i], opt_options); length += getLength(geometries[i], opt_options);
} }
break; break;
} }
@@ -176,101 +134,7 @@ _ol_Sphere_.getLength = function(geometry, opt_options) {
} }
} }
return length; 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. * @param {number} radius The sphere radius.
* @return {number} Area (in square meters). * @return {number} Area (in square meters).
*/ */
_ol_Sphere_.getArea_ = function(coordinates, radius) { function getAreaInternal(coordinates, radius) {
var area = 0, len = coordinates.length; var area = 0, len = coordinates.length;
var x1 = coordinates[len - 1][0]; var x1 = coordinates[len - 1][0];
var y1 = coordinates[len - 1][1]; var y1 = coordinates[len - 1][1];
@@ -300,5 +164,92 @@ _ol_Sphere_.getArea_ = function(coordinates, radius) {
y1 = y2; y1 = y2;
} }
return area * radius * radius / 2.0; 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)];
}
+7 -7
View File
@@ -1,10 +1,10 @@
import * as _ol_extent_ from '../../../../src/ol/extent.js'; import * as _ol_extent_ from '../../../../src/ol/extent.js';
import Circle from '../../../../src/ol/geom/Circle.js'; import Circle from '../../../../src/ol/geom/Circle.js';
import LinearRing from '../../../../src/ol/geom/LinearRing.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() { it('can be constructed with a null geometry', function() {
expect(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() { it('creates the correct polygon', function() {
var extent = [1, 2, 3, 5]; var extent = [1, 2, 3, 5];
var polygon = Polygon.fromExtent(extent); var polygon = fromExtent(extent);
var flatCoordinates = polygon.getFlatCoordinates(); var flatCoordinates = polygon.getFlatCoordinates();
expect(flatCoordinates).to.eql( expect(flatCoordinates).to.eql(
[1, 2, 1, 5, 3, 5, 3, 2, 1, 2]); [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() { it('creates a regular polygon', function() {
var circle = new Circle([0, 0, 0], 1, 'XYZ'); var circle = new Circle([0, 0, 0], 1, 'XYZ');
var polygon = Polygon.fromCircle(circle); var polygon = fromCircle(circle);
var coordinates = polygon.getLinearRing(0).getCoordinates(); var coordinates = polygon.getLinearRing(0).getCoordinates();
expect(coordinates[0].length).to.eql(3); expect(coordinates[0].length).to.eql(3);
expect(coordinates[0][2]).to.eql(0); 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() { it('creates a regular polygon with custom sides and angle', function() {
var circle = new Circle([0, 0], 1); 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(); var coordinates = polygon.getLinearRing(0).getCoordinates();
expect(coordinates[4]).to.eql(coordinates[0]); expect(coordinates[4]).to.eql(coordinates[0]);
expect(coordinates[0][0]).to.roughlyEqual(0, 1e-9); expect(coordinates[0][0]).to.roughlyEqual(0, 1e-9);
+3 -3
View File
@@ -1,7 +1,7 @@
import _ol_Map_ from '../../../../src/ol/Map.js'; import _ol_Map_ from '../../../../src/ol/Map.js';
import _ol_View_ from '../../../../src/ol/View.js'; import _ol_View_ from '../../../../src/ol/View.js';
import * as _ol_extent_ from '../../../../src/ol/extent.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 DragZoom from '../../../../src/ol/interaction/DragZoom.js';
import _ol_layer_Vector_ from '../../../../src/ol/layer/Vector.js'; import _ol_layer_Vector_ from '../../../../src/ol/layer/Vector.js';
import _ol_render_Box_ from '../../../../src/ol/render/Box.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 box = new _ol_render_Box_();
var extent = [-110, 40, -90, 60]; var extent = [-110, 40, -90, 60];
box.geometry_ = Polygon.fromExtent(extent); box.geometry_ = polygonFromExtent(extent);
interaction.box_ = box; interaction.box_ = box;
interaction.onBoxEnd(); interaction.onBoxEnd();
@@ -94,7 +94,7 @@ describe('ol.interaction.DragZoom', function() {
var box = new _ol_render_Box_(); var box = new _ol_render_Box_();
var extent = [-11.25, -11.25, 11.25, 11.25]; var extent = [-11.25, -11.25, 11.25, 11.25];
box.geometry_ = Polygon.fromExtent(extent); box.geometry_ = polygonFromExtent(extent);
interaction.box_ = box; interaction.box_ = box;
map.getView().setResolution(0.25); map.getView().setResolution(0.25);
+171 -171
View File
@@ -1,97 +1,173 @@
// See http://www.movable-type.co.uk/scripts/latlong.html import {getArea, getDistance, getLength} from '../../../src/ol/sphere.js';
// FIXME add tests for offset
import _ol_Sphere_ from '../../../src/ol/Sphere.js';
import WKT from '../../../src/ol/format/WKT.js'; import WKT from '../../../src/ol/format/WKT.js';
import GeometryCollection from '../../../src/ol/geom/GeometryCollection.js'; import GeometryCollection from '../../../src/ol/geom/GeometryCollection.js';
import LineString from '../../../src/ol/geom/LineString.js'; import LineString from '../../../src/ol/geom/LineString.js';
import MultiLineString from '../../../src/ol/geom/MultiLineString.js'; import MultiLineString from '../../../src/ol/geom/MultiLineString.js';
import MultiPoint from '../../../src/ol/geom/MultiPoint.js'; import MultiPoint from '../../../src/ol/geom/MultiPoint.js';
import Point from '../../../src/ol/geom/Point.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); describe('getDistance()', function() {
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('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() { expected.forEach(function(e, i) {
var e, i; it('calculates the distance between two points: ' + i, function() {
for (i = 0; i < expected.length; ++i) { expect(getDistance(e.c1, e.c2)).to.roughlyEqual(e.distance, 1e-6);
e = expected[i]; });
expect(sphere.haversineDistance(e.c1, e.c2)).to.roughlyEqual( });
e.haversineDistance, 1e-9); });
}
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 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],
[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; var geometry;
var expectedArea = 145652224192.4434;
before(function(done) { before(function(done) {
afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) { afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) {
try { try {
@@ -104,100 +180,24 @@ describe('ol.Sphere', function() {
}); });
}); });
it('results match the expected area of Ilinois', function() { it('calculates the area of Ilinois', function() {
var coords = geometry.getPolygon(0).getLinearRing(0).getCoordinates(); var area = getArea(geometry, {projection: 'EPSG:4326'});
var sphere = new _ol_Sphere_(_ol_proj_EPSG4326_.RADIUS); expect(area).to.equal(expectedArea);
expect(sphere.geodesicArea(coords)).to.equal(145978332359.37125);
}); });
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);
});
}); });
}); });
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);
});
});