turf-isobands
Advanced tools
Comparing version 1.0.0 to 1.0.1
536
index.js
@@ -14,3 +14,24 @@ //https://github.com/jasondavies/conrec.js | ||
var size = require('turf-size'); | ||
var Conrec = require('./conrec.js'); | ||
/** | ||
* Takes a FeatureCollection of points with z values and an array of | ||
* value breaks and generates filled contour isobands. These are commonly | ||
* used to create elevation maps, but can be used for general data | ||
* interpolation as well. | ||
* | ||
* @module turf/isobands | ||
* @param {GeoJSONFeatureCollection} points | ||
* @param {string} z - a property name from which z values will be pulled | ||
* @param {number} resolution - resolution of the underlying grid | ||
* @return {Array<number>} breaks - where to draw contours | ||
* @example | ||
* var fs = require('fs') | ||
* var z = 'elevation' | ||
* var resolution = 15 | ||
* var breaks = [.1, 22, 45, 55, 65, 85, 95, 105, 120, 180] | ||
* var points = JSON.parse(fs.readFileSync('/path/to/points.geojson')) | ||
* var isobanded = turf.isobands(points, z, resolution, breaks) | ||
* console.log(isobanded) | ||
*/ | ||
module.exports = function(points, z, resolution, breaks){ | ||
@@ -167,516 +188,1 @@ var addEdgesResult = addEdges(points, z, resolution); | ||
} | ||
/** | ||
* Copyright (c) 2010, Jason Davies. | ||
* | ||
* All rights reserved. This code is based on Bradley White's Java version, | ||
* which is in turn based on Nicholas Yue's C++ version, which in turn is based | ||
* on Paul D. Bourke's original Fortran version. See below for the respective | ||
* copyright notices. | ||
* | ||
* See http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/ for the original | ||
* paper by Paul D. Bourke. | ||
* | ||
* The vector conversion code is based on http://apptree.net/conrec.htm by | ||
* Graham Cox. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* * Neither the name of the <organization> nor the | ||
* names of its contributors may be used to endorse or promote products | ||
* derived from this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
/* | ||
* Copyright (c) 1996-1997 Nicholas Yue | ||
* | ||
* This software is copyrighted by Nicholas Yue. This code is based on Paul D. | ||
* Bourke's CONREC.F routine. | ||
* | ||
* The authors hereby grant permission to use, copy, and distribute this | ||
* software and its documentation for any purpose, provided that existing | ||
* copyright notices are retained in all copies and that this notice is | ||
* included verbatim in any distributions. Additionally, the authors grant | ||
* permission to modify this software and its documentation for any purpose, | ||
* provided that such modifications are not distributed without the explicit | ||
* consent of the authors and that existing copyright notices are retained in | ||
* all copies. Some of the algorithms implemented by this software are | ||
* patented, observe all applicable patent law. | ||
* | ||
* IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR | ||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT | ||
* OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, | ||
* EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, | ||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS | ||
* PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO | ||
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR | ||
* MODIFICATIONS. | ||
*/ | ||
exports.Conrec = Conrec; | ||
var EPSILON = 1e-10; | ||
function pointsEqual(a, b) { | ||
var x = a.x - b.x, y = a.y - b.y; | ||
return x * x + y * y < EPSILON; | ||
} | ||
function reverseList(list) { | ||
var pp = list.head; | ||
while (pp) { | ||
// swap prev/next pointers | ||
var temp = pp.next; | ||
pp.next = pp.prev; | ||
pp.prev = temp; | ||
// continue through the list | ||
pp = temp; | ||
} | ||
// swap head/tail pointers | ||
var temp = list.head; | ||
list.head = list.tail; | ||
list.tail = temp; | ||
} | ||
function ContourBuilder(level) { | ||
this.level = level; | ||
this.s = null; | ||
this.count = 0; | ||
} | ||
ContourBuilder.prototype.remove_seq = function(list) { | ||
// if list is the first item, static ptr s is updated | ||
if (list.prev) { | ||
list.prev.next = list.next; | ||
} else { | ||
this.s = list.next; | ||
} | ||
if (list.next) { | ||
list.next.prev = list.prev; | ||
} | ||
--this.count; | ||
} | ||
ContourBuilder.prototype.addSegment = function(a, b) { | ||
var ss = this.s; | ||
var ma = null; | ||
var mb = null; | ||
var prependA = false; | ||
var prependB = false; | ||
while (ss) { | ||
if (ma == null) { | ||
// no match for a yet | ||
if (pointsEqual(a, ss.head.p)) { | ||
ma = ss; | ||
prependA = true; | ||
} else if (pointsEqual(a, ss.tail.p)) { | ||
ma = ss; | ||
} | ||
} | ||
if (mb == null) { | ||
// no match for b yet | ||
if (pointsEqual(b, ss.head.p)) { | ||
mb = ss; | ||
prependB = true; | ||
} else if (pointsEqual(b, ss.tail.p)) { | ||
mb = ss; | ||
} | ||
} | ||
// if we matched both no need to continue searching | ||
if (mb != null && ma != null) { | ||
break; | ||
} else { | ||
ss = ss.next; | ||
} | ||
} | ||
// c is the case selector based on which of ma and/or mb are set | ||
var c = ((ma != null) ? 1 : 0) | ((mb != null) ? 2 : 0); | ||
switch(c) { | ||
case 0: // both unmatched, add as new sequence | ||
var aa = {p: a, prev: null}; | ||
var bb = {p: b, next: null}; | ||
aa.next = bb; | ||
bb.prev = aa; | ||
// create sequence element and push onto head of main list. The order | ||
// of items in this list is unimportant | ||
ma = {head: aa, tail: bb, next: this.s, prev: null, closed: false}; | ||
if (this.s) { | ||
this.s.prev = ma; | ||
} | ||
this.s = ma; | ||
++this.count; // not essential - tracks number of unmerged sequences | ||
break; | ||
case 1: // a matched, b did not - thus b extends sequence ma | ||
var pp = {p: b}; | ||
if (prependA) { | ||
pp.next = ma.head; | ||
pp.prev = null; | ||
ma.head.prev = pp; | ||
ma.head = pp; | ||
} else { | ||
pp.next = null; | ||
pp.prev = ma.tail; | ||
ma.tail.next = pp; | ||
ma.tail = pp; | ||
} | ||
break; | ||
case 2: // b matched, a did not - thus a extends sequence mb | ||
var pp = {p: a}; | ||
if (prependB) { | ||
pp.next = mb.head; | ||
pp.prev = null; | ||
mb.head.prev = pp; | ||
mb.head = pp; | ||
} else { | ||
pp.next = null; | ||
pp.prev = mb.tail; | ||
mb.tail.next = pp; | ||
mb.tail = pp; | ||
} | ||
break; | ||
case 3: // both matched, can merge sequences | ||
// if the sequences are the same, do nothing, as we are simply closing this path (could set a flag) | ||
if (ma === mb) { | ||
var pp = {p: ma.tail.p, next: ma.head, prev: null}; | ||
ma.head.prev = pp; | ||
ma.head = pp; | ||
ma.closed = true; | ||
break; | ||
} | ||
// there are 4 ways the sequence pair can be joined. The current setting of prependA and | ||
// prependB will tell us which type of join is needed. For head/head and tail/tail joins | ||
// one sequence needs to be reversed | ||
switch((prependA ? 1 : 0) | (prependB ? 2 : 0)) { | ||
case 0: // tail-tail | ||
// reverse ma and append to mb | ||
reverseList(ma); | ||
// fall through to head/tail case | ||
case 1: // head-tail | ||
// ma is appended to mb and ma discarded | ||
mb.tail.next = ma.head; | ||
ma.head.prev = mb.tail; | ||
mb.tail = ma.tail; | ||
//discard ma sequence record | ||
this.remove_seq(ma); | ||
break; | ||
case 3: // head-head | ||
// reverse ma and append mb to it | ||
reverseList(ma); | ||
// fall through to tail/head case | ||
case 2: // tail-head | ||
// mb is appended to ma and mb is discarded | ||
ma.tail.next = mb.head; | ||
mb.head.prev = ma.tail; | ||
ma.tail = mb.tail; | ||
//discard mb sequence record | ||
this.remove_seq(mb); | ||
break; | ||
} | ||
} | ||
} | ||
/** | ||
* Implements CONREC. | ||
* | ||
* @param {function} drawContour function for drawing contour. Defaults to a | ||
* custom "contour builder", which populates the | ||
* contours property. | ||
*/ | ||
function Conrec(drawContour) { | ||
if (!drawContour) { | ||
var c = this; | ||
c.contours = {}; | ||
/** | ||
* drawContour - interface for implementing the user supplied method to | ||
* render the countours. | ||
* | ||
* Draws a line between the start and end coordinates. | ||
* | ||
* @param startX - start coordinate for X | ||
* @param startY - start coordinate for Y | ||
* @param endX - end coordinate for X | ||
* @param endY - end coordinate for Y | ||
* @param contourLevel - Contour level for line. | ||
*/ | ||
this.drawContour = function(startX, startY, endX, endY, contourLevel, k) { | ||
var cb = c.contours[k]; | ||
if (!cb) { | ||
cb = c.contours[k] = new ContourBuilder(contourLevel); | ||
} | ||
cb.addSegment({x: startX, y: startY}, {x: endX, y: endY}); | ||
} | ||
this.contourList = function() { | ||
var l = []; | ||
var a = c.contours; | ||
for (var k in a) { | ||
var s = a[k].s; | ||
var level = a[k].level; | ||
while (s) { | ||
var h = s.head; | ||
var l2 = []; | ||
l2.level = level; | ||
l2.k = k; | ||
while (h && h.p) { | ||
l2.push(h.p); | ||
h = h.next; | ||
} | ||
l.push(l2); | ||
s = s.next; | ||
} | ||
} | ||
l.sort(function(a, b) { return a.k - b.k }); | ||
return l; | ||
} | ||
} else { | ||
this.drawContour = drawContour; | ||
} | ||
this.h = new Array(5); | ||
this.sh = new Array(5); | ||
this.xh = new Array(5); | ||
this.yh = new Array(5); | ||
} | ||
/** | ||
* contour is a contouring subroutine for rectangularily spaced data | ||
* | ||
* It emits calls to a line drawing subroutine supplied by the user which | ||
* draws a contour map corresponding to real*4data on a randomly spaced | ||
* rectangular grid. The coordinates emitted are in the same units given in | ||
* the x() and y() arrays. | ||
* | ||
* Any number of contour levels may be specified but they must be in order of | ||
* increasing value. | ||
* | ||
* | ||
* @param {number[][]} d - matrix of data to contour | ||
* @param {number} ilb,iub,jlb,jub - index bounds of data matrix | ||
* | ||
* The following two, one dimensional arrays (x and y) contain | ||
* the horizontal and vertical coordinates of each sample points. | ||
* @param {number[]} x - data matrix column coordinates | ||
* @param {number[]} y - data matrix row coordinates | ||
* @param {number} nc - number of contour levels | ||
* @param {number[]} z - contour levels in increasing order. | ||
*/ | ||
Conrec.prototype.contour = function(d, ilb, iub, jlb, jub, x, y, nc, z) { | ||
var h = this.h, sh = this.sh, xh = this.xh, yh = this.yh; | ||
var drawContour = this.drawContour; | ||
this.contours = {}; | ||
/** private */ | ||
var xsect = function(p1, p2){ | ||
return (h[p2]*xh[p1]-h[p1]*xh[p2])/(h[p2]-h[p1]); | ||
} | ||
var ysect = function(p1, p2){ | ||
return (h[p2]*yh[p1]-h[p1]*yh[p2])/(h[p2]-h[p1]); | ||
} | ||
var m1; | ||
var m2; | ||
var m3; | ||
var case_value; | ||
var dmin; | ||
var dmax; | ||
var x1 = 0.0; | ||
var x2 = 0.0; | ||
var y1 = 0.0; | ||
var y2 = 0.0; | ||
// The indexing of im and jm should be noted as it has to start from zero | ||
// unlike the fortran counter part | ||
var im = [0, 1, 1, 0]; | ||
var jm = [0, 0, 1, 1]; | ||
// Note that castab is arranged differently from the FORTRAN code because | ||
// Fortran and C/C++ arrays are transposed of each other, in this case | ||
// it is more tricky as castab is in 3 dimensions | ||
var castab = [ | ||
[ | ||
[0, 0, 8], [0, 2, 5], [7, 6, 9] | ||
], | ||
[ | ||
[0, 3, 4], [1, 3, 1], [4, 3, 0] | ||
], | ||
[ | ||
[9, 6, 7], [5, 2, 0], [8, 0, 0] | ||
] | ||
]; | ||
for (var j=(jub-1);j>=jlb;j--) { | ||
for (var i=ilb;i<=iub-1;i++) { | ||
var temp1, temp2; | ||
temp1 = Math.min(d[i][j],d[i][j+1]); | ||
temp2 = Math.min(d[i+1][j],d[i+1][j+1]); | ||
dmin = Math.min(temp1,temp2); | ||
temp1 = Math.max(d[i][j],d[i][j+1]); | ||
temp2 = Math.max(d[i+1][j],d[i+1][j+1]); | ||
dmax = Math.max(temp1,temp2); | ||
if (dmax>=z[0]&&dmin<=z[nc-1]) { | ||
for (var k=0;k<nc;k++) { | ||
if (z[k]>=dmin&&z[k]<=dmax) { | ||
for (var m=4;m>=0;m--) { | ||
if (m>0) { | ||
// The indexing of im and jm should be noted as it has to | ||
// start from zero | ||
h[m] = d[i+im[m-1]][j+jm[m-1]]-z[k]; | ||
xh[m] = x[i+im[m-1]]; | ||
yh[m] = y[j+jm[m-1]]; | ||
} else { | ||
h[0] = 0.25*(h[1]+h[2]+h[3]+h[4]); | ||
xh[0]=0.5*(x[i]+x[i+1]); | ||
yh[0]=0.5*(y[j]+y[j+1]); | ||
} | ||
if (h[m]>EPSILON) { | ||
sh[m] = 1; | ||
} else if (h[m]<-EPSILON) { | ||
sh[m] = -1; | ||
} else | ||
sh[m] = 0; | ||
} | ||
// | ||
// Note: at this stage the relative heights of the corners and the | ||
// centre are in the h array, and the corresponding coordinates are | ||
// in the xh and yh arrays. The centre of the box is indexed by 0 | ||
// and the 4 corners by 1 to 4 as shown below. | ||
// Each triangle is then indexed by the parameter m, and the 3 | ||
// vertices of each triangle are indexed by parameters m1,m2,and | ||
// m3. | ||
// It is assumed that the centre of the box is always vertex 2 | ||
// though this isimportant only when all 3 vertices lie exactly on | ||
// the same contour level, in which case only the side of the box | ||
// is drawn. | ||
// | ||
// | ||
// vertex 4 +-------------------+ vertex 3 | ||
// | \ / | | ||
// | \ m-3 / | | ||
// | \ / | | ||
// | \ / | | ||
// | m=2 X m=2 | the centre is vertex 0 | ||
// | / \ | | ||
// | / \ | | ||
// | / m=1 \ | | ||
// | / \ | | ||
// vertex 1 +-------------------+ vertex 2 | ||
// | ||
// | ||
// | ||
// Scan each triangle in the box | ||
// | ||
for (m=1;m<=4;m++) { | ||
m1 = m; | ||
m2 = 0; | ||
if (m!=4) { | ||
m3 = m+1; | ||
} else { | ||
m3 = 1; | ||
} | ||
case_value = castab[sh[m1]+1][sh[m2]+1][sh[m3]+1]; | ||
if (case_value!=0) { | ||
switch (case_value) { | ||
case 1: // Line between vertices 1 and 2 | ||
x1=xh[m1]; | ||
y1=yh[m1]; | ||
x2=xh[m2]; | ||
y2=yh[m2]; | ||
break; | ||
case 2: // Line between vertices 2 and 3 | ||
x1=xh[m2]; | ||
y1=yh[m2]; | ||
x2=xh[m3]; | ||
y2=yh[m3]; | ||
break; | ||
case 3: // Line between vertices 3 and 1 | ||
x1=xh[m3]; | ||
y1=yh[m3]; | ||
x2=xh[m1]; | ||
y2=yh[m1]; | ||
break; | ||
case 4: // Line between vertex 1 and side 2-3 | ||
x1=xh[m1]; | ||
y1=yh[m1]; | ||
x2=xsect(m2,m3); | ||
y2=ysect(m2,m3); | ||
break; | ||
case 5: // Line between vertex 2 and side 3-1 | ||
x1=xh[m2]; | ||
y1=yh[m2]; | ||
x2=xsect(m3,m1); | ||
y2=ysect(m3,m1); | ||
break; | ||
case 6: // Line between vertex 3 and side 1-2 | ||
x1=xh[m3]; | ||
y1=yh[m3]; | ||
x2=xsect(m1,m2); | ||
y2=ysect(m1,m2); | ||
break; | ||
case 7: // Line between sides 1-2 and 2-3 | ||
x1=xsect(m1,m2); | ||
y1=ysect(m1,m2); | ||
x2=xsect(m2,m3); | ||
y2=ysect(m2,m3); | ||
break; | ||
case 8: // Line between sides 2-3 and 3-1 | ||
x1=xsect(m2,m3); | ||
y1=ysect(m2,m3); | ||
x2=xsect(m3,m1); | ||
y2=ysect(m3,m1); | ||
break; | ||
case 9: // Line between sides 3-1 and 1-2 | ||
x1=xsect(m3,m1); | ||
y1=ysect(m3,m1); | ||
x2=xsect(m1,m2); | ||
y2=ysect(m1,m2); | ||
break; | ||
default: | ||
break; | ||
} | ||
// Put your processing code here and comment out the printf | ||
//printf("%f %f %f %f %f\n",x1,y1,x2,y2,z[k]); | ||
drawContour(x1,y1,x2,y2,z[k],k); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
{ | ||
"name": "turf-isobands", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "turf isobands module", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
48217
11
667
2