// raster-streamlines Version 0.0.1. Copyright 2016 Roger Veciana i Rovira. (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.rs = global.rs || {}))); }(this, (function (exports) { 'use strict'; var streamlines = function(uData, vData, geotransform, flip){ var output = { "type": "FeatureCollection", "features": [] }; var num_lines = 0; var inst = new Streamlines(uData, vData); if(!geotransform){ geotransform = [0,1,0,0,0,1]; } else if(geotransform.length !== 6){ throw new Error('Bad geotransform'); } //Iterate different points to start lines while available pixels var pixel = true; var line = true; var pos = 0; var x, y; while(pixel){ if(pos%4 === 0){ x = 0; y = 0; } else if(pos%4 === 1){ x = uData[0].length - 1; y = uData.length - 1; } else if(pos%4 === 2){ x = uData[0].length - 1; y = 0; } else{ x = 0; y = uData.length - 1; } pixel = inst.findEmptyPixel(x,y,1); line = inst.getLine(pixel.x, pixel.y, flip); if(line){ output.features.push({"type": "Feature", "geometry": { "type": "LineString", "coordinates": inst.applyGeoTransform(line, geotransform)}, "properties": {"num_line": num_lines} }); num_lines++; } pos++; } return output; }; function Streamlines(uData, vData){ if(uData.length <= 1 || vData.length <= 1 || uData[0].length <= 1 || vData[0].length <= 1){ throw new Error('Raster is too small'); } this.uData = uData; this.vData = vData; this.usedPixels = []; for(var i = 0; i=this.usedPixels[0].length || y0<0 || y0 >= this.usedPixels.length){ return false; } for(var i=-dist; i<=dist;i++){ for(var j=-dist; j<=dist;j++){ if(y0+j>=0 &&y0+j=0 && x0+i= 0 && x < this.uData[0].length && y >= 0 && y < this.uData.length){ values = this.getValueAtPoint(x, y); x = x + values.u; y = y + flip * values.v; //The wind convention says v goes from bottom to top if(values.u === 0 && values.v === 0){this.usedPixels[y0][x0] = true; break;} //Zero speed points are problematic if(x < 0 || y < 0 || x>= this.uData[0].length|| y >= this.uData.length || this.usedPixels[Math.floor(y)][Math.floor(x)]){break;} outLine.push([x,y]); lineFound = true; this.usedPixels[Math.floor(y)][Math.floor(x)] = true; } //repeat the operation but backwards, so strange effects in some cases are avoided. x = x0; y = y0; while(x >= 0 && x < this.uData[0].length && y >= 0 && y < this.uData.length){ values = this.getValueAtPoint(x, y); x = x - values.u; y = y - flip * values.v; //The wind convention says v goes from bottom to top if(values.u === 0 && values.v === 0){this.usedPixels[y0][x0] = true; break;} //Zero speed points are problematic if(x < 0 || y < 0 || x>= this.uData[0].length || y >= this.uData.length || this.usedPixels[Math.floor(y)][Math.floor(x)]){break;} outLine.unshift([x,y]); lineFound = true; this.usedPixels[Math.floor(y)][Math.floor(x)] = true; } if(lineFound){ this.usedPixels[y0][x0] = true; return outLine; } else { return false; } }; Streamlines.prototype.applyGeoTransform = function(line, geotransform) { var outLine = []; for(var i = 0; i