diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index c7ea186c66..6a2f9e2089 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -1,10 +1,12 @@ goog.provide('ol.source.Vector'); goog.require('ol.Feature'); -goog.require('ol.filter.Filter'); +goog.require('ol.filter.Extent'); goog.require('ol.filter.Geometry'); +goog.require('ol.filter.Logical'); goog.require('ol.geom.GeometryType'); goog.require('ol.source.Source'); +goog.require('ol.structs.RTree'); @@ -19,13 +21,18 @@ ol.source.FeatureCache = function() { */ this.idLookup_; - /** * @type {Object.} * @private */ this.geometryTypeIndex_; + /** + * @type {ol.structs.RTree} + * @private + */ + this.rTree_; + this.clear(); }; @@ -42,6 +49,8 @@ ol.source.FeatureCache.prototype.clear = function() { geometryTypeIndex[ol.geom.GeometryType[key]] = {}; } this.geometryTypeIndex_ = geometryTypeIndex; + + this.rTree_ = new ol.structs.RTree(); }; @@ -55,17 +64,51 @@ ol.source.FeatureCache.prototype.add = function(feature) { this.idLookup_[id] = feature; - // index by geometry type + // index by geometry type and bounding box if (!goog.isNull(geometry)) { this.geometryTypeIndex_[geometry.getType()][id] = feature; + this.rTree_.put(geometry.getBounds(), feature); } +}; - /** - * TODO: Index by tile coord. To do this for real requires knowledge about - * the evaluated symbolizer literal for each feature. Initially, a pixel - * buffer could be provided. - */ +/** + * @param {ol.filter.Filter=} opt_filter Optional filter. + * @return {Object.} Object of features, keyed by id. + * @private + */ +ol.source.FeatureCache.prototype.getFeaturesObject_ = function(opt_filter) { + var 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) { + 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); + } + } + return features; }; @@ -74,22 +117,7 @@ ol.source.FeatureCache.prototype.add = function(feature) { * @return {Array.} Array of features. */ ol.source.FeatureCache.prototype.getFeatures = function(opt_filter) { - var features; - if (!goog.isDef(opt_filter)) { - features = new Array(); - for (var id in this.idLookup_) { - features.push(this.idLookup_[id]); - } - } else { - if (opt_filter instanceof ol.filter.Geometry) { - features = this.getFeaturesByGeometryType_( - /** @type {ol.filter.Geometry} */ (opt_filter)); - } else { - // TODO: support other filter types - throw new Error('Filter type not supported: ' + opt_filter); - } - } - return features; + return goog.object.getValues(this.getFeaturesObject_(opt_filter)); };