| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209 |
- /*!
- * MarchingSquaresJS
- * version 1.3.3
- * https://github.com/RaumZeit/MarchingSquares.js
- *
- * @license GNU Affero General Public License.
- * Copyright (c) 2015-2019 Ronny Lorenz <ronny@tbi.univie.ac.at>
- */
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
- (factory((global.MarchingSquaresJS = global.MarchingSquaresJS || {})));
- }(this, (function (exports) { 'use strict';
- /*
- * Compute the distance of a value 'v' from 'a' through linear interpolation
- * between the values of 'a' and 'b'
- *
- * Note, that we assume that 'a' and 'b' have unit distance (i.e. 1)
- */
- function linear(a, b, v) {
- if (a < b)
- return (v - a) / (b - a);
- return (a - v) / (a - b);
- }
- function Options() {
- /* Settings common to all implemented algorithms */
- this.successCallback = null;
- this.verbose = false;
- this.polygons = false;
- this.polygons_full = false;
- this.linearRing = true;
- this.noQuadTree = false;
- this.noFrame = false;
- }
- /* Compose settings specific to IsoLines algorithm */
- function isoLineOptions(userSettings) {
- var i,
- key,
- val,
- lineOptions,
- optionKeys;
- lineOptions = new Options();
- userSettings = userSettings ? userSettings : {};
- optionKeys = Object.keys(lineOptions);
- for(i = 0; i < optionKeys.length; i++) {
- key = optionKeys[i];
- val = userSettings[key];
- if ((typeof val !== 'undefined') && (val !== null))
- lineOptions[key] = val;
- }
- /* restore compatibility */
- lineOptions.polygons_full = !lineOptions.polygons;
- /* add interpolation functions (not yet user customizable) */
- lineOptions.interpolate = linear;
- return lineOptions;
- }
- function cell2Polygons(cell, x, y, settings) {
- var polygons = [];
- cell.polygons.forEach(function(p) {
- p.forEach(function(pp) {
- pp[0] += x;
- pp[1] += y;
- });
- if (settings.linearRing)
- p.push(p[0]);
- polygons.push(p);
- });
- return polygons;
- }
- function entry_coordinate(x, y, mode, path) {
- if (mode === 0) { /* down */
- x += 1;
- y += path[0][1];
- } else if (mode === 1) { /* left */
- x += path[0][0];
- } else if (mode === 2) { /* up */
- y += path[0][1];
- } else if (mode === 3) { /* right */
- x += path[0][0];
- y += 1;
- }
- return [ x, y ];
- }
- function skip_coordinate(x, y, mode) {
- if (mode === 0) { /* down */
- x++;
- } else if (mode === 1) ; else if (mode === 2) { /* up */
- y++;
- } else if (mode === 3) { /* right */
- x++;
- y++;
- }
- return [ x, y ];
- }
- function requireLineFrame(data, threshold) {
- var frameRequired,
- cols,
- rows,
- i,
- j;
- frameRequired = true;
- cols = data[0].length;
- rows = data.length;
- for (j = 0; j < rows; j++) {
- if ((data[j][0] >= threshold) ||
- (data[j][cols - 1] >= threshold)) {
- frameRequired = false;
- break;
- }
- }
- if ((frameRequired) &&
- ((data[rows - 1][0] >= threshold) ||
- (data[rows - 1][cols - 1] >= threshold))) {
- frameRequired = false;
- }
- if (frameRequired)
- for (i = 0; i < cols - 1; i++) {
- if ((data[0][i] >= threshold) ||
- (data[rows - 1][i] > threshold)) {
- frameRequired = false;
- break;
- }
- }
- return frameRequired;
- }
- function traceLinePaths(data, cellGrid, settings) {
- var nextedge,
- e,
- ee,
- cc,
- path,
- enter,
- x,
- y,
- finalized,
- origin,
- point,
- dir,
- count,
- found_entry,
- ve;
- var polygons = [];
- var rows = data.length - 1;
- var cols = data[0].length - 1;
- /*
- * directions for out-of-grid moves are:
- * 0 ... "down",
- * 1 ... "left",
- * 2 ... "up",
- * 3 ... "right"
- */
- var valid_entries = [ 'right', /* down */
- 'bottom', /* left */
- 'left', /* up */
- 'top' /* right */
- ];
- var add_x = [ 0, -1, 0, 1 ];
- var add_y = [ -1, 0, 1, 0 ];
- var entry_dir = {
- bottom: 1,
- left: 2,
- top: 3,
- right: 0
- };
- /* first, detect whether we need any outer frame */
- if (!settings.noFrame)
- if (requireLineFrame(data, settings.threshold)) {
- if (settings.linearRing)
- polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0], [0, 0] ]);
- else
- polygons.push([ [0, 0], [0, rows], [cols, rows], [cols, 0] ]);
- }
- /* finally, start tracing back first polygon(s) */
- cellGrid.forEach(function(a, i) {
- a.forEach(function(cell, j) {
- nextedge = null;
- /* trace paths for all available edges that go through this cell */
- for (e = 0; e < 4; e++) {
- nextedge = valid_entries[e];
- if (typeof cell.edges[nextedge] !== 'object')
- continue;
- /* start a new, full path */
- path = [];
- ee = cell.edges[nextedge];
- enter = nextedge;
- x = i;
- y = j;
- finalized = false;
- origin = [ i + ee.path[0][0], j + ee.path[0][1] ];
- /* add start coordinate */
- path.push(origin);
- /* start traceback */
- while (!finalized) {
- cc = cellGrid[x][y];
- if (typeof cc.edges[enter] !== 'object')
- break;
- ee = cc.edges[enter];
- /* remove edge from cell */
- delete cc.edges[enter];
- /* add last point of edge to path arra, since we extend a polygon */
- point = ee.path[1];
- point[0] += x;
- point[1] += y;
- path.push(point);
- enter = ee.move.enter;
- x = x + ee.move.x;
- y = y + ee.move.y;
- /* handle out-of-grid moves */
- if ((typeof cellGrid[x] === 'undefined') ||
- (typeof cellGrid[x][y] === 'undefined')) {
- if (!settings.linearRing)
- break;
- dir = 0;
- count = 0;
- if (x === cols) {
- x--;
- dir = 0; /* move downwards */
- } else if (x < 0) {
- x++;
- dir = 2; /* move upwards */
- } else if (y === rows) {
- y--;
- dir = 3; /* move right */
- } else if (y < 0) {
- y++;
- dir = 1; /* move left */
- }
- if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
- finalized = true;
- enter = nextedge;
- break;
- }
- while (1) {
- found_entry = false;
- if (count > 4)
- throw new Error('Direction change counter overflow! This should never happen!');
- if (!((typeof cellGrid[x] === 'undefined') ||
- (typeof cellGrid[x][y] === 'undefined'))) {
- cc = cellGrid[x][y];
- /* check for re-entry */
- ve = valid_entries[dir];
- if (typeof cc.edges[ve] === 'object') {
- /* found re-entry */
- ee = cc.edges[ve];
- path.push(entry_coordinate(x, y, dir, ee.path));
- enter = ve;
- found_entry = true;
- break;
- }
- }
- if (found_entry) {
- break;
- } else {
- path.push(skip_coordinate(x, y, dir));
- x += add_x[dir];
- y += add_y[dir];
- /* change direction if we'e moved out of grid again */
- if ((typeof cellGrid[x] === 'undefined') ||
- (typeof cellGrid[x][y] === 'undefined')) {
- if (((dir === 0) && (y < 0)) ||
- ((dir === 1) && (x < 0)) ||
- ((dir === 2) && (y === rows)) ||
- ((dir === 3) && (x === cols))) {
- x -= add_x[dir];
- y -= add_y[dir];
- dir = (dir + 1) % 4;
- count++;
- }
- }
- if ((x === i) && (y === j) && (dir === entry_dir[nextedge])) {
- /* we are back where we started off, so finalize the polygon */
- finalized = true;
- enter = nextedge;
- break;
- }
- }
- }
- }
- }
- if ((settings.linearRing) &&
- ((path[path.length - 1][0] !== origin[0]) ||
- (path[path.length - 1][1] !== origin[1])))
- path.push(origin);
- polygons.push(path);
- } /* end forall entry sites */
- }); /* end foreach i */
- }); /* end foreach j */
- return polygons;
- }
- /* quadTree node constructor */
- function TreeNode(data, x, y, dx, dy) {
- var dx_tmp = dx,
- dy_tmp = dy,
- msb_x = 0,
- msb_y = 0;
- /* left-bottom corner of current quadrant */
- this.x = x;
- this.y = y;
- /* minimum value in subtree under this node */
- this.lowerBound = null;
- /* maximum value in subtree under this node */
- this.upperBound = null;
- /*
- * child nodes are layed out in the following way:
- *
- * (x, y + 1) ---- (x + 1, y + 1)
- * | | |
- * | D | C |
- * | | |
- * |----------------------------|
- * | | |
- * | A | B |
- * | | |
- * (x, y) ------------ (x + 1, y)
- */
- this.childA = null;
- this.childB = null;
- this.childC = null;
- this.childD = null;
- if ((dx === 1) && (dy === 1)) {
- /* do not further subdivision */
- this.lowerBound = Math.min(
- data[y][x],
- data[y][x + 1],
- data[y + 1][x + 1],
- data[y + 1][x]
- );
- this.upperBound = Math.max(
- data[y][x],
- data[y][x + 1],
- data[y + 1][x + 1],
- data[y + 1][x]
- );
- } else {
- /* get most significant bit from dx */
- if (dx > 1) {
- while (dx_tmp !== 0) {
- dx_tmp = dx_tmp >> 1;
- msb_x++;
- }
- if (dx === (1 << (msb_x - 1)))
- msb_x--;
- dx_tmp = 1 << (msb_x - 1);
- }
- /* get most significant bit from dx */
- if (dy > 1) {
- while (dy_tmp !== 0) {
- dy_tmp = dy_tmp >> 1;
- msb_y++;
- }
- if (dy === (1 << (msb_y - 1)))
- msb_y--;
- dy_tmp = 1 << (msb_y - 1);
- }
- this.childA = new TreeNode(data, x, y, dx_tmp, dy_tmp);
- this.lowerBound = this.childA.lowerBound;
- this.upperBound = this.childA.upperBound;
- if (dx - dx_tmp > 0) {
- this.childB = new TreeNode(data, x + dx_tmp, y, dx - dx_tmp, dy_tmp);
- this.lowerBound = Math.min(this.lowerBound, this.childB.lowerBound);
- this.upperBound = Math.max(this.upperBound, this.childB.upperBound);
- if (dy - dy_tmp > 0) {
- this.childC = new TreeNode(data, x + dx_tmp, y + dy_tmp, dx - dx_tmp, dy - dy_tmp);
- this.lowerBound = Math.min(this.lowerBound, this.childC.lowerBound);
- this.upperBound = Math.max(this.upperBound, this.childC.upperBound);
- }
- }
- if (dy - dy_tmp > 0) {
- this.childD = new TreeNode(data, x, y + dy_tmp, dx_tmp, dy - dy_tmp);
- this.lowerBound = Math.min(this.lowerBound, this.childD.lowerBound);
- this.upperBound = Math.max(this.upperBound, this.childD.upperBound);
- }
- }
- }
- /**
- * Retrieve a list of cells within a particular range of values by
- * recursivly traversing the quad tree to it's leaves.
- *
- * @param subsumed If 'true' include all cells that are completely
- * subsumed within the specified range. Otherwise,
- * return only cells where at least one corner is
- * outside the specified range.
- *
- * @return An array of objects 'o' where each object has exactly two
- * properties: 'o.x' and 'o.y' denoting the left-bottom corner
- * of the corresponding cell.
- */
- TreeNode.prototype.cellsInBand = function(lowerBound, upperBound, subsumed) {
- var cells = [];
- subsumed = (typeof subsumed === 'undefined') ? true : subsumed;
- if ((this.lowerBound > upperBound) || (this.upperBound < lowerBound))
- return cells;
- if (!(this.childA || this.childB || this.childC || this.childD)) {
- if ((subsumed) ||
- (this.lowerBound <= lowerBound) ||
- (this.upperBound >= upperBound)) {
- cells.push({
- x: this.x,
- y: this.y
- });
- }
- } else {
- if (this.childA)
- cells = cells.concat(this.childA.cellsInBand(lowerBound, upperBound, subsumed));
- if (this.childB)
- cells = cells.concat(this.childB.cellsInBand(lowerBound, upperBound, subsumed));
- if (this.childD)
- cells = cells.concat(this.childD.cellsInBand(lowerBound, upperBound, subsumed));
- if (this.childC)
- cells = cells.concat(this.childC.cellsInBand(lowerBound, upperBound, subsumed));
- }
- return cells;
- };
- TreeNode.prototype.cellsBelowThreshold = function(threshold, subsumed) {
- var cells = [];
- subsumed = (typeof subsumed === 'undefined') ? true : subsumed;
- if (this.lowerBound > threshold)
- return cells;
- if (!(this.childA || this.childB || this.childC || this.childD)) {
- if ((subsumed) ||
- (this.upperBound >= threshold)) {
- cells.push({
- x: this.x,
- y: this.y
- });
- }
- } else {
- if (this.childA)
- cells = cells.concat(this.childA.cellsBelowThreshold(threshold, subsumed));
- if (this.childB)
- cells = cells.concat(this.childB.cellsBelowThreshold(threshold, subsumed));
- if (this.childD)
- cells = cells.concat(this.childD.cellsBelowThreshold(threshold, subsumed));
- if (this.childC)
- cells = cells.concat(this.childC.cellsBelowThreshold(threshold, subsumed));
- }
- return cells;
- };
- /*
- * Given a scalar field `data` construct a QuadTree
- * to efficiently lookup those parts of the scalar
- * field where values are within a particular
- * range of [lowerbound, upperbound] limits.
- */
- function QuadTree(data) {
- var i, cols;
- /* do some input checking */
- if (!data)
- throw new Error('data is required');
- if (!Array.isArray(data) ||
- !Array.isArray(data[0]))
- throw new Error('data must be scalar field, i.e. array of arrays');
- if (data.length < 2)
- throw new Error('data must contain at least two rows');
- /* check if we've got a regular grid */
- cols = data[0].length;
- if (cols < 2)
- throw new Error('data must contain at least two columns');
- for (i = 1; i < data.length; i++) {
- if (!Array.isArray(data[i]))
- throw new Error('Row ' + i + ' is not an array');
- if (data[i].length != cols)
- throw new Error('unequal row lengths detected, please provide a regular grid');
- }
- /* create pre-processing object */
- this.data = data;
- /* root node, i.e. entry to the data */
- this.root = new TreeNode(data, 0, 0, data[0].length - 1, data.length - 1);
- }
- /* eslint no-console: ["error", { allow: ["log"] }] */
- /*
- * Compute the iso lines for a scalar 2D field given
- * a certain threshold by applying the Marching Squares
- * Algorithm. The function returns a list of path coordinates
- */
- function isoLines(input, threshold, options) {
- var settings,
- i,
- j,
- useQuadTree = false,
- multiLine = false,
- tree = null,
- root = null,
- data = null,
- cellGrid = null,
- linePolygons = null,
- ret = [];
- /* validation */
- if (!input) throw new Error('data is required');
- if (threshold === undefined || threshold === null) throw new Error('threshold is required');
- if ((!!options) && (typeof options !== 'object')) throw new Error('options must be an object');
- /* process options */
- settings = isoLineOptions(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 threshold(s) */
- if (Array.isArray(threshold)) {
- multiLine = 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 < threshold.length; i++)
- if (isNaN(+threshold[i]))
- throw new Error('threshold[' + i + '] is not a number');
- } else {
- if (isNaN(+threshold))
- throw new Error('threshold must be a number or array of numbers');
- threshold = [ threshold ];
- }
- /* 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-isoLines: returning single lines (polygons) for each grid cell');
- else
- console.log('MarchingSquaresJS-isoLines: returning line paths (polygons) for entire data grid');
- if (multiLine)
- console.log('MarchingSquaresJS-isoLines: multiple lines requested, returning array of line paths instead of lines for a single threshold');
- }
- /* Done with all input validation, now let's start computing stuff */
- /* loop over all threhsold values */
- threshold.forEach(function(t, i) {
- linePolygons = [];
- /* store bounds for current computation in settings object */
- settings.threshold = t;
- if(settings.verbose)
- console.log('MarchingSquaresJS-isoLines: computing iso lines for threshold ' + t);
- if (settings.polygons) {
- /* compose list of polygons for each single cell */
- if (useQuadTree) {
- /* go through list of cells retrieved from QuadTree */
- root
- .cellsBelowThreshold(settings.threshold, true)
- .forEach(function(c) {
- linePolygons = linePolygons.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)
- linePolygons = linePolygons.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
- .cellsBelowThreshold(settings.threshold, 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);
- }
- }
- }
- linePolygons = traceLinePaths(data, cellGrid, settings);
- }
- /* finally, add polygons to output array */
- if (multiLine)
- ret.push(linePolygons);
- else
- ret = linePolygons;
- if(typeof settings.successCallback === 'function')
- settings.successCallback(ret, t);
- });
- return ret;
- }
- /*
- * Thats all for the public interface, below follows the actual
- * implementation
- */
- /*
- * ################################
- * Isocontour implementation below
- * ################################
- */
- function prepareCell(grid, x, y, settings) {
- var left,
- right,
- top,
- bottom,
- average,
- cell;
- 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 threshold = settings.threshold;
- /*
- * 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) smaller, or (ii)
- * greater or equal to the iso line threshold. We encode
- * this property using 1 bit of information, where
- *
- * 0 ... below,
- * 1 ... above or equal
- *
- * Then we store the cells value as vector
- *
- * cval = (x0, x1, x2, x3)
- *
- * where x0 is the least significant bit (0th),
- * x1 the 2nd bit, and so on. This essentially
- * enables us to work with a single integer number
- */
- cval |= ((x3 >= threshold) ? 8 : 0);
- cval |= ((x2 >= threshold) ? 4 : 0);
- cval |= ((x1 >= threshold) ? 2 : 0);
- cval |= ((x0 >= threshold) ? 1 : 0);
- /* make sure cval is a number */
- cval = +cval;
- /* compose the cell object */
- cell = {
- cval: cval,
- polygons: [],
- edges: {},
- x0: x0,
- x1: x1,
- x2: x2,
- x3: x3
- };
- /*
- * 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
- */
- switch (cval) {
- case 0:
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, 1], [1, 1], [1, 0] ]);
- break;
- case 15:
- /* cell is outside (above) threshold, no polygons */
- break;
- case 14: /* 1110 */
- left = settings.interpolate(x0, x3, threshold);
- bottom = settings.interpolate(x0, x1, threshold);
- if (settings.polygons_full) {
- cell.edges.left = {
- path: [ [0, left], [bottom, 0] ],
- move: {
- x: 0,
- y: -1,
- enter: 'top'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, left], [bottom, 0] ]);
- break;
- case 13: /* 1101 */
- bottom = settings.interpolate(x0, x1, threshold);
- right = settings.interpolate(x1, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.bottom = {
- path: [ [bottom, 0], [1, right] ],
- move: {
- x: 1,
- y: 0,
- enter: 'left'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [bottom, 0], [1, right], [1, 0] ]);
- break;
- case 11: /* 1011 */
- right = settings.interpolate(x1, x2, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.right = {
- path: [ [1, right], [top, 1] ],
- move: {
- x: 0,
- y: 1,
- enter: 'bottom'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [1, right], [top, 1], [1, 1] ]);
- break;
- case 7: /* 0111 */
- left = settings.interpolate(x0, x3, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.top = {
- path: [ [top, 1], [0, left] ],
- move: {
- x: -1,
- y: 0,
- enter: 'right'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [top, 1], [0, left], [0, 1] ]);
- break;
- case 1: /* 0001 */
- left = settings.interpolate(x0, x3, threshold);
- bottom = settings.interpolate(x0, x1, threshold);
- if (settings.polygons_full) {
- cell.edges.bottom = {
- path: [ [bottom, 0], [0, left] ],
- move: {
- x: -1,
- y: 0,
- enter: 'right'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [bottom, 0], [0, left], [0, 1], [1, 1], [1, 0] ]);
- break;
- case 2: /* 0010 */
- bottom = settings.interpolate(x0, x1, threshold);
- right = settings.interpolate(x1, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.right = {
- path: [ [1, right], [bottom, 0] ],
- move: {
- x: 0,
- y: -1,
- enter: 'top'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, 1], [1, 1], [1, right], [bottom, 0] ]);
- break;
- case 4: /* 0100 */
- right = settings.interpolate(x1, x2, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.top = {
- path: [ [top, 1], [1, right] ],
- move: {
- x: 1,
- y: 0,
- enter: 'left'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, 1], [top, 1], [1, right], [1, 0] ]);
- break;
- case 8: /* 1000 */
- left = settings.interpolate(x0, x3, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.left = {
- path: [ [0, left], [top, 1] ],
- move: {
- x: 0,
- y: 1,
- enter: 'bottom'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, left], [top, 1], [1, 1], [1, 0] ]);
- break;
- case 12: /* 1100 */
- left = settings.interpolate(x0, x3, threshold);
- right = settings.interpolate(x1, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.left = {
- path: [ [0, left], [1, right] ],
- move: {
- x: 1,
- y: 0,
- enter: 'left'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, left], [1, right], [1, 0] ]);
- break;
- case 9: /* 1001 */
- bottom = settings.interpolate(x0, x1, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.bottom = {
- path: [ [bottom, 0], [top, 1] ],
- move: {
- x: 0,
- y: 1,
- enter: 'bottom'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [bottom, 0], [top, 1], [1, 1], [1, 0] ]);
- break;
- case 3: /* 0011 */
- left = settings.interpolate(x0, x3, threshold);
- right = settings.interpolate(x1, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.right = {
- path: [ [1, right], [0, left] ],
- move: {
- x: -1,
- y: 0,
- enter: 'right'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, left], [0, 1], [1, 1], [1, right] ]);
- break;
- case 6: /* 0110 */
- bottom = settings.interpolate(x0, x1, threshold);
- top = settings.interpolate(x3, x2, threshold);
- if (settings.polygons_full) {
- cell.edges.top = {
- path: [ [top, 1], [bottom, 0] ],
- move: {
- x: 0,
- y: -1,
- enter: 'top'
- }
- };
- }
- if (settings.polygons)
- cell.polygons.push([ [0, 0], [0, 1], [top, 1], [bottom, 0] ]);
- break;
- case 10: /* 1010 */
- left = settings.interpolate(x0, x3, threshold);
- right = settings.interpolate(x1, x2, threshold);
- bottom = settings.interpolate(x0, x1, threshold);
- top = settings.interpolate(x3, x2, threshold);
- average = (x0 + x1 + x2 + x3) / 4;
- if (settings.polygons_full) {
- if (average < threshold) {
- cell.edges.left = {
- path: [ [0, left], [top, 1] ],
- move: {
- x: 0,
- y: 1,
- enter: 'bottom'
- }
- };
- cell.edges.right = {
- path: [ [1, right], [bottom, 0] ],
- move: {
- x: 0,
- y: -1,
- enter: 'top'
- }
- };
- } else {
- cell.edges.right = {
- path: [ [1, right], [top, 1] ],
- move: {
- x: 0,
- y: 1,
- enter: 'bottom'
- }
- };
- cell.edges.left = {
- path: [ [0, left], [bottom, 0] ],
- move: {
- x: 0,
- y: -1,
- enter: 'top'
- }
- };
- }
- }
- if (settings.polygons) {
- if (average < threshold) {
- cell.polygons.push([ [0, 0], [0, left], [top, 1], [1, 1], [1, right], [bottom, 0] ]);
- } else {
- cell.polygons.push([ [0, 0], [0, left], [bottom, 0] ]);
- cell.polygons.push([ [top, 1], [1, 1], [1, right] ]);
- }
- }
- break;
- case 5: /* 0101 */
- left = settings.interpolate(x0, x3, threshold);
- right = settings.interpolate(x1, x2, threshold);
- bottom = settings.interpolate(x0, x1, threshold);
- top = settings.interpolate(x3, x2, threshold);
- average = (x0 + x1 + x2 + x3) / 4;
- if (settings.polygons_full) {
- if (average < threshold) {
- cell.edges.bottom = {
- path: [ [bottom, 0], [0, left] ],
- move: {
- x: -1,
- y: 0,
- enter: 'right'
- }
- };
- cell.edges.top = {
- path: [ [top, 1], [1, right] ],
- move: {
- x: 1,
- y: 0,
- enter: 'left'
- }
- };
- } else {
- cell.edges.top = {
- path: [ [top, 1], [0, left] ],
- move: {
- x: -1,
- y: 0,
- enter: 'right'
- }
- };
- cell.edges.bottom = {
- path: [ [bottom, 0], [1, right] ],
- move: {
- x: 1,
- y: 0,
- enter: 'left'
- }
- };
- }
- }
- if (settings.polygons) {
- if (average < threshold) {
- cell.polygons.push([ [0, left], [0, 1], [top, 1], [1, right], [1, 0], [bottom, 0] ]);
- } else {
- cell.polygons.push([ [0, left], [0, 1], [top, 1] ]);
- cell.polygons.push([ [bottom, 0], [1, right], [1, 0] ]);
- }
- }
- break;
- }
- return cell;
- }
- exports.isoLines = isoLines;
- exports.isoContours = isoLines;
- Object.defineProperty(exports, '__esModule', { value: true });
- })));
|