Permalink
Browse files

Faster extent + geometry type queries

By maintaining separate R-Trees for each geometry type, we cover
the most critical query from the canvas renderer at higher
speeds. Using the filter's own evaluate method, we can now also
serve arbitrary queries, but they won't be fast.

Still needs unit tests.
  • Loading branch information...
1 parent 619803c commit 4e971b604169e4216dbdc2bc2b173532b9769484 @ahocevar ahocevar committed Feb 6, 2013
Showing with 49 additions and 30 deletions.
  1. +49 −30 src/ol/source/vectorsource.js
@@ -27,16 +27,16 @@ ol.source.FeatureCache = function() {
this.idLookup_;
/**
- * @type {Object.<ol.Feature>}
+ * @type {Object.<string, ol.Feature>}
* @private
*/
this.geometryTypeIndex_;
/**
- * @type {ol.structs.RTree}
+ * @type {Object.<ol.geom.GeometryType, ol.structs.RTree>}
* @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) {
+ if (opt_filter instanceof ol.filter.Geometry) {
+ features = this.geometryTypeIndex_[opt_filter.getType()];
+ } else if (opt_filter instanceof ol.filter.Extent) {
+ var boundsByGeometryType = this.boundsByGeometryType_,
+ extent = opt_filter.getExtent();
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];
- }
+ 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;
+ }
}
- } 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;

0 comments on commit 4e971b6

Please sign in to comment.