Only clamp to source projection extent

This commit is contained in:
Andreas Hocevar
2020-07-06 22:35:34 +02:00
parent 98daf5d63f
commit a9b3a5bcc9
5 changed files with 85 additions and 61 deletions

View File

@@ -71,14 +71,7 @@ import {
clear as clearTransformFuncs,
get as getTransformFunc,
} from './proj/transforms.js';
import {
applyTransform,
getBottomLeft,
getBottomRight,
getTopLeft,
getTopRight,
getWidth,
} from './extent.js';
import {applyTransform, getWidth} from './extent.js';
import {clamp, modulo} from './math.js';
import {getDistance} from './sphere.js';
import {getWorldsAway} from './coordinate.js';
@@ -636,56 +629,35 @@ export function fromUserExtent(extent, destProjection) {
/**
* Creates a safe coordinate transform function from a coordinate transform function.
* "Safe" means that it can handle wrapping of x-coordinates for global projections,
* and that coordinates exceeding the projection validity extent's range will be
* and that coordinates exceeding the source projection validity extent's range will be
* clamped to the validity range.
* @param {Projection} sourceProj Source projection.
* @param {Projection} destProj Destination projection.
* @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} forward Transform function (source to destiation).
* @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} inverse Transform function (destiation to source).
* @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} transform Transform function (source to destiation).
* @return {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} Safe transform function (source to destiation).
*/
export function createSafeCoordinateTransform(
sourceProj,
destProj,
forward,
inverse
) {
export function createSafeCoordinateTransform(sourceProj, destProj, transform) {
return function (coord) {
let x, y, worldsAway;
let sourceX = coord[0];
let sourceY = coord[1];
let transformed, worldsAway;
if (sourceProj.canWrapX()) {
const sourceExtent = sourceProj.getExtent();
const sourceExtentWidth = getWidth(sourceExtent);
worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth);
if (worldsAway) {
// Move x to the real world
x = coord[0] - worldsAway * sourceExtentWidth;
}
}
let transformed = forward(x === undefined ? coord : [x, coord[1]]);
const destExtent = destProj.getExtent();
if (!isFinite(transformed[0]) || !isFinite(transformed[1])) {
// Try to recover from out-of-bounds transform
if (destExtent) {
const corner1 = inverse(getBottomLeft(destExtent));
const corner2 = inverse(getBottomRight(destExtent));
const corner3 = inverse(getTopLeft(destExtent));
const corner4 = inverse(getTopRight(destExtent));
const minX = Math.min(corner1[0], corner2[0], corner3[0], corner4[0]);
const maxX = Math.max(corner1[0], corner2[0], corner3[0], corner4[0]);
const minY = Math.min(corner1[1], corner2[1], corner3[1], corner4[1]);
const maxY = Math.max(corner1[1], corner2[1], corner3[1], corner4[1]);
if (isFinite(minX) && isFinite(maxX)) {
x = clamp(x == undefined ? coord[1] : x, minX, maxX);
}
if (isFinite(minY) && isFinite(maxY)) {
y = clamp(coord[1], minY, maxY);
}
transformed = forward([x, y]);
sourceX = sourceX - worldsAway * sourceExtentWidth;
}
sourceX = clamp(sourceX, sourceExtent[0], sourceExtent[2]);
sourceY = clamp(sourceY, sourceExtent[1], sourceExtent[3]);
transformed = transform([sourceX, sourceY]);
} else {
transformed = transform(coord);
}
if (worldsAway && destProj.canWrapX()) {
// Move transformed coordinate back to the offset world
transformed[0] += worldsAway * getWidth(destExtent);
transformed[0] += worldsAway * getWidth(destProj.getExtent());
}
return transformed;
};

View File

@@ -61,18 +61,8 @@ export function register(proj4) {
addCoordinateTransforms(
proj1,
proj2,
createSafeCoordinateTransform(
proj1,
proj2,
transform.forward,
transform.inverse
),
createSafeCoordinateTransform(
proj2,
proj1,
transform.inverse,
transform.forward
)
createSafeCoordinateTransform(proj1, proj2, transform.forward),
createSafeCoordinateTransform(proj2, proj1, transform.inverse)
);
}
}