将经纬度坐标排序为顺时针四边形

Sort latitude and longitude coordinates into clockwise ordered quadrilateral(将经纬度坐标排序为顺时针四边形)
本文介绍了将经纬度坐标排序为顺时针四边形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

问题

用户最多可以按任意顺序提供四个经纬度坐标.他们使用谷歌地图这样做.使用 Google 的 Polygon API (v3),他们选择的坐标应该突出显示四个坐标之间的选定区域.

Users can provide up to four latitude and longitude coordinates, in any order. They do so with Google Maps. Using Google's Polygon API (v3), the coordinates they select should highlight the selected area between the four coordinates.

问题

如何按(逆)顺时针顺序对一组经纬度坐标进行排序?

How do you sort an array of latitude and longitude coordinates in (counter-)clockwise order?

解决方案和搜索

StackOverflow 问题

  • 绘制可调整大小(不相交)的多边形
  • 如何对 Google 地图多边形中的点进行排序以使线不会交叉?
  • 按顺时针顺序对四个点进行排序

相关网站

  • http://www.daftlogic.com/projects-google-maps-area-calculator-tool.htm
  • http://en.literateprograms.org/Quickhull_%28Javascript%29
  • http://www.geocodezip.com/map-markers_ConvexHull_Polygon.asp
  • http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm

已知算法

  • Graham 的扫描(太复杂)
  • Jarvis March 算法(处理 N 个点)
  • 递归凸包(移除一个点)

代码

这是我目前所拥有的:

// Ensures the markers are sorted: NW, NE, SE, SW
function sortMarkers() {
  var ns = markers.slice( 0 );
  var ew = markers.slice( 0 );

  ew.sort( function( a, b ) {
    if( a.position.lat() < b.position.lat() ) {
      return -1;
    }
    else if( a.position.lat() > b.position.lat() ) {
      return 1;
    }

    return 0;
  });

  ns.sort( function( a, b ) {
    if( a.position.lng() < b.position.lng() ) {
      return -1;
    }
    else if( a.position.lng() > b.position.lng() ) {
      return 1;
    }

    return 0;
  });

  var nw;
  var ne;
  var se;
  var sw;

  if( ew.indexOf( ns[0] ) > 1 ) {
    nw = ns[0];
  }
  else {
    ne = ns[0];
  }

  if( ew.indexOf( ns[1] ) > 1 ) {
    nw = ns[1];
  }
  else {
    ne = ns[1];
  }

  if( ew.indexOf( ns[2] ) > 1 ) {
    sw = ns[2];
  }
  else {
    se = ns[2];
  }

  if( ew.indexOf( ns[3] ) > 1 ) {
    sw = ns[3];
  }
  else {
    se = ns[3];
  }

  markers[0] = nw;
  markers[1] = ne;
  markers[2] = se;
  markers[3] = sw;
}

谢谢.

推荐答案

给出要点:

   4  +        [d]            [g]                 
      |                             
   3 [a]            [e]                 
      |                             
   2  +                  [f]       [h]    
      |                             
   1  +   [b]                             
      |                             
   0  +----+---[c]---+----+----+----+
      0    1    2    3    4    5    6

你想找到以下绑定步行:

