Only clamp to source projection extent
This commit is contained in:
BIN
rendering/cases/reproj-azimuthal-equal-area/expected.png
Normal file
BIN
rendering/cases/reproj-azimuthal-equal-area/expected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
57
rendering/cases/reproj-azimuthal-equal-area/main.js
Normal file
57
rendering/cases/reproj-azimuthal-equal-area/main.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import ImageCanvas from '../../../src/ol/source/ImageCanvas.js';
|
||||||
|
import ImageLayer from '../../../src/ol/layer/Image.js';
|
||||||
|
import Map from '../../../src/ol/Map.js';
|
||||||
|
import View from '../../../src/ol/View.js';
|
||||||
|
import proj4 from 'proj4';
|
||||||
|
import {get as getProjection, transform} from '../../../src/ol/proj.js';
|
||||||
|
import {register} from '../../../src/ol/proj/proj4.js';
|
||||||
|
|
||||||
|
const llpos = [-72, 40];
|
||||||
|
|
||||||
|
proj4.defs(
|
||||||
|
'az',
|
||||||
|
'+proj=aeqd +lat_0=' +
|
||||||
|
llpos[1] +
|
||||||
|
' +lon_0=' +
|
||||||
|
llpos[0] +
|
||||||
|
' +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m'
|
||||||
|
);
|
||||||
|
register(proj4);
|
||||||
|
const aeqd = getProjection('az');
|
||||||
|
|
||||||
|
function canvasFunction(extent, resolution, pixelRatio, size) {
|
||||||
|
size = [Math.round(size[0]), Math.round(size[1])];
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = size[0];
|
||||||
|
canvas.height = size[1];
|
||||||
|
|
||||||
|
// fill the canvas with blue
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.fillStyle = 'blue';
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvasLayer = new ImageLayer({
|
||||||
|
source: new ImageCanvas({
|
||||||
|
projection: 'EPSG:4326',
|
||||||
|
canvasFunction: canvasFunction,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const center = transform(llpos, 'EPSG:4326', aeqd);
|
||||||
|
|
||||||
|
new Map({
|
||||||
|
pixelRatio: 1,
|
||||||
|
target: 'map',
|
||||||
|
layers: [canvasLayer],
|
||||||
|
view: new View({
|
||||||
|
center: center,
|
||||||
|
projection: aeqd,
|
||||||
|
zoom: 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
render({
|
||||||
|
tolerance: 0.001,
|
||||||
|
});
|
||||||
@@ -71,14 +71,7 @@ import {
|
|||||||
clear as clearTransformFuncs,
|
clear as clearTransformFuncs,
|
||||||
get as getTransformFunc,
|
get as getTransformFunc,
|
||||||
} from './proj/transforms.js';
|
} from './proj/transforms.js';
|
||||||
import {
|
import {applyTransform, getWidth} from './extent.js';
|
||||||
applyTransform,
|
|
||||||
getBottomLeft,
|
|
||||||
getBottomRight,
|
|
||||||
getTopLeft,
|
|
||||||
getTopRight,
|
|
||||||
getWidth,
|
|
||||||
} from './extent.js';
|
|
||||||
import {clamp, modulo} from './math.js';
|
import {clamp, modulo} from './math.js';
|
||||||
import {getDistance} from './sphere.js';
|
import {getDistance} from './sphere.js';
|
||||||
import {getWorldsAway} from './coordinate.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.
|
* Creates a safe coordinate transform function from a coordinate transform function.
|
||||||
* "Safe" means that it can handle wrapping of x-coordinates for global projections,
|
* "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.
|
* clamped to the validity range.
|
||||||
* @param {Projection} sourceProj Source projection.
|
* @param {Projection} sourceProj Source projection.
|
||||||
* @param {Projection} destProj Destination 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} transform Transform function (source to destiation).
|
||||||
* @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} inverse Transform function (destiation to source).
|
|
||||||
* @return {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} Safe transform function (source to destiation).
|
* @return {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} Safe transform function (source to destiation).
|
||||||
*/
|
*/
|
||||||
export function createSafeCoordinateTransform(
|
export function createSafeCoordinateTransform(sourceProj, destProj, transform) {
|
||||||
sourceProj,
|
|
||||||
destProj,
|
|
||||||
forward,
|
|
||||||
inverse
|
|
||||||
) {
|
|
||||||
return function (coord) {
|
return function (coord) {
|
||||||
let x, y, worldsAway;
|
let sourceX = coord[0];
|
||||||
|
let sourceY = coord[1];
|
||||||
|
let transformed, worldsAway;
|
||||||
if (sourceProj.canWrapX()) {
|
if (sourceProj.canWrapX()) {
|
||||||
const sourceExtent = sourceProj.getExtent();
|
const sourceExtent = sourceProj.getExtent();
|
||||||
const sourceExtentWidth = getWidth(sourceExtent);
|
const sourceExtentWidth = getWidth(sourceExtent);
|
||||||
worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth);
|
worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth);
|
||||||
if (worldsAway) {
|
if (worldsAway) {
|
||||||
// Move x to the real world
|
// Move x to the real world
|
||||||
x = coord[0] - worldsAway * sourceExtentWidth;
|
sourceX = sourceX - 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 = 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()) {
|
if (worldsAway && destProj.canWrapX()) {
|
||||||
// Move transformed coordinate back to the offset world
|
// Move transformed coordinate back to the offset world
|
||||||
transformed[0] += worldsAway * getWidth(destExtent);
|
transformed[0] += worldsAway * getWidth(destProj.getExtent());
|
||||||
}
|
}
|
||||||
return transformed;
|
return transformed;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,18 +61,8 @@ export function register(proj4) {
|
|||||||
addCoordinateTransforms(
|
addCoordinateTransforms(
|
||||||
proj1,
|
proj1,
|
||||||
proj2,
|
proj2,
|
||||||
createSafeCoordinateTransform(
|
createSafeCoordinateTransform(proj1, proj2, transform.forward),
|
||||||
proj1,
|
createSafeCoordinateTransform(proj2, proj1, transform.inverse)
|
||||||
proj2,
|
|
||||||
transform.forward,
|
|
||||||
transform.inverse
|
|
||||||
),
|
|
||||||
createSafeCoordinateTransform(
|
|
||||||
proj2,
|
|
||||||
proj1,
|
|
||||||
transform.inverse,
|
|
||||||
transform.forward
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,13 +571,18 @@ describe('ol.proj', function () {
|
|||||||
const epsg3857 = getProjection('EPSG:3857');
|
const epsg3857 = getProjection('EPSG:3857');
|
||||||
google.setExtent(epsg3857.getExtent());
|
google.setExtent(epsg3857.getExtent());
|
||||||
google.setGlobal(true);
|
google.setGlobal(true);
|
||||||
const coord = [-190, 90];
|
|
||||||
const transformed = transform(coord, wgs84, google);
|
const coord = [-190, 85];
|
||||||
expect(transformed).to.eql(transform(coord, epsg4326, epsg3857));
|
|
||||||
const got = transform(transformed, google, wgs84);
|
let expected = transform(coord, wgs84, google);
|
||||||
const expected = transform(transformed, epsg3857, epsg4326);
|
let got = transform(coord, epsg4326, epsg3857);
|
||||||
expect(got[0]).to.roughlyEqual(expected[0], 1e-9);
|
expect(got[0]).to.roughlyEqual(expected[0], 1e-7);
|
||||||
expect(got[1]).to.roughlyEqual(expected[1], 1e-9);
|
expect(got[1]).to.roughlyEqual(expected[1], 1e-7);
|
||||||
|
|
||||||
|
expected = transform(expected, google, wgs84);
|
||||||
|
got = transform(got, epsg3857, epsg4326);
|
||||||
|
expect(got[0]).to.roughlyEqual(expected[0], 1e-7);
|
||||||
|
expect(got[1]).to.roughlyEqual(expected[1], 1e-7);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user