我正在尝试检查点位置并检测它们是否在一行中,然后输出包含可能行的对象。问题:
这是我所处的地方的小提琴:
http://jsfiddle.net/kmturley/RAQXf/1/
我们知道点1 - 5的长坐标和纬度坐标。我们想要计算它们之间的红线。
起点数据:
var points = [
{
name: 'Point 1',
lat: 51.509440,
long: -0.126985
},
{
name: 'Point 2',
lat: 51.509453,
long: -0.126180
},
{
name: 'Point 3',
lat: 51.510076,
long: -0.124804
},
{
name: 'Point 4',
lat: 51.510327,
long: -0.124133
},
{
name: 'Point 5',
lat: 51.509440,
long: -0.124175
}
];
以下是我正在使用的功能:
var utils = {
distHaversine: function (lon1, lat1, lon2, lat2) { // calculate distance between two points
var R = 6371; // earth's mean radius in km
var dLat = this.toRad(lat2 - lat1);
var dLon = this.toRad(lon2 - lon1);
lat1 = this.toRad(lat1),
lat2 = this.toRad(lat2);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
},
bearing: function (lon1, lat1, lon2, lat2) { // calculate bearing between two points
lat1 = this.toRad(lat1);
lat2 = this.toRad(lat2);
var dLon = this.toRad(lon2 - lon1);
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
return this.toBrng(Math.atan2(y, x));
},
toRad: function (val) { // convert degrees to radians
return val * Math.PI / 180;
},
toDeg: function (val) { // convert radians to degrees (signed)
return val * 180 / Math.PI;
},
toBrng: function (val) { // convert radians to degrees (as bearing: 0...360)
return (this.toDeg(val) + 360) % 360;
}
};
这就是我所拥有的:
function calculate(items) {
var i = 0,
j = 0,
accuracy = 2,
bearings = {};
// loop through the points and check the distance and bearing of each one
for (i = 0; i < items.length; i += 1) {
for (j = 0; j < items.length; j += 1) {
if (i !== j) {
var bearing = utils.bearing(items[i].long, items[i].lat, items[j].long, items[j].lat);
var distance = utils.distHaversine(items[i].long, items[i].lat, items[j].long, items[j].lat);
var key = Math.round(bearing / accuracy) * accuracy;
// push both points into the bearing array for the same line
if (!bearings[key]) { bearings[key] = {}; }
bearings[key][i] = true;
bearings[key][j] = true;
console.log(Math.round(distance * 1000) + 'm', Math.round(bearing) + '°', items[i].name + ' > ' + items[j].name);
}
}
}
return bearings;
}
function lines(bearings, items) {
var item = {},
key = '',
lines = [];
// loop though the bearings and create lines
for (item in bearings) {
if (utils.size(bearings[item]) > 2) {
var line = { name: 'Line ' + item + '°', points: [] };
for (key in bearings[item]) {
line.points.push(items[parseInt(key)]);
}
lines.push(line);
}
}
return lines;
}
var bearings = calculate(points);
var lines = lines(bearings, points);
console.log('--------');
console.log(lines);
预期产出:
var lines = [
{
name: 'Line 1',
points: [
{
name: 'Point 1',
lat: 51.509440,
long: -0.126985
},
{
name: 'Point 2',
lat: 51.509453,
long: -0.126180
},
{
name: 'Point 5',
lat: 51.509440,
long: -0.124175
}
]
},
{
name: 'Line 2',
points: [
{
name: 'Point 2',
lat: 51.509453,
long: -0.126180
},
{
name: 'Point 3',
lat: 51.510076,
long: -0.124804
},
{
name: 'Point 4',
lat: 51.510327,
long: -0.124133
}
]
}
];
这是我所处的地方的小提琴:
答案 0 :(得分:0)
我更喜欢以独立于语言的方式回答这个问题,因为它使得使用不同语言遇到相同问题的程序员的答案更有用。
如果点之间没有任何其他关系(例如,了解他们所在的街道),则必须首先考虑点对之间的所有线段。 Binomial[n, 2]
点有n
个分段,因此如果您可以添加启发式算法以避免考虑某些分段,那将会很好。
我们有一些线段,我们可以将每个线段与平面上的特定向量L(S)
相关联(让我们称之为L
平面)。当且仅当S1
时,两个线段S2
和L(S1) == L(S2)
将共线。
L(S)
被定义为从某个固定原点O
到从S
延伸的(无限)线上的最近点的向量。如果两个段位于同一条线上,那么它们将共享相同的最近点O
,如果不是,则它们不会。现在,您可以在L
平面上使用quadtree等空间树来查看哪些线段是共线的。
您可以使用详细记录的方法计算向量L(S)
,该方法可以找到到达另一个点的直线上的最近点,但这里有一个快速提醒。
肮脏的细节:当你的原点与任何细分市场共线时,情况会变糟。你必须处理这个案子。我认为处理这种情况的最佳方法是将这些段放在一边,移动原点,然后将算法重新应用于这些段。
此外,您希望用于重合的容差与O
的距离成比例。
答案 1 :(得分:0)
所以我设法通过使用这个脚本来解决问题:
http://www.movable-type.co.uk/scripts/latlon.js
然后是以下代码:
var p1 = new LatLon(item1.lat, items1.long);
var p2 = new LatLon(item2.lat, items2.long);
var p3 = new LatLon(item3.lat, items3.long);
var distance = Math.abs(Math.asin(Math.sin(p1.distanceTo(p3) / R) * Math.sin(p1.bearingTo(p3).toRad() - p1.bearingTo(p2).toRad())) * R);
我有一个主要问题:轴承是度数,但需要在Radians中!
p1.bearingTo(p3).toRad() - p1.bearingTo(p2).toRad()
您可以在此处查看工作版本(使用多个点查找它们之间的行):