wkt-parser
Version:
wkt-parser ===
278 lines (254 loc) • 9.31 kB
JavaScript
import { applyProjectionDefaults } from './util.js';
// Helper function to process units and to_meter
function processUnit(unit) {
let result = { units: null, to_meter: undefined };
if (typeof unit === 'string') {
result.units = unit.toLowerCase();
if (result.units === 'metre') {
result.units = 'meter'; // Normalize 'metre' to 'meter'
}
if (result.units === 'meter') {
result.to_meter = 1; // Only set to_meter if units are 'meter'
}
} else if (unit && unit.name) {
result.units = unit.name.toLowerCase();
if (result.units === 'metre') {
result.units = 'meter'; // Normalize 'metre' to 'meter'
}
result.to_meter = unit.conversion_factor;
}
return result;
}
function toValue(valueOrObject) {
if (typeof valueOrObject === 'object') {
return valueOrObject.value * valueOrObject.unit.conversion_factor;
}
return valueOrObject;
}
function calculateEllipsoid(value, result) {
if (value.ellipsoid.radius) {
result.a = value.ellipsoid.radius;
result.rf = 0;
} else {
result.a = toValue(value.ellipsoid.semi_major_axis);
if (value.ellipsoid.inverse_flattening !== undefined) {
result.rf = value.ellipsoid.inverse_flattening;
} else if (value.ellipsoid.semi_major_axis !== undefined && value.ellipsoid.semi_minor_axis !== undefined) {
result.rf = result.a / (result.a - toValue(value.ellipsoid.semi_minor_axis));
}
}
}
export function transformPROJJSON(projjson, result = {}) {
if (!projjson || typeof projjson !== 'object') {
return projjson; // Return primitive values as-is
}
if (projjson.type === 'BoundCRS') {
transformPROJJSON(projjson.source_crs, result);
if (projjson.transformation) {
if (projjson.transformation.method && projjson.transformation.method.name === 'NTv2') {
// Set nadgrids to the filename from the parameterfile
result.nadgrids = projjson.transformation.parameters[0].value;
} else {
// Populate datum_params if no parameterfile is found
result.datum_params = projjson.transformation.parameters.map((param) => param.value);
}
}
return result; // Return early for BoundCRS
}
// Handle specific keys in PROJJSON
Object.keys(projjson).forEach((key) => {
const value = projjson[key];
if (value === null) {
return;
}
switch (key) {
case 'name':
if (result.srsCode) {
break;
}
result.name = value;
result.srsCode = value; // Map `name` to `srsCode`
break;
case 'type':
if (value === 'GeographicCRS') {
result.projName = 'longlat';
} else if (value === 'GeodeticCRS') {
if (projjson.coordinate_system && projjson.coordinate_system.subtype === 'Cartesian') {
result.projName = 'geocent';
} else {
result.projName = 'longlat';
}
} else if (value === 'ProjectedCRS' && projjson.conversion && projjson.conversion.method) {
result.projName = projjson.conversion.method.name; // Retain original capitalization
}
break;
case 'datum':
case 'datum_ensemble': // Handle both datum and ensemble
if (value.ellipsoid) {
// Extract ellipsoid properties
result.ellps = value.ellipsoid.name;
calculateEllipsoid(value, result);
}
if (value.prime_meridian) {
result.from_greenwich = value.prime_meridian.longitude * Math.PI / 180; // Convert to radians
}
break;
case 'ellipsoid':
result.ellps = value.name;
calculateEllipsoid(value, result);
break;
case 'prime_meridian':
result.long0 = (value.longitude || 0) * Math.PI / 180; // Convert to radians
break;
case 'coordinate_system':
if (value.axis) {
const directionMap = {
'east': 'e',
'north': 'n',
'west': 'w',
'south': 's',
'up': 'u',
'down': 'd',
'geocentricx': 'e',
'geocentricy': 'n',
'geocentricz': 'u',
};
const mapped = value.axis.map((axis) => directionMap[axis.direction.toLowerCase()]);
if (mapped.every(Boolean)) {
result.axis = mapped.join('');
if (result.axis.length === 2) {
result.axis += 'u';
}
}
if (value.unit) {
const { units, to_meter } = processUnit(value.unit);
result.units = units;
result.to_meter = to_meter;
} else if (value.axis[0] && value.axis[0].unit) {
const { units, to_meter } = processUnit(value.axis[0].unit);
result.units = units;
result.to_meter = to_meter;
}
}
break;
case 'id':
if (value.authority && value.code) {
result.title = value.authority + ':' + value.code;
}
break;
case 'conversion':
if (value.method && value.method.name) {
result.projName = value.method.name; // Retain original capitalization
}
if (value.parameters) {
value.parameters.forEach((param) => {
const paramName = param.name.toLowerCase().replace(/\s+/g, '_');
const paramValue = param.value;
if (param.unit && param.unit.conversion_factor) {
result[paramName] = paramValue * param.unit.conversion_factor; // Convert to radians or meters
} else if (param.unit === 'degree') {
result[paramName] = paramValue * Math.PI / 180; // Convert to radians
} else {
result[paramName] = paramValue;
}
});
}
break;
case 'unit':
if (value.name) {
result.units = value.name.toLowerCase();
if (result.units === 'metre') {
result.units = 'meter';
}
}
if (value.conversion_factor) {
result.to_meter = value.conversion_factor;
}
break;
case 'base_crs':
transformPROJJSON(value, result); // Pass `result` directly
result.datumCode = value.id ? value.id.authority + '_' + value.id.code : value.name; // Set datumCode
break;
default:
// Ignore irrelevant or unneeded properties
break;
}
});
// Additional calculated properties
if (result.latitude_of_false_origin !== undefined) {
result.lat0 = result.latitude_of_false_origin; // Already in radians
}
if (result.longitude_of_false_origin !== undefined) {
result.long0 = result.longitude_of_false_origin;
}
if (result.latitude_of_standard_parallel !== undefined) {
result.lat0 = result.latitude_of_standard_parallel;
result.lat1 = result.latitude_of_standard_parallel;
}
if (result.latitude_of_1st_standard_parallel !== undefined) {
result.lat1 = result.latitude_of_1st_standard_parallel;
}
if (result.latitude_of_2nd_standard_parallel !== undefined) {
result.lat2 = result.latitude_of_2nd_standard_parallel;
}
if (result.latitude_of_projection_centre !== undefined) {
result.lat0 = result.latitude_of_projection_centre;
}
if (result.longitude_of_projection_centre !== undefined) {
result.longc = result.longitude_of_projection_centre;
}
if (result.easting_at_false_origin !== undefined) {
result.x0 = result.easting_at_false_origin;
}
if (result.northing_at_false_origin !== undefined) {
result.y0 = result.northing_at_false_origin;
}
if (result.latitude_of_natural_origin !== undefined) {
result.lat0 = result.latitude_of_natural_origin;
}
if (result.longitude_of_natural_origin !== undefined) {
result.long0 = result.longitude_of_natural_origin;
}
if (result.longitude_of_origin !== undefined) {
result.long0 = result.longitude_of_origin;
}
if (result.false_easting !== undefined) {
result.x0 = result.false_easting;
}
if (result.easting_at_projection_centre) {
result.x0 = result.easting_at_projection_centre;
}
if (result.false_northing !== undefined) {
result.y0 = result.false_northing;
}
if (result.northing_at_projection_centre) {
result.y0 = result.northing_at_projection_centre;
}
if (result.standard_parallel_1 !== undefined) {
result.lat1 = result.standard_parallel_1;
}
if (result.standard_parallel_2 !== undefined) {
result.lat2 = result.standard_parallel_2;
}
if (result.scale_factor_at_natural_origin !== undefined) {
result.k0 = result.scale_factor_at_natural_origin;
}
if (result.scale_factor_at_projection_centre !== undefined) {
result.k0 = result.scale_factor_at_projection_centre;
}
if (result.scale_factor_on_pseudo_standard_parallel !== undefined) {
result.k0 = result.scale_factor_on_pseudo_standard_parallel;
}
if (result.azimuth !== undefined) {
result.alpha = result.azimuth;
}
if (result.azimuth_at_projection_centre !== undefined) {
result.alpha = result.azimuth_at_projection_centre;
}
if (result.angle_from_rectified_to_skew_grid) {
result.rectified_grid_angle = result.angle_from_rectified_to_skew_grid;
}
// Apply projection defaults
applyProjectionDefaults(result);
return result;
}