mapshaper 0.7.14 → 0.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mapshaper.js +979 -81
- package/package.json +2 -1
- package/www/geotiff.js +4 -0
- package/www/index.html +4 -33
- package/www/mapshaper-gui.js +7295 -530
- package/www/mapshaper.js +979 -81
- package/www/page.css +0 -2
package/www/mapshaper.js
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
return obj === Object(obj); // via underscore
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function clamp(val, min, max) {
|
|
81
|
+
function clamp$1(val, min, max) {
|
|
82
82
|
return val < min ? min : (val > max ? max : val);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -751,7 +751,7 @@
|
|
|
751
751
|
function findValueByRank(arr, rank) {
|
|
752
752
|
if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
|
|
753
753
|
|
|
754
|
-
rank = clamp(rank | 0, 1, arr.length);
|
|
754
|
+
rank = clamp$1(rank | 0, 1, arr.length);
|
|
755
755
|
var k = rank - 1, // conv. rank to array index
|
|
756
756
|
n = arr.length,
|
|
757
757
|
l = 0,
|
|
@@ -1125,7 +1125,7 @@
|
|
|
1125
1125
|
// self-import and the resulting Rollup circular-dependency warning.
|
|
1126
1126
|
var utils = {
|
|
1127
1127
|
addThousandsSep, addslashes, arrayToIndex,
|
|
1128
|
-
clamp, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
1128
|
+
clamp: clamp$1, cleanNumericString, contains, copyElements, countValues, createBuffer,
|
|
1129
1129
|
defaults, difference,
|
|
1130
1130
|
endsWith, every, expandoBuffer, extend: extend$1, extendBuffer,
|
|
1131
1131
|
find: find$1, findMedian, findQuantile, findRankByValue, findStringPrefix,
|
|
@@ -1298,7 +1298,7 @@
|
|
|
1298
1298
|
}
|
|
1299
1299
|
}
|
|
1300
1300
|
|
|
1301
|
-
function timeEnd(slug) {
|
|
1301
|
+
function timeEnd$1(slug) {
|
|
1302
1302
|
if (useDebug()) {
|
|
1303
1303
|
console.timeEnd(slug);
|
|
1304
1304
|
}
|
|
@@ -1424,7 +1424,7 @@
|
|
|
1424
1424
|
setLoggingFunctions: setLoggingFunctions,
|
|
1425
1425
|
stop: stop$1,
|
|
1426
1426
|
time: time,
|
|
1427
|
-
timeEnd: timeEnd,
|
|
1427
|
+
timeEnd: timeEnd$1,
|
|
1428
1428
|
truncateString: truncateString,
|
|
1429
1429
|
useDebug: useDebug,
|
|
1430
1430
|
useVerbose: useVerbose,
|
|
@@ -4776,7 +4776,18 @@
|
|
|
4776
4776
|
pathIsRectangle: pathIsRectangle
|
|
4777
4777
|
});
|
|
4778
4778
|
|
|
4779
|
+
function runningInBrowser() {
|
|
4780
|
+
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4783
|
+
var Env = /*#__PURE__*/Object.freeze({
|
|
4784
|
+
__proto__: null,
|
|
4785
|
+
runningInBrowser: runningInBrowser
|
|
4786
|
+
});
|
|
4787
|
+
|
|
4779
4788
|
var DEFAULT_MAX_PREVIEW_PIXELS = 4e6;
|
|
4789
|
+
var MAX_EXACT_AVERAGE_PIXELS = 256;
|
|
4790
|
+
var MAX_APPROX_AVERAGE_STEPS = 16;
|
|
4780
4791
|
|
|
4781
4792
|
function getRasterGrid(raster) {
|
|
4782
4793
|
return raster && (raster.grid || raster);
|
|
@@ -4922,6 +4933,13 @@
|
|
|
4922
4933
|
});
|
|
4923
4934
|
}
|
|
4924
4935
|
|
|
4936
|
+
function renderRasterExportPreview(raster, bbox, width, height, opts) {
|
|
4937
|
+
var grid = getRasterGrid(raster);
|
|
4938
|
+
var recipe = getRasterViewRecipe(grid, raster.view && raster.view.recipe, opts);
|
|
4939
|
+
var stats = getRasterViewScalingStats(raster, recipe);
|
|
4940
|
+
return renderRasterGridPreview(grid, recipe, width, height, stats, bbox, getRasterExportResamplingMethod(grid, bbox, width, height));
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4925
4943
|
function getRasterScalingStats(grid, recipe) {
|
|
4926
4944
|
recipe = getRasterViewRecipe(grid, recipe);
|
|
4927
4945
|
return getScalingStats(grid.samples, grid.bands, grid.nodata, recipe);
|
|
@@ -4946,7 +4964,7 @@
|
|
|
4946
4964
|
return stats;
|
|
4947
4965
|
}
|
|
4948
4966
|
|
|
4949
|
-
function renderRasterGridPreview(grid, recipe, width, height, statsArg, sourceBbox) {
|
|
4967
|
+
function renderRasterGridPreview(grid, recipe, width, height, statsArg, sourceBbox, resamplingMethod) {
|
|
4950
4968
|
var samples = grid.samples;
|
|
4951
4969
|
var bands = grid.bands;
|
|
4952
4970
|
var noData = grid.nodata;
|
|
@@ -4954,23 +4972,29 @@
|
|
|
4954
4972
|
var stats = statsArg || getScalingStats(samples, bands, noData, recipe);
|
|
4955
4973
|
var sourceRange = recipe.scaling == 'none' ? getPixelTypeRange(grid.pixelType) : null;
|
|
4956
4974
|
var displayRange = getDisplayRange(recipe.scaleRange);
|
|
4957
|
-
var src, dest, val, isNoData, j;
|
|
4975
|
+
var src, dest, val, isNoData, j, sample;
|
|
4958
4976
|
for (var y = 0; y < height; y++) {
|
|
4959
4977
|
for (var x = 0; x < width; x++) {
|
|
4960
|
-
src = getPreviewSourceOffset(grid, sourceBbox, x, y, width, height, bands);
|
|
4961
4978
|
dest = (y * width + x) * 4;
|
|
4962
|
-
|
|
4979
|
+
if (resamplingMethod) {
|
|
4980
|
+
sample = getResampledRasterSample(grid, sourceBbox, x, y, width, height, resamplingMethod);
|
|
4981
|
+
isNoData = !sample.valid;
|
|
4982
|
+
} else {
|
|
4983
|
+
src = getPreviewSourceOffset(grid, sourceBbox, x, y, width, height, bands);
|
|
4984
|
+
sample = null;
|
|
4985
|
+
isNoData = noData !== null && noData !== undefined && allSamplesAreNoData(samples, src, bands, noData);
|
|
4986
|
+
}
|
|
4963
4987
|
if (bands == 1) {
|
|
4964
|
-
val = scaleSample(samples[src], stats && stats[0], sourceRange, displayRange);
|
|
4988
|
+
val = scaleSample(sample ? sample.values[0] : samples[src], stats && stats[0], sourceRange, displayRange);
|
|
4965
4989
|
pixels[dest] = val;
|
|
4966
4990
|
pixels[dest + 1] = val;
|
|
4967
4991
|
pixels[dest + 2] = val;
|
|
4968
4992
|
pixels[dest + 3] = isNoData ? 0 : 255;
|
|
4969
4993
|
} else {
|
|
4970
4994
|
for (j = 0; j < 3; j++) {
|
|
4971
|
-
pixels[dest + j] = scaleSample(samples[src + j], stats && stats[j], sourceRange, displayRange);
|
|
4995
|
+
pixels[dest + j] = scaleSample(sample ? sample.values[j] : samples[src + j], stats && stats[j], sourceRange, displayRange);
|
|
4972
4996
|
}
|
|
4973
|
-
pixels[dest + 3] = isNoData ? 0 : bands >= 4 ? scaleSample(samples[src + 3], stats && stats[3], sourceRange, [0, 255]) : 255;
|
|
4997
|
+
pixels[dest + 3] = isNoData ? 0 : bands >= 4 ? scaleSample(sample ? sample.values[3] : samples[src + 3], stats && stats[3], sourceRange, [0, 255]) : 255;
|
|
4974
4998
|
}
|
|
4975
4999
|
}
|
|
4976
5000
|
}
|
|
@@ -4984,6 +5008,156 @@
|
|
|
4984
5008
|
};
|
|
4985
5009
|
}
|
|
4986
5010
|
|
|
5011
|
+
function getRasterExportResamplingMethod(grid, bbox, width, height) {
|
|
5012
|
+
var srcSize = getRasterSourcePixelSize(grid, bbox);
|
|
5013
|
+
return width < srcSize.width || height < srcSize.height ? 'average' : 'bilinear';
|
|
5014
|
+
}
|
|
5015
|
+
|
|
5016
|
+
function getRasterSourcePixelSize(grid, bbox) {
|
|
5017
|
+
var rb = grid.bbox;
|
|
5018
|
+
return {
|
|
5019
|
+
width: Math.abs((bbox[2] - bbox[0]) / (rb[2] - rb[0]) * grid.width),
|
|
5020
|
+
height: Math.abs((bbox[3] - bbox[1]) / (rb[3] - rb[1]) * grid.height)
|
|
5021
|
+
};
|
|
5022
|
+
}
|
|
5023
|
+
|
|
5024
|
+
function getResampledRasterSample(grid, bbox, x, y, width, height, method) {
|
|
5025
|
+
return method == 'average' ?
|
|
5026
|
+
getAverageRasterSample(grid, bbox, x, y, width, height) :
|
|
5027
|
+
getBilinearRasterSample(grid, bbox, x, y, width, height);
|
|
5028
|
+
}
|
|
5029
|
+
|
|
5030
|
+
function getAverageRasterSample(grid, bbox, x, y, width, height) {
|
|
5031
|
+
var bounds = getRasterSourcePixelBounds(grid, bbox, x, y, width, height);
|
|
5032
|
+
if (getSourcePixelBoundsArea(bounds) > MAX_EXACT_AVERAGE_PIXELS) {
|
|
5033
|
+
return getApproxAverageRasterSample(grid, bounds);
|
|
5034
|
+
}
|
|
5035
|
+
var samples = grid.samples;
|
|
5036
|
+
var bands = grid.bands;
|
|
5037
|
+
var values = new Array(bands).fill(0);
|
|
5038
|
+
var total = 0;
|
|
5039
|
+
var src, weight;
|
|
5040
|
+
var x0 = Math.max(0, Math.floor(bounds.x0));
|
|
5041
|
+
var x1 = Math.min(grid.width, Math.ceil(bounds.x1));
|
|
5042
|
+
var y0 = Math.max(0, Math.floor(bounds.y0));
|
|
5043
|
+
var y1 = Math.min(grid.height, Math.ceil(bounds.y1));
|
|
5044
|
+
for (var sy = y0; sy < y1; sy++) {
|
|
5045
|
+
for (var sx = x0; sx < x1; sx++) {
|
|
5046
|
+
weight = getIntervalOverlap(bounds.x0, bounds.x1, sx, sx + 1) *
|
|
5047
|
+
getIntervalOverlap(bounds.y0, bounds.y1, sy, sy + 1);
|
|
5048
|
+
if (weight <= 0) continue;
|
|
5049
|
+
src = (sy * grid.width + sx) * bands;
|
|
5050
|
+
if (sampleIsNoData(samples, src, bands, grid.nodata)) continue;
|
|
5051
|
+
for (var band = 0; band < bands; band++) {
|
|
5052
|
+
values[band] += samples[src + band] * weight;
|
|
5053
|
+
}
|
|
5054
|
+
total += weight;
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
if (total <= 0) return {valid: false, values: values};
|
|
5058
|
+
for (var i = 0; i < bands; i++) values[i] /= total;
|
|
5059
|
+
return {valid: true, values: values};
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
function getApproxAverageRasterSample(grid, bounds) {
|
|
5063
|
+
var samples = grid.samples;
|
|
5064
|
+
var bands = grid.bands;
|
|
5065
|
+
var values = new Array(bands).fill(0);
|
|
5066
|
+
var xSteps = Math.min(MAX_APPROX_AVERAGE_STEPS, Math.max(1, Math.ceil(Math.abs(bounds.x1 - bounds.x0))));
|
|
5067
|
+
var ySteps = Math.min(MAX_APPROX_AVERAGE_STEPS, Math.max(1, Math.ceil(Math.abs(bounds.y1 - bounds.y0))));
|
|
5068
|
+
var count = 0;
|
|
5069
|
+
var sx, sy, src;
|
|
5070
|
+
for (var y = 0; y < ySteps; y++) {
|
|
5071
|
+
for (var x = 0; x < xSteps; x++) {
|
|
5072
|
+
sx = Math.max(0, Math.min(grid.width - 1, Math.floor(bounds.x0 + (x + 0.5) / xSteps * (bounds.x1 - bounds.x0))));
|
|
5073
|
+
sy = Math.max(0, Math.min(grid.height - 1, Math.floor(bounds.y0 + (y + 0.5) / ySteps * (bounds.y1 - bounds.y0))));
|
|
5074
|
+
src = (sy * grid.width + sx) * bands;
|
|
5075
|
+
if (sampleIsNoData(samples, src, bands, grid.nodata)) continue;
|
|
5076
|
+
for (var band = 0; band < bands; band++) {
|
|
5077
|
+
values[band] += samples[src + band];
|
|
5078
|
+
}
|
|
5079
|
+
count++;
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
if (count === 0) return {valid: false, values: values};
|
|
5083
|
+
for (var i = 0; i < bands; i++) values[i] /= count;
|
|
5084
|
+
return {valid: true, values: values};
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
function getBilinearRasterSample(grid, bbox, x, y, width, height) {
|
|
5088
|
+
var p = getRasterSourcePixelCenter(grid, bbox, x, y, width, height);
|
|
5089
|
+
var x0 = Math.max(0, Math.min(grid.width - 1, Math.floor(p.x)));
|
|
5090
|
+
var y0 = Math.max(0, Math.min(grid.height - 1, Math.floor(p.y)));
|
|
5091
|
+
var x1 = Math.max(0, Math.min(grid.width - 1, x0 + 1));
|
|
5092
|
+
var y1 = Math.max(0, Math.min(grid.height - 1, y0 + 1));
|
|
5093
|
+
var tx = Math.max(0, Math.min(1, p.x - x0));
|
|
5094
|
+
var ty = Math.max(0, Math.min(1, p.y - y0));
|
|
5095
|
+
var samples = grid.samples;
|
|
5096
|
+
var bands = grid.bands;
|
|
5097
|
+
var values = new Array(bands).fill(0);
|
|
5098
|
+
var offsets = [
|
|
5099
|
+
(y0 * grid.width + x0) * bands,
|
|
5100
|
+
(y0 * grid.width + x1) * bands,
|
|
5101
|
+
(y1 * grid.width + x0) * bands,
|
|
5102
|
+
(y1 * grid.width + x1) * bands
|
|
5103
|
+
];
|
|
5104
|
+
var weights = [
|
|
5105
|
+
(1 - tx) * (1 - ty),
|
|
5106
|
+
tx * (1 - ty),
|
|
5107
|
+
(1 - tx) * ty,
|
|
5108
|
+
tx * ty
|
|
5109
|
+
];
|
|
5110
|
+
var total = 0;
|
|
5111
|
+
offsets.forEach(function(src, i) {
|
|
5112
|
+
if (weights[i] <= 0 || sampleIsNoData(samples, src, bands, grid.nodata)) return;
|
|
5113
|
+
for (var band = 0; band < bands; band++) {
|
|
5114
|
+
values[band] += samples[src + band] * weights[i];
|
|
5115
|
+
}
|
|
5116
|
+
total += weights[i];
|
|
5117
|
+
});
|
|
5118
|
+
if (total <= 0) return {valid: false, values: values};
|
|
5119
|
+
for (var j = 0; j < bands; j++) values[j] /= total;
|
|
5120
|
+
return {valid: true, values: values};
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5123
|
+
function getRasterSourcePixelBounds(grid, bbox, x, y, width, height) {
|
|
5124
|
+
return {
|
|
5125
|
+
x0: mapXToRasterPixel(grid, bbox[0] + x / width * (bbox[2] - bbox[0])),
|
|
5126
|
+
x1: mapXToRasterPixel(grid, bbox[0] + (x + 1) / width * (bbox[2] - bbox[0])),
|
|
5127
|
+
y0: mapYToRasterPixel(grid, bbox[3] - y / height * (bbox[3] - bbox[1])),
|
|
5128
|
+
y1: mapYToRasterPixel(grid, bbox[3] - (y + 1) / height * (bbox[3] - bbox[1]))
|
|
5129
|
+
};
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
function getRasterSourcePixelCenter(grid, bbox, x, y, width, height) {
|
|
5133
|
+
var mapX = bbox[0] + (x + 0.5) / width * (bbox[2] - bbox[0]);
|
|
5134
|
+
var mapY = bbox[3] - (y + 0.5) / height * (bbox[3] - bbox[1]);
|
|
5135
|
+
return {
|
|
5136
|
+
x: mapXToRasterPixel(grid, mapX) - 0.5,
|
|
5137
|
+
y: mapYToRasterPixel(grid, mapY) - 0.5
|
|
5138
|
+
};
|
|
5139
|
+
}
|
|
5140
|
+
|
|
5141
|
+
function mapXToRasterPixel(grid, x) {
|
|
5142
|
+
return (x - grid.bbox[0]) / (grid.bbox[2] - grid.bbox[0]) * grid.width;
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5145
|
+
function mapYToRasterPixel(grid, y) {
|
|
5146
|
+
return (grid.bbox[3] - y) / (grid.bbox[3] - grid.bbox[1]) * grid.height;
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
function getIntervalOverlap(a0, a1, b0, b1) {
|
|
5150
|
+
return Math.max(0, Math.min(Math.max(a0, a1), b1) - Math.max(Math.min(a0, a1), b0));
|
|
5151
|
+
}
|
|
5152
|
+
|
|
5153
|
+
function getSourcePixelBoundsArea(bounds) {
|
|
5154
|
+
return Math.abs((bounds.x1 - bounds.x0) * (bounds.y1 - bounds.y0));
|
|
5155
|
+
}
|
|
5156
|
+
|
|
5157
|
+
function sampleIsNoData(samples, offset, bands, noData) {
|
|
5158
|
+
return noData !== null && noData !== undefined && allSamplesAreNoData(samples, offset, bands, noData);
|
|
5159
|
+
}
|
|
5160
|
+
|
|
4987
5161
|
function renderRawEightBitPreview(grid, width, height, sourceBbox) {
|
|
4988
5162
|
var samples = grid.samples;
|
|
4989
5163
|
var bands = grid.bands;
|
|
@@ -5048,7 +5222,12 @@
|
|
|
5048
5222
|
noteLayerWillChange(lyr, {operation: 'clipRasterToBBox', unit: 'raster'});
|
|
5049
5223
|
raster.grid = cropRasterGrid(grid, crop, clipBbox);
|
|
5050
5224
|
raster.view = raster.view || {};
|
|
5051
|
-
raster.view.
|
|
5225
|
+
delete raster.view.scalingStats;
|
|
5226
|
+
if (runningInBrowser()) {
|
|
5227
|
+
raster.view.preview = createRasterPreview(raster, opts || {});
|
|
5228
|
+
} else {
|
|
5229
|
+
delete raster.view.preview;
|
|
5230
|
+
}
|
|
5052
5231
|
clearLegacyRasterFields(raster);
|
|
5053
5232
|
markLayerChanged(lyr, {operation: 'clipRasterToBBox', unit: 'raster'});
|
|
5054
5233
|
return true;
|
|
@@ -5393,6 +5572,7 @@
|
|
|
5393
5572
|
getRasterViewScalingStats: getRasterViewScalingStats,
|
|
5394
5573
|
getRasterWidth: getRasterWidth,
|
|
5395
5574
|
intersectBboxes: intersectBboxes,
|
|
5575
|
+
renderRasterExportPreview: renderRasterExportPreview,
|
|
5396
5576
|
renderRasterPreview: renderRasterPreview,
|
|
5397
5577
|
renderRasterViewportPreview: renderRasterViewportPreview,
|
|
5398
5578
|
requireRasterLayer: requireRasterLayer
|
|
@@ -10775,15 +10955,6 @@
|
|
|
10775
10955
|
return files;
|
|
10776
10956
|
}
|
|
10777
10957
|
|
|
10778
|
-
function runningInBrowser() {
|
|
10779
|
-
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
10780
|
-
}
|
|
10781
|
-
|
|
10782
|
-
var Env = /*#__PURE__*/Object.freeze({
|
|
10783
|
-
__proto__: null,
|
|
10784
|
-
runningInBrowser: runningInBrowser
|
|
10785
|
-
});
|
|
10786
|
-
|
|
10787
10958
|
// input: A file path or a buffer
|
|
10788
10959
|
function unzipSync(input) {
|
|
10789
10960
|
if (input instanceof ArrayBuffer) {
|
|
@@ -19819,15 +19990,15 @@ ${svg}
|
|
|
19819
19990
|
|
|
19820
19991
|
function exportRasterLayerForSVG(lyr, frame, opts) {
|
|
19821
19992
|
var raster = lyr.raster;
|
|
19822
|
-
var
|
|
19823
|
-
var bbox = transformRasterBboxForSVG(
|
|
19993
|
+
var rendered = renderRasterForSVG(raster, frame, opts);
|
|
19994
|
+
var bbox = transformRasterBboxForSVG(rendered.bbox, frame);
|
|
19824
19995
|
var href;
|
|
19825
19996
|
var layerObj = getEmptyLayerForSVG(lyr, opts);
|
|
19826
|
-
if (!
|
|
19997
|
+
if (!rendered.preview.width || !rendered.preview.height) {
|
|
19827
19998
|
layerObj.children = [];
|
|
19828
19999
|
return layerObj;
|
|
19829
20000
|
}
|
|
19830
|
-
href = encodeRasterPreview(
|
|
20001
|
+
href = encodeRasterPreview(rendered.preview, opts);
|
|
19831
20002
|
layerObj.children = [{
|
|
19832
20003
|
tag: 'image',
|
|
19833
20004
|
properties: {
|
|
@@ -19842,50 +20013,47 @@ ${svg}
|
|
|
19842
20013
|
return layerObj;
|
|
19843
20014
|
}
|
|
19844
20015
|
|
|
19845
|
-
function
|
|
20016
|
+
function renderRasterForSVG(raster, frame, opts) {
|
|
19846
20017
|
var rasterBbox = getRasterBBox(raster);
|
|
19847
|
-
var preview = getRasterPreview(raster);
|
|
19848
20018
|
var rasterBounds = new Bounds(rasterBbox);
|
|
19849
20019
|
var clipBounds = new Bounds(frame.bbox);
|
|
19850
20020
|
var bbox = intersectBboxes(rasterBounds.toArray(), clipBounds.toArray()) || [0, 0, 0, 0];
|
|
19851
|
-
var
|
|
20021
|
+
var svgBbox = transformRasterBboxForSVG(bbox, frame);
|
|
20022
|
+
var size = getSvgRasterOutputSize(raster, bbox, svgBbox, opts);
|
|
19852
20023
|
return {
|
|
19853
20024
|
bbox: bbox,
|
|
19854
|
-
preview:
|
|
20025
|
+
preview: size.width > 0 && size.height > 0 ?
|
|
20026
|
+
renderRasterExportPreview(raster, bbox, size.width, size.height, opts) :
|
|
20027
|
+
{width: 0, height: 0, pixels: new Uint8ClampedArray(0)}
|
|
19855
20028
|
};
|
|
19856
20029
|
}
|
|
19857
20030
|
|
|
19858
|
-
function
|
|
19859
|
-
var
|
|
19860
|
-
var
|
|
19861
|
-
var
|
|
19862
|
-
var
|
|
19863
|
-
var
|
|
19864
|
-
var
|
|
20031
|
+
function getSvgRasterOutputSize(raster, bbox, svgBbox, opts) {
|
|
20032
|
+
var res = getSvgRasterResolution(opts);
|
|
20033
|
+
var sourceSize = getRasterSourceSize(raster, bbox);
|
|
20034
|
+
var svgWidth = Math.abs(svgBbox[2] - svgBbox[0]);
|
|
20035
|
+
var svgHeight = Math.abs(svgBbox[3] - svgBbox[1]);
|
|
20036
|
+
var width = svgWidth > 0 ? Math.max(1, Math.round(svgWidth * res)) : 0;
|
|
20037
|
+
var height = svgHeight > 0 ? Math.max(1, Math.round(svgHeight * res)) : 0;
|
|
19865
20038
|
return {
|
|
19866
|
-
|
|
19867
|
-
|
|
19868
|
-
width: Math.max(0, x1 - x0),
|
|
19869
|
-
height: Math.max(0, y1 - y0)
|
|
20039
|
+
width: Math.max(0, Math.min(Math.max(1, Math.ceil(sourceSize.width)), width)),
|
|
20040
|
+
height: Math.max(0, Math.min(Math.max(1, Math.ceil(sourceSize.height)), height))
|
|
19870
20041
|
};
|
|
19871
20042
|
}
|
|
19872
20043
|
|
|
19873
|
-
function
|
|
19874
|
-
|
|
19875
|
-
|
|
19876
|
-
|
|
19877
|
-
|
|
19878
|
-
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
19883
|
-
|
|
19884
|
-
|
|
19885
|
-
|
|
19886
|
-
height: crop.height,
|
|
19887
|
-
pixels: pixels
|
|
19888
|
-
});
|
|
20044
|
+
function getSvgRasterResolution(opts) {
|
|
20045
|
+
var res = opts.raster_res || opts.rasterRes || 1;
|
|
20046
|
+
if (res > 0 === false) stop$1('Expected raster-res= to be a positive number');
|
|
20047
|
+
return res;
|
|
20048
|
+
}
|
|
20049
|
+
|
|
20050
|
+
function getRasterSourceSize(raster, bbox) {
|
|
20051
|
+
var grid = raster.grid;
|
|
20052
|
+
var rb = getRasterBBox(raster);
|
|
20053
|
+
return {
|
|
20054
|
+
width: Math.abs((bbox[2] - bbox[0]) / (rb[2] - rb[0]) * grid.width),
|
|
20055
|
+
height: Math.abs((bbox[3] - bbox[1]) / (rb[3] - rb[1]) * grid.height)
|
|
20056
|
+
};
|
|
19889
20057
|
}
|
|
19890
20058
|
|
|
19891
20059
|
function transformRasterBboxForSVG(bbox, frame) {
|
|
@@ -23424,20 +23592,11 @@ ${svg}
|
|
|
23424
23592
|
}
|
|
23425
23593
|
if (raster.view) {
|
|
23426
23594
|
copy.view = Object.assign({}, raster.view);
|
|
23427
|
-
|
|
23428
|
-
|
|
23429
|
-
delete copy.view.preview.canvas;
|
|
23430
|
-
if (raster.view.preview.pixels) {
|
|
23431
|
-
copy.view.preview.pixels = typedArrayToBuffer(raster.view.preview.pixels);
|
|
23432
|
-
}
|
|
23433
|
-
}
|
|
23595
|
+
delete copy.view.preview;
|
|
23596
|
+
delete copy.view.scalingStats;
|
|
23434
23597
|
}
|
|
23435
23598
|
if (raster.preview) {
|
|
23436
|
-
copy.preview
|
|
23437
|
-
delete copy.preview.canvas;
|
|
23438
|
-
if (raster.preview.pixels) {
|
|
23439
|
-
copy.preview.pixels = typedArrayToBuffer(raster.preview.pixels);
|
|
23440
|
-
}
|
|
23599
|
+
delete copy.preview;
|
|
23441
23600
|
}
|
|
23442
23601
|
if (raster.pixels) {
|
|
23443
23602
|
copy.pixels = typedArrayToBuffer(raster.pixels);
|
|
@@ -28669,6 +28828,10 @@ ${svg}
|
|
|
28669
28828
|
error('precision= option should be a positive number');
|
|
28670
28829
|
}
|
|
28671
28830
|
|
|
28831
|
+
if (o.raster_type && o.raster_type != 'image' && o.raster_type != 'categorical') {
|
|
28832
|
+
error('Unsupported raster-type:', o.raster_type);
|
|
28833
|
+
}
|
|
28834
|
+
|
|
28672
28835
|
if (o.encoding) {
|
|
28673
28836
|
o.encoding = validateEncoding(o.encoding);
|
|
28674
28837
|
}
|
|
@@ -28682,9 +28845,13 @@ ${svg}
|
|
|
28682
28845
|
}
|
|
28683
28846
|
|
|
28684
28847
|
function validateProjOpts(cmd) {
|
|
28848
|
+
var resampling = cmd.options.resampling;
|
|
28685
28849
|
if (!(cmd.options.crs || cmd.options.match || cmd.options.init)) {
|
|
28686
28850
|
stop$1('Missing projection data');
|
|
28687
28851
|
}
|
|
28852
|
+
if (resampling && resampling != 'nearest' && resampling != 'bilinear') {
|
|
28853
|
+
stop$1('Unsupported resampling method:', resampling);
|
|
28854
|
+
}
|
|
28688
28855
|
}
|
|
28689
28856
|
|
|
28690
28857
|
function validateGridOpts(cmd) {
|
|
@@ -29964,6 +30131,9 @@ ${svg}
|
|
|
29964
30131
|
.option('percentile-range', {
|
|
29965
30132
|
describe: '[raster] input percentile range for percentile scaling, e.g. 2,98'
|
|
29966
30133
|
})
|
|
30134
|
+
.option('raster-type', {
|
|
30135
|
+
describe: '[raster] image or categorical (default is image)'
|
|
30136
|
+
})
|
|
29967
30137
|
.option('rendition', {
|
|
29968
30138
|
describe: '[GeoTIFF] import a GeoTIFF rendition: full,overview-1,etc.'
|
|
29969
30139
|
})
|
|
@@ -30185,6 +30355,10 @@ ${svg}
|
|
|
30185
30355
|
describe: '[SVG] bounding box of SVG map in projected map units',
|
|
30186
30356
|
type: 'bbox'
|
|
30187
30357
|
})
|
|
30358
|
+
.option('raster-res', {
|
|
30359
|
+
describe: '[SVG] raster pixels per SVG pixel (default is 1)',
|
|
30360
|
+
type: 'number'
|
|
30361
|
+
})
|
|
30188
30362
|
.option('fit-extent', {
|
|
30189
30363
|
describe: '[SVG] layer to use for the map extent'
|
|
30190
30364
|
})
|
|
@@ -31206,6 +31380,12 @@ ${svg}
|
|
|
31206
31380
|
describe: 'clip to a lat-long bounding box before projecting',
|
|
31207
31381
|
type: 'bbox'
|
|
31208
31382
|
})
|
|
31383
|
+
.option('nodata-color', {
|
|
31384
|
+
describe: '[raster] color for uncovered pixels after reprojection'
|
|
31385
|
+
})
|
|
31386
|
+
.option('resampling', {
|
|
31387
|
+
describe: '[raster] nearest or bilinear (default is bilinear)'
|
|
31388
|
+
})
|
|
31209
31389
|
.option('target', targetOpt)
|
|
31210
31390
|
.validate(validateProjOpts);
|
|
31211
31391
|
|
|
@@ -35693,6 +35873,7 @@ ${svg}
|
|
|
35693
35873
|
}
|
|
35694
35874
|
|
|
35695
35875
|
var geotiffPromise = null;
|
|
35876
|
+
var geoKeysToProj4Promise = null;
|
|
35696
35877
|
var dynamicImportModule = Function('id', 'return import(id)');
|
|
35697
35878
|
var DEFAULT_MAX_IMPORT_PIXELS = 16e6;
|
|
35698
35879
|
|
|
@@ -35734,6 +35915,18 @@ ${svg}
|
|
|
35734
35915
|
return mod.default && !mod.fromArrayBuffer ? mod.default : mod;
|
|
35735
35916
|
}
|
|
35736
35917
|
|
|
35918
|
+
async function loadGeoKeysToProj4Lib() {
|
|
35919
|
+
var mod;
|
|
35920
|
+
if (runningInBrowser()) {
|
|
35921
|
+
return require$1('geotiff-geokeys-to-proj4');
|
|
35922
|
+
}
|
|
35923
|
+
if (!geoKeysToProj4Promise) {
|
|
35924
|
+
geoKeysToProj4Promise = dynamicImportModule('geotiff-geokeys-to-proj4');
|
|
35925
|
+
}
|
|
35926
|
+
mod = await geoKeysToProj4Promise;
|
|
35927
|
+
return mod.default || mod;
|
|
35928
|
+
}
|
|
35929
|
+
|
|
35737
35930
|
async function openGeoTIFF(source, geotiff) {
|
|
35738
35931
|
if (!source) {
|
|
35739
35932
|
stop$1('Missing GeoTIFF source data');
|
|
@@ -35761,6 +35954,7 @@ ${svg}
|
|
|
35761
35954
|
var sourceId = getSourceId(input);
|
|
35762
35955
|
var raster = {
|
|
35763
35956
|
sourceId: sourceId,
|
|
35957
|
+
interpretation: getRasterInterpretation$1(opts),
|
|
35764
35958
|
grid: {
|
|
35765
35959
|
width: width,
|
|
35766
35960
|
height: height,
|
|
@@ -35785,13 +35979,19 @@ ${svg}
|
|
|
35785
35979
|
}
|
|
35786
35980
|
};
|
|
35787
35981
|
raster.view.recipe = getRasterViewRecipe(raster.grid, raster.view.recipe, opts);
|
|
35788
|
-
|
|
35982
|
+
if (runningInBrowser()) {
|
|
35983
|
+
raster.view.preview = createRasterPreview(raster, opts);
|
|
35984
|
+
}
|
|
35789
35985
|
return {
|
|
35790
35986
|
raster: raster,
|
|
35791
35987
|
source: getSourceInfo$1(input, sourceId, sourceImage)
|
|
35792
35988
|
};
|
|
35793
35989
|
}
|
|
35794
35990
|
|
|
35991
|
+
function getRasterInterpretation$1(opts) {
|
|
35992
|
+
return opts.raster_type || opts.rasterType || 'image';
|
|
35993
|
+
}
|
|
35994
|
+
|
|
35795
35995
|
async function selectGeoTIFFImportImage(tiff, sourceImage, opts) {
|
|
35796
35996
|
var maxPixels = getMaxImportPixels(opts);
|
|
35797
35997
|
var renditions = await getGeoTIFFRenditions(tiff, sourceImage);
|
|
@@ -36040,23 +36240,123 @@ ${svg}
|
|
|
36040
36240
|
}
|
|
36041
36241
|
|
|
36042
36242
|
async function importGeoTIFFCrs(dataset, image) {
|
|
36043
|
-
var
|
|
36243
|
+
var crsInfo = await getGeoTIFFCrsInfo(image);
|
|
36244
|
+
var crsString = crsInfo.crsString;
|
|
36044
36245
|
if (!crsString) {
|
|
36045
|
-
warnOnce(
|
|
36246
|
+
warnOnce(getGeoTIFFCrsWarning(crsInfo));
|
|
36046
36247
|
return;
|
|
36047
36248
|
}
|
|
36048
|
-
await initProjLibrary({crs: crsString});
|
|
36049
36249
|
try {
|
|
36250
|
+
await initProjLibrary({crs: crsString});
|
|
36050
36251
|
setDatasetCrsInfo(dataset, getCrsInfo(crsString));
|
|
36051
36252
|
} catch(e) {
|
|
36052
|
-
dataset.info =
|
|
36253
|
+
dataset.info = dataset.info || {};
|
|
36254
|
+
warnOnce(getGeoTIFFCrsWarning(crsInfo, e.message || e));
|
|
36053
36255
|
}
|
|
36054
36256
|
}
|
|
36055
36257
|
|
|
36056
|
-
function
|
|
36258
|
+
async function getGeoTIFFCrsInfo(image) {
|
|
36057
36259
|
var keys = image.getGeoKeys && image.getGeoKeys() || {};
|
|
36058
|
-
var code = keys.ProjectedCSTypeGeoKey
|
|
36059
|
-
|
|
36260
|
+
var code = keys.ProjectedCSTypeGeoKey;
|
|
36261
|
+
var customProjection;
|
|
36262
|
+
if (isGeoTIFFAuthorityCode(code)) {
|
|
36263
|
+
return {crsString: 'EPSG:' + code};
|
|
36264
|
+
}
|
|
36265
|
+
customProjection = await getGeoTIFFCustomProjection(keys);
|
|
36266
|
+
if (customProjection.crsString) return customProjection;
|
|
36267
|
+
code = keys.GeographicTypeGeoKey;
|
|
36268
|
+
if (isGeoTIFFAuthorityCode(code)) return {crsString: 'EPSG:' + code};
|
|
36269
|
+
return {crsString: null, warning: customProjection.warning};
|
|
36270
|
+
}
|
|
36271
|
+
|
|
36272
|
+
function getGeoTIFFCrsWarning(crsInfo, detail) {
|
|
36273
|
+
if (detail || crsInfo && crsInfo.warning) {
|
|
36274
|
+
logGeoTIFFCrsWarningDetails(detail, crsInfo && crsInfo.warning);
|
|
36275
|
+
}
|
|
36276
|
+
return 'The GeoTIFF does not contain usable CRS data';
|
|
36277
|
+
}
|
|
36278
|
+
|
|
36279
|
+
function isGeoTIFFAuthorityCode(code) {
|
|
36280
|
+
return code > 0 && code != 32767;
|
|
36281
|
+
}
|
|
36282
|
+
|
|
36283
|
+
async function getGeoTIFFCustomProjection(keys) {
|
|
36284
|
+
var converted = await getGeoTIFFProj4FromGeoKeys(keys);
|
|
36285
|
+
if (converted.crsString) return converted;
|
|
36286
|
+
if (keys.ProjectedCSTypeGeoKey != 32767 && keys.ProjectionGeoKey != 32767) return converted;
|
|
36287
|
+
if (keys.ProjCoordTransGeoKey == 11) {
|
|
36288
|
+
return {
|
|
36289
|
+
crsString: getGeoTIFFAlbersProjection(keys),
|
|
36290
|
+
warning: converted.warning
|
|
36291
|
+
};
|
|
36292
|
+
}
|
|
36293
|
+
return converted;
|
|
36294
|
+
}
|
|
36295
|
+
|
|
36296
|
+
async function getGeoTIFFProj4FromGeoKeys(keys) {
|
|
36297
|
+
var geokeysToProj4, result;
|
|
36298
|
+
try {
|
|
36299
|
+
geokeysToProj4 = await loadGeoKeysToProj4Lib();
|
|
36300
|
+
result = geokeysToProj4.toProj4(keys);
|
|
36301
|
+
} catch(e) {
|
|
36302
|
+
return {crsString: null, warning: {type: 'GeoKey converter error', error: e.message || e}};
|
|
36303
|
+
}
|
|
36304
|
+
if (result && result.proj4) {
|
|
36305
|
+
return {crsString: normalizeGeoTIFFProj4(result.proj4)};
|
|
36306
|
+
}
|
|
36307
|
+
return {crsString: null, warning: result && result.errors || null};
|
|
36308
|
+
}
|
|
36309
|
+
|
|
36310
|
+
function normalizeGeoTIFFProj4(str) {
|
|
36311
|
+
return String(str).replace(/\s\+axis=[^ ]+/g, '').trim();
|
|
36312
|
+
}
|
|
36313
|
+
|
|
36314
|
+
function logGeoTIFFCrsWarningDetails(parseError, converterDetails) {
|
|
36315
|
+
if (typeof console == 'undefined' || !console.warn) return;
|
|
36316
|
+
console.warn('Unable to import GeoTIFF CRS metadata', {
|
|
36317
|
+
parseError: parseError || null,
|
|
36318
|
+
converterDetails: converterDetails || null
|
|
36319
|
+
});
|
|
36320
|
+
}
|
|
36321
|
+
|
|
36322
|
+
function getGeoTIFFAlbersProjection(keys) {
|
|
36323
|
+
var units = getGeoTIFFLinearUnits(keys);
|
|
36324
|
+
var ellipsoid = getGeoTIFFEllipsoid(keys);
|
|
36325
|
+
if (!units || !ellipsoid ||
|
|
36326
|
+
!isFinite(keys.ProjStdParallel1GeoKey) || !isFinite(keys.ProjStdParallel2GeoKey) ||
|
|
36327
|
+
!isFinite(keys.ProjNatOriginLatGeoKey) || !isFinite(keys.ProjNatOriginLongGeoKey)) {
|
|
36328
|
+
return null;
|
|
36329
|
+
}
|
|
36330
|
+
return [
|
|
36331
|
+
'+proj=aea',
|
|
36332
|
+
'+lat_1=' + keys.ProjStdParallel1GeoKey,
|
|
36333
|
+
'+lat_2=' + keys.ProjStdParallel2GeoKey,
|
|
36334
|
+
'+lat_0=' + keys.ProjNatOriginLatGeoKey,
|
|
36335
|
+
'+lon_0=' + keys.ProjNatOriginLongGeoKey,
|
|
36336
|
+
'+x_0=' + (keys.ProjFalseEastingGeoKey || 0),
|
|
36337
|
+
'+y_0=' + (keys.ProjFalseNorthingGeoKey || 0),
|
|
36338
|
+
ellipsoid,
|
|
36339
|
+
units
|
|
36340
|
+
].join(' ');
|
|
36341
|
+
}
|
|
36342
|
+
|
|
36343
|
+
function getGeoTIFFLinearUnits(keys) {
|
|
36344
|
+
var code = keys.ProjLinearUnitsGeoKey;
|
|
36345
|
+
if (!code || code == 9001) return '+units=m';
|
|
36346
|
+
if (code == 9002) return '+units=ft';
|
|
36347
|
+
if (code == 9003) return '+to_meter=0.3048006096012192';
|
|
36348
|
+
return null;
|
|
36349
|
+
}
|
|
36350
|
+
|
|
36351
|
+
function getGeoTIFFEllipsoid(keys) {
|
|
36352
|
+
if (keys.GeographicTypeGeoKey == 4326) return '+datum=WGS84';
|
|
36353
|
+
if (isFinite(keys.GeogSemiMajorAxisGeoKey) && isFinite(keys.GeogInvFlatteningGeoKey)) {
|
|
36354
|
+
return '+a=' + keys.GeogSemiMajorAxisGeoKey + ' +rf=' + keys.GeogInvFlatteningGeoKey;
|
|
36355
|
+
}
|
|
36356
|
+
if (isFinite(keys.GeogSemiMajorAxisGeoKey) && isFinite(keys.GeogSemiMinorAxisGeoKey)) {
|
|
36357
|
+
return '+a=' + keys.GeogSemiMajorAxisGeoKey + ' +b=' + keys.GeogSemiMinorAxisGeoKey;
|
|
36358
|
+
}
|
|
36359
|
+
return null;
|
|
36060
36360
|
}
|
|
36061
36361
|
|
|
36062
36362
|
async function importImageRaster(input, optsArg) {
|
|
@@ -36074,6 +36374,7 @@ ${svg}
|
|
|
36074
36374
|
bbox = getWorldFileBBox(transform, decoded.width, decoded.height);
|
|
36075
36375
|
raster = {
|
|
36076
36376
|
sourceId: sourceId,
|
|
36377
|
+
interpretation: getRasterInterpretation(opts),
|
|
36077
36378
|
grid: {
|
|
36078
36379
|
width: decoded.width,
|
|
36079
36380
|
height: decoded.height,
|
|
@@ -36098,7 +36399,9 @@ ${svg}
|
|
|
36098
36399
|
}
|
|
36099
36400
|
};
|
|
36100
36401
|
raster.view.recipe = getRasterViewRecipe(raster.grid, raster.view.recipe, opts);
|
|
36101
|
-
|
|
36402
|
+
if (runningInBrowser()) {
|
|
36403
|
+
raster.view.preview = createRasterPreview(raster, opts);
|
|
36404
|
+
}
|
|
36102
36405
|
dataset = {
|
|
36103
36406
|
info: {
|
|
36104
36407
|
raster_sources: [getSourceInfo(imageInput, sourceId, imageType, input)]
|
|
@@ -36113,6 +36416,10 @@ ${svg}
|
|
|
36113
36416
|
return dataset;
|
|
36114
36417
|
}
|
|
36115
36418
|
|
|
36419
|
+
function getRasterInterpretation(opts) {
|
|
36420
|
+
return opts.raster_type || opts.rasterType || 'image';
|
|
36421
|
+
}
|
|
36422
|
+
|
|
36116
36423
|
async function decodeImage(input, imageType) {
|
|
36117
36424
|
if (runningInBrowser()) {
|
|
36118
36425
|
return decodeImageInBrowser(input.content, imageType);
|
|
@@ -40708,7 +41015,7 @@ ${svg}
|
|
|
40708
41015
|
if (!opts.debug_points) {
|
|
40709
41016
|
dissolveBufferDataset2(dataset2, opts);
|
|
40710
41017
|
}
|
|
40711
|
-
timeEnd('buffer');
|
|
41018
|
+
timeEnd$1('buffer');
|
|
40712
41019
|
return dataset2;
|
|
40713
41020
|
}
|
|
40714
41021
|
|
|
@@ -50715,6 +51022,581 @@ ${svg}
|
|
|
50715
51022
|
getUtmParams: getUtmParams
|
|
50716
51023
|
});
|
|
50717
51024
|
|
|
51025
|
+
var DEFAULT_MESH_INTERVAL = 32;
|
|
51026
|
+
var DEFAULT_MAX_EDGE_FACTOR = 20;
|
|
51027
|
+
|
|
51028
|
+
function projectRasterGridForward(raster, srcCRS, destCRS, optsArg) {
|
|
51029
|
+
var opts = optsArg || {};
|
|
51030
|
+
var grid = getRasterGrid(raster);
|
|
51031
|
+
var interval = opts.raster_mesh_interval || opts.rasterMeshInterval || DEFAULT_MESH_INTERVAL;
|
|
51032
|
+
var transform = getProjTransform2(srcCRS, destCRS);
|
|
51033
|
+
var timing = opts.timing;
|
|
51034
|
+
var mesh, bbox, outSize, outGrid;
|
|
51035
|
+
validateRasterGridForProjection(grid);
|
|
51036
|
+
timeStart(timing, 'mesh');
|
|
51037
|
+
mesh = buildProjectedRasterMesh(grid, transform, interval);
|
|
51038
|
+
classifyProjectedMeshCells(mesh, opts);
|
|
51039
|
+
timeEnd(timing, 'mesh');
|
|
51040
|
+
bbox = opts.output_bbox || opts.outputBbox || getProjectedMeshBBox(mesh);
|
|
51041
|
+
if (!bbox) stop$1('Unable to project raster layer');
|
|
51042
|
+
outSize = getOutputGridSize(grid, bbox, opts);
|
|
51043
|
+
outGrid = createProjectedRasterGrid(grid, bbox, outSize.width, outSize.height, opts);
|
|
51044
|
+
timeStart(timing, 'rasterize');
|
|
51045
|
+
rasterizeProjectedMesh(grid, outGrid, mesh, getRasterProjectionSampleMethod(raster, opts));
|
|
51046
|
+
timeEnd(timing, 'rasterize');
|
|
51047
|
+
if (timing) {
|
|
51048
|
+
timing.outputWidth = outGrid.width;
|
|
51049
|
+
timing.outputHeight = outGrid.height;
|
|
51050
|
+
timing.meshVertices = mesh.vertices.length;
|
|
51051
|
+
timing.meshCells = mesh.cells.length;
|
|
51052
|
+
timing.meshSkippedCells = mesh.skippedCellCount;
|
|
51053
|
+
}
|
|
51054
|
+
return outGrid;
|
|
51055
|
+
}
|
|
51056
|
+
|
|
51057
|
+
function getRasterProjectionSampleMethod(raster, opts) {
|
|
51058
|
+
var method = opts.resampling || opts.sample_method || opts.sampleMethod || getDefaultRasterProjectionSampleMethod(raster);
|
|
51059
|
+
if (method != 'nearest' && method != 'bilinear') {
|
|
51060
|
+
stop$1('Unsupported resampling method:', method);
|
|
51061
|
+
}
|
|
51062
|
+
return method;
|
|
51063
|
+
}
|
|
51064
|
+
|
|
51065
|
+
function getDefaultRasterProjectionSampleMethod(raster) {
|
|
51066
|
+
return rasterAppearsCategorical(raster) ? 'nearest' : 'bilinear';
|
|
51067
|
+
}
|
|
51068
|
+
|
|
51069
|
+
function rasterAppearsCategorical(raster) {
|
|
51070
|
+
var grid = getRasterGrid(raster);
|
|
51071
|
+
var recipe = raster && raster.view && raster.view.recipe || {};
|
|
51072
|
+
var derivation = raster && raster.derivation || {};
|
|
51073
|
+
return raster && raster.interpretation == 'categorical' ||
|
|
51074
|
+
grid && grid.colorModel == 'palette' ||
|
|
51075
|
+
recipe.type == 'palette' ||
|
|
51076
|
+
recipe.type == 'categorical' ||
|
|
51077
|
+
derivation.type == 'palette' ||
|
|
51078
|
+
derivation.type == 'categorical';
|
|
51079
|
+
}
|
|
51080
|
+
|
|
51081
|
+
function getProjectedRasterGridBBox(raster, srcCRS, destCRS, optsArg) {
|
|
51082
|
+
var opts = optsArg || {};
|
|
51083
|
+
var grid = getRasterGrid(raster);
|
|
51084
|
+
var interval = opts.raster_mesh_interval || opts.rasterMeshInterval || DEFAULT_MESH_INTERVAL;
|
|
51085
|
+
var transform = getProjTransform2(srcCRS, destCRS);
|
|
51086
|
+
var mesh, bbox;
|
|
51087
|
+
validateRasterGridForProjection(grid);
|
|
51088
|
+
mesh = buildProjectedRasterMesh(grid, transform, interval);
|
|
51089
|
+
classifyProjectedMeshCells(mesh, opts);
|
|
51090
|
+
bbox = getProjectedMeshBBox(mesh);
|
|
51091
|
+
return bbox;
|
|
51092
|
+
}
|
|
51093
|
+
|
|
51094
|
+
function getProjectedRasterMeshBBox(mesh, optsArg) {
|
|
51095
|
+
classifyProjectedMeshCells(mesh, optsArg || {});
|
|
51096
|
+
return getProjectedMeshBBox(mesh);
|
|
51097
|
+
}
|
|
51098
|
+
|
|
51099
|
+
function buildProjectedRasterMesh(grid, transform, interval) {
|
|
51100
|
+
var xs = getMeshStops(grid.width, interval);
|
|
51101
|
+
var ys = getMeshStops(grid.height, interval);
|
|
51102
|
+
var vertices = [];
|
|
51103
|
+
for (var y = 0; y < ys.length; y++) {
|
|
51104
|
+
for (var x = 0; x < xs.length; x++) {
|
|
51105
|
+
vertices.push(projectRasterMeshVertex(grid, xs[x], ys[y], transform));
|
|
51106
|
+
}
|
|
51107
|
+
}
|
|
51108
|
+
return {
|
|
51109
|
+
xs: xs,
|
|
51110
|
+
ys: ys,
|
|
51111
|
+
vertices: vertices
|
|
51112
|
+
};
|
|
51113
|
+
}
|
|
51114
|
+
|
|
51115
|
+
function classifyProjectedMeshCells(mesh, opts) {
|
|
51116
|
+
var cols = mesh.xs.length;
|
|
51117
|
+
var cells = [];
|
|
51118
|
+
var lengths = [];
|
|
51119
|
+
var maxEdge, skipped;
|
|
51120
|
+
for (var y = 0; y < mesh.ys.length - 1; y++) {
|
|
51121
|
+
for (var x = 0; x < mesh.xs.length - 1; x++) {
|
|
51122
|
+
var cell = getMeshCell(mesh, cols, x, y);
|
|
51123
|
+
cell.maxEdge = getCellMaxEdge(cell);
|
|
51124
|
+
cells.push(cell);
|
|
51125
|
+
if (cell.valid) lengths.push(cell.maxEdge);
|
|
51126
|
+
}
|
|
51127
|
+
}
|
|
51128
|
+
maxEdge = getProjectedMeshMaxEdge(lengths, opts);
|
|
51129
|
+
skipped = 0;
|
|
51130
|
+
cells.forEach(function(cell) {
|
|
51131
|
+
if (!cell.valid || cell.maxEdge > maxEdge) {
|
|
51132
|
+
cell.valid = false;
|
|
51133
|
+
skipped++;
|
|
51134
|
+
}
|
|
51135
|
+
});
|
|
51136
|
+
if (opts.raster_component_filter || opts.rasterComponentFilter) {
|
|
51137
|
+
skipped += keepLargestValidCellComponent(cells, mesh.xs.length - 1, mesh.ys.length - 1);
|
|
51138
|
+
}
|
|
51139
|
+
mesh.cells = cells;
|
|
51140
|
+
mesh.maxEdge = maxEdge;
|
|
51141
|
+
mesh.skippedCellCount = skipped;
|
|
51142
|
+
}
|
|
51143
|
+
|
|
51144
|
+
function keepLargestValidCellComponent(cells, cols, rows) {
|
|
51145
|
+
var componentIds = new Int32Array(cells.length);
|
|
51146
|
+
var components = [];
|
|
51147
|
+
var componentId = 0;
|
|
51148
|
+
var largestId = -1;
|
|
51149
|
+
var largestSize = 0;
|
|
51150
|
+
var skipped = 0;
|
|
51151
|
+
componentIds.fill(-1);
|
|
51152
|
+
for (var i = 0; i < cells.length; i++) {
|
|
51153
|
+
if (!cells[i].valid || componentIds[i] != -1) continue;
|
|
51154
|
+
components[componentId] = floodFillCellComponent(cells, componentIds, cols, rows, i, componentId);
|
|
51155
|
+
if (components[componentId].size > largestSize) {
|
|
51156
|
+
largestSize = components[componentId].size;
|
|
51157
|
+
largestId = componentId;
|
|
51158
|
+
}
|
|
51159
|
+
componentId++;
|
|
51160
|
+
}
|
|
51161
|
+
if (largestId == -1) return 0;
|
|
51162
|
+
cells.forEach(function(cell, i) {
|
|
51163
|
+
if (cell.valid && !componentShouldBeKept(components[componentIds[i]], components[largestId])) {
|
|
51164
|
+
cell.valid = false;
|
|
51165
|
+
skipped++;
|
|
51166
|
+
}
|
|
51167
|
+
});
|
|
51168
|
+
return skipped;
|
|
51169
|
+
}
|
|
51170
|
+
|
|
51171
|
+
function floodFillCellComponent(cells, componentIds, cols, rows, start, componentId) {
|
|
51172
|
+
var stack = [start];
|
|
51173
|
+
var component = {
|
|
51174
|
+
size: 0,
|
|
51175
|
+
bbox: [Infinity, Infinity, -Infinity, -Infinity]
|
|
51176
|
+
};
|
|
51177
|
+
while (stack.length > 0) {
|
|
51178
|
+
var id = stack.pop();
|
|
51179
|
+
var x, y;
|
|
51180
|
+
if (!cells[id].valid || componentIds[id] != -1) continue;
|
|
51181
|
+
componentIds[id] = componentId;
|
|
51182
|
+
component.size++;
|
|
51183
|
+
expandComponentBBox(component, cells[id]);
|
|
51184
|
+
x = id % cols;
|
|
51185
|
+
y = Math.floor(id / cols);
|
|
51186
|
+
if (x > 0) stack.push(id - 1);
|
|
51187
|
+
if (x < cols - 1) stack.push(id + 1);
|
|
51188
|
+
if (y > 0) stack.push(id - cols);
|
|
51189
|
+
if (y < rows - 1) stack.push(id + cols);
|
|
51190
|
+
}
|
|
51191
|
+
return component;
|
|
51192
|
+
}
|
|
51193
|
+
|
|
51194
|
+
function componentShouldBeKept(component, mainComponent) {
|
|
51195
|
+
if (component == mainComponent) return true;
|
|
51196
|
+
// A valid antimeridian split can create multiple disconnected source-grid
|
|
51197
|
+
// components whose projected bboxes overlap. Remote components are more
|
|
51198
|
+
// likely to be projection discontinuities that would create spiky triangles.
|
|
51199
|
+
return bboxesOverlap(component.bbox, mainComponent.bbox);
|
|
51200
|
+
}
|
|
51201
|
+
|
|
51202
|
+
function expandComponentBBox(component, cell) {
|
|
51203
|
+
[cell.v00, cell.v10, cell.v01, cell.v11].forEach(function(p) {
|
|
51204
|
+
if (p.x < component.bbox[0]) component.bbox[0] = p.x;
|
|
51205
|
+
if (p.y < component.bbox[1]) component.bbox[1] = p.y;
|
|
51206
|
+
if (p.x > component.bbox[2]) component.bbox[2] = p.x;
|
|
51207
|
+
if (p.y > component.bbox[3]) component.bbox[3] = p.y;
|
|
51208
|
+
});
|
|
51209
|
+
}
|
|
51210
|
+
|
|
51211
|
+
function bboxesOverlap(a, b) {
|
|
51212
|
+
return a[0] <= b[2] && a[2] >= b[0] && a[1] <= b[3] && a[3] >= b[1];
|
|
51213
|
+
}
|
|
51214
|
+
|
|
51215
|
+
function getMeshCell(mesh, cols, x, y) {
|
|
51216
|
+
var v = y * cols + x;
|
|
51217
|
+
var v00 = mesh.vertices[v];
|
|
51218
|
+
var v10 = mesh.vertices[v + 1];
|
|
51219
|
+
var v01 = mesh.vertices[v + cols];
|
|
51220
|
+
var v11 = mesh.vertices[v + cols + 1];
|
|
51221
|
+
return {
|
|
51222
|
+
v00: v00,
|
|
51223
|
+
v10: v10,
|
|
51224
|
+
v01: v01,
|
|
51225
|
+
v11: v11,
|
|
51226
|
+
valid: vertexIsValid(v00) && vertexIsValid(v10) && vertexIsValid(v01) && vertexIsValid(v11)
|
|
51227
|
+
};
|
|
51228
|
+
}
|
|
51229
|
+
|
|
51230
|
+
function getCellMaxEdge(cell) {
|
|
51231
|
+
if (!cell.valid) return Infinity;
|
|
51232
|
+
return Math.max(
|
|
51233
|
+
getProjectedEdgeLength(cell.v00, cell.v10),
|
|
51234
|
+
getProjectedEdgeLength(cell.v10, cell.v11),
|
|
51235
|
+
getProjectedEdgeLength(cell.v11, cell.v01),
|
|
51236
|
+
getProjectedEdgeLength(cell.v01, cell.v00)
|
|
51237
|
+
);
|
|
51238
|
+
}
|
|
51239
|
+
|
|
51240
|
+
function getProjectedEdgeLength(a, b) {
|
|
51241
|
+
var dx = a.x - b.x;
|
|
51242
|
+
var dy = a.y - b.y;
|
|
51243
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
51244
|
+
}
|
|
51245
|
+
|
|
51246
|
+
function getProjectedMeshMaxEdge(lengths, opts) {
|
|
51247
|
+
var factor = opts.raster_max_edge_factor || opts.rasterMaxEdgeFactor || DEFAULT_MAX_EDGE_FACTOR;
|
|
51248
|
+
if (lengths.length === 0) return 0;
|
|
51249
|
+
lengths.sort(function(a, b) { return a - b; });
|
|
51250
|
+
return lengths[Math.floor(lengths.length / 2)] * factor;
|
|
51251
|
+
}
|
|
51252
|
+
|
|
51253
|
+
function validateRasterGridForProjection(grid) {
|
|
51254
|
+
var t = grid && grid.transform;
|
|
51255
|
+
if (!grid || !grid.samples || !grid.bbox) stop$1('Raster layer is missing required projection data');
|
|
51256
|
+
if (t && (t[1] !== 0 || t[3] !== 0)) {
|
|
51257
|
+
stop$1('Raster reprojection does not support rotated or skewed rasters');
|
|
51258
|
+
}
|
|
51259
|
+
}
|
|
51260
|
+
|
|
51261
|
+
function getMeshStops(size, interval) {
|
|
51262
|
+
var stops = [];
|
|
51263
|
+
var i;
|
|
51264
|
+
interval = Math.max(1, interval | 0);
|
|
51265
|
+
for (i = 0; i < size; i += interval) {
|
|
51266
|
+
stops.push(i);
|
|
51267
|
+
}
|
|
51268
|
+
if (stops[stops.length - 1] != size) stops.push(size);
|
|
51269
|
+
return stops;
|
|
51270
|
+
}
|
|
51271
|
+
|
|
51272
|
+
function projectRasterMeshVertex(grid, px, py, transform) {
|
|
51273
|
+
var xy = rasterPixelToMapXY(grid, px, py);
|
|
51274
|
+
var p = transform(xy[0], xy[1]);
|
|
51275
|
+
return {
|
|
51276
|
+
sx: px,
|
|
51277
|
+
sy: py,
|
|
51278
|
+
x: p && isFinite(p[0]) ? p[0] : NaN,
|
|
51279
|
+
y: p && isFinite(p[1]) ? p[1] : NaN
|
|
51280
|
+
};
|
|
51281
|
+
}
|
|
51282
|
+
|
|
51283
|
+
function rasterPixelToMapXY(grid, px, py) {
|
|
51284
|
+
var t = grid.transform;
|
|
51285
|
+
var bbox = grid.bbox;
|
|
51286
|
+
if (t) {
|
|
51287
|
+
return [
|
|
51288
|
+
t[0] * px + t[1] * py + t[2],
|
|
51289
|
+
t[3] * px + t[4] * py + t[5]
|
|
51290
|
+
];
|
|
51291
|
+
}
|
|
51292
|
+
return [
|
|
51293
|
+
bbox[0] + px / grid.width * (bbox[2] - bbox[0]),
|
|
51294
|
+
bbox[3] - py / grid.height * (bbox[3] - bbox[1])
|
|
51295
|
+
];
|
|
51296
|
+
}
|
|
51297
|
+
|
|
51298
|
+
function getProjectedMeshBBox(mesh) {
|
|
51299
|
+
var xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity;
|
|
51300
|
+
mesh.cells.forEach(function(cell) {
|
|
51301
|
+
if (!cell.valid) return;
|
|
51302
|
+
[cell.v00, cell.v10, cell.v01, cell.v11].forEach(function(p) {
|
|
51303
|
+
if (p.x < xmin) xmin = p.x;
|
|
51304
|
+
if (p.x > xmax) xmax = p.x;
|
|
51305
|
+
if (p.y < ymin) ymin = p.y;
|
|
51306
|
+
if (p.y > ymax) ymax = p.y;
|
|
51307
|
+
});
|
|
51308
|
+
});
|
|
51309
|
+
return xmin < Infinity && xmax > xmin && ymax > ymin ? [xmin, ymin, xmax, ymax] : null;
|
|
51310
|
+
}
|
|
51311
|
+
|
|
51312
|
+
function createProjectedRasterGrid(grid, bbox, widthArg, heightArg, opts) {
|
|
51313
|
+
var width = widthArg || grid.width;
|
|
51314
|
+
var height = heightArg || grid.height;
|
|
51315
|
+
var bands = getOutputBandCount(grid, opts);
|
|
51316
|
+
var samples = new grid.samples.constructor(width * height * bands);
|
|
51317
|
+
var coverage = new Uint8Array(width * height);
|
|
51318
|
+
fillProjectedRasterSamples(samples, bands, grid, opts || {});
|
|
51319
|
+
return Object.assign({}, grid, {
|
|
51320
|
+
width: width,
|
|
51321
|
+
height: height,
|
|
51322
|
+
bands: bands,
|
|
51323
|
+
samples: samples,
|
|
51324
|
+
coverage: coverage,
|
|
51325
|
+
bbox: bbox,
|
|
51326
|
+
transform: [
|
|
51327
|
+
(bbox[2] - bbox[0]) / width,
|
|
51328
|
+
0,
|
|
51329
|
+
bbox[0],
|
|
51330
|
+
0,
|
|
51331
|
+
-(bbox[3] - bbox[1]) / height,
|
|
51332
|
+
bbox[3]
|
|
51333
|
+
]
|
|
51334
|
+
});
|
|
51335
|
+
}
|
|
51336
|
+
|
|
51337
|
+
function getOutputGridSize(grid, bbox, opts) {
|
|
51338
|
+
var width = opts.output_width || opts.outputWidth;
|
|
51339
|
+
var height = opts.output_height || opts.outputHeight;
|
|
51340
|
+
var pixels, aspect;
|
|
51341
|
+
if (width || height) {
|
|
51342
|
+
return {
|
|
51343
|
+
width: width || Math.max(1, Math.round(grid.width * height / grid.height)),
|
|
51344
|
+
height: height || Math.max(1, Math.round(grid.height * width / grid.width))
|
|
51345
|
+
};
|
|
51346
|
+
}
|
|
51347
|
+
pixels = grid.width * grid.height;
|
|
51348
|
+
aspect = (bbox[2] - bbox[0]) / (bbox[3] - bbox[1]);
|
|
51349
|
+
if (!isFinite(aspect) || aspect <= 0) return {width: grid.width, height: grid.height};
|
|
51350
|
+
width = Math.max(1, Math.round(Math.sqrt(pixels * aspect)));
|
|
51351
|
+
height = Math.max(1, Math.round(pixels / width));
|
|
51352
|
+
return {width: width, height: height};
|
|
51353
|
+
}
|
|
51354
|
+
|
|
51355
|
+
function getOutputBandCount(grid, opts) {
|
|
51356
|
+
var color = getNoDataColor(opts);
|
|
51357
|
+
return color && color.a === 0 && grid.bands > 1 && grid.bands < 4 ? 4 : grid.bands;
|
|
51358
|
+
}
|
|
51359
|
+
|
|
51360
|
+
function fillProjectedRasterSamples(samples, bands, grid, opts) {
|
|
51361
|
+
var color = getNoDataColor(opts);
|
|
51362
|
+
var noData = grid.nodata;
|
|
51363
|
+
if (color) {
|
|
51364
|
+
fillProjectedRasterColor(samples, bands, color);
|
|
51365
|
+
return;
|
|
51366
|
+
}
|
|
51367
|
+
if (noData === null || noData === undefined || !isFinite(noData)) return;
|
|
51368
|
+
samples.fill(noData);
|
|
51369
|
+
}
|
|
51370
|
+
|
|
51371
|
+
function getNoDataColor(opts) {
|
|
51372
|
+
var arg = opts.nodata_color || opts.nodataColor;
|
|
51373
|
+
var color;
|
|
51374
|
+
if (arg == null || arg === '') return null;
|
|
51375
|
+
if (String(arg).toLowerCase() == 'transparent') {
|
|
51376
|
+
return {r: 0, g: 0, b: 0, a: 0};
|
|
51377
|
+
}
|
|
51378
|
+
color = parseColor(arg);
|
|
51379
|
+
if (!color) stop$1('Unsupported nodata-color:', arg);
|
|
51380
|
+
return color;
|
|
51381
|
+
}
|
|
51382
|
+
|
|
51383
|
+
function fillProjectedRasterColor(samples, bands, color) {
|
|
51384
|
+
var gray = Math.round(0.299 * color.r + 0.587 * color.g + 0.114 * color.b);
|
|
51385
|
+
var alpha = Math.round((color.a == null ? 1 : color.a) * 255);
|
|
51386
|
+
for (var i = 0; i < samples.length; i += bands) {
|
|
51387
|
+
if (bands == 1) {
|
|
51388
|
+
samples[i] = gray;
|
|
51389
|
+
} else {
|
|
51390
|
+
samples[i] = color.r;
|
|
51391
|
+
samples[i + 1] = color.g;
|
|
51392
|
+
samples[i + 2] = color.b;
|
|
51393
|
+
if (bands > 3) samples[i + 3] = alpha;
|
|
51394
|
+
}
|
|
51395
|
+
}
|
|
51396
|
+
}
|
|
51397
|
+
|
|
51398
|
+
function rasterizeProjectedMesh(srcGrid, destGrid, mesh, sampleMethod) {
|
|
51399
|
+
mesh.cells.forEach(function(cell) {
|
|
51400
|
+
if (!cell.valid) return;
|
|
51401
|
+
rasterizeProjectedTriangle(srcGrid, destGrid, cell.v00, cell.v10, cell.v11, sampleMethod);
|
|
51402
|
+
rasterizeProjectedTriangle(srcGrid, destGrid, cell.v00, cell.v11, cell.v01, sampleMethod);
|
|
51403
|
+
});
|
|
51404
|
+
}
|
|
51405
|
+
|
|
51406
|
+
function rasterizeProjectedTriangle(srcGrid, destGrid, a, b, c, sampleMethod) {
|
|
51407
|
+
var bbox, x0, x1, y0, y1, det, w1, w2, w3, sx, sy, ap, bp, cp;
|
|
51408
|
+
if (!vertexIsValid(a) || !vertexIsValid(b) || !vertexIsValid(c)) return;
|
|
51409
|
+
ap = vertexToDestPixel(destGrid, a);
|
|
51410
|
+
bp = vertexToDestPixel(destGrid, b);
|
|
51411
|
+
cp = vertexToDestPixel(destGrid, c);
|
|
51412
|
+
det = triangleDet(ap, bp, cp);
|
|
51413
|
+
if (det === 0) return;
|
|
51414
|
+
bbox = getTrianglePixelBounds(destGrid, ap, bp, cp);
|
|
51415
|
+
x0 = bbox[0]; y0 = bbox[1]; x1 = bbox[2]; y1 = bbox[3];
|
|
51416
|
+
for (var y = y0; y <= y1; y++) {
|
|
51417
|
+
for (var x = x0; x <= x1; x++) {
|
|
51418
|
+
w1 = edgeFunction(bp, cp, x + 0.5, y + 0.5) / det;
|
|
51419
|
+
w2 = edgeFunction(cp, ap, x + 0.5, y + 0.5) / det;
|
|
51420
|
+
w3 = 1 - w1 - w2;
|
|
51421
|
+
if (w1 < -1e-9 || w2 < -1e-9 || w3 < -1e-9) continue;
|
|
51422
|
+
sx = w1 * a.sx + w2 * b.sx + w3 * c.sx;
|
|
51423
|
+
sy = w1 * a.sy + w2 * b.sy + w3 * c.sy;
|
|
51424
|
+
copyRasterSample(srcGrid, destGrid, sx, sy, x, y, sampleMethod);
|
|
51425
|
+
}
|
|
51426
|
+
}
|
|
51427
|
+
}
|
|
51428
|
+
|
|
51429
|
+
function vertexToDestPixel(grid, vertex) {
|
|
51430
|
+
var p = mapXYToRasterPixel(grid, vertex.x, vertex.y);
|
|
51431
|
+
return {
|
|
51432
|
+
x: p[0],
|
|
51433
|
+
y: p[1],
|
|
51434
|
+
sx: vertex.sx,
|
|
51435
|
+
sy: vertex.sy
|
|
51436
|
+
};
|
|
51437
|
+
}
|
|
51438
|
+
|
|
51439
|
+
function getTrianglePixelBounds(grid, p1, p2, p3) {
|
|
51440
|
+
return [
|
|
51441
|
+
clamp(Math.floor(Math.min(p1.x, p2.x, p3.x)), 0, grid.width - 1),
|
|
51442
|
+
clamp(Math.floor(Math.min(p1.y, p2.y, p3.y)), 0, grid.height - 1),
|
|
51443
|
+
clamp(Math.ceil(Math.max(p1.x, p2.x, p3.x)), 0, grid.width - 1),
|
|
51444
|
+
clamp(Math.ceil(Math.max(p1.y, p2.y, p3.y)), 0, grid.height - 1)
|
|
51445
|
+
];
|
|
51446
|
+
}
|
|
51447
|
+
|
|
51448
|
+
function mapXYToRasterPixel(grid, x, y) {
|
|
51449
|
+
var bbox = grid.bbox;
|
|
51450
|
+
return [
|
|
51451
|
+
(x - bbox[0]) / (bbox[2] - bbox[0]) * grid.width,
|
|
51452
|
+
(bbox[3] - y) / (bbox[3] - bbox[1]) * grid.height
|
|
51453
|
+
];
|
|
51454
|
+
}
|
|
51455
|
+
|
|
51456
|
+
function copyRasterSample(srcGrid, destGrid, sx, sy, dx, dy, sampleMethod) {
|
|
51457
|
+
if (sampleMethod == 'bilinear') {
|
|
51458
|
+
copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
51459
|
+
} else {
|
|
51460
|
+
copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy);
|
|
51461
|
+
}
|
|
51462
|
+
}
|
|
51463
|
+
|
|
51464
|
+
function copyNearestRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
51465
|
+
var srcX = clamp(Math.floor(sx), 0, srcGrid.width - 1);
|
|
51466
|
+
var srcY = clamp(Math.floor(sy), 0, srcGrid.height - 1);
|
|
51467
|
+
var src = (srcY * srcGrid.width + srcX) * srcGrid.bands;
|
|
51468
|
+
var dest = (dy * destGrid.width + dx) * destGrid.bands;
|
|
51469
|
+
if (!rasterSourcePixelIsCovered(srcGrid, srcX, srcY)) return;
|
|
51470
|
+
for (var band = 0; band < srcGrid.bands; band++) {
|
|
51471
|
+
destGrid.samples[dest + band] = srcGrid.samples[src + band];
|
|
51472
|
+
}
|
|
51473
|
+
if (destGrid.bands > srcGrid.bands) destGrid.samples[dest + 3] = 255;
|
|
51474
|
+
if (destGrid.coverage) destGrid.coverage[dy * destGrid.width + dx] = 1;
|
|
51475
|
+
}
|
|
51476
|
+
|
|
51477
|
+
function copyBilinearRasterSample(srcGrid, destGrid, sx, sy, dx, dy) {
|
|
51478
|
+
var srcX = clamp(Math.floor(sx - 0.5), 0, srcGrid.width - 1);
|
|
51479
|
+
var srcY = clamp(Math.floor(sy - 0.5), 0, srcGrid.height - 1);
|
|
51480
|
+
var srcX2 = clamp(srcX + 1, 0, srcGrid.width - 1);
|
|
51481
|
+
var srcY2 = clamp(srcY + 1, 0, srcGrid.height - 1);
|
|
51482
|
+
var tx = clamp(sx - 0.5 - srcX, 0, 1);
|
|
51483
|
+
var ty = clamp(sy - 0.5 - srcY, 0, 1);
|
|
51484
|
+
var src00 = (srcY * srcGrid.width + srcX) * srcGrid.bands;
|
|
51485
|
+
var src10 = (srcY * srcGrid.width + srcX2) * srcGrid.bands;
|
|
51486
|
+
var src01 = (srcY2 * srcGrid.width + srcX) * srcGrid.bands;
|
|
51487
|
+
var src11 = (srcY2 * srcGrid.width + srcX2) * srcGrid.bands;
|
|
51488
|
+
var dest = (dy * destGrid.width + dx) * destGrid.bands;
|
|
51489
|
+
if (!srcGrid.coverage) {
|
|
51490
|
+
copyBilinearRasterSampleFast(srcGrid, destGrid, src00, src10, src01, src11, dest, tx, ty);
|
|
51491
|
+
if (destGrid.coverage) destGrid.coverage[dy * destGrid.width + dx] = 1;
|
|
51492
|
+
return;
|
|
51493
|
+
}
|
|
51494
|
+
if (copyBilinearRasterSampleWithCoverage(srcGrid, destGrid, srcX, srcY, srcX2, srcY2, src00, src10, src01, src11, dest, tx, ty)) {
|
|
51495
|
+
if (destGrid.coverage) destGrid.coverage[dy * destGrid.width + dx] = 1;
|
|
51496
|
+
}
|
|
51497
|
+
}
|
|
51498
|
+
|
|
51499
|
+
function copyBilinearRasterSampleFast(srcGrid, destGrid, src00, src10, src01, src11, dest, tx, ty) {
|
|
51500
|
+
if (srcGrid.bands == 3) {
|
|
51501
|
+
copyBilinearRgbSample(srcGrid.samples, destGrid.samples, src00, src10, src01, src11, dest, tx, ty);
|
|
51502
|
+
} else if (srcGrid.bands == 4) {
|
|
51503
|
+
copyBilinearRgbaSample(srcGrid.samples, destGrid.samples, src00, src10, src01, src11, dest, tx, ty);
|
|
51504
|
+
} else {
|
|
51505
|
+
copyBilinearGenericSample(srcGrid.samples, destGrid.samples, srcGrid.bands, src00, src10, src01, src11, dest, tx, ty);
|
|
51506
|
+
}
|
|
51507
|
+
if (destGrid.bands > srcGrid.bands) destGrid.samples[dest + 3] = 255;
|
|
51508
|
+
}
|
|
51509
|
+
|
|
51510
|
+
function copyBilinearRgbSample(src, destArr, src00, src10, src01, src11, dest, tx, ty) {
|
|
51511
|
+
copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, 0, tx, ty);
|
|
51512
|
+
copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, 1, tx, ty);
|
|
51513
|
+
copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, 2, tx, ty);
|
|
51514
|
+
}
|
|
51515
|
+
|
|
51516
|
+
function copyBilinearRgbaSample(src, destArr, src00, src10, src01, src11, dest, tx, ty) {
|
|
51517
|
+
copyBilinearRgbSample(src, destArr, src00, src10, src01, src11, dest, tx, ty);
|
|
51518
|
+
copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, 3, tx, ty);
|
|
51519
|
+
}
|
|
51520
|
+
|
|
51521
|
+
function copyBilinearGenericSample(src, destArr, bands, src00, src10, src01, src11, dest, tx, ty) {
|
|
51522
|
+
for (var band = 0; band < bands; band++) {
|
|
51523
|
+
copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, band, tx, ty);
|
|
51524
|
+
}
|
|
51525
|
+
}
|
|
51526
|
+
|
|
51527
|
+
function copyBilinearBand(src, destArr, src00, src10, src01, src11, dest, band, tx, ty) {
|
|
51528
|
+
var a = src[src00 + band] * (1 - tx) + src[src10 + band] * tx;
|
|
51529
|
+
var b = src[src01 + band] * (1 - tx) + src[src11 + band] * tx;
|
|
51530
|
+
destArr[dest + band] = Math.round(a * (1 - ty) + b * ty);
|
|
51531
|
+
}
|
|
51532
|
+
|
|
51533
|
+
function copyBilinearRasterSampleWithCoverage(srcGrid, destGrid, srcX, srcY, srcX2, srcY2, src00, src10, src01, src11, dest, tx, ty) {
|
|
51534
|
+
var coords = [
|
|
51535
|
+
[srcX, srcY, src00, (1 - tx) * (1 - ty)],
|
|
51536
|
+
[srcX2, srcY, src10, tx * (1 - ty)],
|
|
51537
|
+
[srcX, srcY2, src01, (1 - tx) * ty],
|
|
51538
|
+
[srcX2, srcY2, src11, tx * ty]
|
|
51539
|
+
];
|
|
51540
|
+
var total = 0;
|
|
51541
|
+
var val, item;
|
|
51542
|
+
for (var band = 0; band < srcGrid.bands; band++) {
|
|
51543
|
+
val = 0;
|
|
51544
|
+
total = 0;
|
|
51545
|
+
for (var i = 0; i < coords.length; i++) {
|
|
51546
|
+
item = coords[i];
|
|
51547
|
+
if (item[3] <= 0 || !rasterSourcePixelIsCovered(srcGrid, item[0], item[1])) continue;
|
|
51548
|
+
val += srcGrid.samples[item[2] + band] * item[3];
|
|
51549
|
+
total += item[3];
|
|
51550
|
+
}
|
|
51551
|
+
if (total <= 0) return false;
|
|
51552
|
+
destGrid.samples[dest + band] = Math.round(val / total);
|
|
51553
|
+
}
|
|
51554
|
+
if (destGrid.bands > srcGrid.bands) destGrid.samples[dest + 3] = 255;
|
|
51555
|
+
return true;
|
|
51556
|
+
}
|
|
51557
|
+
|
|
51558
|
+
function rasterSourcePixelIsCovered(grid, x, y) {
|
|
51559
|
+
return !grid.coverage || grid.coverage[y * grid.width + x] > 0;
|
|
51560
|
+
}
|
|
51561
|
+
|
|
51562
|
+
function timeStart(timing, name) {
|
|
51563
|
+
if (!timing) return;
|
|
51564
|
+
timing[name + 'Start'] = getTimer();
|
|
51565
|
+
}
|
|
51566
|
+
|
|
51567
|
+
function timeEnd(timing, name) {
|
|
51568
|
+
if (!timing) return;
|
|
51569
|
+
timing[name + 'Ms'] = getTimer() - timing[name + 'Start'];
|
|
51570
|
+
}
|
|
51571
|
+
|
|
51572
|
+
function getTimer() {
|
|
51573
|
+
return typeof performance != 'undefined' && performance.now ? performance.now() : Date.now();
|
|
51574
|
+
}
|
|
51575
|
+
|
|
51576
|
+
function vertexIsValid(p) {
|
|
51577
|
+
return p && isFinite(p.x) && isFinite(p.y);
|
|
51578
|
+
}
|
|
51579
|
+
|
|
51580
|
+
function triangleDet(a, b, c) {
|
|
51581
|
+
return edgeFunction(a, b, c.x, c.y);
|
|
51582
|
+
}
|
|
51583
|
+
|
|
51584
|
+
function edgeFunction(a, b, x, y) {
|
|
51585
|
+
return (x - a.x) * (b.y - a.y) - (y - a.y) * (b.x - a.x);
|
|
51586
|
+
}
|
|
51587
|
+
|
|
51588
|
+
function clamp(val, min, max) {
|
|
51589
|
+
return val < min ? min : val > max ? max : val;
|
|
51590
|
+
}
|
|
51591
|
+
|
|
51592
|
+
var RasterReprojection = /*#__PURE__*/Object.freeze({
|
|
51593
|
+
__proto__: null,
|
|
51594
|
+
buildProjectedRasterMesh: buildProjectedRasterMesh,
|
|
51595
|
+
getProjectedRasterGridBBox: getProjectedRasterGridBBox,
|
|
51596
|
+
getProjectedRasterMeshBBox: getProjectedRasterMeshBBox,
|
|
51597
|
+
projectRasterGridForward: projectRasterGridForward
|
|
51598
|
+
});
|
|
51599
|
+
|
|
50718
51600
|
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
50719
51601
|
var srcInfo, destInfo, destStr;
|
|
50720
51602
|
var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
|
|
@@ -50751,7 +51633,7 @@ ${svg}
|
|
|
50751
51633
|
stop$1("Missing projection data");
|
|
50752
51634
|
}
|
|
50753
51635
|
|
|
50754
|
-
if (!datasetHasGeometry(dataset)) {
|
|
51636
|
+
if (!datasetHasGeometry(dataset) && !datasetHasRaster(dataset)) {
|
|
50755
51637
|
// still set the crs of datasets that are missing geometry
|
|
50756
51638
|
setDatasetCrsInfo(dataset, destInfo);
|
|
50757
51639
|
return false;
|
|
@@ -50805,6 +51687,7 @@ ${svg}
|
|
|
50805
51687
|
return a.name != b.name ||
|
|
50806
51688
|
a.geometry_type != b.geometry_type ||
|
|
50807
51689
|
a.data !== b.data ||
|
|
51690
|
+
a.raster !== b.raster ||
|
|
50808
51691
|
!arraysAreEqual(a.shapes, b.shapes);
|
|
50809
51692
|
}
|
|
50810
51693
|
|
|
@@ -50852,6 +51735,8 @@ ${svg}
|
|
|
50852
51735
|
dataset.layers.forEach(function(lyr) {
|
|
50853
51736
|
if (layerHasPoints(lyr)) {
|
|
50854
51737
|
badPoints += projectPointLayer(lyr, proj); // v2 compatible (invalid points are removed)
|
|
51738
|
+
} else if (layerHasRaster(lyr)) {
|
|
51739
|
+
projectRasterLayer(lyr, src, dest, opts);
|
|
50855
51740
|
}
|
|
50856
51741
|
});
|
|
50857
51742
|
if (dataset.arcs) {
|
|
@@ -50877,6 +51762,18 @@ ${svg}
|
|
|
50877
51762
|
dataset.info.crs = dest;
|
|
50878
51763
|
}
|
|
50879
51764
|
|
|
51765
|
+
function projectRasterLayer(lyr, src, dest, opts) {
|
|
51766
|
+
var raster = lyr.raster;
|
|
51767
|
+
raster.grid = projectRasterGridForward(raster, src, dest, opts || {});
|
|
51768
|
+
raster.view = raster.view || {};
|
|
51769
|
+
delete raster.view.scalingStats;
|
|
51770
|
+
if (runningInBrowser()) {
|
|
51771
|
+
raster.view.preview = createRasterPreview(raster, opts || {});
|
|
51772
|
+
} else {
|
|
51773
|
+
delete raster.view.preview;
|
|
51774
|
+
}
|
|
51775
|
+
}
|
|
51776
|
+
|
|
50880
51777
|
// * Heals cuts in previously split-apart polygons
|
|
50881
51778
|
// * Removes line intersections
|
|
50882
51779
|
// * TODO: what if a layer contains polygons with desired overlaps? should
|
|
@@ -57269,7 +58166,7 @@ ${svg}
|
|
|
57269
58166
|
});
|
|
57270
58167
|
}
|
|
57271
58168
|
|
|
57272
|
-
var version = "0.7.
|
|
58169
|
+
var version = "0.7.16";
|
|
57273
58170
|
|
|
57274
58171
|
// Parse command line args into commands and run them
|
|
57275
58172
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -58798,6 +59695,7 @@ ${svg}
|
|
|
58798
59695
|
Lines,
|
|
58799
59696
|
Logging,
|
|
58800
59697
|
Profile,
|
|
59698
|
+
RasterReprojection,
|
|
58801
59699
|
RasterUtils,
|
|
58802
59700
|
Merging,
|
|
58803
59701
|
MosaicIndex$1,
|