Try harder to get the projection from GeoTIFF headers
This commit is contained in:
@@ -8,6 +8,11 @@
|
||||
* @enum {string}
|
||||
*/
|
||||
const Units = {
|
||||
/**
|
||||
* Radians
|
||||
* @api
|
||||
*/
|
||||
RADIANS: 'radians',
|
||||
/**
|
||||
* Degrees
|
||||
* @api
|
||||
@@ -40,6 +45,26 @@ const Units = {
|
||||
USFEET: 'us-ft',
|
||||
};
|
||||
|
||||
/**
|
||||
* See http://duff.ess.washington.edu/data/raster/drg/docs/geotiff.txt
|
||||
* @type {Object<number, Units>}
|
||||
*/
|
||||
const unitByCode = {
|
||||
'9001': Units.METERS,
|
||||
'9002': Units.FEET,
|
||||
'9003': Units.USFEET,
|
||||
'9101': Units.RADIANS,
|
||||
'9102': Units.DEGREES,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} code Unit code.
|
||||
* @return {Units} Units.
|
||||
*/
|
||||
export function fromCode(code) {
|
||||
return unitByCode[code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Meters per unit lookup table.
|
||||
* @const
|
||||
@@ -48,6 +73,7 @@ const Units = {
|
||||
*/
|
||||
export const METERS_PER_UNIT = {};
|
||||
// use the radius of the Normal sphere
|
||||
METERS_PER_UNIT[Units.RADIANS] = 6370997 / (2 * Math.PI);
|
||||
METERS_PER_UNIT[Units.DEGREES] = (2 * Math.PI * 6370997) / 360;
|
||||
METERS_PER_UNIT[Units.FEET] = 0.3048;
|
||||
METERS_PER_UNIT[Units.METERS] = 1;
|
||||
|
||||
@@ -5,10 +5,11 @@ import DataTile from './DataTile.js';
|
||||
import State from './State.js';
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff';
|
||||
import {Projection, get as getCachedProjection} from '../proj.js';
|
||||
import {create as createDecoderWorker} from '../worker/geotiff-decoder.js';
|
||||
import {getIntersection} from '../extent.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
import {toSize} from '../size.js';
|
||||
import {fromCode as unitsFromCode} from '../proj/Units.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SourceInfo
|
||||
@@ -25,10 +26,22 @@ import {toSize} from '../size.js';
|
||||
* near-infrared band, configure `bands: [4]`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GeoKeys
|
||||
* @property {number} GTModelTypeGeoKey Model type.
|
||||
* @property {number} GTRasterTypeGeoKey Raster type.
|
||||
* @property {number} GeogAngularUnitsGeoKey Angular units.
|
||||
* @property {number} GeogInvFlatteningGeoKey Inverse flattening.
|
||||
* @property {number} GeogSemiMajorAxisGeoKey Semi-major axis.
|
||||
* @property {number} GeographicTypeGeoKey Geographic coordinate system code.
|
||||
* @property {number} ProjLinearUnitsGeoKey Projected linear unit code.
|
||||
* @property {number} ProjectedCSTypeGeoKey Projected coordinate system code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GeoTIFFImage
|
||||
* @property {Object} fileDirectory The file directory.
|
||||
* @property {Object} geoKeys The parsed geo-keys.
|
||||
* @property {GeoKeys} geoKeys The parsed geo-keys.
|
||||
* @property {boolean} littleEndian Uses little endian byte order.
|
||||
* @property {Object} tiles The tile cache.
|
||||
* @property {boolean} isTiled The image is tiled.
|
||||
@@ -91,6 +104,49 @@ function getResolution(image, referenceImage) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GeoTIFFImage} image A GeoTIFF.
|
||||
* @return {import("../proj/Projection.js").default} The image projection.
|
||||
*/
|
||||
function getProjection(image) {
|
||||
const geoKeys = image.geoKeys;
|
||||
if (!geoKeys) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (geoKeys.ProjectedCSTypeGeoKey) {
|
||||
const code = 'EPSG:' + geoKeys.ProjectedCSTypeGeoKey;
|
||||
let projection = getCachedProjection(code);
|
||||
if (!projection) {
|
||||
const units = unitsFromCode(geoKeys.ProjLinearUnitsGeoKey);
|
||||
if (units) {
|
||||
projection = new Projection({
|
||||
code: code,
|
||||
units: units,
|
||||
});
|
||||
}
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
if (geoKeys.GeographicTypeGeoKey) {
|
||||
const code = 'EPSG:' + geoKeys.GeographicTypeGeoKey;
|
||||
let projection = getCachedProjection(code);
|
||||
if (!projection) {
|
||||
const units = unitsFromCode(geoKeys.GeogAngularUnitsGeoKey);
|
||||
if (units) {
|
||||
projection = new Projection({
|
||||
code: code,
|
||||
units: units,
|
||||
});
|
||||
}
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("geotiff/src/geotiff.js").GeoTIFF|import("geotiff/src/geotiff.js").MultiGeoTIFF} tiff A GeoTIFF.
|
||||
* @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
|
||||
@@ -419,17 +475,13 @@ class GeoTIFFSource extends DataTile {
|
||||
const firstSource = sources[0];
|
||||
for (let i = firstSource.length - 1; i >= 0; --i) {
|
||||
const image = firstSource[i];
|
||||
if (image.geoKeys) {
|
||||
const code =
|
||||
image.geoKeys.ProjectedCSTypeGeoKey ||
|
||||
image.geoKeys.GeographicTypeGeoKey;
|
||||
if (code) {
|
||||
this.projection = getProjection('EPSG:' + code);
|
||||
const projection = getProjection(image);
|
||||
if (projection) {
|
||||
this.projection = projection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.samplesPerPixel_ = samplesPerPixel;
|
||||
this.nodataValues_ = nodataValues;
|
||||
|
||||
@@ -2,7 +2,7 @@ import GeoTIFFSource from '../../../../../src/ol/source/GeoTIFF.js';
|
||||
import State from '../../../../../src/ol/source/State.js';
|
||||
import TileState from '../../../../../src/ol/TileState.js';
|
||||
|
||||
describe('ol.source.GeoTIFF', function () {
|
||||
describe('ol/source/GeoTIFF', function () {
|
||||
/** @type {GeoTIFFSource} */
|
||||
let source;
|
||||
beforeEach(function () {
|
||||
@@ -30,6 +30,7 @@ describe('ol.source.GeoTIFF', function () {
|
||||
expect(source.nodataValues_).to.eql([[0]]);
|
||||
expect(source.getTileGrid().getResolutions().length).to.be(1);
|
||||
expect(source.projection.getCode()).to.be('EPSG:4326');
|
||||
expect(source.projection.getUnits()).to.be('degrees');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user