【问题标题】:Calculate the center point of multiple latitude/longitude coordinate pairs计算多个经纬度坐标对的中心点
【发布时间】:2011-10-04 00:17:21
【问题描述】:

给定一组纬度和经度点,我如何计算该组中心点(也就是将视图以所有点为中心的点)的纬度和经度?

编辑:我使用过的 Python 解决方案:

Convert lat/lon (must be in radians) to Cartesian coordinates for each location.
X = cos(lat) * cos(lon)
Y = cos(lat) * sin(lon)
Z = sin(lat)

Compute average x, y and z coordinates.
x = (x1 + x2 + ... + xn) / n
y = (y1 + y2 + ... + yn) / n
z = (z1 + z2 + ... + zn) / n

Convert average x, y, z coordinate to latitude and longitude.
Lon = atan2(y, x)
Hyp = sqrt(x * x + y * y)
Lat = atan2(z, hyp)

【问题讨论】:

  • 关于您的解决方案:对于球形地球的假设,您的错误可能不会太大,但最好将地球描述为椭球体。
  • 把它写成python函数并分享到gist.github.com/3718961
  • 非常重要的是要注意,这是假设您的纬度和经度以弧度为单位的!我挠了挠头,没有意识到这一点。要从十进制转换为弧度,请乘以十进制 * pi/180。然后从弧度转换回十进制,乘以 180/pi。 HTH
  • 抱歉迟到了,但我想知道,这个算法背后的数学原理是什么,有人可以告诉我一些解释这个问题的读物吗?谢谢!
  • 请问z是什么?

标签: math latitude-longitude geo


【解决方案1】:

谢谢!这是使用度数的 OP 解决方案的 C# 版本。它利用System.Device.Location.GeoCoordinate

    public static GeoCoordinate GetCentralGeoCoordinate(
        IList<GeoCoordinate> geoCoordinates)
    {
        if (geoCoordinates.Count == 1)
        {
            return geoCoordinates.Single();
        }

        double x = 0;
        double y = 0;
        double z = 0;

        foreach (var geoCoordinate in geoCoordinates)
        {
            var latitude = geoCoordinate.Latitude * Math.PI / 180;
            var longitude = geoCoordinate.Longitude * Math.PI / 180;

            x += Math.Cos(latitude) * Math.Cos(longitude);
            y += Math.Cos(latitude) * Math.Sin(longitude);
            z += Math.Sin(latitude);
        }

        var total = geoCoordinates.Count;

        x = x / total;
        y = y / total;
        z = z / total;

        var centralLongitude = Math.Atan2(y, x);
        var centralSquareRoot = Math.Sqrt(x * x + y * y);
        var centralLatitude = Math.Atan2(z, centralSquareRoot);

        return new GeoCoordinate(centralLatitude * 180 / Math.PI, centralLongitude * 180 / Math.PI);
    }

