地理坐标偏移 - 机场跑道图
Geo Coordinates offset - airport runways diagram
我正在尝试生成机场跑道图,如下所示:
每个机场都有一个跑道列表,如下所示:
const runways = [
{
identifier1: "110L",
identifier2: "28R",
length: 3107,
width: 75,
latitude1: 37.66247544,
longitude1: -122.12726156,
latitude2: 37.65822686,
longitude2: -122.11795339,
},
{
identifier1: "10R",
identifier2: "28L",
length: 5694,
width: 150,
latitude1: 37.66204453,
longitude1: -122.12979078,
latitude2: 37.65426,
longitude2: -122.11273375,
},
];
如您所见,每条跑道都有起点和终点地理点。
对于视觉效果,我使用 svg-airports,上面的跑道示例表示为:
<airport-diagram width="200" height="200">
<airport-runway
length-ft="3107"
true-heading="119"
offset-angle="29"
offset-x="300"
offset-y="1000"
>
<runway-id name="10L" pattern="left"></runway-id>
<runway-id name="28R" pattern="right"></runway-id>
</airport-runway>
<airport-runway
length-ft="5694"
true-heading="119"
offset-angle="29"
offset-x="300"
offset-y="-1000"
>
<runway-id name="10R" pattern="right"></runway-id>
<runway-id name="28L" pattern="left"></runway-id>
</airport-runway>
</airport-diagram>
如您所见,每条跑道都有以下值
- 长度
- 真航向
- 偏移角度
- 偏移-x
- 偏移-y
我能够提供长度,因为我已经从我的 airport
中获得了该信息,并且我正在计算真实航向(方位角)如下:
function radians(n) {
return n * (Math.PI / 180);
}
function degrees(n) {
return n * (180 / Math.PI);
}
function getBearing(startLat, startLong, endLat, endLong) {
startLat = radians(startLat);
startLong = radians(startLong);
endLat = radians(endLat);
endLong = radians(endLong);
var dLong = endLong - startLong;
var dPhi = Math.log(
Math.tan(endLat / 2.0 + Math.PI / 4.0) /
Math.tan(startLat / 2.0 + Math.PI / 4.0)
);
if (Math.abs(dLong) > Math.PI) {
if (dLong > 0.0) dLong = -(2.0 * Math.PI - dLong);
else dLong = 2.0 * Math.PI + dLong;
}
return (degrees(Math.atan2(dLong, dPhi)) + 180.0) % 180.0;
}
问题是,我可以根据跑道之间的地理坐标计算offset-angle
、offset-x
和offset-y
吗?
P.S:偏移值以英尺为单位。
将longitude/latitude转换为笛卡尔坐标。那么它应该很容易。
我认为转换是问题所在。
对于机场(相对较小),可以使用简单的equirectangular projection。
<!doctype html>
<html>
<body>
<script src="t.js"></script>
<script src="svg-airports-1.0.js" async></script>
</body>
</html>
// t.js
// important parts within ////// commments
const runways = [
{
identifier1: "110L",
identifier2: "28R",
length: 3107,
width: 75,
latitude1: 37.66247544,
longitude1: -122.12726156,
latitude2: 37.65822686,
longitude2: -122.11795339,
}, {
identifier1: "10R",
identifier2: "28L",
length: 5694,
width: 150,
latitude1: 37.66204453,
longitude1: -122.12979078,
latitude2: 37.65426,
longitude2: -122.11273375,
},
];
function runways2html(runways,scale=1.0) {
//
airport = document.createElement("airport-diagram")
document.body.appendChild(airport)
//////////////////////////////////////////////////////////////////////
const radians = n => n * (Math.PI / 180)
const degrees = n => n * (180 / Math.PI)
const avg = (v1,v2) => .5*(v1+v2)
const lon2x = lon => R*(lon-lon0)*cosLat0
const lat2y = lat => R*(lat-lat0)
//
var lons = runways.map(({longitude1,longitude2}) => [longitude1,longitude2]).flat().map(v => radians(v))
var lats = runways.map(({latitude1,latitude2}) => [latitude1,latitude2]).flat().map(v => radians(v))
var lonMax = Math.max(...lons)
var lonMin = Math.min(...lons)
var latMax = Math.max(...lats)
var latMin = Math.min(...lats)
var lon0 = avg(lonMin,lonMax)
var lat0 = avg(latMin,latMax)
var cosLat0 = Math.cos(lat0)
var R = 20902000 // Earth radius in feet (??)
//////////////////////////////////////////////////////////////////////
var [xMin,xMax] = [lonMin,lonMax].map(lon2x)
var [yMin,yMax] = [latMin,latMax].map(lat2y)
var width = xMax-xMin
var height = yMax-yMin
var [width,height] = [width,height].map(v => v*scale)
airport.setAttribute("width",width)
airport.setAttribute("height",height)
//
runways.forEach(runway => {
var {
identifier1,
identifier2,
length,
width,
latitude1,
longitude1,
latitude2,
longitude2,
} = runway
//////////////////////////////////////////////////////////////////////
var [longitude1,longitude2,latitude1,latitude2] = [longitude1,longitude2,latitude1,latitude2].map(v => radians(v))
var [x1,x2] = [longitude1,longitude2].map(lon2x)
var [y1,y2] = [latitude1,latitude2].map(lat2y)
var heading = Math.atan2(x2-x1,y2-y1)
heading = degrees(heading)
var x = avg(x1,x2)
var y = avg(y1,y2)
//////////////////////////////////////////////////////////////////////
var runway = document.createElement("airport-runway")
runway.setAttribute("length-ft",length)
runway.setAttribute("true-heading",heading)
runway.setAttribute("offset-angle",0)
runway.setAttribute("offset-x",x)
runway.setAttribute("offset-y",y)
var [id1,id2] = [0,1].map(i => document.createElement("runway-id"))
id1.setAttribute("name",identifier1)
id1.setAttribute("pattern",identifier1.endsWith("L")?"left":"right") // ??
id2.setAttribute("name",identifier2)
id2.setAttribute("pattern",identifier1.endsWith("L")?"right":"left") // ??
runway.appendChild(id1)
runway.appendChild(id2)
airport.appendChild(runway)
})
}
runways2html(runways,0.2)
我正在尝试生成机场跑道图,如下所示:
每个机场都有一个跑道列表,如下所示:
const runways = [
{
identifier1: "110L",
identifier2: "28R",
length: 3107,
width: 75,
latitude1: 37.66247544,
longitude1: -122.12726156,
latitude2: 37.65822686,
longitude2: -122.11795339,
},
{
identifier1: "10R",
identifier2: "28L",
length: 5694,
width: 150,
latitude1: 37.66204453,
longitude1: -122.12979078,
latitude2: 37.65426,
longitude2: -122.11273375,
},
];
如您所见,每条跑道都有起点和终点地理点。 对于视觉效果,我使用 svg-airports,上面的跑道示例表示为:
<airport-diagram width="200" height="200">
<airport-runway
length-ft="3107"
true-heading="119"
offset-angle="29"
offset-x="300"
offset-y="1000"
>
<runway-id name="10L" pattern="left"></runway-id>
<runway-id name="28R" pattern="right"></runway-id>
</airport-runway>
<airport-runway
length-ft="5694"
true-heading="119"
offset-angle="29"
offset-x="300"
offset-y="-1000"
>
<runway-id name="10R" pattern="right"></runway-id>
<runway-id name="28L" pattern="left"></runway-id>
</airport-runway>
</airport-diagram>
如您所见,每条跑道都有以下值
- 长度
- 真航向
- 偏移角度
- 偏移-x
- 偏移-y
我能够提供长度,因为我已经从我的 airport
中获得了该信息,并且我正在计算真实航向(方位角)如下:
function radians(n) {
return n * (Math.PI / 180);
}
function degrees(n) {
return n * (180 / Math.PI);
}
function getBearing(startLat, startLong, endLat, endLong) {
startLat = radians(startLat);
startLong = radians(startLong);
endLat = radians(endLat);
endLong = radians(endLong);
var dLong = endLong - startLong;
var dPhi = Math.log(
Math.tan(endLat / 2.0 + Math.PI / 4.0) /
Math.tan(startLat / 2.0 + Math.PI / 4.0)
);
if (Math.abs(dLong) > Math.PI) {
if (dLong > 0.0) dLong = -(2.0 * Math.PI - dLong);
else dLong = 2.0 * Math.PI + dLong;
}
return (degrees(Math.atan2(dLong, dPhi)) + 180.0) % 180.0;
}
问题是,我可以根据跑道之间的地理坐标计算offset-angle
、offset-x
和offset-y
吗?
P.S:偏移值以英尺为单位。
将longitude/latitude转换为笛卡尔坐标。那么它应该很容易。 我认为转换是问题所在。
对于机场(相对较小),可以使用简单的equirectangular projection。
<!doctype html>
<html>
<body>
<script src="t.js"></script>
<script src="svg-airports-1.0.js" async></script>
</body>
</html>
// t.js
// important parts within ////// commments
const runways = [
{
identifier1: "110L",
identifier2: "28R",
length: 3107,
width: 75,
latitude1: 37.66247544,
longitude1: -122.12726156,
latitude2: 37.65822686,
longitude2: -122.11795339,
}, {
identifier1: "10R",
identifier2: "28L",
length: 5694,
width: 150,
latitude1: 37.66204453,
longitude1: -122.12979078,
latitude2: 37.65426,
longitude2: -122.11273375,
},
];
function runways2html(runways,scale=1.0) {
//
airport = document.createElement("airport-diagram")
document.body.appendChild(airport)
//////////////////////////////////////////////////////////////////////
const radians = n => n * (Math.PI / 180)
const degrees = n => n * (180 / Math.PI)
const avg = (v1,v2) => .5*(v1+v2)
const lon2x = lon => R*(lon-lon0)*cosLat0
const lat2y = lat => R*(lat-lat0)
//
var lons = runways.map(({longitude1,longitude2}) => [longitude1,longitude2]).flat().map(v => radians(v))
var lats = runways.map(({latitude1,latitude2}) => [latitude1,latitude2]).flat().map(v => radians(v))
var lonMax = Math.max(...lons)
var lonMin = Math.min(...lons)
var latMax = Math.max(...lats)
var latMin = Math.min(...lats)
var lon0 = avg(lonMin,lonMax)
var lat0 = avg(latMin,latMax)
var cosLat0 = Math.cos(lat0)
var R = 20902000 // Earth radius in feet (??)
//////////////////////////////////////////////////////////////////////
var [xMin,xMax] = [lonMin,lonMax].map(lon2x)
var [yMin,yMax] = [latMin,latMax].map(lat2y)
var width = xMax-xMin
var height = yMax-yMin
var [width,height] = [width,height].map(v => v*scale)
airport.setAttribute("width",width)
airport.setAttribute("height",height)
//
runways.forEach(runway => {
var {
identifier1,
identifier2,
length,
width,
latitude1,
longitude1,
latitude2,
longitude2,
} = runway
//////////////////////////////////////////////////////////////////////
var [longitude1,longitude2,latitude1,latitude2] = [longitude1,longitude2,latitude1,latitude2].map(v => radians(v))
var [x1,x2] = [longitude1,longitude2].map(lon2x)
var [y1,y2] = [latitude1,latitude2].map(lat2y)
var heading = Math.atan2(x2-x1,y2-y1)
heading = degrees(heading)
var x = avg(x1,x2)
var y = avg(y1,y2)
//////////////////////////////////////////////////////////////////////
var runway = document.createElement("airport-runway")
runway.setAttribute("length-ft",length)
runway.setAttribute("true-heading",heading)
runway.setAttribute("offset-angle",0)
runway.setAttribute("offset-x",x)
runway.setAttribute("offset-y",y)
var [id1,id2] = [0,1].map(i => document.createElement("runway-id"))
id1.setAttribute("name",identifier1)
id1.setAttribute("pattern",identifier1.endsWith("L")?"left":"right") // ??
id2.setAttribute("name",identifier2)
id2.setAttribute("pattern",identifier1.endsWith("L")?"right":"left") // ??
runway.appendChild(id1)
runway.appendChild(id2)
airport.appendChild(runway)
})
}
runways2html(runways,0.2)