1
0
Fork 0

Improved maps display and Airports dialog

- Display taxiways
- Display different surface types
- control over components (taxiways, parking positions, towers) displayed
- include distance and course to airport.
This commit is contained in:
Stuart Buchanan 2012-09-19 22:35:56 +01:00
parent 9281025930
commit 60e6be0e0f
2 changed files with 308 additions and 143 deletions

View file

@ -1,3 +1,19 @@
# Mapping from surface codes to
var SURFACECOLORS = {
1 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
2 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
3 : { type: "turf", r:0.2, g:0.5, b:0.2 },
4 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
5 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
# Helipads
6 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
7 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
8 : { type: "turf", r:0.2, g:0.5, b:0.2 },
9 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
0 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
};
# Runway # Runway
# #
var Runway = { var Runway = {
@ -34,12 +50,20 @@ var Runway = {
var AirportMap = { var AirportMap = {
# Create AirportMap from hash # Create AirportMap from hash
# #
# @param apt Hash containing airport data as returned from airportinfo() # @param apt Hash containing airport data as returned from airportinfo()
new: func(apt) # @param rwy Whether to display runways (default=1)
# @param taxi Whether to display taxiways (default=1)
# @param park Whether to display parking positions (default = 1)
# @param twr Whether to display tower positions (default = 1)
new: func(apt, rwy=1, taxi=1, park=1, twr=1)
{ {
return { return {
parents: [AirportMap], parents: [AirportMap],
_apt: apt _apt: apt,
_display_runways: rwy,
_display_taxiways: taxi,
_display_parking: park,
_display_tower: twr,
}; };
}, },
# Build the graphical representation of the represented airport # Build the graphical representation of the represented airport
@ -50,133 +74,180 @@ var AirportMap = {
var rws_done = {}; var rws_done = {};
me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id); me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id);
foreach(var rw; keys(me._apt.runways)) # Taxiways drawn first so the runways and parking positions end up on top.
if (me._display_taxiways)
{ {
var is_heli = substr(rw, 0, 1) == "H"; foreach(var taxi; me._apt.taxiways)
var rw_dir = is_heli ? nil : int(substr(rw, 0, 2));
var rw_rec = "";
var thresh_rec = 0;
if( rw_dir != nil )
{ {
rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36)); var clr = SURFACECOLORS[taxi.surface];
if( size(rw) == 3 ) if (clr == nil) { clr = SURFACECOLORS[0]};
{
var map_rec = { var icon_taxi =
"R": "L", me.grp_apt.createChild("path", "taxi")
"L": "R", .setStrokeLineWidth(0)
"C": "C" .setColor(clr.r, clr.g, clr.b)
}; .setColorFill(clr.r, clr.g, clr.b);
rw_rec ~= map_rec[substr(rw, 2)];
}
if( rws_done[rw_rec] != nil ) var txi = Runway.new(taxi);
continue; var beg1 = txi.pointOffCenterline(0, 0.5 * taxi.width);
var beg2 = txi.pointOffCenterline(0, -0.5 * taxi.width);
var end1 = txi.pointOffCenterline(taxi.length, 0.5 * taxi.width);
var end2 = txi.pointOffCenterline(taxi.length, -0.5 * taxi.width);
var rw_rec = me._apt.runways[rw_rec]; icon_taxi.setDataGeo
if( rw_rec != nil )
thresh_rec = rw_rec.threshold;
}
rws_done[rw] = 1;
rw = me._apt.runways[rw];
var icon_rw =
me.grp_apt.createChild("path", "runway-" ~ rw.id)
.setStrokeLineWidth(0.5)
.setColor(1.0,1.0,1.0)
.setColorFill(0.2, 0.2, 0.2);
var rwy = Runway.new(rw);
var beg_thr = rwy.pointOffCenterline(rw.threshold);
var beg_thr1 = rwy.pointOffCenterline(rw.threshold, 0.5 * rw.width);
var beg_thr2 = rwy.pointOffCenterline(rw.threshold, -0.5 * rw.width);
var beg1 = rwy.pointOffCenterline(0, 0.5 * rw.width);
var beg2 = rwy.pointOffCenterline(0, -0.5 * rw.width);
var end_thr = rwy.pointOffCenterline(rw.length - thresh_rec);
var end_thr1 = rwy.pointOffCenterline(rw.length - thresh_rec, 0.5 * rw.width);
var end_thr2 = rwy.pointOffCenterline(rw.length - thresh_rec, -0.5 * rw.width);
var end1 = rwy.pointOffCenterline(rw.length, 0.5 * rw.width);
var end2 = rwy.pointOffCenterline(rw.length, -0.5 * rw.width);
icon_rw.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_CLOSE_PATH ],
[ beg1[0], beg1[1],
beg2[0], beg2[1],
end2[0], end2[1],
end1[0], end1[1] ]
);
if( rw.length / rw.width > 3 and !is_heli )
{
# only runways which are much longer than wide are
# real runways, otherwise it's probably a heliport.
var icon_cl =
me.grp_apt.createChild("path", "centerline")
.setStrokeLineWidth(0.5)
.setColor(1,1,1)
.setStrokeDashArray([15, 10]);
icon_cl.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO ],
[ beg_thr[0], beg_thr[1],
end_thr[0], end_thr[1] ]
);
var icon_thr =
me.grp_apt.createChild("path", "threshold")
.setStrokeLineWidth(1.5)
.setColor(1,1,1);
icon_thr.setDataGeo
( (
[ canvas.Path.VG_MOVE_TO, [ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO, canvas.Path.VG_LINE_TO,
canvas.Path.VG_MOVE_TO, canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO ], canvas.Path.VG_LINE_TO,
[ beg_thr1[0], beg_thr1[1], canvas.Path.VG_CLOSE_PATH ],
beg_thr2[0], beg_thr2[1], [ beg1[0], beg1[1],
end_thr1[0], end_thr1[1], beg2[0], beg2[1],
end_thr2[0], end_thr2[1] ] end2[0], end2[1],
end1[0], end1[1] ]
); );
} }
} }
foreach(var park; me._apt.parking()) if (me._display_runways)
{ {
var icon_park = foreach(var rw; keys(me._apt.runways))
me.grp_apt.createChild("text", "parking-" ~ park.name) {
.setDrawMode( canvas.Text.ALIGNMENT var is_heli = substr(rw, 0, 1) == "H";
+ canvas.Text.TEXT ) var rw_dir = is_heli ? nil : int(substr(rw, 0, 2));
.setText(park.name)
.setFont("LiberationFonts/LiberationMono-Bold.ttf") var rw_rec = "";
.setGeoPosition(park.lat, park.lon) var thresh_rec = 0;
.setFontSize(15, 1.3); if( rw_dir != nil )
{
rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36));
if( size(rw) == 3 )
{
var map_rec = {
"R": "L",
"L": "R",
"C": "C"
};
rw_rec ~= map_rec[substr(rw, 2)];
}
if( rws_done[rw_rec] != nil )
continue;
var rw_rec = me._apt.runways[rw_rec];
if( rw_rec != nil )
thresh_rec = rw_rec.threshold;
}
rws_done[rw] = 1;
rw = me._apt.runways[rw];
var clr = SURFACECOLORS[rw.surface];
if (clr == nil) { clr = SURFACECOLORS[0]};
var icon_rw =
me.grp_apt.createChild("path", "runway-" ~ rw.id)
.setStrokeLineWidth(0.5)
.setColor(1.0,1.0,1.0)
.setColorFill(clr.r, clr.g, clr.b);
var rwy = Runway.new(rw);
var beg_thr = rwy.pointOffCenterline(rw.threshold);
var beg_thr1 = rwy.pointOffCenterline(rw.threshold, 0.5 * rw.width);
var beg_thr2 = rwy.pointOffCenterline(rw.threshold, -0.5 * rw.width);
var beg1 = rwy.pointOffCenterline(0, 0.5 * rw.width);
var beg2 = rwy.pointOffCenterline(0, -0.5 * rw.width);
var end_thr = rwy.pointOffCenterline(rw.length - thresh_rec);
var end_thr1 = rwy.pointOffCenterline(rw.length - thresh_rec, 0.5 * rw.width);
var end_thr2 = rwy.pointOffCenterline(rw.length - thresh_rec, -0.5 * rw.width);
var end1 = rwy.pointOffCenterline(rw.length, 0.5 * rw.width);
var end2 = rwy.pointOffCenterline(rw.length, -0.5 * rw.width);
icon_rw.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_CLOSE_PATH ],
[ beg1[0], beg1[1],
beg2[0], beg2[1],
end2[0], end2[1],
end1[0], end1[1] ]
);
if( rw.length / rw.width > 3 and !is_heli )
{
# only runways which are much longer than wide are
# real runways, otherwise it's probably a heliport.
var icon_cl =
me.grp_apt.createChild("path", "centerline")
.setStrokeLineWidth(0.5)
.setColor(1,1,1)
.setStrokeDashArray([15, 10]);
icon_cl.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO ],
[ beg_thr[0], beg_thr[1],
end_thr[0], end_thr[1] ]
);
var icon_thr =
me.grp_apt.createChild("path", "threshold")
.setStrokeLineWidth(1.5)
.setColor(1,1,1);
icon_thr.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO ],
[ beg_thr1[0], beg_thr1[1],
beg_thr2[0], beg_thr2[1],
end_thr1[0], end_thr1[1],
end_thr2[0], end_thr2[1] ]
);
}
}
} }
var icon_tower = if (me._display_parking)
me.grp_apt.createChild("path", "tower") {
.setStrokeLineWidth(1) foreach(var park; me._apt.parking())
.setScale(1.5) {
.setColor(0.2,0.2,1.0) var icon_park =
.moveTo(-3, 0) me.grp_apt.createChild("text", "parking-" ~ park.name)
.vert(-10) .setDrawMode( canvas.Text.ALIGNMENT
.line(-3, -10) + canvas.Text.TEXT )
.horiz(12) .setText(park.name)
.line(-3, 10) .setFont("LiberationFonts/LiberationMono-Bold.ttf")
.vert(10); .setGeoPosition(park.lat, park.lon)
.setFontSize(15, 1.3);
var pos = me._apt.tower(); }
icon_tower.setGeoPosition(pos.lat, pos.lon); }
if (me._display_tower)
{
var icon_tower =
me.grp_apt.createChild("path", "tower")
.setStrokeLineWidth(1)
.setScale(1.5)
.setColor(0.2,0.2,1.0)
.moveTo(-3, 0)
.vert(-10)
.line(-3, -10)
.horiz(12)
.line(-3, 10)
.vert(10);
var pos = me._apt.tower();
icon_tower.setGeoPosition(pos.lat, pos.lon);
}
} }
}; };

