Javascript 将纬度和经度坐标按顺时针顺序排列为四边形
问题 用户最多可以按任意顺序提供四个纬度和经度坐标。他们使用谷歌地图来实现这一点。使用谷歌的Javascript 将纬度和经度坐标按顺时针顺序排列为四边形,javascript,geometry,coordinates,grahams-scan,Javascript,Geometry,Coordinates,Grahams Scan,问题 用户最多可以按任意顺序提供四个纬度和经度坐标。他们使用谷歌地图来实现这一点。使用谷歌的PolygonAPI(v3),他们选择的坐标应该突出显示四个坐标之间的选定区域 问题 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)
Polygon
API(v3),他们选择的坐标应该突出显示四个坐标之间的选定区域
问题
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;
}
如何按(逆时针)顺时针顺序对纬度和经度坐标数组进行排序
解决方案和搜索
堆栈溢出问题
- 格雷厄姆扫描(太复杂)
- 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;
}
//确保标记已排序:NW、NE、SE、SW
函数排序标记(){
var ns=标记。切片(0);
var ew=标记。切片(0);
ew.sort(功能(a,b){
if(a.position.lat()b.position.lat()){
返回1;
}
返回0;
});
ns.排序(函数(a,b){
如果(a.position.lng()b.position.lng()){
返回1;
}
返回0;
});
西北风;
var-ne;
var-se;
var-sw;
if(ew.indexOf(ns[0])>1){
nw=ns[0];
}
否则{
ne=ns[0];
}
if(ew.indexOf(ns[1])>1){
nw=ns[1];
}
否则{
ne=ns[1];
}
if(ew.indexOf(ns[2])>1){
sw=ns[2];
}
否则{
se=ns[2];
}
if(ew.indexOf(ns[3])>1){
sw=ns[3];
}
否则{
se=ns[3];
}
标记[0]=nw;
标记[1]=ne;
标记[2]=se;
标记[3]=sw;
}
谢谢。算法思想:取四个点的平均值,得到多边形内部的一个点。然后使用逆三角函数计算该中心点和每个点之间的光线角度,如所述。然后按角度排序。这应该给你一个(逆)顺时针排序,这取决于排序顺序和你认为的“零度”。 更新: 这里有一些代码。大部分未经测试,但这是一个想法
function sorted_points(points) {
points = points.slice(0); // copy the array, since sort() modifies it
var stringify_point = function(p) { return p.x + ',' + p.y; };
// finds a point in the interior of `pts`
var avg_points = function(pts) {
var x = 0;
y = 0;
for(i = 0; i < pts.length; i++) {
x += pts[i].x;
y += pts[i].y;
}
return {x: x/pts.length, y:y/pts.length};
}
var center = avg_points(points);
// calculate the angle between each point and the centerpoint, and sort by those angles
var angles = {};
for(i = 0; i < points.length; i++) {
angles[stringify_point(points[i])] = Math.atan(points[i].x - center.x, points[i].y - center.y);
}
points.sort(function(p1, p2) {
return angles[stringify_point(p1)] - angles[stringify_point(p2)];
});
return points;
}
函数排序\u点(点){
points=points.slice(0);//复制数组,因为sort()会修改它
var stringify_point=函数(p){return p.x+','+p.y;};
//在“pts”的内部找到一个点`
var平均值=功能(pts){
var x=0;
y=0;
对于(i=0;i
它按逆时针方向对点(如{x:1,y:1}
)进行排序 鉴于以下几点:
4 + [d] [g]
|
3 [a] [e]
|
2 + [f] [h]
|
1 + [b]
|
0 +----+---[c]---+----+----+----+
0 1 2 3 4 5 6
您希望找到以下绑定行走:
4 + ___[d]------------[g]
| __/ \
3 [a]/ [e]__ \
| \ \_ ```--- \
2 + \ `[f] \___[h]
| \ __/
1 + [b] __/
| \ /
0 +----+--`[c]---+----+----+----+
0 1 2 3 4 5 6
?
如果这是正确的,这里有一个方法:
- 在点集中找到最上面的点Ptop。如果是平局,则选择具有最小x坐标的点
- 通过比较穿过Ptop时每对点(不包括Ptop!)Pi和Pj形成的直线的斜率mi和mj对所有点进行排序
- 如果mi和mj相等,让最接近Ptop的点Pi或Pj排在第一位
- 如果mi为正,mj为负(或零),Pj排在第一位
- 如果mi和mj都是正的或负的,那么让属于斜率最大的直线的点排在第一位
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;
}
对于一年后来到这里的人,有类似的问题: 我不同意所选择的答案。即使在给定的时钟方向上,该阶也没有奇异解。 给定坐标的凸包消除了点e和f。然后可以将其附着在路径上的任何位置。 客观地说,h,e,f,c可以改进为h,f,e,c,保持x分量的方向一致-在这种情况下为负
这一点的重要性使得无法保证在所选步行范围内的结果区域中包含任何地图位置。这是一个极好的解决方案,但可能我被最初的问题弄糊涂了。按顺时针方向假设,不来梅似乎不合适。我本以为会有这样的订单:汉堡,普拉哈,斯图加德,巴黎,加来,鹿特丹,阿姆斯特丹,Bremen@Jon史蒂文斯,不,这是应该的。可以这样想:在顶端城市(汉堡)上系一根绳子,绳子末端有一个小重量。将重物一直向右拖动,使绳索笔直,然后释放重物。绳子穿过城市的顺序是正确的排序顺序。HTHBart,我知道这一部分,但从您的ascii映射来看,排序顺序似乎更符合这一点。此外,最初的要求是(逆时针)。不一定是基于字符串/绳索的。@Jon Stevens,不,ascii映射也按如下顺序排序:
d
位于顶部,然后是g、h、e、f、c、b、a
。最初的要求并不那么精确:OP也提到了“凸面外壳”,而这与它无关。我所知道的是,OP说:“……这正是我所期待的。”
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;
}