you want to find the following bound walk:

   4  +     ___[d]------------[g]                 
      |  __/                         
   3 [a]/           [e]__                
      |              \_ ```---      
   2  +                `[f]   \___[h]    
      |              __/            
   1  +   [b]      __/                   
      |          /                
   0  +----+--`[c]---+----+----+----+
      0    1    2    3    4    5    6

?

如果这是正确的,这里有一个方法:

If this is correct, here's a way:

  • 在点集中找到最高点,Ptop.如果出现平局,则选择 x 坐标最小的点
  • 通过比较每对点的直线的斜率 mi 和 mj 对所有点进行排序(不包括 Ptop!) Pi 和 Pj 在通过 Ptop 时使
    • 如果 mi 和 mj 相等,让点 Pi 或 Pj 最接近Ptop先来
    • 如果 mi 为正且 mj 为负(或零),则 Pj 在前
    • 如果 mi 和 mj 都是正数或负数,让属于斜率最大的线的点在前
    • find the upper most point, Ptop, in the set of points. In case of a tie, pick the point with the smallest x coordinate
    • sort all points by comparing the slopes mi and mj of the lines each pair of points (excluding Ptop!) Pi and Pj make when passing through Ptop
      • if mi and mj are equal, let the point Pi or Pj closest to Ptop come first
      • if mi is positive and mj is negative (or zero), Pj comes first
      • if both mi and mj are either positive or negative, let the point belonging to the line with the largest slope come first

      这是地图的快速演示:

      (我对 JavaScript 知之甚少,所以我可能或可能已经违反了一些 JavaScript 代码约定......):

      (I know little JavaScript, so I might, or probably have, violated some JavaScript code conventions...):

      var points = [
          new Point("Stuttgard", 48.7771056, 9.1807688),
          new Point("Rotterdam", 51.9226899, 4.4707867),
          new Point("Paris", 48.8566667, 2.3509871),
          new Point("Hamburg", 53.5538148, 9.9915752),
          new Point("Praha", 50.0878114, 14.4204598),
          new Point("Amsterdam", 52.3738007, 4.8909347),
          new Point("Bremen", 53.074981, 8.807081),
          new Point("Calais", 50.9580293, 1.8524129),
      ];
      var upper = upperLeft(points);
      
      print("points :: " + points);
      print("upper  :: " + upper);
      points.sort(pointSort);
      print("sorted :: " + points);
      
      // A representation of a 2D Point.
      function Point(label, lat, lon) {
      
          this.label = label;
          this.x = (lon + 180) * 360;
          this.y = (lat + 90) * 180;
      
          this.distance=function(that) {
              var dX = that.x - this.x;
              var dY = that.y - this.y;
              return Math.sqrt((dX*dX) + (dY*dY));
          }
      
          this.slope=function(that) {
              var dX = that.x - this.x;
              var dY = that.y - this.y;
              return dY / dX;
          }
      
          this.toString=function() {
              return this.label;
          }
      }
      
      // A custom sort function that sorts p1 and p2 based on their slope
      // that is formed from the upper most point from the array of points.
      function pointSort(p1, p2) {
          // Exclude the 'upper' point from the sort (which should come first).
          if(p1 == upper) return -1;
          if(p2 == upper) return 1;
      
          // Find the slopes of 'p1' and 'p2' when a line is 
          // drawn from those points through the 'upper' point.
          var m1 = upper.slope(p1);
          var m2 = upper.slope(p2);
      
          // 'p1' and 'p2' are on the same line towards 'upper'.
          if(m1 == m2) {
              // The point closest to 'upper' will come first.
              return p1.distance(upper) < p2.distance(upper) ? -1 : 1;
          }
      
          // If 'p1' is to the right of 'upper' and 'p2' is the the left.
          if(m1 <= 0 && m2 > 0) return -1;
      
          // If 'p1' is to the left of 'upper' and 'p2' is the the right.
          if(m1 > 0 && m2 <= 0) return 1;
      
          // It seems that both slopes are either positive, or negative.
          return m1 > m2 ? -1 : 1;
      }
      
      // Find the upper most point. In case of a tie, get the left most point.
      function upperLeft(points) {
          var top = points[0];
          for(var i = 1; i < points.length; i++) {
              var temp = points[i];
              if(temp.y > top.y || (temp.y == top.y && temp.x < top.x)) {
                  top = temp;
              }
          }
          return top;
      }
      

      注意:您应该双重或三重检查从 lat,lonx,y 的转换,因为我是 GIS 新手!!!但也许你甚至不需要转换任何东西.如果不这样做,upperLeft 函数可能只返回最低点而不是最高点,具体取决于相关点的位置.再次:三重检查这些假设!

      Note: your should double, or triple check the conversions from lat,lon to x,y as I am a novice if it comes to GIS!!! But perhaps you don't even need to convert anything. If you don't, the upperLeft function might just return the lowest point instead of the highest, depending on the locations of the points in question. Again: triple check these assumptions!

      执行上面的代码片段时,会打印以下内容:

      When executing the snippet above, the following gets printed:

      points :: Stuttgard,Rotterdam,Paris,Hamburg,Praha,Amsterdam,Bremen,Calais
      upper  :: Hamburg
      sorted :: Hamburg,Praha,Stuttgard,Paris,Bremen,Calais,Rotterdam,Amsterdam
      

      交替距离函数

      function distance(lat1, lng1, lat2, lng2) {
        var R = 6371; // km
        var dLat = (lat2-lat1).toRad();
        var dLon = (lng2-lng1).toRad();
        var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
                Math.sin(dLon/2) * Math.sin(dLon/2);
        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return R * c;
      }
      

      这篇关于将经纬度坐标排序为顺时针四边形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

      本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

在开发JS过程中,会经常遇到两个小数相运算的情况,但是运算结果却与预期不同,调试一下发现计算结果竟然有那么长一串尾巴。如下图所示: 产生原因: JavaScript对小数运算会先转成二进制,运算完毕再转回十进制,过程中会有丢失,不过不是所有的小数间运算会
问题描述: 在javascript中引用js代码,然后导致反斜杠丢失,发现字符串中的所有\信息丢失。比如在js中引用input type=text onkeyup=value=value.replace(/[^\d]/g,) ,结果导致正则表达式中的\丢失。 问题原因: 该字符串含有\,javascript对字符串进行了转
Rails/Javascript: How to inject rails variables into (very) simple javascript(Rails/Javascript:如何将 rails 变量注入(非常)简单的 javascript)
CoffeeScript always returns in anonymous function(CoffeeScript 总是以匿名函数返回)
Ordinals in words javascript(javascript中的序数)
getFullYear returns year before on first day of year(getFullYear 在一年的第一天返回前一年)