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

View File

@@ -2,14 +2,7 @@
* @module ol/interaction/DragZoom * @module ol/interaction/DragZoom
*/ */
import DragBox from './DragBox.js'; import DragBox from './DragBox.js';
import {
createOrUpdateFromCoordinates,
getBottomLeft,
getTopRight,
scaleFromCenter,
} from '../extent.js';
import {easeOut} from '../easing.js'; import {easeOut} from '../easing.js';
import {fromExtent as polygonFromExtent} from '../geom/Polygon.js';
import {shiftKeyOnly} from '../events/condition.js'; import {shiftKeyOnly} from '../events/condition.js';
/** /**
@@ -71,22 +64,17 @@ class DragZoom extends DragBox {
onBoxEnd(event) { onBoxEnd(event) {
const map = this.getMap(); const map = this.getMap();
const view = /** @type {!import("../View.js").default} */ (map.getView()); const view = /** @type {!import("../View.js").default} */ (map.getView());
let extent = this.getGeometry().getExtent(); let geometry = this.getGeometry();
if (this.out_) { if (this.out_) {
const size = /** @type {!import("../size.js").Size} */ (map.getSize()); const rotatedExtent = view.rotatedExtentForGeometry(geometry);
const mapExtent = view.calculateExtentInternal(size); const resolution = view.getResolutionForExtentInternal(rotatedExtent);
const boxPixelExtent = createOrUpdateFromCoordinates([ const factor = view.getResolution() / resolution;
map.getPixelFromCoordinateInternal(getBottomLeft(extent)), geometry = geometry.clone();
map.getPixelFromCoordinateInternal(getTopRight(extent)), geometry.scale(factor * factor);
]);
const factor = view.getResolutionForExtentInternal(boxPixelExtent, size);
scaleFromCenter(mapExtent, 1 / factor);
extent = mapExtent;
} }
view.fitInternal(polygonFromExtent(extent), { view.fitInternal(geometry, {
duration: this.duration_, duration: this.duration_,
easing: easeOut, easing: easeOut,
}); });