Fix dragzoom with rotated view

When the view is rotated the extent of the drag box is not the same as the
drag box.
This commit is contained in:
Maximilian Krög
2021-05-08 02:10:05 +02:00
parent b89809c1a1
commit c19ebc72cb
2 changed files with 47 additions and 49 deletions

View File

@@ -1076,7 +1076,7 @@ class View extends BaseObject {
* the given size.
*/
getResolutionForExtentInternal(extent, opt_size) {
const size = opt_size || this.getViewportSize_();
const size = opt_size || this.getViewportSizeMinusPadding_();
const xResolution = getWidth(extent) / size[0];
const yResolution = getHeight(extent) / size[1];
return Math.max(xResolution, yResolution);
@@ -1298,6 +1298,32 @@ class View extends BaseObject {
this.fitInternal(geometry, opt_options);
}
/**
* Calculate rotated extent
* @param {import("./geom/SimpleGeometry.js").default} geometry The geometry.
* @return {import("./extent").Extent} The rotated extent for the geometry.
*/
rotatedExtentForGeometry(geometry) {
const rotation = this.getRotation();
const cosAngle = Math.cos(rotation);
const sinAngle = Math.sin(-rotation);
const coords = geometry.getFlatCoordinates();
const stride = geometry.getStride();
let minRotX = +Infinity;
let minRotY = +Infinity;
let maxRotX = -Infinity;
let maxRotY = -Infinity;
for (let i = 0, ii = coords.length; i < ii; i += stride) {
const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;
const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;
minRotX = Math.min(minRotX, rotX);
minRotY = Math.min(minRotY, rotY);
maxRotX = Math.max(maxRotX, rotX);
maxRotY = Math.max(maxRotY, rotY);
}
return [minRotX, minRotY, maxRotX, maxRotY];
}
/**
* @param {import("./geom/SimpleGeometry.js").default} geometry The geometry.
* @param {FitOptions} [opt_options] Options.
@@ -1319,44 +1345,28 @@ class View extends BaseObject {
} else {
minResolution = 0;
}
const coords = geometry.getFlatCoordinates();
// calculate rotated extent
const rotation = this.getRotation();
const cosAngle = Math.cos(-rotation);
let sinAngle = Math.sin(-rotation);
let minRotX = +Infinity;
let minRotY = +Infinity;
let maxRotX = -Infinity;
let maxRotY = -Infinity;
const stride = geometry.getStride();
for (let i = 0, ii = coords.length; i < ii; i += stride) {
const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;
const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;
minRotX = Math.min(minRotX, rotX);
minRotY = Math.min(minRotY, rotY);
maxRotX = Math.max(maxRotX, rotX);
maxRotY = Math.max(maxRotY, rotY);
}
const rotatedExtent = this.rotatedExtentForGeometry(geometry);
// calculate resolution
let resolution = this.getResolutionForExtentInternal(
[minRotX, minRotY, maxRotX, maxRotY],
[size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]
);
let resolution = this.getResolutionForExtentInternal(rotatedExtent, [
size[0] - padding[1] - padding[3],
size[1] - padding[0] - padding[2],
]);
resolution = isNaN(resolution)
? minResolution
: Math.max(resolution, minResolution);
resolution = this.getConstrainedResolution(resolution, nearest ? 0 : 1);
// calculate center
sinAngle = -sinAngle; // go back to original rotation
let centerRotX = (minRotX + maxRotX) / 2;
let centerRotY = (minRotY + maxRotY) / 2;
centerRotX += ((padding[1] - padding[3]) / 2) * resolution;
centerRotY += ((padding[0] - padding[2]) / 2) * resolution;
const centerX = centerRotX * cosAngle - centerRotY * sinAngle;
const centerY = centerRotY * cosAngle + centerRotX * sinAngle;
const rotation = this.getRotation();
const sinAngle = Math.sin(rotation);
const cosAngle = Math.cos(rotation);
const centerRot = getCenter(rotatedExtent);
centerRot[0] += ((padding[1] - padding[3]) / 2) * resolution;
centerRot[1] += ((padding[0] - padding[2]) / 2) * resolution;
const centerX = centerRot[0] * cosAngle - centerRot[1] * sinAngle;
const centerY = centerRot[1] * cosAngle + centerRot[0] * sinAngle;
const center = this.getConstrainedCenter([centerX, centerY], resolution);
const callback = options.callback ? options.callback : VOID;