Merge branch 'master' into tracking-rewrite
This commit is contained in:
commit
8e8b8588bf
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.xz binary
|
2
Makefile
2
Makefile
|
@ -24,7 +24,7 @@ UNAME := $(shell uname)
|
||||||
|
|
||||||
ifeq ($(UNAME), Linux)
|
ifeq ($(UNAME), Linux)
|
||||||
LIBS+=-lrt
|
LIBS+=-lrt
|
||||||
CFLAGS+=-std=c11 -D_BSD_SOURCE=1 -D_POSIX_C_SOURCE=200809L
|
CFLAGS+=-std=c11 -D_DEFAULT_SOURCE
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME), Darwin)
|
ifeq ($(UNAME), Darwin)
|
||||||
# TODO: Putting GCC in C11 mode breaks things.
|
# TODO: Putting GCC in C11 mode breaks things.
|
||||||
|
|
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
|
@ -16,6 +16,7 @@
|
||||||
<script type="text/javascript" src="config.js"></script>
|
<script type="text/javascript" src="config.js"></script>
|
||||||
<script type="text/javascript" src="markers.js"></script>
|
<script type="text/javascript" src="markers.js"></script>
|
||||||
<script type="text/javascript" src="dbloader.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="planeObject.js"></script>
|
||||||
<script type="text/javascript" src="formatter.js"></script>
|
<script type="text/javascript" src="formatter.js"></script>
|
||||||
<script type="text/javascript" src="flags.js"></script>
|
<script type="text/javascript" src="flags.js"></script>
|
||||||
|
|
|
@ -58,43 +58,194 @@ var _beechcraft_svg =
|
||||||
var _heavy_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";
|
"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 = {
|
// From https://discussions.flightaware.com/ads-b-flight-tracking-f21/some-custom-svg-plane-icons-t37783.html
|
||||||
generic : {
|
// by Peter Lowden
|
||||||
scale : 0.4,
|
// licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
|
||||||
size : [64, 64],
|
|
||||||
anchor : [32, 32],
|
|
||||||
path : _generic_plane_svg
|
|
||||||
},
|
|
||||||
|
|
||||||
light : {
|
// NB: scaled so that 1 pixel is about 1.33m (0.75px = 1m)
|
||||||
scale : 0.4,
|
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],
|
size : [64, 64],
|
||||||
anchor : [32, 25],
|
anchor : [32, 25],
|
||||||
path : _beechcraft_svg
|
path : _beechcraft_svg
|
||||||
},
|
},
|
||||||
|
|
||||||
medium : {
|
"A2" : {
|
||||||
scale : 0.4,
|
key : "A2",
|
||||||
|
scale : 0.35,
|
||||||
size : [64, 64],
|
size : [64, 64],
|
||||||
anchor : [32, 32],
|
anchor : [32, 32],
|
||||||
path : _generic_plane_svg
|
path : _generic_plane_svg
|
||||||
},
|
},
|
||||||
|
|
||||||
heavy : {
|
"A3" : {
|
||||||
scale : 0.6,
|
key : "A3",
|
||||||
|
scale : 0.40,
|
||||||
|
size : [64, 64],
|
||||||
|
anchor : [32, 32],
|
||||||
|
path : _generic_plane_svg
|
||||||
|
},
|
||||||
|
|
||||||
|
"A5" : {
|
||||||
|
key : "A5",
|
||||||
|
scale : 0.73,
|
||||||
size : [64, 64],
|
size : [64, 64],
|
||||||
anchor : [32, 32],
|
anchor : [32, 32],
|
||||||
path : _heavy_svg
|
path : _heavy_svg
|
||||||
},
|
},
|
||||||
|
|
||||||
rotorcraft : {
|
"A7" : {
|
||||||
scale : 0.5,
|
key : "A7",
|
||||||
|
scale : 0.50,
|
||||||
size : [64, 64],
|
size : [64, 64],
|
||||||
anchor : [22, 32],
|
anchor : [22, 32],
|
||||||
path : _rotorcraft_svg
|
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) {
|
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">';
|
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 + '"';
|
svg += '<path d="' + path + '"';
|
||||||
|
|
|
@ -39,12 +39,17 @@ function PlaneObject(icao) {
|
||||||
this.marker = null;
|
this.marker = null;
|
||||||
this.markerStyle = null;
|
this.markerStyle = null;
|
||||||
this.markerIcon = null;
|
this.markerIcon = null;
|
||||||
|
this.markerStaticStyle = null;
|
||||||
|
this.markerStaticIcon = null;
|
||||||
this.markerStyleKey = null;
|
this.markerStyleKey = null;
|
||||||
this.markerSvgKey = null;
|
this.markerSvgKey = null;
|
||||||
|
|
||||||
// request metadata
|
// start from a computed registration, let the DB override it
|
||||||
this.registration = null;
|
// if it has something else.
|
||||||
|
this.registration = registration_from_hexid(this.icao);
|
||||||
this.icaotype = null;
|
this.icaotype = null;
|
||||||
|
|
||||||
|
// request metadata
|
||||||
getAircraftData(this.icao).done(function(data) {
|
getAircraftData(this.icao).done(function(data) {
|
||||||
if ("r" in data) {
|
if ("r" in data) {
|
||||||
this.registration = data.r;
|
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() {
|
PlaneObject.prototype.getMarkerColor = function() {
|
||||||
// Emergency squawks override everything else
|
// Emergency squawks override everything else
|
||||||
if (this.squawk in SpecialSquawks)
|
if (this.squawk in SpecialSquawks)
|
||||||
|
@ -269,35 +258,71 @@ PlaneObject.prototype.updateIcon = function() {
|
||||||
var col = this.getMarkerColor();
|
var col = this.getMarkerColor();
|
||||||
var opacity = (this.position_from_mlat ? 0.75 : 1.0);
|
var opacity = (this.position_from_mlat ? 0.75 : 1.0);
|
||||||
var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor);
|
var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor);
|
||||||
var type = this.getMarkerIconType();
|
var baseMarker = getBaseMarker(this.category, this.icaotype);
|
||||||
var weight = ((this.selected ? 2 : 1) / MarkerIcons[type].scale).toFixed(1);
|
var weight = ((this.selected ? 2 : 1) / baseMarker.scale).toFixed(1);
|
||||||
var rotation = (this.track === null ? 0 : this.track);
|
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;
|
var styleKey = opacity + '!' + rotation;
|
||||||
|
|
||||||
if (this.markerStyle === null || this.markerIcon === null || this.markerSvgKey != svgKey) {
|
if (this.markerStyle === null || this.markerIcon === null || this.markerSvgKey != svgKey) {
|
||||||
//console.log(this.icao + " new icon and style " + this.markerSvgKey + " -> " + svgKey);
|
//console.log(this.icao + " new icon and style " + this.markerSvgKey + " -> " + svgKey);
|
||||||
|
|
||||||
this.markerIcon = new ol.style.Icon({
|
var icon = new ol.style.Icon({
|
||||||
anchor: MarkerIcons[type].anchor,
|
anchor: baseMarker.anchor,
|
||||||
anchorXUnits: 'pixels',
|
anchorXUnits: 'pixels',
|
||||||
anchorYUnits: 'pixels',
|
anchorYUnits: 'pixels',
|
||||||
scale: MarkerIcons[type].scale,
|
scale: baseMarker.scale,
|
||||||
imgSize: MarkerIcons[type].size,
|
imgSize: baseMarker.size,
|
||||||
src: svgPathToURI(MarkerIcons[type].path, MarkerIcons[type].size, outline, weight, col),
|
src: svgPathToURI(baseMarker.path, baseMarker.size, outline, weight, col),
|
||||||
rotation: rotation * Math.PI / 180.0,
|
rotation: (baseMarker.noRotate ? 0 : rotation * Math.PI / 180.0),
|
||||||
opacity: opacity
|
opacity: opacity,
|
||||||
|
rotateWithView: (baseMarker.noRotate ? false : true)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.markerStyleKey = styleKey;
|
if (baseMarker.noRotate) {
|
||||||
this.markerSvgKey = svgKey;
|
// 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({
|
this.markerStyle = new ol.style.Style({
|
||||||
image: this.markerIcon
|
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;
|
||||||
|
|
||||||
if (this.marker !== null) {
|
if (this.marker !== null) {
|
||||||
this.marker.setStyle(this.markerStyle);
|
this.marker.setStyle(this.markerStyle);
|
||||||
|
this.markerStatic.setStyle(this.markerStaticStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +330,9 @@ PlaneObject.prototype.updateIcon = function() {
|
||||||
//console.log(this.icao + " new rotation");
|
//console.log(this.icao + " new rotation");
|
||||||
this.markerIcon.setRotation(rotation * Math.PI / 180.0);
|
this.markerIcon.setRotation(rotation * Math.PI / 180.0);
|
||||||
this.markerIcon.setOpacity(opacity);
|
this.markerIcon.setOpacity(opacity);
|
||||||
|
if (this.staticIcon) {
|
||||||
|
this.staticIcon.setOpacity(opacity);
|
||||||
|
}
|
||||||
this.markerStyleKey = styleKey;
|
this.markerStyleKey = styleKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,8 +413,9 @@ PlaneObject.prototype.updateTick = function(receiver_timestamp, last_timestamp)
|
||||||
PlaneObject.prototype.clearMarker = function() {
|
PlaneObject.prototype.clearMarker = function() {
|
||||||
if (this.marker) {
|
if (this.marker) {
|
||||||
PlaneIconFeatures.remove(this.marker);
|
PlaneIconFeatures.remove(this.marker);
|
||||||
|
PlaneIconFeatures.remove(this.markerStatic);
|
||||||
/* FIXME google.maps.event.clearListeners(this.marker, 'click'); */
|
/* 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 (this.marker) {
|
||||||
if (moved) {
|
if (moved) {
|
||||||
this.marker.setGeometry(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
|
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 {
|
} else {
|
||||||
this.marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
|
this.marker = new ol.Feature(new ol.geom.Point(ol.proj.fromLonLat(this.position)));
|
||||||
this.marker.hex = this.icao;
|
this.marker.hex = this.icao;
|
||||||
this.marker.setStyle(this.markerStyle);
|
this.marker.setStyle(this.markerStyle);
|
||||||
PlaneIconFeatures.push(this.marker);
|
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
315
public_html/registrations.js
Normal file
315
public_html/registrations.js
Normal 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;
|
||||||
|
}
|
40
tools/README.aircraft-db
Normal file
40
tools/README.aircraft-db
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
The dump1090 webmap uses a static database of json files to provide aircraft
|
||||||
|
information.
|
||||||
|
|
||||||
|
This directory has some tools to turn a CSV file with aircraft data into
|
||||||
|
the json format that the dump1090 map expects.
|
||||||
|
|
||||||
|
The default data comes from a database kindly provided by VRS (unfortunately
|
||||||
|
no longer updated). This data is in vrs.csv. It was extracted by:
|
||||||
|
|
||||||
|
$ wget http://www.virtualradarserver.co.uk/Files/BasicAircraftLookup.sqb.gz
|
||||||
|
$ gunzip BasicAircraftLookup.sqb.gz
|
||||||
|
$ tools/vrs-to-csv.py BasicAircraftLookup.sqb >tools/vrs.csv
|
||||||
|
|
||||||
|
You can modify vrs.csv (or build a new CSV entirely) and update the database.
|
||||||
|
|
||||||
|
First, as an optional step, you can prune out all registrations which match
|
||||||
|
what the in-browser hexid-to-registration logic would generate anyway. This
|
||||||
|
requires nodejs, see the comments in filter-regs.js
|
||||||
|
|
||||||
|
$ nodejs tools/filter-regs.js <tools/vrs.csv >tools/vrs-pruned.csv
|
||||||
|
|
||||||
|
Next, turn the pruned CSV into a set of json files:
|
||||||
|
|
||||||
|
$ tools/csv-to-json.py tools/vrs-pruned.csv public_html/db
|
||||||
|
|
||||||
|
The contents of public_html/db should be installed where the webmap can find
|
||||||
|
them; the Debian packaging puts these in
|
||||||
|
/usr/share/dump1090-mutability/html/db
|
||||||
|
|
||||||
|
The CSV format is very simple. The first line must be a header line that names
|
||||||
|
the columns. These columns are understood:
|
||||||
|
|
||||||
|
icao24: the 6-digit hex address of the aircraft
|
||||||
|
r: the registration / tail number of the aircraft
|
||||||
|
t: the ICAO aircraft type of the aircraft, e.g. B773
|
||||||
|
|
||||||
|
Any other columns are put into the json DB under the name you give them, but
|
||||||
|
the standard map code won't do anything special with them. You can pick these
|
||||||
|
columns up in the PlaneObject constructor (see planeObject.js where it calls
|
||||||
|
getAircraftData()) for later use.
|
|
@ -5,28 +5,40 @@
|
||||||
# into a bunch of json files suitable for use by the webmap
|
# into a bunch of json files suitable for use by the webmap
|
||||||
#
|
#
|
||||||
|
|
||||||
import sqlite3, json, sys
|
import sqlite3, json, sys, csv
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
def extract(dbfile, todir, blocklimit, debug):
|
def readcsv(name, infile, blocks):
|
||||||
ac_count = 0
|
print >>sys.stderr, 'Reading from', name
|
||||||
block_count = 0
|
|
||||||
|
|
||||||
blocks = {}
|
if len(blocks) == 0:
|
||||||
for i in xrange(16):
|
for i in xrange(16):
|
||||||
blocks['%01X' % i] = {}
|
blocks['%01X' % i] = {}
|
||||||
|
|
||||||
print >>sys.stderr, 'Reading', dbfile
|
ac_count = 0
|
||||||
with closing(sqlite3.connect(dbfile)) as db:
|
|
||||||
with closing(db.execute('SELECT a.Icao, a.Registration, m.Icao FROM Aircraft a, Model m WHERE a.ModelID = m.ModelID')) as c:
|
reader = csv.DictReader(infile)
|
||||||
for icao24, reg, icaotype in c:
|
if not 'icao24' in reader.fieldnames:
|
||||||
|
raise RuntimeError('CSV should have at least an "icao24" column')
|
||||||
|
for row in reader:
|
||||||
|
icao24 = row['icao24']
|
||||||
|
|
||||||
|
entry = {}
|
||||||
|
for k,v in row.items():
|
||||||
|
if k != 'icao24' and v != '':
|
||||||
|
entry[k] = v
|
||||||
|
|
||||||
|
if len(entry) > 0:
|
||||||
|
ac_count += 1
|
||||||
|
|
||||||
bkey = icao24[0:1].upper()
|
bkey = icao24[0:1].upper()
|
||||||
dkey = icao24[1:].upper()
|
dkey = icao24[1:].upper()
|
||||||
blocks[bkey][dkey] = {}
|
blocks[bkey].setdefault(dkey, {}).update(entry)
|
||||||
if reg: blocks[bkey][dkey]['r'] = reg
|
|
||||||
if icaotype: blocks[bkey][dkey]['t'] = icaotype
|
print >>sys.stderr, 'Read', ac_count, 'aircraft from', name
|
||||||
ac_count += 1
|
|
||||||
print >>sys.stderr, 'Read', ac_count, 'aircraft'
|
def writedb(blocks, todir, blocklimit, debug):
|
||||||
|
block_count = 0
|
||||||
|
|
||||||
print >>sys.stderr, 'Writing blocks:',
|
print >>sys.stderr, 'Writing blocks:',
|
||||||
|
|
||||||
|
@ -83,8 +95,20 @@ def extract(dbfile, todir, blocklimit, debug):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 3:
|
if len(sys.argv) < 3:
|
||||||
print >>sys.stderr, 'Syntax: %s <path to BasicAircraftLookup.sqb> <path to DB dir>' % sys.argv[0]
|
print >>sys.stderr, 'Reads a CSV file with aircraft information and produces a directory of JSON files'
|
||||||
|
print >>sys.stderr, 'Syntax: %s <path to CSV> [... additional CSV files ...] <path to DB dir>' % sys.argv[0]
|
||||||
|
print >>sys.stderr, 'Use "-" as the CSV path to read from stdin'
|
||||||
|
print >>sys.stderr, 'If multiple CSV files are specified and they provide conflicting data'
|
||||||
|
print >>sys.stderr, 'then the data from the last-listed CSV file is used'
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
blocks = {}
|
||||||
|
for filename in sys.argv[1:-1]:
|
||||||
|
if filename == '-':
|
||||||
|
readcsv('stdin', sys.stdin, blocks)
|
||||||
else:
|
else:
|
||||||
extract(sys.argv[1], sys.argv[2], 1000, False)
|
with closing(open(filename, 'r')) as infile:
|
||||||
|
readcsv(filename, infile, blocks)
|
||||||
|
|
||||||
|
writedb(blocks, sys.argv[-1], 1000, False)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
38
tools/filter-regs.js
Normal file
38
tools/filter-regs.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// This script processes a CSV file that contains
|
||||||
|
// ICAO addresses (column 'icao24') and registrations
|
||||||
|
// (column 'r')
|
||||||
|
//
|
||||||
|
// It removes all registration entries that exactly match
|
||||||
|
// what dump1090 would have computed from the hexid anyway,
|
||||||
|
// reducing the size of the CSV in the cases where the
|
||||||
|
// two approaches match.
|
||||||
|
//
|
||||||
|
// Any additional columns are passed through unchanged.
|
||||||
|
//
|
||||||
|
// To run it:
|
||||||
|
//
|
||||||
|
// sudo apt-get install nodejs
|
||||||
|
// sudo apt-get install npm
|
||||||
|
// npm install csv # must be done in the same dir as this script
|
||||||
|
// nodejs filter-regs.js <input.csv >output.csv
|
||||||
|
|
||||||
|
var reglookup = require('../public_html/registrations.js');
|
||||||
|
var csv = require('csv');
|
||||||
|
|
||||||
|
var parser = csv.parse({columns: true});
|
||||||
|
var writer = csv.stringify({header: true});
|
||||||
|
var transformer = csv.transform(function (record, callback) {
|
||||||
|
if (('icao24' in record) && ('r' in record)) {
|
||||||
|
var computed = reglookup(record.icao24);
|
||||||
|
if (computed === record.r) {
|
||||||
|
record.r = '';
|
||||||
|
} else if (computed !== null) {
|
||||||
|
console.warn(record.icao24 + " computed " + computed + " but CSV data had " + record.r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, record);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stdin.pipe(parser).pipe(transformer).pipe(writer).pipe(process.stdout);
|
31
tools/vrs-to-csv.py
Executable file
31
tools/vrs-to-csv.py
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
#
|
||||||
|
# Converts a Virtual Radar Server BasicAircraftLookup.sqb database
|
||||||
|
# to a CSV file suitable for feeding to csv-to-json.py
|
||||||
|
#
|
||||||
|
|
||||||
|
import sqlite3, csv, sys
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
|
def extract(dbfile):
|
||||||
|
writer = csv.DictWriter(sys.stdout,
|
||||||
|
fieldnames=['icao24', 'r', 't'])
|
||||||
|
writer.writeheader()
|
||||||
|
with closing(sqlite3.connect(dbfile)) as db:
|
||||||
|
with closing(db.execute('SELECT a.Icao, a.Registration, m.Icao FROM Aircraft a, Model m WHERE a.ModelID = m.ModelID')) as c:
|
||||||
|
for icao24, reg, icaotype in c:
|
||||||
|
writer.writerow({
|
||||||
|
'icao24': icao24,
|
||||||
|
'r': reg,
|
||||||
|
't': icaotype
|
||||||
|
})
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print >>sys.stderr, 'Reads a VRS sqlite database and writes a CSV to stdout'
|
||||||
|
print >>sys.stderr, 'Syntax: %s <path to BasicAircraftLookup.sqb>' % sys.argv[0]
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
extract(sys.argv[1])
|
||||||
|
sys.exit(0)
|
BIN
tools/vrs.csv.xz
Normal file
BIN
tools/vrs.csv.xz
Normal file
Binary file not shown.
Loading…
Reference in a new issue