Adding methods for getting geodesic measures from geometries. Assuming geometries can be transformed into Geographic/WGS84, getGeodesicLength and getGeodesicArea should return reasonable 'on the ground' metrics. Use getLength and getArea for the planar metrics. r=crschmidt (closes #1819)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@9248 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -56,6 +56,14 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
|
||||
*/
|
||||
displaySystem: 'metric',
|
||||
|
||||
/**
|
||||
* Property: geodesic
|
||||
* {Boolean} Calculate geodesic metrics instead of planar metrics. This
|
||||
* requires that geometries can be transformed into Geographic/WGS84
|
||||
* (if that is not already the map projection). Default is false.
|
||||
*/
|
||||
geodesic: false,
|
||||
|
||||
/**
|
||||
* Property: displaySystemUnits
|
||||
* {Object} Units for various measurement systems. Values are arrays
|
||||
@@ -213,10 +221,17 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
|
||||
* {Float} The geometry area in the given units.
|
||||
*/
|
||||
getArea: function(geometry, units) {
|
||||
var area = geometry.getArea();
|
||||
var area, geomUnits;
|
||||
if(this.geodesic) {
|
||||
area = geometry.getGeodesicArea(this.map.getProjectionObject());
|
||||
geomUnits = "m";
|
||||
} else {
|
||||
area = geometry.getArea();
|
||||
geomUnits = this.map.getUnits();
|
||||
}
|
||||
var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
|
||||
if(inPerDisplayUnit) {
|
||||
var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[this.map.getUnits()];
|
||||
var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
|
||||
area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
|
||||
}
|
||||
return area;
|
||||
@@ -257,10 +272,17 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
|
||||
* {Float} The geometry length in the given units.
|
||||
*/
|
||||
getLength: function(geometry, units) {
|
||||
var length = geometry.getLength();
|
||||
var length, geomUnits;
|
||||
if(this.geodesic) {
|
||||
length = geometry.getGeodesicLength(this.map.getProjectionObject());
|
||||
geomUnits = "m";
|
||||
} else {
|
||||
length = geometry.getLength();
|
||||
geomUnits = this.map.getUnits();
|
||||
}
|
||||
var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
|
||||
if(inPerDisplayUnit) {
|
||||
var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[this.map.getUnits()];
|
||||
var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
|
||||
length *= (inPerMapUnit / inPerDisplayUnit);
|
||||
}
|
||||
return length;
|
||||
|
||||
@@ -231,6 +231,52 @@ OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, {
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getGeodesicArea
|
||||
* Calculate the approximate area of the polygon were it projected onto
|
||||
* the earth.
|
||||
*
|
||||
* Parameters:
|
||||
* projection - {<OpenLayers.Projection>} The spatial reference system
|
||||
* for the geometry coordinates. If not provided, Geographic/WGS84 is
|
||||
* assumed.
|
||||
*
|
||||
* Reference:
|
||||
* 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 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
|
||||
*
|
||||
* Returns:
|
||||
* {float} The approximate geodesic area of the geometry in square meters.
|
||||
*/
|
||||
getGeodesicArea: function(projection) {
|
||||
var area = 0.0;
|
||||
for(var i=0, len=this.components.length; i<len; i++) {
|
||||
area += this.components[i].getGeodesicArea(projection);
|
||||
}
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getGeodesicLength
|
||||
* Calculate the approximate length of the geometry were it projected onto
|
||||
* the earth.
|
||||
*
|
||||
* projection - {<OpenLayers.Projection>} The spatial reference system
|
||||
* for the geometry coordinates. If not provided, Geographic/WGS84 is
|
||||
* assumed.
|
||||
*
|
||||
* Returns:
|
||||
* {Float} The appoximate geodesic length of the geometry in meters.
|
||||
*/
|
||||
getGeodesicLength: function(projection) {
|
||||
var length = 0.0;
|
||||
for(var i=0, len=this.components.length; i<len; i++) {
|
||||
length += this.components[i].getGeodesicLength(projection);
|
||||
}
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: move
|
||||
* Moves a geometry by the given displacement along positive x and y axes.
|
||||
|
||||
@@ -52,5 +52,41 @@ OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, {
|
||||
return length;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getGeodesicLength
|
||||
* Calculate the approximate length of the geometry were it projected onto
|
||||
* the earth.
|
||||
*
|
||||
* projection - {<OpenLayers.Projection>} The spatial reference system
|
||||
* for the geometry coordinates. If not provided, Geographic/WGS84 is
|
||||
* assumed.
|
||||
*
|
||||
* Returns:
|
||||
* {Float} The appoximate geodesic length of the geometry in meters.
|
||||
*/
|
||||
getGeodesicLength: function(projection) {
|
||||
var geom = this; // so we can work with a clone if needed
|
||||
if(projection) {
|
||||
var gg = new OpenLayers.Projection("EPSG:4326");
|
||||
if(!gg.equals(projection)) {
|
||||
geom = this.clone().transform(projection, gg);
|
||||
}
|
||||
}
|
||||
var length = 0.0;
|
||||
if(geom.components && (geom.components.length > 1)) {
|
||||
var p1, p2;
|
||||
for(var i=1, len=geom.components.length; i<len; i++) {
|
||||
p1 = geom.components[i-1];
|
||||
p2 = geom.components[i];
|
||||
// this returns km and requires lon/lat properties
|
||||
length += OpenLayers.Util.distVincenty(
|
||||
{lon: p1.x, lat: p1.y}, {lon: p2.x, lat: p2.y}
|
||||
);
|
||||
}
|
||||
}
|
||||
// convert to m
|
||||
return length * 1000;
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Geometry.Curve"
|
||||
});
|
||||
|
||||
@@ -205,6 +205,50 @@ OpenLayers.Geometry.LinearRing = OpenLayers.Class(
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getGeodesicArea
|
||||
* Calculate the approximate area of the polygon were it projected onto
|
||||
* the earth. Note that this area will be positive if ring is oriented
|
||||
* clockwise, otherwise it will be negative.
|
||||
*
|
||||
* Parameters:
|
||||
* projection - {<OpenLayers.Projection>} The spatial reference system
|
||||
* for the geometry coordinates. If not provided, Geographic/WGS84 is
|
||||
* assumed.
|
||||
*
|
||||
* Reference:
|
||||
* 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 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
|
||||
*
|
||||
* Returns:
|
||||
* {float} The approximate signed geodesic area of the polygon in square
|
||||
* meters.
|
||||
*/
|
||||
getGeodesicArea: function(projection) {
|
||||
var ring = this; // so we can work with a clone if needed
|
||||
if(projection) {
|
||||
var gg = new OpenLayers.Projection("EPSG:4326");
|
||||
if(!gg.equals(projection)) {
|
||||
ring = this.clone().transform(projection, gg);
|
||||
}
|
||||
}
|
||||
var area = 0.0;
|
||||
var len = ring.components && ring.components.length;
|
||||
if(len > 2) {
|
||||
var p1, p2;
|
||||
for(var i=0; i<len-1; i++) {
|
||||
p1 = ring.components[i];
|
||||
p2 = ring.components[i+1];
|
||||
area += OpenLayers.Util.rad(p2.x - p1.x) *
|
||||
(2 + Math.sin(OpenLayers.Util.rad(p1.y)) +
|
||||
Math.sin(OpenLayers.Util.rad(p2.y)));
|
||||
}
|
||||
area = area * 6378137.0 * 6378137.0 / 2.0;
|
||||
}
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: containsPoint
|
||||
* Test if a point is inside a linear ring. For the case where a point
|
||||
|
||||
@@ -60,6 +60,35 @@ OpenLayers.Geometry.Polygon = OpenLayers.Class(
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: getGeodesicArea
|
||||
* Calculate the approximate area of the polygon were it projected onto
|
||||
* the earth.
|
||||
*
|
||||
* Parameters:
|
||||
* projection - {<OpenLayers.Projection>} The spatial reference system
|
||||
* for the geometry coordinates. If not provided, Geographic/WGS84 is
|
||||
* assumed.
|
||||
*
|
||||
* Reference:
|
||||
* 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 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
|
||||
*
|
||||
* Returns:
|
||||
* {float} The approximate geodesic area of the polygon in square meters.
|
||||
*/
|
||||
getGeodesicArea: function(projection) {
|
||||
var area = 0.0;
|
||||
if(this.components && (this.components.length > 0)) {
|
||||
area += Math.abs(this.components[0].getGeodesicArea(projection));
|
||||
for(var i=1, len=this.components.length; i<len; i++) {
|
||||
area -= Math.abs(this.components[i].getGeodesicArea(projection));
|
||||
}
|
||||
}
|
||||
return area;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: containsPoint
|
||||
* Test if a point is inside a polygon. Points on a polygon edge are
|
||||
|
||||
Reference in New Issue
Block a user