diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index d9ac0832d2..9898c1c7fc 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -27,16 +27,16 @@ ol.source.FeatureCache = function() { this.idLookup_; /** - * @type {Object.} + * @type {Object.} * @private */ this.geometryTypeIndex_; /** - * @type {ol.structs.RTree} + * @type {Object.} * @private */ - this.rTree_; + this.boundsByGeometryType_; this.clear(); @@ -49,13 +49,16 @@ ol.source.FeatureCache = function() { ol.source.FeatureCache.prototype.clear = function() { this.idLookup_ = {}; - var geometryTypeIndex = {}; + var geometryTypeIndex = {}, + boundsByGeometryType = {}, + geometryType; for (var key in ol.geom.GeometryType) { - geometryTypeIndex[ol.geom.GeometryType[key]] = {}; + geometryType = ol.geom.GeometryType[key]; + geometryTypeIndex[geometryType] = {}; + boundsByGeometryType[geometryType] = new ol.structs.RTree(); } this.geometryTypeIndex_ = geometryTypeIndex; - - this.rTree_ = new ol.structs.RTree(); + this.boundsByGeometryType_ = boundsByGeometryType; }; @@ -71,8 +74,10 @@ ol.source.FeatureCache.prototype.add = function(feature) { // index by geometry type and bounding box if (!goog.isNull(geometry)) { - this.geometryTypeIndex_[geometry.getType()][id] = feature; - this.rTree_.put(geometry.getBounds(), feature); + var geometryType = geometry.getType(); + this.geometryTypeIndex_[geometryType][id] = feature; + this.boundsByGeometryType_[geometryType].put(geometry.getBounds(), + feature); } }; @@ -83,34 +88,48 @@ ol.source.FeatureCache.prototype.add = function(feature) { * @private */ ol.source.FeatureCache.prototype.getFeaturesObject_ = function(opt_filter) { - var features; + var i, features; if (!goog.isDef(opt_filter)) { features = this.idLookup_; } else { - if (opt_filter instanceof ol.filter.Logical) { - features = {}; - var filters = opt_filter.getFilters(), - filterFeatures, key, or; - for (var i = filters.length - 1; i >= 0; --i) { - filterFeatures = this.getFeaturesObject_(filters[i]); - goog.object.extend(features, filterFeatures); - if (opt_filter.operator === ol.filter.LogicalOperator.AND) { - or = features; - features = {}; - for (key in or) { - if (filterFeatures[key]) { - features[key] = or[key]; - } - } - } - } - } else if (opt_filter instanceof ol.filter.Geometry) { + if (opt_filter instanceof ol.filter.Geometry) { features = this.geometryTypeIndex_[opt_filter.getType()]; } else if (opt_filter instanceof ol.filter.Extent) { - features = this.rTree_.find(opt_filter.getExtent()); - } else { - // TODO: support other filter types - throw new Error('Filter type not supported: ' + opt_filter); + var boundsByGeometryType = this.boundsByGeometryType_, + extent = opt_filter.getExtent(); + features = {}; + for (i in boundsByGeometryType) { + goog.object.extend(features, boundsByGeometryType[i].find(extent)); + } + } else if (opt_filter instanceof ol.filter.Logical) { + var filters = opt_filter.getFilters(); + if (filters.length === 2) { + var filter, geometryFilter, extentFilter; + for (i = 0; i <= 1; ++i) { + filter = filters[i]; + if (filter instanceof ol.filter.Geometry) { + geometryFilter = filter; + } else if (filter instanceof ol.filter.Extent) { + extentFilter = filter; + } + } + if (extentFilter && geometryFilter) { + features = this.boundsByGeometryType_[geometryFilter.getType()] + .find(extentFilter.getExtent()); + } + } + } + if (!goog.isDef(features)) { + // TODO: support fast lane for other filter types + var candidates = this.idLookup_, + feature; + features = {}; + for (i in candidates) { + feature = candidates[i]; + if (opt_filter.evaluate(feature) === true) { + features[i] = feature; + } + } } } return features;