Merge remote-tracking branch 'upstream/master' into dev

This commit is contained in:
Oliver Jowett 2016-09-10 21:40:13 +01:00
commit ac2b977168
51 changed files with 877 additions and 162 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -16,6 +16,7 @@
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript" src="markers.js"></script>
<script type="text/javascript" src="dbloader.js"></script>
<script type="text/javascript" src="registrations.js"></script>
<script type="text/javascript" src="planeObject.js"></script>
<script type="text/javascript" src="formatter.js"></script>
<script type="text/javascript" src="flags.js"></script>

View file

@ -66,6 +66,27 @@ function createBaseLayers() {
}
}
var nexrad = new ol.layer.Tile({
name: 'nexrad',
title: 'NEXRAD',
type: 'overlay',
opacity: 0.5,
visible: false
});
us.push(nexrad);
var refreshNexrad = function() {
// re-build the source to force a refresh of the nexrad tiles
var now = new Date().getTime();
nexrad.setSource(new ol.source.XYZ({
url : 'http://mesonet{1-3}.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/{z}/{x}/{y}.png?_=' + now,
attributions: 'NEXRAD courtesy of <a href="http://mesonet.agron.iastate.edu/">IEM</a>'
}));
};
refreshNexrad();
window.setInterval(refreshNexrad, 5 * 60000);
if (world.length > 0) {
layers.push(new ol.layer.Group({
name: 'world',

View file

@ -58,43 +58,194 @@ var _beechcraft_svg =
var _heavy_svg =
"m28.64874,12.035023l0,8.801421l-4.585627,3.066495c0.126825,-0.257055 0.094102,-0.531839 0.095802,-0.802796l-0.015437,-3.087446l-2.230453,-0.012673l0.019009,3.599141c0.000513,0.577993 0.076338,0.923195 0.589296,1.241956l-5.533809,3.630512c0.166511,-0.256275 0.153699,-0.551367 0.153699,-0.841892l-0.005929,-3.270195l-2.160751,-0.012672l-0.006337,3.637159c0.016349,0.5301 0.096662,1.090947 0.576623,1.419379l-11.976014,7.825597c-2.106287,1.48859 -1.705322,3.044253 -1.56512,4.587637l26.645047,-9.048544l0,13.750239l0.722364,5.062875l-8.681027,6.387208c-1.239945,1.059417 -1.080616,2.171837 -0.842757,3.256969l11.278998,-2.946479c0.130159,3.116897 1.559821,3.171571 1.780561,0.006336l11.278998,2.94648c0.23786,-1.085133 0.397189,-2.197552 -0.842756,-3.256969l-8.681026,-6.387207l0.722362,-5.062875l0,-13.750239l26.645048,9.042207c0.140203,-1.543381 0.541167,-3.092711 -1.56512,-4.581301l-11.976015,-7.825597c0.47996,-0.328434 0.553938,-0.889279 0.570286,-1.419379l0,-3.63716l-2.160751,0.012673l-0.005378,3.328244c-0.002334,0.294243 0.007077,0.545056 0.178191,0.817583l-5.565189,-3.664251c0.512962,-0.318761 0.59512,-0.663963 0.595633,-1.241956l0.019009,-3.599141l-2.230454,0.012673l-0.015793,3.100403c0.001462,0.282341 -0.019949,0.535579 0.124839,0.794638l-4.614307,-3.071294l0,-8.801421c-1.111672,-11.152869 -5.489391,-11.217579 -6.735717,-0.006336z";
var MarkerIcons = {
generic : {
scale : 0.4,
size : [64, 64],
anchor : [32, 32],
path : _generic_plane_svg
},
// From https://discussions.flightaware.com/ads-b-flight-tracking-f21/some-custom-svg-plane-icons-t37783.html
// by Peter Lowden
// licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
light : {
scale : 0.4,
// NB: scaled so that 1 pixel is about 1.33m (0.75px = 1m)
var _a320 = {
key: "a320",
scale: 0.60 * 0.75,
size: [64, 64],
anchor: [32, 28],
path: "m 32,1 2,1 2,3 0,18 4,1 0,-4 3,0 0,5 17,6 0,3 -15,-2 -9,0 0,12 -2,6 7,3 0,2 -8,-1 -1,2 -1,-2 -8,1 0,-2 7,-3 -2,-6 0,-12 -9,0 -15,2 0,-3 17,-6 0,-5 3,0 0,4 4,-1 0,-18 2,-3 2,-1z"
};
var _b777 = {
key: "b777",
scale: 1.15 * 0.75,
size: [64, 64],
anchor: [32, 32],
path: "m 32,1 2,1 1,2 0,20 4,4 0,-4 3,0 0,4 -1,2 17,12 0,2 -16,-5 -7,0 0,13 -1,5 7,5 0,2 -8,-2 -1,2 -1,-2 -8,2 0,-2 7,-5 -1,-5 0,-13 -7,0 -16,5 0,-2 17,-12 -1,-2 0,-4 3,0 0,4 4,-4 0,-20 1,-2 2,-1z"
};
var _dash8 = {
key: "dash8",
scale: 0.52 * 0.75,
size: [64, 64],
anchor: [32, 30],
path: "m 32,1 3,4 0,20 4,0 0,-5 1,-1 1,1 0,5 17,2 0,3 -17,2 0,3 -1,1 -1,-1 0,-3 -4,0 0,15 -1,8 6,0 1,1 0,3 -8,0 -1,1 -1,-1 -8,0 0,-3 1,-1 6,0 -1,-8 0,-15 -4,0 0,3, -1,1 -1,-1 0,-3 -17,-2 0,-3 17,-2 0,-5 1,-1 1,1 0,5 4,0 0,-20 3,-4z"
};
var _b200 = {
key: "b200",
scale: 0.31 * 0.75,
size: [64, 64],
anchor: [32, 19],
path: "m 32,1 1,0 1,2 1,4 0,5 5,0 0,-5 -1,-1 2,-2 2,2 -1,1 0,5 17,2 0,3 -17,3 0,1 -2,0 0,-1 -5,0 0,5 -2,8 6,3 0,2 -6,-1 -1,0 -6,1 0,-2 6,-3 -2,-8 0,-5 -5,0 0,1, -2,0 0,-1 -17,-3 0,-3 17,-2 0,-5 -1,-1 2,-2 2,2 -1,1 0,5 5,0 0,-5 1,-4 1,-2 z"
};
var _g650 = {
key: "g650",
scale: 0.58 * 0.75,
size: [64, 64],
anchor: [32, 26],
path: "m 32,1 1,0 1,2 1,4 0,10 21,17 0,5 -2,-2 -16,-8 -3,0 0,3 2,0 1,1 0,5 -1,1 0,3 -2,0 0,1 7,5 0,3 -9,-3 -1,0 -9,3 0,-3 7,-5 0,-1 -2,0 0,-3 -1,-1 0,-5 1,-1 2,0 0,-3 -3,0 -16,8 -2,2 0,-5 21,-17 0,-10 1,-4 1,-2z"
};
var _c130 = {
key: "c130",
scale: 0.75 * 0.75,
size: [64, 64],
anchor: [32, 17],
path: "m 31,1 1,0 1,1 1,2 0,8 3,0 0,-3 1,-1 1,1 0,3 6,0 0,-3 1,-1 1,1 0,3 10,1 0,2 -1,1 -17,3 -5,0 0,10 -1,1 8,2 0,1 -1,1 -8,0 -1,1 -1,-1 -8,0 -1,-1 0,-1 8,-2 -1,-1 0,-10 -5,0 -17,-3 -1,-1 0,-2 10,-1 0,-3 1,-1 1,1 0,3 6,0 0,-3 1,-1 1,1 0,3 3,0 0,-8 1,-2 1,-1 z"
};
var _balloon = {
key: "balloon",
scale: 0.50,
size: [64, 64],
anchor: [32, 32],
path: "m 27,1 10,0 3,1 3,1 1,1 2,1 6,6 1,2 1,1 1,3 1,3 0,10 -1,3 -1,3 -1,1 -1,2 -6,6 -2,1 -1,1 -2,1 -2,1 -2,8 -1,0 2,-8 -3,1 -6,0 -3,-1 2,8 9,0 0,6 -10,0 0,-6 -2,-8 -2,-1 -2,-1 -1,-1 -2,-1 -6,-6 -1,-2 -1,-1 -1,-3 -1,-3 0,-10 1,-3 1,-3 1,-1 1,-2 6,-6 2,-1 1,-1 3,-1 3,-1 z",
noRotate: true,
markerRadius: 32
};
// by Oliver Jowett <oliver@mutability.co.uk>
// licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
var _a380 = {
key: "a380",
scale: 1.26 * 0.75,
size: [64, 64],
anchor: [32, 30],
path: "m 32,59 -1,-4 -4,1 -7,3 -1,0 1,-3 1,-1 7,-6 2,-2 -1,-5 0,-9 -1,-2 -2,0 -6,2 -5,2 -5,2 -9,4 0,1 0,-3 1,-2 9,-7 -1,-1 0,-4 1,-1 1,0 1,1 0,3 1,0 5,-4 0,-5 1,-1 1,0 1,1 0,3 6,-5 1,-2 0,-7 1,-5 1,-2 1,-1 1,1 1,2 1,5 0,7 1,2 6,5 0,-3 1,-1 1,0 1,1 0,5 5,4 1,0 0,-3 1,-1 1,0 1,1 0,4 -1,1 9,7 1,2 0,3 0,-1 -9,-4 -5,-2 -5,-2 -6,-2 -2,0 -1,2 0,9 -1,5 2,2 7,6 1,1 1,3 -1,0 -7,-3 -4,-1 -1,4 z"
};
var _b738 = {
key: "b738",
scale: 0.63 * 0.75,
size: [64, 64],
anchor: [32, 32],
path: "m 32,61 -1,-1 -9,2 -2,1 0,-2 9,-6 1,-1 -1,-9 0,-11 -7,0 -1,1 0,-1 -3,1 -1,1 0,-1 -3,1 -9,3 -1,1 0,-2 1,-2 17,-9 1,-1 -1,-2 0,-3 1,-1 2,0 1,1 0,3 3,-2 0,-13 1,-5 1,-3 1,-1 1,1 1,3 1,5 0,13 3,2 0,-3 1,-1 2,0 1,1 0,3 -1,2 1,1 17,9 1,2 0,2 -1,-1 -9,-3 -3,-1 0,1 -1,-1 -3,-1 0,1 -1,-1 -7,0 0,11 -1,9 1,1 9,6 0,2 -2,-1 -9,-2 -1,1 z"
};
var TypeIcons = {
'A318': _a320, // shortened a320
'A319': _a320, // shortened a320
'A320': _a320,
'A321': _a320, // stretched a320
'A388': _a380,
// dubious since these are old-generation 737s
// but the shape is similar
'B731': _b738,
'B732': _b738,
'B733': _b738,
'B734': _b738,
'B735': _b738,
// these probably need reworking
// since they vary in length
'B736': _b738,
'B737': _b738,
'B738': _b738,
'B739': _b738,
'B772': _b777, // all pretty similar except for length
'B77W': _b777,
'B773': _b777,
'B77L': _b777,
'DH8A': _dash8,
'DH8B': _dash8,
'DH8C': _dash8,
'DH8D': _dash8,
'BE20': _b200,
'GLF5': _g650, // close enough
'GLF6': _g650,
'C130': _c130,
'C30J': _c130
};
var CategoryIcons = {
"A1" : {
key : "A1",
scale : 0.30,
size : [64, 64],
anchor : [32, 25],
path : _beechcraft_svg
},
medium : {
scale : 0.4,
"A2" : {
key : "A2",
scale : 0.35,
size : [64, 64],
anchor : [32, 32],
path : _generic_plane_svg
},
heavy : {
scale : 0.6,
"A3" : {
key : "A3",
scale : 0.40,
size : [64, 64],
anchor : [32, 32],
path : _generic_plane_svg
},
"A5" : {
key : "A5",
scale : 0.73,
size : [64, 64],
anchor : [32, 32],
path : _heavy_svg
},
rotorcraft : {
scale : 0.5,
"A7" : {
key : "A7",
scale : 0.50,
size : [64, 64],
anchor : [22, 32],
path : _rotorcraft_svg
}
},
"B2" : _balloon
};
var DefaultIcon = {
key : "default",
scale : 0.4,
size : [64, 64],
anchor : [32, 32],
path : _generic_plane_svg
};
function getBaseMarker(category, type) {
if (type in TypeIcons) {
return TypeIcons[type];
}
if (category in CategoryIcons) {
return CategoryIcons[category];
}
return DefaultIcon;
}
function svgPathToSvg(path, size, stroke, width, fill) {
var svg = '<svg width="' + size[0] + 'px" height="' + size[1] + 'px" version="1.1" xmlns="http://www.w3.org/2000/svg">';
svg += '<path d="' + path + '"';

View file

@ -39,12 +39,17 @@ function PlaneObject(icao) {
this.marker = null;
this.markerStyle = null;
this.markerIcon = null;
this.markerStaticStyle = null;
this.markerStaticIcon = null;
this.markerStyleKey = null;
this.markerSvgKey = null;
// request metadata
this.registration = null;
// start from a computed registration, let the DB override it
// if it has something else.
this.registration = registration_from_hexid(this.icao);
this.icaotype = null;
// request metadata
getAircraftData(this.icao).done(function(data) {
if ("r" in data) {
this.registration = data.r;
@ -178,22 +183,6 @@ PlaneObject.prototype.clearLines = function() {
}
};
PlaneObject.prototype.getMarkerIconType = function() {
var lookup = {
'A1' : 'light',
'A2' : 'medium',
'A3' : 'medium',
'A5' : 'heavy',
'A7' : 'rotorcraft'
};
if (this.category === null || !(this.category in lookup))
return 'generic'
else
return lookup[this.category];
}
PlaneObject.prototype.getMarkerColor = function() {
// Emergency squawks override everything else
if (this.squawk in SpecialSquawks)
@ -269,35 +258,71 @@ PlaneObject.prototype.updateIcon = function() {
var col = this.getMarkerColor();
var opacity = (this.position_from_mlat ? 0.75 : 1.0);
var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor);
var type = this.getMarkerIconType();
var weight = ((this.selected ? 2 : 1) / MarkerIcons[type].scale).toFixed(1);
var baseMarker = getBaseMarker(this.category, this.icaotype);
var weight = ((this.selected ? 2 : 1) / baseMarker.scale).toFixed(1);
var rotation = (this.track === null ? 0 : this.track);
var svgKey = col + '!' + outline + '!' + type + '!' + weight;
var svgKey = col + '!' + outline + '!' + baseMarker.key + '!' + weight;
var styleKey = opacity + '!' + rotation;
if (this.markerStyle === null || this.markerIcon === null || this.markerSvgKey != svgKey) {
//console.log(this.icao + " new icon and style " + this.markerSvgKey + " -> " + svgKey);
this.markerIcon = new ol.style.Icon({
anchor: MarkerIcons[type].anchor,
var icon = new ol.style.Icon({
anchor: baseMarker.anchor,
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
scale: MarkerIcons[type].scale,
imgSize: MarkerIcons[type].size,
src: svgPathToURI(MarkerIcons[type].path, MarkerIcons[type].size, outline, weight, col),
rotation: rotation * Math.PI / 180.0,
opacity: opacity
scale: baseMarker.scale,
imgSize: baseMarker.size,
src: svgPathToURI(baseMarker.path, baseMarker.size, outline, weight, col),
rotation: (baseMarker.noRotate ? 0 : rotation * Math.PI / 180.0),
opacity: opacity,
rotateWithView: (baseMarker.noRotate ? false : true)
});
if (baseMarker.noRotate) {
// the base marker won't be rotated
this.markerStaticIcon = icon;
this.markerStaticStyle = new ol.style.Style({
image: this.markerStaticIcon
});
// create an arrow that we will rotate around the base marker
// to indicate heading
var offset = baseMarker.markerRadius * baseMarker.scale + 6;
var size = offset * 2;
var arrowPath = "M " + offset + ",0 m 4,4 -8,0 4,-4 z";
this.markerIcon = new ol.style.Icon({
anchor: [offset, offset],
anchorXUnits: 'pixels',
anchorYUnits: 'pixels',
scale: 1.0,
imgSize: [size, size],
src: svgPathToURI(arrowPath, [size, size], outline, 1, outline),
rotation: rotation * Math.PI / 180.0,
opacity: opacity,
rotateWithView: true
});
this.markerStyle = new ol.style.Style({
image: this.markerIcon
});
} else {
this.markerIcon = icon;
this.markerStyle = new ol.style.Style({
image: this.markerIcon
});
this.markerStaticIcon = null;
this.markerStaticStyle = new ol.style.Style({});
}
this.markerStyleKey = styleKey;
this.markerSvgKey = svgKey;
this.markerStyle = new ol.style.Style({
image: this.markerIcon
});
if (this.marker !== null) {
this.marker.setStyle(this.markerStyle);
this.markerStatic.setStyle(this.markerStaticStyle);
}
}
@ -305,6 +330,9 @@ PlaneObject.prototype.updateIcon = function() {
//console.log(this.icao + " new rotation");
this.markerIcon.setRotation(rotation * Math.PI / 180.0);
this.markerIcon.setOpacity(opacity);
if (this.staticIcon) {
this.staticIcon.setOpacity(opacity);
}
this.markerStyleKey = styleKey;
}
@ -385,8 +413,9 @@ PlaneObject.prototype.updateTick = function(receiver_timestamp, last_timestamp)
PlaneObject.prototype.clearMarker = function() {
if (this.marker) {
PlaneIconFeatures.remove(this.marker);
PlaneIconFeatures.remove(this.markerStatic);
/* FIXME google.maps.event.clearListeners(this.marker, 'click'); */
this.marker = null;
this.marker = this.markerStatic = null;
}
};
@ -401,12 +430,18 @@ PlaneObject.prototype.updateMarker = function(moved) {
if (this.marker) {
if (moved) {
this.marker.setGeometry(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
this.markerStatic.setGeometry(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
}
} else {
this.marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
} else {
this.marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
this.marker.hex = this.icao;
this.marker.setStyle(this.markerStyle);
PlaneIconFeatures.push(this.marker);
this.markerStatic = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
this.markerStatic.hex = this.icao;
this.markerStatic.setStyle(this.markerStaticStyle);
PlaneIconFeatures.push(this.markerStatic);
}
};

View file

@ -0,0 +1,315 @@
// Various reverse-engineered versions of the allocation algorithms
// used by different countries to allocate 24-bit ICAO addresses based
// on the aircraft registration.
//
// These were worked out by looking at the allocation patterns and
// working backwards to an algorithm that generates that pattern,
// spot-checking aircraft to see if it worked.
// YMMV.
registration_from_hexid = (function () {
// hide the guts in a closure
var limited_alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // 24 chars; no I, O
var full_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 26 chars
// handles 3-letter suffixes assigned with a regular pattern
//
// start: first hexid of range
// s1: major stride (interval between different first letters)
// s2: minor stride (interval between different second letters)
// prefix: the registration prefix
//
// optionally:
// alphabet: the alphabet to use (defaults full_alphabet)
// first: the suffix to use at the start of the range (default: AAA)
// last: the last valid suffix in the range (default: ZZZ)
var stride_mappings = [
{ start: 0x008011, s1: 26*26, s2: 26, prefix: "ZS-" },
{ start: 0x390000, s1: 1024, s2: 32, prefix: "F-G" },
{ start: 0x398000, s1: 1024, s2: 32, prefix: "F-H" },
{ start: 0x3C4421, s1: 1024, s2: 32, prefix: "D-A", first: 'AAA', last: 'OZZ' },
{ start: 0x3C0001, s1: 26*26, s2: 26, prefix: "D-A", first: 'PAA', last: 'ZZZ' },
{ start: 0x3C8421, s1: 1024, s2: 32, prefix: "D-B", first: 'AAA', last: 'OZZ' },
{ start: 0x3C2001, s1: 26*26, s2: 26, prefix: "D-B", first: 'PAA', last: 'ZZZ' },
{ start: 0x3CC000, s1: 26*26, s2: 26, prefix: "D-C" },
{ start: 0x3D04A8, s1: 26*26, s2: 26, prefix: "D-E" },
{ start: 0x3D4950, s1: 26*26, s2: 26, prefix: "D-F" },
{ start: 0x3D8DF8, s1: 26*26, s2: 26, prefix: "D-G" },
{ start: 0x3DD2A0, s1: 26*26, s2: 26, prefix: "D-H" },
{ start: 0x3E1748, s1: 26*26, s2: 26, prefix: "D-I" },
{ start: 0x448421, s1: 1024, s2: 32, prefix: "OO-" },
{ start: 0x458421, s1: 1024, s2: 32, prefix: "OY-" },
{ start: 0x460000, s1: 26*26, s2: 26, prefix: "OH-" },
{ start: 0x468421, s1: 1024, s2: 32, prefix: "SX-" },
{ start: 0x490421, s1: 1024, s2: 32, prefix: "CS-" },
{ start: 0x4A0421, s1: 1024, s2: 32, prefix: "YR-" },
{ start: 0x4B8421, s1: 1024, s2: 32, prefix: "TC-" },
{ start: 0x740421, s1: 1024, s2: 32, prefix: "JY-" },
{ start: 0x760421, s1: 1024, s2: 32, prefix: "AP-" },
{ start: 0x768421, s1: 1024, s2: 32, prefix: "9V-" },
{ start: 0x778421, s1: 1024, s2: 32, prefix: "YK-" },
{ start: 0xC00001, s1: 26*26, s2: 26, prefix: "C-F" },
{ start: 0xC044A9, s1: 26*26, s2: 26, prefix: "C-G" },
{ start: 0xE01041, s1: 4096, s2: 64, prefix: "LV-" }
];
// numeric registrations
// start: start hexid in range
// first: first numeric registration
// count: number of numeric registrations
// template: registration template, trailing characters are replaced with the numeric registration
var numeric_mappings = [
{ start: 0x140000, first: 0, count: 100000, template: "RA-00000" },
{ start: 0x0B03E8, first: 1000, count: 1000, template: "CU-T0000" }
];
// fill in some derived data
for (var i = 0; i < stride_mappings.length; ++i) {
var mapping = stride_mappings[i];
if (!mapping.alphabet) {
mapping.alphabet = full_alphabet;
}
if (mapping.first) {
var c1 = mapping.alphabet.indexOf(mapping.first.charAt(0));
var c2 = mapping.alphabet.indexOf(mapping.first.charAt(1));
var c3 = mapping.alphabet.indexOf(mapping.first.charAt(2));
mapping.offset = c1 * mapping.s1 + c2 * mapping.s2 + c3;
} else {
mapping.offset = 0;
}
if (mapping.last) {
var c1 = mapping.alphabet.indexOf(mapping.last.charAt(0));
var c2 = mapping.alphabet.indexOf(mapping.last.charAt(1));
var c3 = mapping.alphabet.indexOf(mapping.last.charAt(2));
mapping.end = mapping.start - mapping.offset +
c1 * mapping.s1 +
c2 * mapping.s2 +
c3 - mapping.offset;
} else {
mapping.end = mapping.start - mapping.offset +
(mapping.alphabet.length - 1) * mapping.s1 +
(mapping.alphabet.length - 1) * mapping.s2 +
(mapping.alphabet.length - 1);
}
}
for (var i = 0; i < numeric_mappings.length; ++i) {
numeric_mappings[i].end = numeric_mappings[i].start + numeric_mappings[i].count - 1;
}
function lookup(hexid) {
var hexid = +("0x" + hexid);
reg = n_reg(hexid);
if (reg)
return reg;
reg = ja_reg(hexid);
if (reg)
return reg;
reg = hl_reg(hexid);
if (reg)
return reg;
reg = numeric_reg(hexid);
if (reg)
return reg;
reg = stride_reg(hexid);
if (reg)
return reg;
return null;
}
function stride_reg(hexid) {
// try the mappings in stride_mappings
var i;
for (i = 0; i < stride_mappings.length; ++i) {
var mapping = stride_mappings[i];
if (hexid < mapping.start || hexid > mapping.end)
continue;
var offset = hexid - mapping.start + mapping.offset;
var i1 = Math.floor(offset / mapping.s1);
offset = offset % mapping.s1;
var i2 = Math.floor(offset / mapping.s2);
offset = offset % mapping.s2;
var i3 = offset;
if (i1 < 0 || i1 >= mapping.alphabet.length ||
i2 < 0 || i2 >= mapping.alphabet.length ||
i3 < 0 || i3 >= mapping.alphabet.length)
continue;
return mapping.prefix + mapping.alphabet.charAt(i1) + mapping.alphabet.charAt(i2) + mapping.alphabet.charAt(i3);
}
// nothing
return null;
}
function numeric_reg(hexid) {
// try the mappings in numeric_mappings
var i;
for (i = 0; i < numeric_mappings.length; ++i) {
var mapping = numeric_mappings[i];
if (hexid < mapping.start || hexid > mapping.end)
continue;
var reg = (hexid - mapping.start + mapping.first) + "";
return mapping.template.substring(0, mapping.template.length - reg.length) + reg;
}
}
//
// US N-numbers
//
function n_letters(rem) {
if (rem == 0)
return "";
--rem;
return limited_alphabet.charAt(Math.floor(rem / 25)) + n_letter(rem % 25);
}
function n_letter(rem) {
if (rem == 0)
return "";
--rem;
return limited_alphabet.charAt(rem);
}
function n_reg(hexid) {
var offset = hexid - 0xA00001;
if (offset < 0 || offset >= 915399) {
return null;
}
var digit1 = Math.floor(offset / 101711) + 1;
var reg = "N" + digit1;
offset = offset % 101711;
if (offset <= 600) {
// Na, NaA .. NaZ, NaAA .. NaZZ
return reg + n_letters(offset);
}
// Na0* .. Na9*
offset -= 601;
var digit2 = Math.floor(offset / 10111);
reg += digit2;
offset = offset % 10111;
if (offset <= 600) {
// Nab, NabA..NabZ, NabAA..NabZZ
return reg + n_letters(offset);
}
// Nab0* .. Nab9*
offset -= 601;
var digit3 = Math.floor(offset / 951);
reg += digit3;
offset = offset % 951;
if (offset <= 600) {
// Nabc, NabcA .. NabcZ, NabcAA .. NabcZZ
return reg + n_letters(offset);
}
// Nabc0* .. Nabc9*
offset -= 601;
var digit4 = Math.floor(offset / 35);
reg += digit4.toFixed(0);
offset = offset % 35;
if (offset <= 24) {
// Nabcd, NabcdA .. NabcdZ
return reg + n_letter(offset);
}
// Nabcd0 .. Nabcd9
offset -= 25;
return reg + offset.toFixed(0);
}
// South Korea
function hl_reg(hexid) {
if (hexid >= 0x71BA00 && hexid <= 0x71bf99) {
return "HL" + (hexid - 0x71BA00 + 0x7200).toString(16);
}
if (hexid >= 0x71C000 && hexid <= 0x71C099) {
return "HL" + (hexid - 0x71C000 + 0x8000).toString(16);
}
if (hexid >= 0x71C200 && hexid <= 0x71C299) {
return "HL" + (hexid - 0x71C200 + 0x8200).toString(16);
}
return null;
}
// Japan
function ja_reg(hexid) {
var offset = hexid - 0x840000;
if (offset < 0 || offset >= 229840)
return null;
var reg = "JA";
var digit1 = Math.floor(offset / 22984);
if (digit1 < 0 || digit1 > 9)
return null;
reg += digit1;
offset = offset % 22984;
var digit2 = Math.floor(offset / 916);
if (digit2 < 0 || digit2 > 9)
return null;
reg += digit2;
offset = offset % 916;
if (offset < 340) {
// 3rd is a digit, 4th is a digit or letter
var digit3 = Math.floor(offset / 34);
reg += digit3;
offset = offset % 34;
if (offset < 10) {
// 4th is a digit
return reg + offset;
}
// 4th is a letter
offset -= 10;
return reg + limited_alphabet.charAt(offset);
}
// 3rd and 4th are letters
offset -= 340;
var letter3 = Math.floor(offset / 24);
return reg + limited_alphabet.charAt(letter3) + limited_alphabet.charAt(offset % 24);
}
return lookup;
})();
// make nodejs happy:
if (typeof module !== 'undefined') {
module.exports = registration_from_hexid;
}

View file

@ -366,27 +366,74 @@ function initialize_map() {
document.getElementById("infoblock_country").style.display = 'none'; // hide country row
}
// Initialize OL3
// Initialize OL3
var layers = createBaseLayers();
var iconsLayer = new ol.layer.Vector({
name: 'ac_positions',
type: 'overlay',
title: 'Aircraft positions',
source: new ol.source.Vector({
features: PlaneIconFeatures,
})
});
layers.push(new ol.layer.Group({
title: 'Overlays',
layers: [
new ol.layer.Vector({
name: 'site_pos',
type: 'overlay',
title: 'Site position and range rings',
source: new ol.source.Vector({
features: StaticFeatures,
})
}),
new ol.layer.Vector({
name: 'ac_trail',
type: 'overlay',
title: 'Selected aircraft trail',
source: new ol.source.Vector({
features: PlaneTrailFeatures,
})
}),
iconsLayer
]
}));
var foundType = false;
ol.control.LayerSwitcher.forEachRecursive(layers, function(lyr) {
if (lyr.get('type') !== 'base')
if (!lyr.get('name'))
return;
if (MapType === lyr.get('name')) {
foundType = true;
lyr.setVisible(true);
} else {
lyr.setVisible(false);
}
lyr.on('change:visible', function(evt) {
if (evt.target.getVisible()) {
MapType = localStorage['MapType'] = evt.target.get('name');
if (lyr.get('type') === 'base') {
if (MapType === lyr.get('name')) {
foundType = true;
lyr.setVisible(true);
} else {
lyr.setVisible(false);
}
});
lyr.on('change:visible', function(evt) {
if (evt.target.getVisible()) {
MapType = localStorage['MapType'] = evt.target.get('name');
}
});
} else if (lyr.get('type') === 'overlay') {
var visible = localStorage['layer_' + lyr.get('name')];
if (visible != undefined) {
// javascript, why must you taunt me with gratuitous type problems
lyr.setVisible(visible === "true");
}
lyr.on('change:visible', function(evt) {
localStorage['layer_' + evt.target.get('name')] = evt.target.getVisible();
});
}
})
if (!foundType) {
@ -400,35 +447,7 @@ function initialize_map() {
});
}
var iconsLayer = new ol.layer.Vector({
title: 'Aircraft positions',
source: new ol.source.Vector({
features: PlaneIconFeatures,
})
});
layers.push(new ol.layer.Group({
title: 'Overlays',
layers: [
new ol.layer.Vector({
title: 'Site position and range rings',
source: new ol.source.Vector({
features: StaticFeatures,
})
}),
new ol.layer.Vector({
title: 'Selected aircraft trail',
source: new ol.source.Vector({
features: PlaneTrailFeatures,
})
}),
iconsLayer
]
}));
OLMap = new ol.Map({
OLMap = new ol.Map({
target: 'map_canvas',
layers: layers,
view: new ol.View({