Replace ol/Sphere with ol/sphere

This commit is contained in:
Tim Schaub
2017-12-20 08:44:01 -08:00
parent 43342cd133
commit 54b8622114
9 changed files with 330 additions and 402 deletions

View File

@@ -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).

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Measure
shortdesc: Using a draw interaction to measure lengths and areas.
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
calculated by assuming great circle segments between geometry coordinates.
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
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 <code>ol.Sphere</code>.</p>
use the functions in the <code>ol/sphere</code> module.</p>
tags: "draw, edit, measure, vector"
---
<div id="map" class="map"></div>

View File

@@ -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) +

View File

@@ -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));

View File

@@ -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();

View File

@@ -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.<number>} */
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);

View File

@@ -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.<number>} input Input coordinate array.
* @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
];
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] :

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
* 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.<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.
* 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)];
}

View File

@@ -1,119 +1,86 @@
// 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() {
describe('getDistance()', function() {
var sphere = new _ol_Sphere_(6371);
var expected = [{
c1: [0, 0],
c2: [0, 0],
haversineDistance: 0
distance: 0
}, {
c1: [0, 0],
c2: [45, 45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [0, 0],
c2: [-45, 45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [0, 0],
c2: [-45, -45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [0, 0],
c2: [45, -45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [45, 45],
c2: [45, 45],
haversineDistance: 0
distance: 0
}, {
c1: [45, 45],
c2: [-45, 45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [45, 45],
c2: [-45, -45],
haversineDistance: 13343.391197347048
distance: 13343409.628023949
}, {
c1: [45, 45],
c2: [45, -45],
haversineDistance: 10007.543398010286
distance: 10007557.221017962
}, {
c1: [-45, 45],
c2: [-45, 45],
haversineDistance: 0
distance: 0
}, {
c1: [-45, 45],
c2: [-45, -45],
haversineDistance: 10007.543398010286
distance: 10007557.221017962
}, {
c1: [-45, 45],
c2: [45, -45],
haversineDistance: 13343.391197347048
distance: 13343409.628023949
}, {
c1: [-45, -45],
c2: [-45, -45],
haversineDistance: 0
distance: 0
}, {
c1: [-45, -45],
c2: [45, -45],
haversineDistance: 6671.695598673525
distance: 6671704.814011975
}, {
c1: [45, -45],
c2: [45, -45],
haversineDistance: 0
distance: 0
}];
describe('haversineDistance', function() {
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('Vincenty area', 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('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);
});
});
});
describe('ol.Sphere.getLength()', function() {
describe('getLength()', function() {
var cases = [{
geometry: new Point([0, 0]),
length: 0
@@ -175,14 +142,14 @@ describe('ol.Sphere.getLength()', function() {
cases.forEach(function(c, i) {
it('works for case ' + i, function() {
var c = cases[i];
var length = _ol_Sphere_.getLength(c.geometry, c.options);
var length = getLength(c.geometry, c.options);
expect(length).to.roughlyEqual(c.length, 1e-8);
});
});
});
});
describe('ol.Sphere.getArea()', function() {
describe('getArea()', function() {
var geometry;
before(function(done) {
afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) {
@@ -197,7 +164,9 @@ describe('ol.Sphere.getArea()', function() {
});
it('calculates the area of Ilinois', function() {
var area = _ol_Sphere_.getArea(geometry, {projection: 'EPSG:4326'});
var area = getArea(geometry, {projection: 'EPSG:4326'});
expect(area).to.equal(145652224192.4434);
});
});
});