View file

@ -30,11 +30,23 @@
<hrule/> <hrule/>
<nasal> <nasal>
<open> <open><![CDATA[
setprop("/sim/gui/dialogs/airports/selected-airport/rwy", ""); setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", ""); setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
setprop("/sim/gui/dialogs/airports/list", ""); setprop("/sim/gui/dialogs/airports/list", "");
if (getprop("/sim/gui/dialogs/airports/display-taxiways") == "") {
setprop("/sim/gui/dialogs/airports/display-taxiways", "1");
}
if (getprop("/sim/gui/dialogs/airports/display-parking") == "") {
setprop("/sim/gui/dialogs/airports/display-parking", "0");
}
if (getprop("/sim/gui/dialogs/airports/display-tower") == "") {
setprop("/sim/gui/dialogs/airports/display-tower", "1");
}
var airport_id = getprop("/sim/presets/airport-id"); var airport_id = getprop("/sim/presets/airport-id");
if (airport_id == nil) { airport_id = "KSFO"; } if (airport_id == nil) { airport_id = "KSFO"; }
@ -75,7 +87,7 @@
var info = airportinfo(airport_id); var info = airportinfo(airport_id);
setprop("/sim/gui/dialogs/airports/selected-airport/id", airport_id); setprop("/sim/gui/dialogs/airports/selected-airport/id", airport_id);
setprop("/sim/gui/dialogs/airports/selected-airport/name", info.name ~ " (" ~ airport_id ~ ")"); setprop("/sim/gui/dialogs/airports/selected-airport/name", info.name ~ " (" ~ airport_id ~ ")");
setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lon, info.lat)); setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lat, info.lon));
setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon); setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon);
setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation); setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation);
setprop("/sim/gui/dialogs/airports/selected-airport/rwy", ""); setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
@ -105,6 +117,14 @@
setprop("/sim/gui/dialogs/airports/selected-airport/longest-runway", longest_runway); setprop("/sim/gui/dialogs/airports/selected-airport/longest-runway", longest_runway);
var airport_pos = geo.Coord.new();
airport_pos.set_latlon(info.lat, info.lon);
var dst = airport_pos.distance_to(geo.aircraft_position()) / 1852.0;
var crs = airport_pos.course_to(geo.aircraft_position());
setprop("/sim/gui/dialogs/airports/selected-airport/distance-nm", dst);
setprop("/sim/gui/dialogs/airports/selected-airport/course-deg", crs);
gui.dialog_update("airports", "runway-list"); gui.dialog_update("airports", "runway-list");
gui.dialog_update("airports", "parking-list"); gui.dialog_update("airports", "parking-list");
} }
@ -136,12 +156,11 @@
} else { } else {
setprop("/sim/presets/runway", ""); setprop("/sim/presets/runway", "");
setprop("/sim/presets/parkpos", getprop("/sim/gui/dialogs/airports/selected-airport/parkpos")); setprop("/sim/presets/parkpos", getprop("/sim/gui/dialogs/airports/selected-airport/parkpos"));
} }
} }
update_info(); update_info();
]]>
</open> </open>
</nasal> </nasal>
@ -234,7 +253,7 @@
<text> <text>
<row>0</row> <row>0</row>
<col>0</col> <col>0</col>
<width>200</width> <width>100</width>
<halign>right</halign> <halign>right</halign>
<label>Airport:</label> <label>Airport:</label>
</text> </text>
@ -251,7 +270,7 @@
<row>1</row> <row>1</row>
<col>0</col> <col>0</col>
<halign>right</halign> <halign>right</halign>
<label>Lon/Lat:</label> <label>Lat / Lon:</label>
</text> </text>
<text> <text>
<row>1</row> <row>1</row>
@ -263,16 +282,16 @@
<text> <text>
<row>1</row> <row>1</row>
<col>3</col> <col>2</col>
<halign>right</halign> <halign>right</halign>
<label>Elevation (ft):</label> <label>Elevation:</label>
</text> </text>
<text> <text>
<row>1</row> <row>1</row>
<col>4</col> <col>3</col>
<halign>left</halign> <halign>left</halign>
<live>true</live> <live>true</live>
<format>%.0f</format> <format>%.0f ft</format>
<property>/sim/gui/dialogs/airports/selected-airport/elevation-ft</property> <property>/sim/gui/dialogs/airports/selected-airport/elevation-ft</property>
</text> </text>
@ -280,17 +299,47 @@
<row>2</row> <row>2</row>
<col>0</col> <col>0</col>
<halign>right</halign> <halign>right</halign>
<label>Longest runway (ft):</label> <label>Longest runway:</label>
</text> </text>
<text> <text>
<row>2</row> <row>2</row>
<col>1</col> <col>1</col>
<halign>left</halign> <halign>left</halign>
<live>true</live> <live>true</live>
<format>%.0f</format> <format>%.0f ft</format>
<property>/sim/gui/dialogs/airports/selected-airport/longest-runway</property> <property>/sim/gui/dialogs/airports/selected-airport/longest-runway</property>
</text> </text>
<text>
<row>3</row>
<col>0</col>
<halign>right</halign>
<label>Distance:</label>
</text>
<text>
<row>3</row>
<col>1</col>
<halign>left</halign>
<live>true</live>
<format>%.1f nm</format>
<property>/sim/gui/dialogs/airports/selected-airport/distance-nm</property>
</text>
<text>
<row>3</row>
<col>2</col>
<halign>right</halign>
<label>Course:</label>
</text>
<text>
<row>3</row>
<col>3</col>
<halign>left</halign>
<live>true</live>
<format>%.0f deg</format>
<property>/sim/gui/dialogs/airports/selected-airport/course-deg</property>
</text>
</group> </group>
<hrule/> <hrule/>
@ -437,7 +486,11 @@
map.removeAllChildren(); map.removeAllChildren();
layer_runways = map.createChild("group", "runways"); layer_runways = map.createChild("group", "runways");
var airport = canvas.AirportMap.new(apt); var display_taxiways = getprop("/sim/gui/dialogs/airports/display-taxiways");
var display_parking = getprop("/sim/gui/dialogs/airports/display-parking");
var display_tower = getprop("/sim/gui/dialogs/airports/display-tower");
var airport = canvas.AirportMap.new(apt, 1, display_taxiways, display_parking, display_tower);
airport.build(layer_runways); airport.build(layer_runways);
map._node.getNode("ref-lat", 1).setDoubleValue(apt.lat); map._node.getNode("ref-lat", 1).setDoubleValue(apt.lat);
@ -513,18 +566,26 @@
} }
} }
var aptlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/id", updateMap); var listeners = [];
var rwylistener = setlistener("/sim/gui/dialogs/airports/selected-airport/rwy", updateRunwayHighlight);
var parkposlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/parkpos", updateParkingHighlight); append(listeners, setlistener("/sim/gui/dialogs/airports/selected-airport/id", updateMap));
append(listeners, setlistener("/sim/gui/dialogs/airports/selected-airport/rwy", updateRunwayHighlight));
append(listeners, setlistener("/sim/gui/dialogs/airports/selected-airport/parkpos", updateParkingHighlight));
append(listeners, setlistener("/sim/gui/dialogs/airports/display-taxiways", updateMap));
append(listeners, setlistener("/sim/gui/dialogs/airports/display-parking", updateMap));
append(listeners, setlistener("/sim/gui/dialogs/airports/display-tower", updateMap));
update_info(); update_info();
updateZoom(); updateZoom();
]]> ]]>
</load> </load>
<close> <close><![CDATA[
removelistener(aptlistener); foreach (var listener, listeners)
removelistener(rwylistener); {
removelistener(parkposlistener); removelistener(listener);
}
]]>
</close> </close>
</nasal> </nasal>
</canvas> </canvas>
@ -549,7 +610,8 @@
</button> </button>
<text> <text>
<label>MMM</label> <label>MMMM</label>
<halign>center</halign>
<format>Zoom %d</format> <format>Zoom %d</format>
<property>/sim/gui/dialogs/airports/zoom</property> <property>/sim/gui/dialogs/airports/zoom</property>
<live>true</live> <live>true</live>
@ -563,11 +625,43 @@
<binding> <binding>
<command>property-adjust</command> <command>property-adjust</command>
<property>//sim/gui/dialogs/airports/zoom</property> <property>/sim/gui/dialogs/airports/zoom</property>
<step>1</step> <step>1</step>
<max>4</max> <max>4</max>
</binding> </binding>
</button> </button>
<empty><stretch>true</stretch></empty>
<checkbox>
<name>display-taxiways</name>
<label>Display Taxiways</label>
<property>/sim/gui/dialogs/airports/display-taxiways</property>
<binding>
<command>dialog-apply</command>
<object-name>display-taxiways</object-name>
</binding>
</checkbox>
<checkbox>
<name>display-parking</name>
<label>Display Parking Position</label>
<property>/sim/gui/dialogs/airports/display-parking</property>
<binding>
<command>dialog-apply</command>
<object-name>display-parking</object-name>
</binding>
</checkbox>
<checkbox>
<name>display-tower</name>
<label>Display Tower</label>
<property>/sim/gui/dialogs/airports/display-tower</property>
<binding>
<command>dialog-apply</command>
<object-name>display-tower</object-name>
</binding>
</checkbox>
</group> </group>
</group> </group>
</group> </group>
@ -581,7 +675,7 @@
<empty><stretch>true</stretch></empty> <empty><stretch>true</stretch></empty>
<button> <button>
<legend>OK</legend> <legend>Go To Airport</legend>
<equal>true</equal> <equal>true</equal>
<binding> <binding>
<command>dialog-apply</command> <command>dialog-apply</command>
@ -602,7 +696,7 @@
<empty><stretch>true</stretch></empty> <empty><stretch>true</stretch></empty>
<button> <button>
<legend>Cancel</legend> <legend>Close</legend>
<equal>true</equal> <equal>true</equal>
<key>Esc</key> <key>Esc</key>
<binding> <binding>