【讨论】:

    【解决方案2】:

    仅对它们进行平均的简单方法在它们从 359' 回绕到 0' 时会出现带有角度的奇怪边缘情况。

    一位much earlier question on SO 询问如何找到一组罗盘角度的平均值。

    推荐的球坐标方法的扩展是:

    • 将每个纬度/经度对转换为单位长度的 3D 向量。
    • 对每个向量求和
    • 归一化结果向量
    • 转换回球坐标

    【讨论】:

    • 看起来不错,我根据在这个网站上找到的内容做了类似的事情:geomidpoint.com/calculation.html
    • downvoter - 请解释一下,如果可以的话,提供更好的解决方案。
    【解决方案3】:

    我发现这篇文章非常有用,所以这里是 PHP 的解决方案。我一直在成功使用它,只是想为另一个开发者节省一些时间。

    /**
     * Get a center latitude,longitude from an array of like geopoints
     *
     * @param array data 2 dimensional array of latitudes and longitudes
     * For Example:
     * $data = array
     * (
     *   0 = > array(45.849382, 76.322333),
     *   1 = > array(45.843543, 75.324143),
     *   2 = > array(45.765744, 76.543223),
     *   3 = > array(45.784234, 74.542335)
     * );
    */
    function GetCenterFromDegrees($data)
    {
        if (!is_array($data)) return FALSE;
    
        $num_coords = count($data);
    
        $X = 0.0;
        $Y = 0.0;
        $Z = 0.0;
    
        foreach ($data as $coord)
        {
            $lat = $coord[0] * pi() / 180;
            $lon = $coord[1] * pi() / 180;
    
            $a = cos($lat) * cos($lon);
            $b = cos($lat) * sin($lon);
            $c = sin($lat);
    
            $X += $a;
            $Y += $b;
            $Z += $c;
        }
    
        $X /= $num_coords;
        $Y /= $num_coords;
        $Z /= $num_coords;
    
        $lon = atan2($Y, $X);
        $hyp = sqrt($X * $X + $Y * $Y);
        $lat = atan2($Z, $hyp);
    
        return array($lat * 180 / pi(), $lon * 180 / pi());
    }
    

    【讨论】:

    • 我已经使用了这个解决方案,但它给出了一个错误的解决方案 - 如果我在地图上搜索某些坐标的中心,它会“权衡”这些点并且倾向于停留在有更多点的地方.
    • @Alnitak 在这里我们要搜索由坐标包围的区域的中心。你确定你评论的地方是对的吗?
    【解决方案4】:

    非常有用的帖子!我已经在 J​​avaScript 中实现了这个,特此我的代码。我已经成功使用了这个。

    function rad2degr(rad) { return rad * 180 / Math.PI; }
    function degr2rad(degr) { return degr * Math.PI / 180; }
    
    /**
     * @param latLngInDeg array of arrays with latitude and longtitude
     *   pairs in degrees. e.g. [[latitude1, longtitude1], [latitude2
     *   [longtitude2] ...]
     *
     * @return array with the center latitude longtitude pairs in 
     *   degrees.
     */
    function getLatLngCenter(latLngInDegr) {
        var LATIDX = 0;
        var LNGIDX = 1;
        var sumX = 0;
        var sumY = 0;
        var sumZ = 0;
    
        for (var i=0; i<latLngInDegr.length; i++) {
            var lat = degr2rad(latLngInDegr[i][LATIDX]);
            var lng = degr2rad(latLngInDegr[i][LNGIDX]);
            // sum of cartesian coordinates
            sumX += Math.cos(lat) * Math.cos(lng);
            sumY += Math.cos(lat) * Math.sin(lng);
            sumZ += Math.sin(lat);
        }
    
        var avgX = sumX / latLngInDegr.length;
        var avgY = sumY / latLngInDegr.length;
        var avgZ = sumZ / latLngInDegr.length;
    
        // convert average x, y, z coordinate to latitude and longtitude
        var lng = Math.atan2(avgY, avgX);
        var hyp = Math.sqrt(avgX * avgX + avgY * avgY);
        var lat = Math.atan2(avgZ, hyp);
    
        return ([rad2degr(lat), rad2degr(lng)]);
    }
    

    【讨论】:

    • 我知道这篇文章已经过时了,但您能否发布一个参考资料或解释您发布的算法背后的数学的东西?谢谢!
    • 完美运行!谢谢
    • 我使用 Google Apps Script 测试了该脚本,但结果不是轨道的确切中心点。它在附近的某个地方,但不是直接在赛道上。有没有更好的公式来获得赛道上的确切中间点?
    【解决方案5】:

    原函数的Javascript版本

    /**
     * Get a center latitude,longitude from an array of like geopoints
     *
     * @param array data 2 dimensional array of latitudes and longitudes
     * For Example:
     * $data = array
     * (
     *   0 = > array(45.849382, 76.322333),
     *   1 = > array(45.843543, 75.324143),
     *   2 = > array(45.765744, 76.543223),
     *   3 = > array(45.784234, 74.542335)
     * );
    */
    function GetCenterFromDegrees(data)
    {       
        if (!(data.length > 0)){
            return false;
        } 
    
        var num_coords = data.length;
    
        var X = 0.0;
        var Y = 0.0;
        var Z = 0.0;
    
        for(i = 0; i < data.length; i++){
            var lat = data[i][0] * Math.PI / 180;
            var lon = data[i][1] * Math.PI / 180;
    
            var a = Math.cos(lat) * Math.cos(lon);
            var b = Math.cos(lat) * Math.sin(lon);
            var c = Math.sin(lat);
    
            X += a;
            Y += b;
            Z += c;
        }
    
        X /= num_coords;
        Y /= num_coords;
        Z /= num_coords;
    
        var lon = Math.atan2(Y, X);
        var hyp = Math.sqrt(X * X + Y * Y);
        var lat = Math.atan2(Z, hyp);
    
        var newX = (lat * 180 / Math.PI);
        var newY = (lon * 180 / Math.PI);
    
        return new Array(newX, newY);
    }
    

    【讨论】:

      【解决方案6】:

      为了可能节省一两分钟的时间,这里是在 Objective-C 中而不是 python 中使用的解决方案。此版本采用包含 MKMapCoordinates 的 NSValues 的 NSArray,这在我的实现中被调用:

      #import <MapKit/MKGeometry.h>
      
      + (CLLocationCoordinate2D)centerCoordinateForCoordinates:(NSArray *)coordinateArray {
          double x = 0;
          double y = 0;
          double z = 0;
      
          for(NSValue *coordinateValue in coordinateArray) {
              CLLocationCoordinate2D coordinate = [coordinateValue MKCoordinateValue];
      
              double lat = GLKMathDegreesToRadians(coordinate.latitude);
              double lon = GLKMathDegreesToRadians(coordinate.longitude);
              x += cos(lat) * cos(lon);
              y += cos(lat) * sin(lon);
              z += sin(lat);
          }
      
          x = x / (double)coordinateArray.count;
          y = y / (double)coordinateArray.count;
          z = z / (double)coordinateArray.count;
      
          double resultLon = atan2(y, x);
          double resultHyp = sqrt(x * x + y * y);
          double resultLat = atan2(z, resultHyp);
      
          CLLocationCoordinate2D result = CLLocationCoordinate2DMake(GLKMathRadiansToDegrees(resultLat), GLKMathRadiansToDegrees(resultLon));
          return result;
      }
      

      【讨论】:

      • 对于任何人来说,为了它的价值,不要使用自己的宏来表示弧度,而是导入 &lt;GLKit/GLKMath.h&gt; 并使用 GLKMathDegreesToRadiansGLKMathRadiansToDegrees
      【解决方案7】:

      非常好的解决方案,正是我的 swift 项目所需要的,所以这里有一个 swift 端口。谢谢&这里也是一个游乐场项目: https://github.com/ppoh71/playgounds/tree/master/centerLocationPoint.playground

      /*
      * calculate the center point of multiple latitude longitude coordinate-pairs
      */
      
      import CoreLocation
      import GLKit
      
      var LocationPoints = [CLLocationCoordinate2D]()
      
      //add some points to Location ne, nw, sw, se , it's a rectangle basicaly
      LocationPoints.append(CLLocationCoordinate2D(latitude: 37.627512369999998, longitude: -122.38780611999999))
      LocationPoints.append(CLLocationCoordinate2D(latitude: 37.627512369999998, longitude:  -122.43105867))
      LocationPoints.append(CLLocationCoordinate2D(latitude: 37.56502528, longitude: -122.43105867))
      LocationPoints.append(CLLocationCoordinate2D(latitude: 37.56502528, longitude: -122.38780611999999))
      
      // center func
      func getCenterCoord(LocationPoints: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D{
      
          var x:Float = 0.0;
          var y:Float = 0.0;
          var z:Float = 0.0;
      
          for points in LocationPoints {
      
           let lat = GLKMathDegreesToRadians(Float(points.latitude));
           let long = GLKMathDegreesToRadians(Float(points.longitude));
      
              x += cos(lat) * cos(long);
              y += cos(lat) * sin(long);
              z += sin(lat);
          }
      
          x = x / Float(LocationPoints.count);
          y = y / Float(LocationPoints.count);
          z = z / Float(LocationPoints.count);
      
          let resultLong = atan2(y, x);
          let resultHyp = sqrt(x * x + y * y);
          let resultLat = atan2(z, resultHyp);
      
      
      
          let result = CLLocationCoordinate2D(latitude: CLLocationDegrees(GLKMathRadiansToDegrees(Float(resultLat))), longitude: CLLocationDegrees(GLKMathRadiansToDegrees(Float(resultLong))));
      
          return result;
      
      }
      
      //get the centerpoint
      var centerPoint = getCenterCoord(LocationPoints)
      print("Latitude: \(centerPoint.latitude) / Longitude: \(centerPoint.longitude)")
      

      【讨论】:

        【解决方案8】:

        Java 版本,如果有人需要的话。常量定义为静态的,不会计算两次。

        /**************************************************************************************************************
         *   Center of geometry defined by coordinates
         **************************************************************************************************************/
        private static double pi = Math.PI / 180;
        private static double xpi = 180 / Math.PI;
        
        public static Coordinate center(Coordinate... arr) {
            if (arr.length == 1) {
                return arr[0];
            }
            double x = 0, y = 0, z = 0;
        
            for (Coordinate c : arr) {
                double latitude = c.lat() * pi, longitude = c.lon() * pi;
                double cl = Math.cos(latitude);//save it as we need it twice
                x += cl * Math.cos(longitude);
                y += cl * Math.sin(longitude);
                z += Math.sin(latitude);
            }
        
            int total = arr.length;
        
            x = x / total;
            y = y / total;
            z = z / total;
        
            double centralLongitude = Math.atan2(y, x);
            double centralSquareRoot = Math.sqrt(x * x + y * y);
            double centralLatitude = Math.atan2(z, centralSquareRoot);
        
            return new Coordinate(centralLatitude * xpi, centralLongitude * xpi);
        }
        

        【讨论】:

          【解决方案9】:

          如果您有兴趣获得一个非常简化的点“中心”(例如,简单地将地图居中到 gmaps 多边形的中心),那么这里有一个对我有用的基本方法。

          public function center() {
              $minlat = false;
              $minlng = false;
              $maxlat = false;
              $maxlng = false;
              $data_array = json_decode($this->data, true);
              foreach ($data_array as $data_element) {
                  $data_coords = explode(',',$data_element);
                  if (isset($data_coords[1])) {
                      if ($minlat === false) { $minlat = $data_coords[0]; } else { $minlat = ($data_coords[0] < $minlat) ? $data_coords[0] : $minlat; }
                      if ($maxlat === false) { $maxlat = $data_coords[0]; } else { $maxlat = ($data_coords[0] > $maxlat) ? $data_coords[0] : $maxlat; }
                      if ($minlng === false) { $minlng = $data_coords[1]; } else { $minlng = ($data_coords[1] < $minlng) ? $data_coords[1] : $minlng; }
                      if ($maxlng === false) { $maxlng = $data_coords[1]; } else { $maxlng = ($data_coords[1] > $maxlng) ? $data_coords[1] : $maxlng; }
                  }
              }
              $lat = $maxlat - (($maxlat - $minlat) / 2);
              $lng = $maxlng - (($maxlng - $minlng) / 2);
              return $lat.','.$lng;
          }
          

          这将返回多边形中心的中间 lat/lng 坐标。

          【讨论】:

            【解决方案10】:

            在 Django 中,这是微不足道的(实际上有效,我遇到了一些解决方案没有正确返回纬度负数的问题)。

            例如,假设您使用的是django-geopostcodes(我是其中的作者)。

            from django.contrib.gis.geos import MultiPoint
            from django.contrib.gis.db.models.functions import Distance
            from django_geopostcodes.models import Locality
            
            qs = Locality.objects.anything_icontains('New York')
            points = [locality.point for locality in qs]
            multipoint = MultiPoint(*points)
            point = multipoint.centroid
            

            point 是一个 Django Point 实例,然后可用于检索距离该中心点 10 公里范围内的所有对象;

            Locality.objects.filter(point__distance_lte=(point, D(km=10)))\
                .annotate(distance=Distance('point', point))\
                .order_by('distance')
            

            将其更改为原始 Python 很简单;

            from django.contrib.gis.geos import Point, MultiPoint
            
            points = [
                Point((145.137075, -37.639981)),
                Point((144.137075, -39.639981)),
            ]
            multipoint = MultiPoint(*points)
            point = multipoint.centroid
            

            在幕后,Django 正在使用 GEOS - 更多详细信息请访问 https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geos/

            【讨论】:

              【解决方案11】:

              这是基于@Yodacheese 使用 Google Maps api 的 C# 答案的 Android 版本:

              public static LatLng GetCentralGeoCoordinate(List<LatLng> geoCoordinates) {        
                  if (geoCoordinates.size() == 1)
                  {
                      return geoCoordinates.get(0);
                  }
              
                  double x = 0;
                  double y = 0;
                  double z = 0;
              
                  for(LatLng geoCoordinate : geoCoordinates)
                  {
                      double  latitude = geoCoordinate.latitude * Math.PI / 180;
                      double longitude = geoCoordinate.longitude * Math.PI / 180;
              
                      x += Math.cos(latitude) * Math.cos(longitude);
                      y += Math.cos(latitude) * Math.sin(longitude);
                      z += Math.sin(latitude);
                  }
              
                  int total = geoCoordinates.size();
              
                  x = x / total;
                  y = y / total;
                  z = z / total;
              
                  double centralLongitude = Math.atan2(y, x);
                  double centralSquareRoot = Math.sqrt(x * x + y * y);
                  double centralLatitude = Math.atan2(z, centralSquareRoot);
              
                  return new LatLng(centralLatitude * 180 / Math.PI, centralLongitude * 180 / Math.PI);
              
              }
              

              在 app build.gradle 中添加:

              implementation 'com.google.android.gms:play-services-maps:17.0.0'
              

              【讨论】:

                【解决方案12】:

                Dart 实现 Flutter 以查找多个纬度、经度的中心点。

                导入数学包

                import 'dart:math' as math;
                

                经纬度表

                List<LatLng> latLongList = [LatLng(12.9824, 80.0603),LatLng(13.0569,80.2425,)];
                
                LatLng getCenterLatLong(List<LatLng> latLongList) {
                    double pi = math.pi / 180;
                    double xpi = 180 / math.pi;
                    double x = 0, y = 0, z = 0;
                
                    if(latLongList.length==1)
                    {
                        return latLongList[0];
                    }
                    for (int i = 0; i < latLongList.length; i++) {
                      double latitude = latLongList[i].latitude * pi;
                      double longitude = latLongList[i].longitude * pi;
                      double c1 = math.cos(latitude);
                      x = x + c1 * math.cos(longitude);
                      y = y + c1 * math.sin(longitude);
                      z = z + math.sin(latitude);
                    }
                
                    int total = latLongList.length;
                    x = x / total;
                    y = y / total;
                    z = z / total;
                
                    double centralLongitude = math.atan2(y, x);
                    double centralSquareRoot = math.sqrt(x * x + y * y);
                    double centralLatitude = math.atan2(z, centralSquareRoot);
                
                    return LatLng(centralLatitude*xpi,centralLongitude*xpi);
                }
                

                【讨论】:

                  【解决方案13】:

                  这里是寻找中心点的python版本。 lat1 和 lon1 是纬度和经度列表。 它将返回中心点的经纬度。

                  import numpy as np
                  
                  def GetCenterFromDegrees(lat1,lon1):
                      if (len(lat1) <= 0):
                          return false;
                  
                      num_coords = len(lat1)
                      X = 0.0
                      Y = 0.0
                      Z = 0.0
                  
                      for i in range (len(lat1)):
                          lat = lat1[i] * np.pi / 180
                          lon = lon1[i] * np.pi / 180
                  
                          a = np.cos(lat) * np.cos(lon)
                          b = np.cos(lat) * np.sin(lon)
                          c = np.sin(lat);
                  
                          X += a
                          Y += b
                          Z += c
                  
                      X /= num_coords
                      Y /= num_coords
                      Z /= num_coords
                  
                      lon = np.arctan2(Y, X)
                      hyp = np.sqrt(X * X + Y * Y)
                      lat = np.arctan2(Z, hyp)
                  
                      newX = (lat * 180 / np.pi)
                      newY = (lon * 180 / np.pi)
                      return newX, newY
                  

                  【讨论】:

                    【解决方案14】:

                    这与加权平均问题相同,其中所有权重都相同,并且有两个维度。

                    找到您的中心纬度的所有纬度的平均值和中心经度的所有经度的平均值。

                    Caveat Emptor:这是一个近距离近似值,当由于地球曲率与平均值的偏差超过几英里时,误差将变得难以控制。请记住,纬度和经度是度数(不是真正的网格)。

                    【讨论】:

                    • [-179,0],[+179,0] 的平均值为 [0,0],与正确结果相差甚远 ;)
                    【解决方案15】:

                    如果您想考虑所使用的椭球体,您可以找到公式 这里http://www.ordnancesurvey.co.uk/oswebsite/gps/docs/A_Guide_to_Coordinate_Systems_in_Great_Britain.pdf

                    见附录 B

                    该文档包含许多其他有用的东西

                    B

                    【讨论】:

                    【解决方案16】:

                    PHP 中的对象不足。给定坐标对数组,返回中心。

                    /**
                     * Calculate center of given coordinates
                     * @param  array    $coordinates    Each array of coordinate pairs
                     * @return array                    Center of coordinates
                     */
                    function getCoordsCenter($coordinates) {    
                        $lats = $lons = array();
                        foreach ($coordinates as $key => $value) {
                            array_push($lats, $value[0]);
                            array_push($lons, $value[1]);
                        }
                        $minlat = min($lats);
                        $maxlat = max($lats);
                        $minlon = min($lons);
                        $maxlon = max($lons);
                        $lat = $maxlat - (($maxlat - $minlat) / 2);
                        $lng = $maxlon - (($maxlon - $minlon) / 2);
                        return array("lat" => $lat, "lon" => $lng);
                    }
                    

                    从 #4 中汲取灵感

                    【讨论】:

                    • 这不适用于穿过 180 度子午线的坐标。例如,两个经度点 -175 和 175 将在您的算法中返回 0 的中心,因此实际中心将是 -180 或 180。
                    【解决方案17】:

                    我在下面的 javascript 中完成了这项任务

                    function GetCenterFromDegrees(data){
                        // var data = [{lat:22.281610498720003,lng:70.77577162868579},{lat:22.28065743343672,lng:70.77624369747241},{lat:22.280860953131217,lng:70.77672113067706},{lat:22.281863655593973,lng:70.7762061465462}];
                        var num_coords = data.length;
                        var X = 0.0;
                        var Y = 0.0;
                        var Z = 0.0;
                    
                        for(i=0; i<num_coords; i++){
                            var lat = data[i].lat * Math.PI / 180;
                            var lon = data[i].lng * Math.PI / 180;
                            var a = Math.cos(lat) * Math.cos(lon);
                            var b = Math.cos(lat) * Math.sin(lon);
                            var c = Math.sin(lat);
                    
                            X += a;
                            Y += b;
                            Z += c;
                        }
                    
                        X /= num_coords;
                        Y /= num_coords;
                        Z /= num_coords;
                    
                        lon = Math.atan2(Y, X);
                        var hyp = Math.sqrt(X * X + Y * Y);
                        lat = Math.atan2(Z, hyp);
                    
                        var finalLat = lat * 180 / Math.PI;
                        var finalLng =  lon * 180 / Math.PI; 
                    
                        var finalArray = Array();
                        finalArray.push(finalLat);
                        finalArray.push(finalLng);
                        return finalArray;
                    }
                    

                    【讨论】:

                      【解决方案18】:

                      Dart/Flutter 计算多个经纬度坐标对的中心点

                      Map<String, double> getLatLngCenter(List<List<double>> coords) {
                          const LATIDX = 0;
                          const LNGIDX = 1;
                          double sumX = 0;
                          double sumY = 0;
                          double sumZ = 0;
                      
                          for (var i = 0; i < coords.length; i++) {
                            var lat = VectorMath.radians(coords[i][LATIDX]);
                            var lng = VectorMath.radians(coords[i][LNGIDX]);
                            // sum of cartesian coordinates
                            sumX += Math.cos(lat) * Math.cos(lng);
                            sumY += Math.cos(lat) * Math.sin(lng);
                            sumZ += Math.sin(lat);
                          }
                      
                          var avgX = sumX / coords.length;
                          var avgY = sumY / coords.length;
                          var avgZ = sumZ / coords.length;
                      
                          // convert average x, y, z coordinate to latitude and longtitude
                          var lng = Math.atan2(avgY, avgX);
                          var hyp = Math.sqrt(avgX * avgX + avgY * avgY);
                          var lat = Math.atan2(avgZ, hyp);
                      
                          return {
                            "latitude": VectorMath.degrees(lat),
                            "longitude": VectorMath.degrees(lng)
                          };
                        }
                      

                      【讨论】:

                        【解决方案19】:

                        如果您希望图像中的所有点都可见,则需要纬度和经度的极值,并确保您的视图包含这些值以及您想要的任何边框。

                        (根据 Alnitak 的回答,您如何计算极值可能有点问题,但如果它们在环绕的经度的任一侧有几度,那么您将做主并采取正确的范围。 )

                        如果您不想扭曲这些点所在的任何地图,请调整边界框的纵横比,使其适合您分配给视图但仍包含极值的任何像素。

                        要使点保持在某个任意缩放级别的中心,请计算“恰好适合”上述点的边界框的中心,并将该点保持为中心点。

                        【讨论】:

                          【解决方案20】:

                          作为对这个帖子的感谢,这里是我对 Ruby 实现的一点贡献,希望我能从他们宝贵的时间中节省几分钟:

                          def self.find_center(locations)
                          
                           number_of_locations = locations.length
                          
                           return locations.first if number_of_locations == 1
                          
                           x = y = z = 0.0
                           locations.each do |station|
                             latitude = station.latitude * Math::PI / 180
                             longitude = station.longitude * Math::PI / 180
                          
                             x += Math.cos(latitude) * Math.cos(longitude)
                             y += Math.cos(latitude) * Math.sin(longitude)
                             z += Math.sin(latitude)
                           end
                          
                           x = x/number_of_locations
                           y = y/number_of_locations
                           z = z/number_of_locations
                          
                           central_longitude =  Math.atan2(y, x)
                           central_square_root = Math.sqrt(x * x + y * y)
                           central_latitude = Math.atan2(z, central_square_root)
                          
                           [latitude: central_latitude * 180 / Math::PI, 
                           longitude: central_longitude * 180 / Math::PI]
                          end
                          

                          【讨论】:

                            【解决方案21】:

                            我使用了从 www.geomidpoint.com 获得的公式并编写了以下 C++ 实现。 arraygeocoords 是我自己的类,它们的功能应该是不言自明的。

                            /*
                             * midpoints calculated using formula from www.geomidpoint.com
                             */
                               geocoords geocoords::calcmidpoint( array<geocoords>& points )
                               {
                                  if( points.empty() ) return geocoords();
                            
                                  float cart_x = 0,
                                        cart_y = 0,
                                        cart_z = 0;
                            
                                  for( auto& point : points )
                                  {
                                     cart_x += cos( point.lat.rad() ) * cos( point.lon.rad() );
                                     cart_y += cos( point.lat.rad() ) * sin( point.lon.rad() );
                                     cart_z += sin( point.lat.rad() );
                                  }
                            
                                  cart_x /= points.numelems();
                                  cart_y /= points.numelems();
                                  cart_z /= points.numelems();
                            
                                  geocoords mean;
                            
                                  mean.lat.rad( atan2( cart_z, sqrt( pow( cart_x, 2 ) + pow( cart_y, 2 ))));
                                  mean.lon.rad( atan2( cart_y, cart_x ));
                            
                                  return mean;
                               }
                            

                            【讨论】:

                              【解决方案22】:

                              Scala 版本:

                              import scala.math._
                                  
                              case class Coordinate(latitude: Double, longitude: Double)
                                  
                              def center(coordinates: List[Coordinate]) = {
                                val (a: Double, b: Double, c: Double) = coordinates.fold((0.0, 0.0, 0.0)) {
                                  case ((x: Double, y: Double, z: Double), coord: Coordinate) =>
                                    val latitude = coord.latitude * Pi / 180
                                    val longitude = coord.longitude * Pi / 180
                                    (x + cos(latitude) * cos(longitude), y + cos(latitude) * sin(longitude), z + sin(latitude))
                                }
                                val total = coordinates.length
                                val (x: Double, y: Double, z: Double) = (a / total, b / total, c / total)
                                val centralLongitude = atan2(y, x)
                                val centralSquareRoot = sqrt(x * x + y * y)
                                val centralLatitude = atan2(z, centralSquareRoot)
                                  
                                Coordinate(centralLatitude * 180 / Pi, centralLongitude * 180 / Pi);
                              }
                              
                              

                              【讨论】:

                                猜你喜欢
                                • 2013-08-07
                                • 2015-10-04
                                • 1970-01-01
                                • 2016-02-03
                                • 1970-01-01
                                • 2014-12-16
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多