diff --git a/examples/measure.html b/examples/measure.html index 2a1773f053..0341173c75 100644 --- a/examples/measure.html +++ b/examples/measure.html @@ -75,10 +75,11 @@ +
-

NOTE: Measure is done in simple way on projected plane. Earth +

NOTE: If use geodesic measures is not checked, measure is done in simple way on projected plane. Earth curvature is not taken into account

See the measure.js source to see how this is done.

diff --git a/examples/measure.js b/examples/measure.js index 127eeaf275..c437e778c2 100644 --- a/examples/measure.js +++ b/examples/measure.js @@ -1,5 +1,6 @@ goog.require('ol.Map'); goog.require('ol.Overlay'); +goog.require('ol.Sphere'); goog.require('ol.View'); goog.require('ol.geom.LineString'); goog.require('ol.geom.Polygon'); @@ -7,6 +8,7 @@ goog.require('ol.interaction'); goog.require('ol.interaction.Draw'); goog.require('ol.layer.Tile'); goog.require('ol.layer.Vector'); +goog.require('ol.proj'); goog.require('ol.source.MapQuest'); goog.require('ol.source.Vector'); goog.require('ol.style.Circle'); @@ -14,6 +16,9 @@ goog.require('ol.style.Fill'); goog.require('ol.style.Stroke'); goog.require('ol.style.Style'); + +var wgs84Sphere = new ol.Sphere(6378137); + var raster = new ol.layer.Tile({ source: new ol.source.MapQuest({layer: 'sat'}) }); @@ -135,6 +140,7 @@ var map = new ol.Map({ map.on('pointermove', pointerMoveHandler); var typeSelect = document.getElementById('type'); +var geodesicCheckbox = document.getElementById('geodesic'); var draw; // global so we can remove it later function addInteraction() { @@ -238,7 +244,19 @@ typeSelect.onchange = function(e) { * @return {string} */ var formatLength = function(line) { - var length = Math.round(line.getLength() * 100) / 100; + var length; + if (geodesicCheckbox.checked) { + var coordinates = line.getCoordinates(); + length = 0; + var sourceProj = map.getView().getProjection(); + for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) { + var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326'); + var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326'); + length += wgs84Sphere.haversineDistance(c1, c2); + } + } else { + length = Math.round(line.getLength() * 100) / 100; + } var output; if (length > 100) { output = (Math.round(length / 1000 * 100) / 100) + @@ -257,7 +275,16 @@ var formatLength = function(line) { * @return {string} */ var formatArea = function(polygon) { - var area = polygon.getArea(); + var area; + if (geodesicCheckbox.checked) { + var sourceProj = map.getView().getProjection(); + var geom = /** @type {ol.geom.Polygon} */(polygon.clone().transform( + sourceProj, 'EPSG:4326')); + var coordinates = geom.getLinearRing(0).getCoordinates(); + area = Math.abs(wgs84Sphere.geodesicArea(coordinates)); + } else { + area = polygon.getArea(); + } var output; if (area > 10000) { output = (Math.round(area / 1000000 * 100) / 100) + diff --git a/src/ol/sphere/sphere.js b/src/ol/sphere/sphere.js index 7dd37905d8..f192cb6187 100644 --- a/src/ol/sphere/sphere.js +++ b/src/ol/sphere/sphere.js @@ -57,6 +57,36 @@ ol.Sphere.prototype.cosineDistance = function(c1, c2) { }; +/** + * Returns the geodesic area for a list of coordinates. + * + * [Reference](http://trs-new.jpl.nasa.gov/dspace/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) { + var area = 0, len = coordinates.length; + var x1 = coordinates[len - 1][0]; + var y1 = coordinates[len - 1][1]; + for (var i = 0; i < len; i++) { + var x2 = coordinates[i][0], y2 = coordinates[i][1]; + area += goog.math.toRadians(x2 - x1) * + (2 + Math.sin(goog.math.toRadians(y1)) + + Math.sin(goog.math.toRadians(y2))); + x1 = x2; + y1 = y2; + } + return area * this.radius * this.radius / 2.0; +}; + + /** * Returns the distance of c3 from the great circle path defined by c1 and c2. * @@ -110,6 +140,7 @@ ol.Sphere.prototype.finalBearing = function(c1, c2) { * @param {ol.Coordinate} c1 Coordinate 1. * @param {ol.Coordinate} c2 Coordinate 2. * @return {number} Haversine distance. + * @api */ ol.Sphere.prototype.haversineDistance = function(c1, c2) { var lat1 = goog.math.toRadians(c1[1]); diff --git a/test/spec/ol/format/wkt/illinois.wkt b/test/spec/ol/format/wkt/illinois.wkt new file mode 100644 index 0000000000..581a1eb833 --- /dev/null +++ b/test/spec/ol/format/wkt/illinois.wkt @@ -0,0 +1 @@ +MULTIPOLYGON(((-88.071564 37.51099,-88.087883 37.476273,-88.311707 37.442852,-88.359177 37.409309,-88.419853 37.420292,-88.467644 37.400757,-88.511322 37.296852,-88.501427 37.257782,-88.450699 37.205669,-88.422516 37.15691,-88.45047 37.098671,-88.476799 37.072144,-88.4907 37.06818,-88.517273 37.06477,-88.559273 37.072815,-88.61422 37.109047,-88.68837 37.13541,-88.739113 37.141182,-88.746506 37.152107,-88.863289 37.202194,-88.932503 37.218407,-88.993172 37.220036,-89.065033 37.18586,-89.116821 37.112137,-89.146347 37.093185,-89.169548 37.064236,-89.174332 37.025711,-89.150246 36.99844,-89.12986 36.988113,-89.193512 36.986771,-89.210052 37.028973,-89.237679 37.041733,-89.264053 37.087124,-89.284233 37.091244,-89.303291 37.085384,-89.3097 37.060909,-89.264244 37.027733,-89.262001 37.008686,-89.282768 36.999207,-89.310982 37.009682,-89.38295 37.049213,-89.37999 37.099083,-89.423798 37.137203,-89.440521 37.165318,-89.468216 37.224266,-89.465309 37.253731,-89.489594 37.256001,-89.513885 37.276402,-89.513885 37.304962,-89.50058 37.329441,-89.468742 37.339409,-89.435738 37.355717,-89.427574 37.411018,-89.453621 37.453186,-89.494781 37.491726,-89.524971 37.571957,-89.513367 37.615929,-89.51918 37.650375,-89.513374 37.67984,-89.521523 37.694798,-89.581436 37.706104,-89.666458 37.745453,-89.675858 37.78397,-89.691055 37.804794,-89.728447 37.840992,-89.851715 37.905064,-89.861046 37.905487,-89.866814 37.891876,-89.900551 37.875904,-89.937874 37.878044,-89.978912 37.911884,-89.958229 37.963634,-90.010811 37.969318,-90.041924 37.993206,-90.119339 38.032272,-90.134712 38.053951,-90.207527 38.088905,-90.254059 38.122169,-90.289635 38.166817,-90.336716 38.188713,-90.364769 38.234299,-90.369347 38.323559,-90.358688 38.36533,-90.339607 38.390846,-90.301842 38.427357,-90.265785 38.518688,-90.26123 38.532768,-90.240944 38.562805,-90.183708 38.610271,-90.183578 38.658772,-90.20224 38.700363,-90.196571 38.723965,-90.163399 38.773098,-90.135178 38.785484,-90.121727 38.80051,-90.113121 38.830467,-90.132812 38.853031,-90.243927 38.914509,-90.278931 38.924717,-90.31974 38.924908,-90.413071 38.96233,-90.469841 38.959179,-90.530426 38.891609,-90.570328 38.871326,-90.627213 38.880795,-90.668877 38.935253,-90.70607 39.037792,-90.707588 39.058178,-90.690399 39.0937,-90.716736 39.144211,-90.718193 39.195873,-90.732338 39.224747,-90.738083 39.24781,-90.779343 39.296803,-90.850494 39.350452,-90.947891 39.400585,-91.036339 39.444412,-91.064384 39.473984,-91.093613 39.528927,-91.156189 39.552593,-91.203247 39.600021,-91.317665 39.685917,-91.367088 39.72464,-91.373421 39.761272,-91.381714 39.803772,-91.449188 39.863049,-91.450989 39.885242,-91.434052 39.901829,-91.430389 39.921837,-91.447243 39.946064,-91.487289 40.005753,-91.504005 40.066711,-91.516129 40.134544,-91.506546 40.200459,-91.498932 40.251377,-91.486694 40.309624,-91.448593 40.371902,-91.418816 40.386875,-91.385757 40.392361,-91.372757 40.402988,-91.385399 40.44725,-91.374794 40.503654,-91.382103 40.528496,-91.412872 40.547993,-91.411118 40.572971,-91.37561 40.603439,-91.262062 40.639545,-91.214912 40.643818,-91.162498 40.656311,-91.129158 40.682148,-91.119987 40.705402,-91.092751 40.761547,-91.088905 40.833729,-91.04921 40.879585,-90.983276 40.923927,-90.960709 40.950504,-90.954651 41.070362,-90.957787 41.104359,-90.990341 41.144371,-91.018257 41.165825,-91.05632 41.176258,-91.101524 41.231522,-91.102348 41.267818,-91.07328 41.334896,-91.055786 41.401379,-91.027489 41.423508,-91.000694 41.431084,-90.949654 41.421234,-90.844139 41.444622,-90.7799 41.449821,-90.708214 41.450062,-90.658791 41.462318,-90.6007 41.509586,-90.54084 41.52597,-90.454994 41.527546,-90.434967 41.543579,-90.423004 41.567272,-90.348366 41.586849,-90.339348 41.602798,-90.341133 41.64909,-90.326027 41.722736,-90.304886 41.756466,-90.25531 41.781738,-90.195839 41.806137,-90.154518 41.930775,-90.14267 41.983963,-90.150536 42.033428,-90.168098 42.061043,-90.166649 42.103745,-90.176086 42.120502,-90.191574 42.122688,-90.230934 42.159721,-90.323601 42.197319,-90.367729 42.210209,-90.407173 42.242645,-90.417984 42.263924,-90.427681 42.340633,-90.441597 42.360073,-90.491043 42.388783,-90.563583 42.421837,-90.605827 42.46056,-90.648346 42.475643,-90.651772 42.494698,-90.638329 42.509361,-90.419975 42.508362,-89.923569 42.504108,-89.834618 42.50346,-89.400497 42.49749,-89.359444 42.497906,-88.939079 42.490864,-88.764954 42.490906,-88.70652 42.489655,-88.297897 42.49197,-88.194702 42.489613,-87.79731 42.489132,-87.836945 42.314213,-87.760239 42.156456,-87.670547 42.059822,-87.612625 41.847332,-87.529861 41.723591,-87.532646 41.469715,-87.532448 41.301304,-87.531731 41.173756,-87.532021 41.00993,-87.532669 40.745411,-87.53717 40.49461,-87.535675 40.483246,-87.535339 40.166195,-87.535774 39.887302,-87.535576 39.609341,-87.538567 39.477448,-87.540215 39.350525,-87.597664 39.338268,-87.625237 39.307404,-87.610619 39.297661,-87.615799 39.281418,-87.606895 39.258163,-87.584564 39.248753,-87.588593 39.208466,-87.594208 39.198128,-87.607925 39.196068,-87.644257 39.168507,-87.670326 39.146679,-87.659454 39.130653,-87.662262 39.113468,-87.631668 39.103943,-87.630867 39.088974,-87.612007 39.084606,-87.58532 39.062435,-87.581749 38.995743,-87.591858 38.994083,-87.547905 38.977077,-87.53347 38.963703,-87.530182 38.931919,-87.5392 38.904861,-87.559059 38.869812,-87.550507 38.857891,-87.507889 38.795559,-87.519028 38.776699,-87.508003 38.769722,-87.508316 38.736633,-87.543892 38.685974,-87.588478 38.672169,-87.625191 38.642811,-87.628647 38.622917,-87.619827 38.599209,-87.640594 38.593178,-87.652855 38.573872,-87.672943 38.547424,-87.65139 38.515369,-87.653534 38.500443,-87.679909 38.504005,-87.692818 38.481533,-87.756096 38.466125,-87.758659 38.457096,-87.738953 38.44548,-87.748428 38.417965,-87.784019 38.378124,-87.834503 38.352524,-87.850082 38.286098,-87.863007 38.285362,-87.874039 38.316788,-87.883446 38.315552,-87.888466 38.300659,-87.914108 38.281048,-87.913651 38.302345,-87.925919 38.304771,-87.980019 38.241085,-87.986008 38.234814,-87.977928 38.200714,-87.932289 38.171131,-87.931992 38.157528,-87.950569 38.136913,-87.973503 38.13176,-88.018547 38.103302,-88.012329 38.092346,-87.964867 38.096748,-87.975296 38.073307,-88.034729 38.054085,-88.043091 38.04512,-88.041473 38.038303,-88.021698 38.033531,-88.029213 38.008236,-88.021706 37.975056,-88.042511 37.956264,-88.041771 37.934498,-88.064621 37.929783,-88.078941 37.944,-88.084 37.92366,-88.030441 37.917591,-88.026588 37.905758,-88.044868 37.896004,-88.100082 37.90617,-88.101456 37.895306,-88.075737 37.867809,-88.034241 37.843746,-88.042137 37.827522,-88.089264 37.831249,-88.086029 37.817612,-88.035576 37.805683,-88.072472 37.735401,-88.133636 37.700745,-88.15937 37.660686,-88.157631 37.628479,-88.134171 37.583572,-88.071564 37.51099))) diff --git a/test/spec/ol/sphere/sphere.test.js b/test/spec/ol/sphere/sphere.test.js index 63ee5434a6..465a42bcbe 100644 --- a/test/spec/ol/sphere/sphere.test.js +++ b/test/spec/ol/sphere/sphere.test.js @@ -264,8 +264,30 @@ describe('ol.Sphere', function() { }); + describe('Vincenty area', function() { + var geometry; + before(function(done) { + afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) { + try { + var format = new ol.format.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(); + expect(ol.sphere.WGS84.geodesicArea(coords)).to.equal(145978332359.37125); + }); + }); + }); goog.require('goog.math'); goog.require('ol.Sphere'); +goog.require('ol.sphere.WGS84'); +goog.require('ol.format.WKT');