#13690 VectorSource#getFeaturesInExtent add projection parameter
This commit is contained in:
@@ -858,3 +858,47 @@ export function wrapX(extent, projection) {
|
|||||||
}
|
}
|
||||||
return extent;
|
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 {TRUE, VOID} from '../functions.js';
|
||||||
import {all as allStrategy} from '../loadingstrategy.js';
|
import {all as allStrategy} from '../loadingstrategy.js';
|
||||||
import {assert} from '../asserts.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 {extend} from '../array.js';
|
||||||
import {getUid} from '../util.js';
|
import {getUid} from '../util.js';
|
||||||
import {getValues, isEmpty} from '../obj.js';
|
import {getValues, isEmpty} from '../obj.js';
|
||||||
@@ -736,12 +736,23 @@ class VectorSource extends Source {
|
|||||||
* features.
|
* features.
|
||||||
*
|
*
|
||||||
* @param {import("../extent.js").Extent} extent Extent.
|
* @param {import("../extent.js").Extent} extent Extent.
|
||||||
|
* @param {import("../proj/Projection.js").default} [projection] Projection.
|
||||||
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
* @return {Array<import("../Feature.js").default<Geometry>>} Features.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getFeaturesInExtent(extent) {
|
getFeaturesInExtent(extent, projection) {
|
||||||
if (this.featuresRtree_) {
|
if (this.featuresRtree_) {
|
||||||
|
const multiWorld = projection && projection.canWrapX() && this.getWrapX();
|
||||||
|
|
||||||
|
if (!multiWorld) {
|
||||||
return this.featuresRtree_.getInExtent(extent);
|
return this.featuresRtree_.getInExtent(extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
const extents = wrapAndSliceX(extent, projection);
|
||||||
|
|
||||||
|
return [].concat(
|
||||||
|
...extents.map((anExtent) => this.featuresRtree_.getInExtent(anExtent))
|
||||||
|
);
|
||||||
} else if (this.featuresCollection_) {
|
} else if (this.featuresCollection_) {
|
||||||
return this.featuresCollection_.getArray().slice(0);
|
return this.featuresCollection_.getArray().slice(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Point from '../../../../../src/ol/geom/Point.js';
|
|||||||
import VectorLayer from '../../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../../src/ol/layer/Vector.js';
|
||||||
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../../src/ol/source/Vector.js';
|
||||||
import View from '../../../../../src/ol/View.js';
|
import View from '../../../../../src/ol/View.js';
|
||||||
|
import sinon from 'sinon';
|
||||||
import {bbox as bboxStrategy} from '../../../../../src/ol/loadingstrategy.js';
|
import {bbox as bboxStrategy} from '../../../../../src/ol/loadingstrategy.js';
|
||||||
import {
|
import {
|
||||||
fromLonLat,
|
fromLonLat,
|
||||||
@@ -979,4 +980,45 @@ describe('ol.source.Vector', function () {
|
|||||||
expect(source.getFeatures().length).to.be(0);
|
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);
|
).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