通常地圖量算指的是距離量算和麪積量算。git
在線的各種地圖也都提供了純客戶端的地圖量算——不須要和服務器交互,技術上用三角函數就能夠,雖然本文也討論這個話題,可是會比較下適用於不一樣狀況的量算。github
簡單事情簡單作:直接計算地圖座標系的距離和麪積。貼OpenLayers的代碼。算法
線段距離量算:服務器
getLength: function() {
var length = 0.0;
if ( this.components && (this.components.length > 1)) {
for(var i=1, len=this.components.length; i<len; i++) {
length += this.components[i-1].distanceTo(this.components[i]);
}
}
return length;
}
經過節點間的距離和,獲得距離長度,而兩點間的距離計算,a2+b2=c2的三角函數再熟悉不過了。函數
多邊形面積量算:ui
getArea: function() {
var area = 0.0;
if ( this.components && (this.components.length > 2)) {
var sum = 0.0;
for (var i=0, len=this.components.length; i<len - 1; i++) {
var b = this.components[i];
var c = this.components[i+1];
sum += (b.x + c.x) * (c.y - b.y);
}
area = - sum / 2.0;
}
return area;
}
有了以上的公式,就能完成基本的客戶端量算功能了。 this
如今出現了一個問題,這種基於地圖的量算準確嗎?碰到了經緯度地圖的話結果難道是度爲單位?spa
因爲地圖是通過地圖投影以後顯示到二維座標系上的,因此地圖上兩點之間的直線映射到地球球面以後,可能就不是兩點之間的最短距離了(固然若是地圖自己是等角投影就沒問題了,這裏就再也不深刻討論有關投影的知識了),偏差產生了。這個偏差對科學研究很重要,但對於咱們平常生活來講,可能並不重要,爲何呢?一般咱們的測距、測面積都是在城市級別,甚至只是在街道級別,那麼這相對投影所帶來的地圖變形來講,微不足道,所以若是是這方面的應用,那麼以上的測距和測面積的算法足夠用了。可是,若是非要更加精確的計算結果該如何辦?下面就講講在客戶端實現近似精確的計算方法:component
測地距離,摘自OpenLayers:orm
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;
}
考慮到投影的問題,首先要對目標幾何對象作投影轉換,轉換爲EPSG:4326,而後基於該大地參考系,計算兩點間的球面距離,相比於非測地距離量算,這裏的重點是在一個特定的大地參考系下計算兩點或多點的球面距離,所以結果也更加精確。
測地面積,摘自OpenLayers:
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;
}
一樣的,首先對目標幾何對象作投影轉換,轉成咱們所熟知的EPSG:4326,而後再計算球面面積。球面面積計算也不一樣於平面多邊形的面積計算,須要立體幾何的知識了,呵呵。
通常,這種計算更適合在經緯度地圖中使用,普通的米制投影地圖可使用簡單的方法,城市級的量算偏差基本能夠忽略。固然,也不能排除對距離和麪積特別敏感的案例,以前也接觸過一些在通訊領域的案例,最終使用了後面這種測地算法。
最後,說說在iClient中如何用的問題。
iClient自身是帶了服務器的量算功能的,而若是但願使用客戶端量算的話,iClient for JavaScript已經在Geometry的公共接口中提供了,可自行查找;而iClient for Flex沒有提供相似的功能,那麼最好藉助openscales-geometry庫中所帶的方法——getLength/getGeodesicLength/getArea/getGeodesicArea得到幫助。爲了簡化openscales和iClient for Flex之間的幾何對象轉換關係,能夠用https://github.com/SuperMap/OpenScales-FeatureTransform 項目提供的方法來處理。