#13690 VectorSource#getFeaturesInExtent add projection parameter
This commit is contained in:
@@ -858,3 +858,47 @@ export function wrapX(extent, projection) {
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fits the extent to the real world
|
||||
*
|
||||
* If the extent does not cross the anti meridian, this will return the extent in an array
|
||||
* If the extent crosses the anti meridian, the extent will be sliced, so each part fits within the
|
||||
* real world
|
||||
*
|
||||
*
|
||||
* @param {Extent} extent Extent.
|
||||
* @param {import("./proj/Projection.js").default} projection Projection
|
||||
* @return {Array<Extent>} The extent within the real world extent.
|
||||
*/
|
||||
export function wrapAndSliceX(extent, projection) {
|
||||
if (projection.canWrapX()) {
|
||||
const projectionExtent = projection.getExtent();
|
||||
|
||||
if (!isFinite(extent[0]) || !isFinite(extent[2])) {
|
||||
return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];
|
||||
}
|
||||
|
||||
wrapX(extent, projection);
|
||||
const worldWidth = getWidth(projectionExtent);
|
||||
|
||||
if (getWidth(extent) > worldWidth) {
|
||||
// the extent wraps around on itself
|
||||
return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];
|
||||
} else if (extent[0] < projectionExtent[0]) {
|
||||
// the extent crosses the anti meridian, so it needs to be sliced
|
||||
return [
|
||||
[extent[0] + worldWidth, extent[1], projectionExtent[2], extent[3]],
|
||||
[projectionExtent[0], extent[1], extent[2], extent[3]],
|
||||
];
|
||||
} else if (extent[2] > projectionExtent[2]) {
|
||||
// the extent crosses the anti meridian, so it needs to be sliced
|
||||
return [
|
||||
[extent[0], extent[1], projectionExtent[2], extent[3]],
|
||||
[projectionExtent[0], extent[1], extent[2] - worldWidth, extent[3]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [extent];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import VectorEventType from './VectorEventType.js';
|
||||
import {TRUE, VOID} from '../functions.js';
|
||||
import {all as allStrategy} from '../loadingstrategy.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {containsExtent, equals} from '../extent.js';
|
||||
import {containsExtent, equals, wrapAndSliceX} from '../extent.js';
|
||||
import {extend} from '../array.js';
|
||||
import {getUid} from '../util.js';
|
||||
import {getValues, isEmpty} from '../obj.js';
|
||||
@@ -736,12 +736,23 @@ class VectorSource extends Source {
|
||||
* features.
|
||||
*
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {import("../proj/Projection.js").default} [projection] Projection.
|
||||
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeaturesInExtent(extent) {
|
||||
getFeaturesInExtent(extent, projection) {
|
||||
if (this.featuresRtree_) {
|
||||
return this.featuresRtree_.getInExtent(extent);
|
||||
const multiWorld = projection && projection.canWrapX() && this.getWrapX();
|
||||
|
||||
if (!multiWorld) {
|
||||
return this.featuresRtree_.getInExtent(extent);
|
||||
}
|
||||
|
||||
const extents = wrapAndSliceX(extent, projection);
|
||||
|
||||
return [].concat(
|
||||
...extents.map((anExtent) => this.featuresRtree_.getInExtent(anExtent))
|
||||
);
|
||||
} else if (this.featuresCollection_) {
|
||||
return this.featuresCollection_.getArray().slice(0);
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,7 @@ import Point from '../../../../../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../../../../../src/ol/layer/Vector.js';
|
||||
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
||||
import View from '../../../../../src/ol/View.js';
|
||||
import sinon from 'sinon';
|
||||
import {bbox as bboxStrategy} from '../../../../../src/ol/loadingstrategy.js';
|
||||
import {
|
||||
fromLonLat,
|
||||
@@ -979,4 +980,45 @@ describe('ol.source.Vector', function () {
|
||||
expect(source.getFeatures().length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFeaturesInExtent()', function () {
|
||||
it('adjusts the extent if projection canWrapX', function () {
|
||||
const a = new Feature(new Point([0, 0]));
|
||||
const b = new Feature(new Point([179, 0]));
|
||||
const c = new Feature(new Point([-179, 0]));
|
||||
|
||||
const source = new VectorSource({
|
||||
features: [a, b, c],
|
||||
});
|
||||
|
||||
const projection = getProjection('EPSG:4326');
|
||||
|
||||
expect(
|
||||
source.getFeaturesInExtent([-180, -90, 180, 90], projection).length
|
||||
).to.be(3);
|
||||
const onlyB = source.getFeaturesInExtent([1, -90, 180, 90], projection);
|
||||
expect(onlyB.length).to.be(1);
|
||||
expect(onlyB).to.contain(b);
|
||||
const bAndC = source.getFeaturesInExtent([1, -90, 182, 90], projection);
|
||||
expect(bAndC.length).to.be(2);
|
||||
expect(bAndC).to.contain(b);
|
||||
expect(bAndC).to.contain(c);
|
||||
|
||||
const onlyC = source.getFeaturesInExtent([-180, -90, -1, 90], projection);
|
||||
expect(onlyC.length).to.be(1);
|
||||
expect(onlyC).to.contain(c);
|
||||
|
||||
const bAndCAgain = source.getFeaturesInExtent(
|
||||
[-182, -90, -1, 90],
|
||||
projection
|
||||
);
|
||||
expect(bAndCAgain.length).to.be(2);
|
||||
expect(bAndCAgain).to.contain(b);
|
||||
expect(bAndCAgain).to.contain(c);
|
||||
|
||||
const onlyA = source.getFeaturesInExtent([359, -90, 361, 90], projection);
|
||||
expect(onlyA.length).to.be(1);
|
||||
expect(onlyA).to.contain(a);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -964,4 +964,52 @@ describe('ol/extent.js', function () {
|
||||
).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('wrapAndSliceX', function () {
|
||||
const projection = get('EPSG:4326');
|
||||
|
||||
it('leaves real world extent untouched', function () {
|
||||
expect(_ol_extent_.wrapAndSliceX([16, 48, 18, 49], projection)).to.eql([
|
||||
[16, 48, 18, 49],
|
||||
]);
|
||||
});
|
||||
|
||||
it('slices +180 crossing extents', function () {
|
||||
expect(_ol_extent_.wrapAndSliceX([164, 48, 198, 49], projection)).to.eql([
|
||||
[164, 48, 180, 49],
|
||||
[-180, 48, -162, 49],
|
||||
]);
|
||||
|
||||
expect(_ol_extent_.wrapAndSliceX([178, 48, 198, 49], projection)).to.eql([
|
||||
[178, 48, 180, 49],
|
||||
[-180, 48, -162, 49],
|
||||
]);
|
||||
});
|
||||
|
||||
it('slices -180 crossing extents', function () {
|
||||
expect(
|
||||
_ol_extent_.wrapAndSliceX([-198, 48, -160, 49], projection)
|
||||
).to.eql([
|
||||
[162, 48, 180, 49],
|
||||
[-180, 48, -160, 49],
|
||||
]);
|
||||
|
||||
expect(
|
||||
_ol_extent_.wrapAndSliceX([-202, 48, -160, 49], projection)
|
||||
).to.eql([
|
||||
[158, 48, 180, 49],
|
||||
[-180, 48, -160, 49],
|
||||
]);
|
||||
});
|
||||
|
||||
it('fits infinite extents to the projection extent', function () {
|
||||
expect(
|
||||
_ol_extent_.wrapAndSliceX([-Infinity, 48, -160, 49], projection)
|
||||
).to.eql([[-180, 48, 180, 49]]);
|
||||
|
||||
expect(
|
||||
_ol_extent_.wrapAndSliceX([-198, 48, Infinity, 49], projection)
|
||||
).to.eql([[-180, 48, 180, 49]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user