Skip to content

Commit 2f71f1b

Browse files
committedOct 7, 2021
COG Support
1 parent 5b32e41 commit 2f71f1b

40 files changed

+1345
-1791
lines changed
 

‎.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,5 @@ data/veneto/*.tif
9898
dist/
9999

100100
# DS_Store
101-
DS_Store
101+
.DS_Store
102+
*/*/.DS_Store

‎README.md

+1-7
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,10 @@ To run tests:
102102
npm run setup
103103
```
104104

105-
2. Spin up the test node server
106-
```
107-
npm run server
108-
```
109-
110-
3. In a separate tab, run tests
105+
2. Run tests. Each test file will automatically spin up a server using [srvd](https://github.com/danieljdufour/srvd).
111106
```
112107
npm run test
113108
```
114109

115110
# Used By
116111
<a href="https://geotiff.io"><img src="https://github.com/GeoTIFF/geotiff.io/raw/master/assets/favicon.png" height="75px"></a>
117-
<a href="https://www.usda.gov/"><img src="https://www.usda.gov/themes/usda/img/usda-symbol.svg" height="75px"></a>

‎package-lock.json

+555-1,057
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+13-4
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
"dev": "webpack --mode development --target node --watch",
1818
"documentation": "./node_modules/.bin/documentation build src/** --config documentation.yml -f html -o docs && echo 'geoblaze.io' > docs/CNAME",
1919
"fix": "eslint src --fix",
20+
"format": "npx prettier --arrow-parens=avoid --print-width=160 --trailing-comma=none --require-pragma --write src/*.js src/*/*.js",
2021
"lint": "eslint src",
21-
"serve": "npx srvd --debug --port=3000 --wait=10 &",
22-
"test": "npm run serve && sleep 1 && for f in src/*/*test*.js; do node -r esm $f; done",
22+
"serve": "npx srvd --debug --port=3000 --wait=120",
23+
"test": "for f in src/*/*test*.js; do echo \"\nrunning $f\" && node -r esm $f; done",
2324
"test-loading-builds": "npm run serve && sleep 2 && node test-loading-builds.js",
2425
"setup": "bash setup.sh"
2526
},
@@ -48,19 +49,26 @@
4849
"homepage": "https://github.com/GeoTIFF/geoblaze#readme",
4950
"dependencies": {
5051
"@turf/combine": "^4.7.3",
52+
"calc-stats": "^0.0.4",
5153
"cross-fetch": "^3.1.4",
52-
"georaster": "^1.0.3",
54+
"fast-max": "^0.3.0",
55+
"fast-min": "^0.2.0",
56+
"faster-median": "^0.2.1",
57+
"georaster": "^1.5.4",
5358
"get-depth": "^0.0.0",
5459
"mathjs": "^6.6.1",
5560
"proj4": "^2.6.0",
61+
"proj4-fully-loaded": "^0.0.4",
5662
"terraformer-arcgis-parser": "^1.0.5",
57-
"underscore": "^1.8.3"
63+
"underscore": "^1.8.3",
64+
"xdim": "^1.2.1"
5865
},
5966
"devDependencies": {
6067
"@babel/core": "^7.9.0",
6168
"@babel/plugin-transform-runtime": "^7.9.0",
6269
"@babel/preset-env": "^7.9.0",
6370
"@babel/register": "^7.9.0",
71+
"@turf/bbox": "^6.5.0",
6472
"@turf/bbox-polygon": "^6.0.1",
6573
"@turf/helpers": "^6.1.4",
6674
"babel-eslint": "^8.2.3",
@@ -85,6 +93,7 @@
8593
"path": "^0.12.7",
8694
"puppeteer": "^1.11.0",
8795
"shapefile": "^0.6.6",
96+
"srvd": "^0.2.1",
8897
"webpack": "^4.42.1",
8998
"webpack-cli": "^3.3.11",
9099
"webpack-dev-server": "^3.10.3",

‎src/band-arithmetic/band-arithmetic.module.js

+49-53
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import _ from 'underscore';
22
import parseGeoraster from 'georaster';
33
import { parse } from 'mathjs';
44

5+
import get from '../get';
6+
import wrap from '../wrap-func';
57
import utils from '../utils';
6-
const { listVariables } = utils;
78

89
const regexMultiCharacter = /[A-z]{2}/g;
910

@@ -18,7 +19,7 @@ const containsNoDataValue = (bandValues, noDataValue) => {
1819
const isLeafNode = node => !node.op;
1920

2021
const parseAST = (ast, numBands) => {
21-
return new Function(...listVariables(numBands), `return ${parseNode(ast)}`);
22+
return new Function(...utils.listVariables(numBands), `return ${parseNode(ast)}`);
2223
};
2324

2425
const parseNode = node => {
@@ -74,60 +75,55 @@ const arithmeticError = arithmetic => {
7475
}
7576
};
7677

77-
const bandArithmetic = (georaster, arithmetic) => {
78-
return new Promise((resolve, reject) => {
79-
if (georaster.values.length < 2) {
80-
return reject(new Error('Band arithmetic is not available for this raster. Please make sure you are using a multi-band raster.'));
81-
}
78+
const bandArithmetic = async (georaster, arithmetic) => {
79+
const { noDataValue } = georaster;
80+
81+
const bands = await get(georaster, undefined, false);
82+
83+
if (bands.length < 2) {
84+
return reject(new Error('Band arithmetic is not available for this raster. Please make sure you are using a multi-band raster.'));
85+
}
8286

83-
const parseError = arithmeticError(arithmetic);
84-
if (parseError) return reject(new Error(parseError));
85-
86-
try {
87-
const bands = georaster.values;
88-
const noDataValue = georaster.noDataValue;
89-
const values = [];
90-
const numRows = bands[0].length;
91-
92-
const ast = parse(arithmetic.toLowerCase());
93-
const arithmeticFunction = parseAST(ast, bands.length);
94-
95-
for (let i = 0; i < numRows; i++) {
96-
const bandRows = getBandRows(bands, i);
97-
const row = [];
98-
const numValues = bandRows[0].length;
99-
100-
for (let j = 0; j < numValues; j++) {
101-
const bandValues = getBandValues(bandRows, j);
102-
if (containsNoDataValue(bandValues, noDataValue)) {
103-
row.push(noDataValue);
104-
} else {
105-
const value = arithmeticFunction(...bandValues);
106-
if (value === Infinity || value === -Infinity || isNaN(value)) {
107-
row.push(noDataValue);
108-
} else {
109-
row.push(value);
110-
}
111-
}
87+
const parseError = arithmeticError(arithmetic);
88+
if (parseError) throw new Error(parseError);
89+
90+
const values = [];
91+
const numRows = bands[0].length;
92+
93+
const ast = parse(arithmetic.toLowerCase());
94+
const arithmeticFunction = parseAST(ast, bands.length);
95+
96+
for (let i = 0; i < numRows; i++) {
97+
const bandRows = getBandRows(bands, i);
98+
const row = [];
99+
const numValues = bandRows[0].length;
100+
101+
for (let j = 0; j < numValues; j++) {
102+
const bandValues = getBandValues(bandRows, j);
103+
if (containsNoDataValue(bandValues, noDataValue)) {
104+
row.push(noDataValue);
105+
} else {
106+
const value = arithmeticFunction(...bandValues);
107+
if (value === Infinity || value === -Infinity || isNaN(value)) {
108+
row.push(noDataValue);
109+
} else {
110+
row.push(value);
112111
}
113-
values.push(row);
114112
}
115-
116-
const metadata = _.pick(georaster, ...[
117-
'noDataValue',
118-
'projection',
119-
'xmin',
120-
'ymax',
121-
'pixelWidth',
122-
'pixelHeight'
123-
]);
124-
return parseGeoraster([values], metadata).then(georaster => resolve(georaster));
125-
126-
} catch(e) {
127-
console.error(e);
128-
return reject(e);
129113
}
130-
});
114+
values.push(row);
115+
}
116+
117+
const metadata = _.pick(georaster, ...[
118+
'noDataValue',
119+
'projection',
120+
'xmin',
121+
'ymax',
122+
'pixelWidth',
123+
'pixelHeight'
124+
]);
125+
const newGeoRaster = await parseGeoraster([values], metadata);
126+
return newGeoRaster;
131127
};
132128

133-
export default bandArithmetic;
129+
export default wrap(bandArithmetic);

‎src/band-arithmetic/band-arithmetic.test.js

+109-23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import test from "flug";
2+
import { serve } from "srvd";
3+
import get from '../get';
24
import load from '../load';
5+
import parse from '../parse';
36
import bandArithmetic from './band-arithmetic.module';
47

8+
// url is cached so only need 1 request
9+
serve({ debug: true, max: 1, port: 3000 });
10+
511
const url = 'http://localhost:3000/data/rgb/wildfires.tiff';
612

713
const calculation1 = 'a + b';
@@ -43,73 +49,153 @@ function expectNoNaNValues ({ georaster, eq }) {
4349
});
4450
});
4551
}
46-
// left the time measuring code commented out in the tests to make
47-
// it easier to return and further optimize the code
4852

49-
test('Band Arithmetic: Run Calculation 1', async function ({ eq }) {
53+
54+
test('(Legacy) Band Arithmetic: Run Calculation 1', async function ({ eq }) {
5055
const georaster = await load(url);
5156
const computedGeoraster = await bandArithmetic(georaster, calculation1);
5257
const value = computedGeoraster.values[0][0][0];
53-
const a = georaster.values[0][0][0];
54-
const b = georaster.values[1][0][0];
58+
const originalValues = await get(georaster);
59+
const a = originalValues[0][0][0];
60+
const b = originalValues[1][0][0];
5561
eq(value, getExpectedValue1(a, b));
5662
expectNoInfinityValues({ georaster: computedGeoraster, eq });
5763
});
5864

59-
test('Band Arithmetic: Run Calculation 2', async ({ eq }) => {
65+
test('(Legacy) Band Arithmetic: Run Calculation 2', async ({ eq }) => {
6066
const georaster = await load(url);
6167
const computedGeoraster = await bandArithmetic(georaster, calculation2);
6268
const value = computedGeoraster.values[0][0][0];
63-
const a = georaster.values[0][0][0];
64-
const b = georaster.values[1][0][0];
69+
const originalValues = await get(georaster);
70+
const a = originalValues[0][0][0];
71+
const b = originalValues[1][0][0];
6572
eq(value, getExpectedValue2(a, b));
6673
expectNoInfinityValues({ georaster: computedGeoraster, eq });
6774
});
6875

69-
test('Band Arithmetic: Run Calculation 3', async ({ eq }) => {
76+
test('(Legacy) Band Arithmetic: Run Calculation 3', async ({ eq }) => {
7077
const georaster = await load(url);
7178
const computedGeoraster = await bandArithmetic(georaster, calculation3);
7279
const value = computedGeoraster.values[0][0][0];
73-
const a = georaster.values[0][0][0];
74-
const c = georaster.values[2][0][0];
80+
const originalValues = await get(georaster);
81+
const a = originalValues[0][0][0];
82+
const c = originalValues[2][0][0];
7583
eq(value, getExpectedValue3(a, c));
7684
expectNoInfinityValues({ georaster: computedGeoraster, eq });
7785
});
7886

79-
test('Band Arithmetic: Run Calculation 3', async ({ eq }) => {
87+
test('(Legacy) Band Arithmetic: Run Calculation 4', async ({ eq }) => {
8088
const georaster = await load(url);
8189
const computedGeoraster = await bandArithmetic(georaster, calculation4);
8290
const value = computedGeoraster.values[0][0][0];
83-
const a = georaster.values[0][0][0];
84-
const b = georaster.values[1][0][0];
91+
const originalValues = await get(georaster);
92+
const a = originalValues[0][0][0];
93+
const b = originalValues[1][0][0];
8594
eq(value, getExpectedValue4(a, b));
8695
expectNoInfinityValues({ georaster: computedGeoraster, eq });
8796
});
8897

89-
test('Band Arithmetic: Run Calculation 3', async ({ eq }) => {
98+
test('(Legacy) Band Arithmetic: Run Calculation 5', async ({ eq }) => {
9099
const georaster = await load(url);
91100
const computedGeoraster = await bandArithmetic(georaster, calculation5);
92101
const value = computedGeoraster.values[0][0][0];
93-
const a = georaster.values[0][0][0];
94-
const b = georaster.values[1][0][0];
95-
const c = georaster.values[2][0][0];
102+
const originalValues = await get(georaster);
103+
const a = originalValues[0][0][0];
104+
const b = originalValues[1][0][0];
105+
const c = originalValues[2][0][0];
96106
eq(value, getExpectedValue5(a, b, c));
97107
expectNoInfinityValues({ georaster: computedGeoraster, eq });
98108
});
99109

100-
test('Band Arithmetic: Run Calculation 6', async ({ eq }) => {
110+
test('(Legacy) Band Arithmetic: Run Calculation 6', async ({ eq }) => {
101111
const georaster = await load(url);
102112
const computedGeoraster = await bandArithmetic(georaster, calculation6);
103113
const value = computedGeoraster.values[0][0][0];
104-
const a = georaster.values[0][0][0];
105-
const b = georaster.values[1][0][0];
106-
const c = georaster.values[2][0][0];
114+
const originalValues = await get(georaster);
115+
const a = originalValues[0][0][0];
116+
const b = originalValues[1][0][0];
117+
const c = originalValues[2][0][0];
107118
eq(value, getExpectedValue6(a, b, c));
108119
expectNoInfinityValues({ georaster: computedGeoraster, eq });
109120
});
110121

111-
test('Band Arithmetic: Run Calculation 7', async ({ eq }) => {
122+
test('(Legacy) Band Arithmetic: Run Calculation 7', async ({ eq }) => {
112123
const georaster = await load(url);
113124
const computedGeoraster = await bandArithmetic(georaster, calculation7);
114125
expectNoNaNValues({ georaster: computedGeoraster, eq });
115126
});
127+
128+
129+
// MODERN
130+
test('(Modern) Band Arithmetic: Run Calculation 1', async function ({ eq }) {
131+
const georaster = await parse(url);
132+
const computedGeoraster = await bandArithmetic(url, calculation1);
133+
const value = computedGeoraster.values[0][0][0];
134+
const originalValues = await get(georaster);
135+
const a = originalValues[0][0][0];
136+
const b = originalValues[1][0][0];
137+
eq(value, getExpectedValue1(a, b));
138+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
139+
});
140+
141+
test('(Modern) Band Arithmetic: Run Calculation 2', async ({ eq }) => {
142+
const georaster = await parse(url);
143+
const computedGeoraster = await bandArithmetic(url, calculation2);
144+
const value = computedGeoraster.values[0][0][0];
145+
const originalValues = await get(georaster);
146+
const a = originalValues[0][0][0];
147+
const b = originalValues[1][0][0];
148+
eq(value, getExpectedValue2(a, b));
149+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
150+
});
151+
152+
test('(Modern) Band Arithmetic: Run Calculation 3', async ({ eq }) => {
153+
const georaster = await parse(url);
154+
const computedGeoraster = await bandArithmetic(url, calculation3);
155+
const value = computedGeoraster.values[0][0][0];
156+
const originalValues = await get(georaster);
157+
const a = originalValues[0][0][0];
158+
const c = originalValues[2][0][0];
159+
eq(value, getExpectedValue3(a, c));
160+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
161+
});
162+
163+
test('(Modern) Band Arithmetic: Run Calculation 4', async ({ eq }) => {
164+
const georaster = await parse(url);
165+
const computedGeoraster = await bandArithmetic(url, calculation4);
166+
const value = computedGeoraster.values[0][0][0];
167+
const originalValues = await get(georaster);
168+
const a = originalValues[0][0][0];
169+
const b = originalValues[1][0][0];
170+
eq(value, getExpectedValue4(a, b));
171+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
172+
});
173+
174+
test('(Modern) Band Arithmetic: Run Calculation 5', async ({ eq }) => {
175+
const georaster = await parse(url);
176+
const computedGeoraster = await bandArithmetic(url, calculation5);
177+
const value = computedGeoraster.values[0][0][0];
178+
const originalValues = await get(georaster);
179+
const a = originalValues[0][0][0];
180+
const b = originalValues[1][0][0];
181+
const c = originalValues[2][0][0];
182+
eq(value, getExpectedValue5(a, b, c));
183+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
184+
});
185+
186+
test('(Modern) Band Arithmetic: Run Calculation 6', async ({ eq }) => {
187+
const georaster = await parse(url);
188+
const computedGeoraster = await bandArithmetic(url, calculation6);
189+
const value = computedGeoraster.values[0][0][0];
190+
const originalValues = await get(georaster);
191+
const a = originalValues[0][0][0];
192+
const b = originalValues[1][0][0];
193+
const c = originalValues[2][0][0];
194+
eq(value, getExpectedValue6(a, b, c));
195+
expectNoInfinityValues({ georaster: computedGeoraster, eq });
196+
});
197+
198+
test('(Modern) Band Arithmetic: Run Calculation 7', async ({ eq }) => {
199+
const computedGeoraster = await bandArithmetic(url, calculation7);
200+
expectNoNaNValues({ georaster: computedGeoraster, eq });
201+
});

0 commit comments

Comments
 (0)
Please sign in to comment.