node-red-contrib-tak-registration
Version:
A Node-RED node to register to TAK and to help wrap files as datapackages to send to TAK
1,828 lines (1,584 loc) • 51.8 kB
JavaScript
/* eslint no-console: ["error", { allow: ["log"] }] */
/* eslint-env browser,node */
import {isoBandOptions} from './options.js';
import {cell2Polygons, traceBandPaths} from './polygons.js';
import {QuadTree} from './quadtree.js';
/*
* lookup table to generate polygon paths or edges required to
* trace the full polygon(s)
*/
var shapeCoordinates = {
square: function(cell, x0, x1, x2, x3, opt) {
if (opt.polygons)
cell.polygons.push([ [0,0], [0, 1], [1, 1], [1, 0] ]);
},
triangle_bl: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, leftbottom], [bottomleft, 0], [0, 0] ]);
},
triangle_br: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright, 0], [1, rightbottom], [1, 0] ]);
},
triangle_tr: function(cell, x0, x1, x2, x3, opt) {
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.rt = {
path: [ [1, righttop], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
}
if (opt.polygons)
cell.polygons.push([ [1, righttop], [topright, 1], [1, 1] ]);
},
triangle_tl: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tl = {
path: [ [topleft, 1], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, lefttop], [0, 1], [topleft, 1] ]);
},
tetragon_t: function(cell, x0, x1, x2, x3, opt) {
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.rt = {
path: [ [1, righttop], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, lefttop], [0, 1], [1, 1], [1, righttop] ]);
},
tetragon_r: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright, 0], [topright, 1], [1, 1], [1, 0] ]);
},
tetragon_b: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [1, rightbottom], [1, 0] ]);
},
tetragon_l: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tl = {
path: [ [topleft, 1], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, 1], [topleft, 1], [bottomleft, 0] ]);
},
tetragon_bl: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [0, leftbottom], [0, lefttop], [bottomright, 0] ]);
},
tetragon_br: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [1, righttop], [1, rightbottom], [bottomright, 0] ]);
},
tetragon_tr: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.rb = {
path: [ [1, rightbottom], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
}
if (opt.polygons)
cell.polygons.push([ [1, rightbottom], [topleft, 1], [topright, 1], [1, righttop] ]);
},
tetragon_tl: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tr = {
path: [ [topright, 1], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [topright, 1], [0, leftbottom], [0, lefttop], [topleft, 1] ]);
},
tetragon_lr: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lt = {
path: [ [0, lefttop], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, leftbottom], [0, lefttop], [1, righttop], [1, rightbottom] ]);
},
tetragon_tb: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tr = {
path: [ [topright, 1], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
cell.edges.bl = {
path: [ [bottomleft, 0], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [topleft, 1], [topright, 1], [bottomright, 0] ]);
},
pentagon_tr: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tl = {
path: [[topleft, 1], [1, rightbottom]],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, 1], [topleft, 1], [1, rightbottom], [1, 0] ]);
},
pentagon_tl: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [topright, 1], [1, 1], [1, 0] ]);
},
pentagon_br: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.rt = {
path: [ [1, righttop], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, 1], [1, 1], [1, righttop], [bottomleft, 0] ]);
},
pentagon_bl: function(cell, x0, x1, x2, x3, opt) {
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, lefttop], [0, 1], [1, 1], [1, 0], [bottomright, 0] ]);
},
pentagon_tr_rl: function(cell, x0, x1, x2, x3, opt) {
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tl = {
path: [ [topleft, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, lefttop], [0, 1], [topleft, 1], [1, righttop], [1, rightbottom] ]);
},
pentagon_rb_bt: function(cell, x0, x1, x2, x3, opt) {
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.rt = {
path: [ [1, righttop], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
cell.edges.bl = {
path: [ [bottomleft, 0], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
}
if (opt.polygons)
cell.polygons.push([ [topright, 1], [1, 1], [1, righttop], [bottomright, 0], [bottomleft, 0] ]);
},
pentagon_bl_lr: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright, 0], [0, leftbottom], [0, lefttop], [1, rightbottom], [1, 0] ]);
},
pentagon_lt_tb: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [topleft, 1], [topright, 1], [bottomleft, 0] ]);
},
pentagon_bl_tb: function(cell, x0, x1, x2, x3, opt) {
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
cell.edges.tl = {
path: [ [ topleft, 1], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, lefttop], [0, 1], [topleft, 1], [bottomright, 0], [bottomleft, 0] ]);
},
pentagon_lt_rl: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate(x1, x3, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lt = {
path: [ [0, lefttop], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
cell.edges.rt = {
path: [ [1, righttop], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, leftbottom], [0, lefttop], [topright, 1], [1, 1], [1, righttop] ]);
},
pentagon_tr_bt: function(cell, x0, x1, x2, x3, opt) {
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [topleft, 1], [topright, 1], [1, rightbottom], [1, 0], [bottomright, 0] ]);
},
pentagon_rb_lr: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [1, righttop], [1, rightbottom], [bottomleft, 0] ]);
},
hexagon_lt_tr: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [topleft, 1], [topright, 1], [1, rightbottom], [1, 0] ]);
},
hexagon_bl_lt: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright, 0], [0, leftbottom], [0, lefttop], [topright, 1], [1, 1], [1, 0] ]);
},
hexagon_bl_rb: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
cell.edges.rt = {
path: [ [1, righttop], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [0, lefttop], [0, 1], [1, 1], [1, righttop], [bottomright, 0] ]);
},
hexagon_tr_rb: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.tl = {
path: [ [topleft, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, 1], [topleft, 1], [1, righttop], [1, rightbottom], [bottomleft, 0] ]);
},
hexagon_lt_rb: function(cell, x0, x1, x2, x3, opt) {
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
cell.edges.rt = {
path: [ [1, righttop], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [topright, 1], [1, 1], [1, righttop], [bottomleft, 0] ]);
},
hexagon_bl_tr: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
cell.edges.tl = {
path: [ [topleft, 1], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright, 0], [0, lefttop], [0, 1], [topleft, 1], [1, rightbottom], [1, 0] ]);
},
heptagon_tr: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var topright = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [topright, 1] ],
move: {
x: 0,
y: 1,
enter: 'br'
}
};
cell.edges.rt = {
path: [ [1, righttop], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [0, leftbottom], [0, lefttop], [topright, 1], [1, 1], [1, righttop], [bottomright, 0] ]);
},
heptagon_bl: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.lb = {
path: [ [0, leftbottom], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomleft, 0] ],
move: {
x: 0,
y: -1,
enter: 'tl'
}
};
}
if (opt.polygons)
cell.polygons.push([ [0, 0], [0, leftbottom], [topleft, 1], [topright, 1], [1, righttop], [1, rightbottom], [bottomleft, 0] ]);
},
heptagon_tl: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var lefttop = opt.interpolate(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, lefttop] ],
move: {
x: -1,
y: 0,
enter: 'rt'
}
};
cell.edges.tl = {
path: [ [topleft, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [0, lefttop], [0, 1], [topleft, 1], [1, righttop], [1, rightbottom], [bottomright, 0] ]);
},
heptagon_br: function(cell, x0, x1, x2, x3, opt) {
var bottomright = opt.interpolate(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.br = {
path: [ [bottomright, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, rightbottom] ],
move: {
x: 1,
y: 0,
enter: 'lb'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomright,0], [0, leftbottom], [0, lefttop], [topleft, 1], [topright, 1], [1, rightbottom], [1, 0] ]);
},
octagon: function(cell, x0, x1, x2, x3, opt) {
var bottomleft = opt.interpolate_a(x0, x1, opt.minV, opt.maxV);
var bottomright = opt.interpolate_b(x0, x1, opt.minV, opt.maxV);
var leftbottom = opt.interpolate_a(x0, x3, opt.minV, opt.maxV);
var lefttop = opt.interpolate_b(x0, x3, opt.minV, opt.maxV);
var topleft = opt.interpolate_a(x3, x2, opt.minV, opt.maxV);
var topright = opt.interpolate_b(x3, x2, opt.minV, opt.maxV);
var righttop = opt.interpolate_b(x1, x2, opt.minV, opt.maxV);
var rightbottom = opt.interpolate_a(x1, x2, opt.minV, opt.maxV);
if (opt.polygons_full) {
cell.edges.bl = {
path: [ [bottomleft, 0], [0, leftbottom] ],
move: {
x: -1,
y: 0,
enter: 'rb'
}
};
cell.edges.lt = {
path: [ [0, lefttop], [topleft, 1] ],
move: {
x: 0,
y: 1,
enter: 'bl'
}
};
cell.edges.tr = {
path: [ [topright, 1], [1, righttop] ],
move: {
x: 1,
y: 0,
enter: 'lt'
}
};
cell.edges.rb = {
path: [ [1, rightbottom], [bottomright, 0] ],
move: {
x: 0,
y: -1,
enter: 'tr'
}
};
}
if (opt.polygons)
cell.polygons.push([ [bottomleft, 0], [0, leftbottom], [0, lefttop], [topleft, 1], [topright, 1], [1, righttop], [1, rightbottom], [bottomright, 0] ]);
}
};
/*
* Compute isobands(s) for a scalar 2D field given a certain
* threshold and a bandwidth by applying the Marching Squares
* Algorithm. The function returns a list of path coordinates
* either for individual polygons within each grid cell, or the
* outline of connected polygons.
*/
function isoBands(input, minV, bandWidth, options) {
var i,
j,
settings,
useQuadTree = false,
tree = null,
root = null,
data = null,
cellGrid = null,
multiBand = false,
bw = [],
bandPolygons = [],
ret = [];
/* basic input validation */
if (!input) throw new Error('data is required');
if (minV === undefined || minV === null) throw new Error('lowerBound is required');
if (bandWidth === undefined || bandWidth === null) throw new Error('bandWidth is required');
if ((!!options) && (typeof options !== 'object')) throw new Error('options must be an object');
settings = isoBandOptions(options);
/* check for input data */
if (input instanceof QuadTree) {
tree = input;
root = input.root;
data = input.data;
if (!settings.noQuadTree)
useQuadTree = true;
} else if (Array.isArray(input) && Array.isArray(input[0])) {
data = input;
} else {
throw new Error('input is neither array of arrays nor object retrieved from \'QuadTree()\'');
}
/* check and prepare input thresholds */
if (Array.isArray(minV)) {
multiBand = true;
/* activate QuadTree optimization if not explicitly forbidden by user settings */
if (!settings.noQuadTree)
useQuadTree = true;
/* check if all minV are numbers */
for (i = 0; i < minV.length; i++)
if (isNaN(+minV[i]))
throw new Error('lowerBound[' + i + '] is not a number');
if (Array.isArray(bandWidth)) {
if (minV.length !== bandWidth.length)
throw new Error('lowerBound and bandWidth have unequal lengths');
/* check bandwidth values */
for (i = 0; i < bandWidth.length; i++)
if (isNaN(+bandWidth[i]))
throw new Error('bandWidth[' + i + '] is not a number');
} else {
if (isNaN(+bandWidth))
throw new Error('bandWidth must be a number');
bw = [];
for (i = 0; i < minV.length; i++) {
bw.push(bandWidth);
}
bandWidth = bw;
}
} else {
if (isNaN(+minV))
throw new Error('lowerBound must be a number');
minV = [ minV ];
if (isNaN(+bandWidth))
throw new Error('bandWidth must be a number');
bandWidth = [ bandWidth ];
}
/* create QuadTree root node if not already present */
if ((useQuadTree) && (!root)) {
tree = new QuadTree(data);
root = tree.root;
data = tree.data;
}
if (settings.verbose) {
if(settings.polygons)
console.log('MarchingSquaresJS-isoBands: returning single polygons for each grid cell');
else
console.log('MarchingSquaresJS-isoBands: returning polygon paths for entire data grid');
if (multiBand)
console.log('MarchingSquaresJS-isoBands: multiple bands requested, returning array of band polygons instead of polygons for a single band');
}
/* Done with all input validation, now let's start computing stuff */
/* loop over all minV values */
minV.forEach(function(lowerBound, b) {
bandPolygons = [];
/* store bounds for current computation in settings object */
settings.minV = lowerBound;
settings.maxV = lowerBound + bandWidth[b];
if(settings.verbose)
console.log('MarchingSquaresJS-isoBands: computing isobands for [' + lowerBound + ':' + (lowerBound + bandWidth[b]) + ']');
if (settings.polygons) {
/* compose list of polygons for each single cell */
if (useQuadTree) {
/* go through list of cells retrieved from QuadTree */
root
.cellsInBand(settings.minV, settings.maxV, true)
.forEach(function(c) {
bandPolygons = bandPolygons.concat(
cell2Polygons(
prepareCell(data,
c.x,
c.y,
settings),
c.x,
c.y,
settings
));
});
} else {
/* go through entire array of input data */
for (j = 0; j < data.length - 1; ++j) {
for (i = 0; i < data[0].length - 1; ++i)
bandPolygons = bandPolygons.concat(
cell2Polygons(
prepareCell(data,
i,
j,
settings),
i,
j,
settings
));
}
}
} else {
/* sparse grid of input data cells */
cellGrid = [];
for (i = 0; i < data[0].length - 1; ++i)
cellGrid[i] = [];
/* compose list of polygons for entire input grid */
if (useQuadTree) {
/* collect the cells */
root
.cellsInBand(settings.minV, settings.maxV, false)
.forEach(function(c) {
cellGrid[c.x][c.y] = prepareCell(data,
c.x,
c.y,
settings);
});
} else {
/* prepare cells */
for (i = 0; i < data[0].length - 1; ++i) {
for (j = 0; j < data.length - 1; ++j) {
cellGrid[i][j] = prepareCell(data,
i,
j,
settings);
}
}
}
bandPolygons = traceBandPaths(data, cellGrid, settings);
}
/* finally, add polygons to output array */
if (multiBand)
ret.push(bandPolygons);
else
ret = bandPolygons;
if(typeof settings.successCallback === 'function')
settings.successCallback(ret, lowerBound, bandWidth[b]);
});
return ret;
}
/*
* Thats all for the public interface, below follows the actual
* implementation
*/
/*
* For isoBands, each square is defined by the three states
* of its corner points. However, since computers use power-2
* values, we use 2bits per trit, i.e.:
*
* 00 ... below minV
* 01 ... between minV and maxV
* 10 ... above maxV
*
* Hence we map the 4-trit configurations as follows:
*
* 0000 => 0
* 0001 => 1
* 0002 => 2
* 0010 => 4
* 0011 => 5
* 0012 => 6
* 0020 => 8
* 0021 => 9
* 0022 => 10
* 0100 => 16
* 0101 => 17
* 0102 => 18
* 0110 => 20
* 0111 => 21
* 0112 => 22
* 0120 => 24
* 0121 => 25
* 0122 => 26
* 0200 => 32
* 0201 => 33
* 0202 => 34
* 0210 => 36
* 0211 => 37
* 0212 => 38
* 0220 => 40
* 0221 => 41
* 0222 => 42
* 1000 => 64
* 1001 => 65
* 1002 => 66
* 1010 => 68
* 1011 => 69
* 1012 => 70
* 1020 => 72
* 1021 => 73
* 1022 => 74
* 1100 => 80
* 1101 => 81
* 1102 => 82
* 1110 => 84
* 1111 => 85
* 1112 => 86
* 1120 => 88
* 1121 => 89
* 1122 => 90
* 1200 => 96
* 1201 => 97
* 1202 => 98
* 1210 => 100
* 1211 => 101
* 1212 => 102
* 1220 => 104
* 1221 => 105
* 1222 => 106
* 2000 => 128
* 2001 => 129
* 2002 => 130
* 2010 => 132
* 2011 => 133
* 2012 => 134
* 2020 => 136
* 2021 => 137
* 2022 => 138
* 2100 => 144
* 2101 => 145
* 2102 => 146
* 2110 => 148
* 2111 => 149
* 2112 => 150
* 2120 => 152
* 2121 => 153
* 2122 => 154
* 2200 => 160
* 2201 => 161
* 2202 => 162
* 2210 => 164
* 2211 => 165
* 2212 => 166
* 2220 => 168
* 2221 => 169
* 2222 => 170
*/
/*
* ####################################
* Some small helper functions
* ####################################
*/
function computeCenterAverage(bl, br, tr, tl, minV, maxV) {
var average = (tl + tr + br + bl) / 4;
if (average > maxV)
return 2; /* above isoband limits */
if (average < minV)
return 0; /* below isoband limits */
return 1; /* within isoband limits */
}
function prepareCell(grid, x, y, opt) {
var cell,
center_avg;
/* compose the 4-trit corner representation */
var cval = 0;
var x3 = grid[y + 1][x];
var x2 = grid[y + 1][x + 1];
var x1 = grid[y][x + 1];
var x0 = grid[y][x];
var minV = opt.minV;
var maxV = opt.maxV;
/*
* Note that missing data within the grid will result
* in horribly failing to trace full polygon paths
*/
if(isNaN(x0) || isNaN(x1) || isNaN(x2) || isNaN(x3)) {
return;
}
/*
* Here we detect the type of the cell
*
* x3 ---- x2
* | |
* | |
* x0 ---- x1
*
* with edge points
*
* x0 = (x,y),
* x1 = (x + 1, y),
* x2 = (x + 1, y + 1), and
* x3 = (x, y + 1)
*
* and compute the polygon intersections with the edges
* of the cell. Each edge value may be (i) below, (ii) within,
* or (iii) above the values of the isoband limits. We
* encode this property using 2 bits of information, where
*
* 00 ... below,
* 01 ... within, and
* 10 ... above
*
* Then we store the cells value as vector
*
* cval = (x0, x1, x2, x3)
*
* where x0 are the two least significant bits (0th, 1st),
* x1 the 2nd and 3rd bit, and so on. This essentially
* enables us to work with a single integer number
*/
cval |= (x3 < minV) ? 0 : (x3 > maxV) ? 128 : 64;
cval |= (x2 < minV) ? 0 : (x2 > maxV) ? 32 : 16;
cval |= (x1 < minV) ? 0 : (x1 > maxV) ? 8 : 4;
cval |= (x0 < minV) ? 0 : (x0 > maxV) ? 2 : 1;
/* make sure cval is a number */
cval = +cval;
/*
* cell center average trit for ambiguous cases, where
* 0 ... below iso band
* 1 ... within iso band
* 2 ... above isoband
*/
center_avg = 0;
cell = {
cval: cval,
polygons: [],
edges: {},
x0: x0,
x1: x1,
x2: x2,
x3: x3,
x: x,
y: y
};
/*
* Compute interpolated intersections of the polygon(s)
* with the cell borders and (i) add edges for polygon
* trace-back, or (ii) a list of small closed polygons
* according to look-up table
*/
switch (cval) {
case 85: /* 1111 */
shapeCoordinates.square(cell, x0, x1, x2, x3, opt);
/* fall through */
case 0: /* 0000 */
/* fall through */
case 170: /* 2222 */
break;
/* single triangle cases */
case 169: /* 2221 */
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
break;
case 166: /* 2212 */
shapeCoordinates.triangle_br(cell, x0, x1, x2, x3, opt);
break;
case 154: /* 2122 */
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
break;
case 106: /* 1222 */
shapeCoordinates.triangle_tl(cell, x0, x1, x2, x3, opt);
break;
case 1: /* 0001 */
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
break;
case 4: /* 0010 */
shapeCoordinates.triangle_br(cell, x0, x1, x2, x3, opt);
break;
case 16: /* 0100 */
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
break;
case 64: /* 1000 */
shapeCoordinates.triangle_tl(cell, x0, x1, x2, x3, opt);
break;
/* single trapezoid cases */
case 168: /* 2220 */
shapeCoordinates.tetragon_bl(cell, x0, x1, x2, x3, opt);
break;
case 162: /* 2202 */
shapeCoordinates.tetragon_br(cell, x0, x1, x2, x3, opt);
break;
case 138: /* 2022 */
shapeCoordinates.tetragon_tr(cell, x0, x1, x2, x3, opt);
break;
case 42: /* 0222 */
shapeCoordinates.tetragon_tl(cell, x0, x1, x2, x3, opt);
break;
case 2: /* 0002 */
shapeCoordinates.tetragon_bl(cell, x0, x1, x2, x3, opt);
break;
case 8: /* 0020 */
shapeCoordinates.tetragon_br(cell, x0, x1, x2, x3, opt);
break;
case 32: /* 0200 */
shapeCoordinates.tetragon_tr(cell, x0, x1, x2, x3, opt);
break;
case 128: /* 2000 */
shapeCoordinates.tetragon_tl(cell, x0, x1, x2, x3, opt);
break;
/* single rectangle cases */
case 5: /* 0011 */
shapeCoordinates.tetragon_b(cell, x0, x1, x2, x3, opt);
break;
case 20: /* 0110 */
shapeCoordinates.tetragon_r(cell, x0, x1, x2, x3, opt);
break;
case 80: /* 1100 */
shapeCoordinates.tetragon_t(cell, x0, x1, x2, x3, opt);
break;
case 65: /* 1001 */
shapeCoordinates.tetragon_l(cell, x0, x1, x2, x3, opt);
break;
case 165: /* 2211 */
shapeCoordinates.tetragon_b(cell, x0, x1, x2, x3, opt);
break;
case 150: /* 2112 */
shapeCoordinates.tetragon_r(cell, x0, x1, x2, x3, opt);
break;
case 90: /* 1122 */
shapeCoordinates.tetragon_t(cell, x0, x1, x2, x3, opt);
break;
case 105: /* 1221 */
shapeCoordinates.tetragon_l(cell, x0, x1, x2, x3, opt);
break;
case 160: /* 2200 */
shapeCoordinates.tetragon_lr(cell, x0, x1, x2, x3, opt);
break;
case 130: /* 2002 */
shapeCoordinates.tetragon_tb(cell, x0, x1, x2, x3, opt);
break;
case 10: /* 0022 */
shapeCoordinates.tetragon_lr(cell, x0, x1, x2, x3, opt);
break;
case 40: /* 0220 */
shapeCoordinates.tetragon_tb(cell, x0, x1, x2, x3, opt);
break;
/* single pentagon cases */
case 101: /* 1211 */
shapeCoordinates.pentagon_tr(cell, x0, x1, x2, x3, opt);
break;
case 149: /* 2111 */
shapeCoordinates.pentagon_tl(cell, x0, x1, x2, x3, opt);
break;
case 86: /* 1112 */
shapeCoordinates.pentagon_bl(cell, x0, x1, x2, x3, opt);
break;
case 89: /* 1121 */
shapeCoordinates.pentagon_br(cell, x0, x1, x2, x3, opt);
break;
case 69: /* 1011 */
shapeCoordinates.pentagon_tr(cell, x0, x1, x2, x3, opt);
break;
case 21: /* 0111 */
shapeCoordinates.pentagon_tl(cell, x0, x1, x2, x3, opt);
break;
case 84: /* 1110 */
shapeCoordinates.pentagon_bl(cell, x0, x1, x2, x3, opt);
break;
case 81: /* 1101 */
shapeCoordinates.pentagon_br(cell, x0, x1, x2, x3, opt);
break;
case 96: /* 1200 */
shapeCoordinates.pentagon_tr_rl(cell, x0, x1, x2, x3, opt);
break;
case 24: /* 0120 */
shapeCoordinates.pentagon_rb_bt(cell, x0, x1, x2, x3, opt);
break;
case 6: /* 0012 */
shapeCoordinates.pentagon_bl_lr(cell, x0, x1, x2, x3, opt);
break;
case 129: /* 2001 */
shapeCoordinates.pentagon_lt_tb(cell, x0, x1, x2, x3, opt);
break;
case 74: /* 1022 */
shapeCoordinates.pentagon_tr_rl(cell, x0, x1, x2, x3, opt);
break;
case 146: /* 2102 */
shapeCoordinates.pentagon_rb_bt(cell, x0, x1, x2, x3, opt);
break;
case 164: /* 2210 */
shapeCoordinates.pentagon_bl_lr(cell, x0, x1, x2, x3, opt);
break;
case 41: /* 0221 */
shapeCoordinates.pentagon_lt_tb(cell, x0, x1, x2, x3, opt);
break;
case 66: /* 1002 */
shapeCoordinates.pentagon_bl_tb(cell, x0, x1, x2, x3, opt);
break;
case 144: /* 2100 */
shapeCoordinates.pentagon_lt_rl(cell, x0, x1, x2, x3, opt);
break;
case 36: /* 0210 */
shapeCoordinates.pentagon_tr_bt(cell, x0, x1, x2, x3, opt);
break;
case 9: /* 0021 */
shapeCoordinates.pentagon_rb_lr(cell, x0, x1, x2, x3, opt);
break;
case 104: /* 1220 */
shapeCoordinates.pentagon_bl_tb(cell, x0, x1, x2, x3, opt);
break;
case 26: /* 0122 */
shapeCoordinates.pentagon_lt_rl(cell, x0, x1, x2, x3, opt);
break;
case 134: /* 2012 */
shapeCoordinates.pentagon_tr_bt(cell, x0, x1, x2, x3, opt);
break;
case 161: /* 2201 */
shapeCoordinates.pentagon_rb_lr(cell, x0, x1, x2, x3, opt);
break;
/* single hexagon cases */
case 37: /* 0211 */
shapeCoordinates.hexagon_lt_tr(cell, x0, x1, x2, x3, opt);
break;
case 148: /* 2110 */
shapeCoordinates.hexagon_bl_lt(cell, x0, x1, x2, x3, opt);
break;
case 82: /* 1102 */
shapeCoordinates.hexagon_bl_rb(cell, x0, x1, x2, x3, opt);
break;
case 73: /* 1021 */
shapeCoordinates.hexagon_tr_rb(cell, x0, x1, x2, x3, opt);
break;
case 133: /* 2011 */
shapeCoordinates.hexagon_lt_tr(cell, x0, x1, x2, x3, opt);
break;
case 22: /* 0112 */
shapeCoordinates.hexagon_bl_lt(cell, x0, x1, x2, x3, opt);
break;
case 88: /* 1120 */
shapeCoordinates.hexagon_bl_rb(cell, x0, x1, x2, x3, opt);
break;
case 97: /* 1201 */
shapeCoordinates.hexagon_tr_rb(cell, x0, x1, x2, x3, opt);
break;
case 145: /* 2101 */
shapeCoordinates.hexagon_lt_rb(cell, x0, x1, x2, x3, opt);
break;
case 25: /* 0121 */
shapeCoordinates.hexagon_lt_rb(cell, x0, x1, x2, x3, opt);
break;
case 70: /* 1012 */
shapeCoordinates.hexagon_bl_tr(cell, x0, x1, x2, x3, opt);
break;
case 100: /* 1210 */
shapeCoordinates.hexagon_bl_tr(cell, x0, x1, x2, x3, opt);
break;
/* 6-sided saddles */
case 17: /* 0101 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 2 */
if (center_avg === 0) {
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.hexagon_lt_rb(cell, x0, x1, x2, x3, opt);
}
break;
case 68: /* 1010 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 2 */
if (center_avg === 0) {
shapeCoordinates.triangle_tl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.triangle_br(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.hexagon_bl_tr(cell, x0, x1, x2, x3, opt);
}
break;
case 153: /* 2121 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.hexagon_lt_rb(cell, x0, x1, x2, x3, opt);
}
break;
case 102: /* 1212 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_tl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.triangle_br(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.hexagon_bl_tr(cell, x0, x1, x2, x3, opt);
}
break;
/* 7-sided saddles */
case 152: /* 2120 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_bl(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_tr(cell, x0, x1, x2, x3, opt);
}
break;
case 137: /* 2021 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_tr(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_bl(cell, x0, x1, x2, x3, opt);
}
break;
case 98: /* 1202 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_tl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_br(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_tl(cell, x0, x1, x2, x3, opt);
}
break;
case 38: /* 0212 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 0 */
if (center_avg === 2) {
shapeCoordinates.triangle_br(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_tl(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_br(cell, x0, x1, x2, x3, opt);
}
break;
case 18: /* 0102 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 2 */
if (center_avg === 0) {
shapeCoordinates.triangle_tr(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_bl(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_tr(cell, x0, x1, x2, x3, opt);
}
break;
case 33: /* 0201 */
center_avg = computeCenterAverage(x0, x1, x2, x3, minV, maxV);
/* should never be center_avg === 2 */
if (center_avg === 0) {
shapeCoordinates.triangle_bl(cell, x0, x1, x2, x3, opt);
shapeCoordinates.tetragon_tr(cell, x0, x1, x2, x3, opt);
} else {
shapeCoordinates.heptagon_bl(cell, x0, x1, x2, x3, opt);
}
break;
case 72: /* 1020 */
center_avg = compu