Replace use of filter with expressions
The canvas vector layer still has the (API candidate) `getFeatures` method that accepts an arbitrary expression (was filter). This, and the `getFeaturesObject` method under it are only used in the tests. The rendering code that was using filters is now calling `layer.getFeaturesObjectForExtent` with an explicit extent and optional geometry type.
This commit is contained in:
@@ -2,7 +2,9 @@ goog.provide('ol.expression');
|
||||
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expression.Call');
|
||||
goog.require('ol.expression.Expression');
|
||||
goog.require('ol.expression.Identifier');
|
||||
goog.require('ol.expression.Parser');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
@@ -35,6 +37,30 @@ ol.expression.parse = function(source) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether an expression is a call expression that calls one of the
|
||||
* `ol.expression.lib` functions.
|
||||
*
|
||||
* @param {ol.expression.Expression} expr The candidate expression.
|
||||
* @return {string|undefined} If the candidate expression is a call to a lib
|
||||
* function, the return will be the function name. If not, the return will be
|
||||
* `undefined`.
|
||||
*/
|
||||
ol.expression.isLibCall = function(expr) {
|
||||
var name;
|
||||
if (expr instanceof ol.expression.Call) {
|
||||
var callee = expr.getCallee();
|
||||
if (callee instanceof ol.expression.Identifier) {
|
||||
name = callee.getName();
|
||||
if (!ol.expression.lib.hasOwnProperty(name)) {
|
||||
name = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Library of well-known functions. These are available to expressions parsed
|
||||
* with `ol.expression.parse`.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
@exportSymbol ol.filter.Filter
|
||||
@exportSymbol ol.filter.Geometry
|
||||
@exportSymbol ol.filter.Logical
|
||||
|
||||
@exportSymbol ol.filter.LogicalOperator
|
||||
@exportProperty ol.filter.LogicalOperator.AND
|
||||
@exportProperty ol.filter.LogicalOperator.OR
|
||||
@@ -1,3 +0,0 @@
|
||||
/**
|
||||
* @namespace ol.filter
|
||||
*/
|
||||
@@ -1,39 +0,0 @@
|
||||
goog.provide('ol.filter.Extent');
|
||||
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.filter.Filter');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {ol.Extent} extent The extent.
|
||||
*/
|
||||
ol.filter.Extent = function(extent) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.extent_ = extent;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Extent, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} The filter extent.
|
||||
*/
|
||||
ol.filter.Extent.prototype.getExtent = function() {
|
||||
return this.extent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Extent.prototype.applies = function(feature) {
|
||||
return ol.extent.intersects(feature.getGeometry().getBounds(), this.extent_);
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
goog.provide('ol.filter.Filter');
|
||||
|
||||
goog.require('ol.Feature');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new filter which can be used to filter features based on a
|
||||
* function.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* new ol.style.Rule({
|
||||
* filter: new ol.filter.Filter(function(feature) {
|
||||
* return feature.get('where') == 'outer';
|
||||
* }),
|
||||
* symbolizers: [
|
||||
* ...
|
||||
*
|
||||
* @constructor
|
||||
* @param {function(this:ol.filter.Filter, ol.Feature)=} opt_filterFunction
|
||||
* Filter function. Should return true if the passed feature passes the
|
||||
* filter, false otherwise.
|
||||
*/
|
||||
ol.filter.Filter = function(opt_filterFunction) {
|
||||
if (goog.isDef(opt_filterFunction)) {
|
||||
this.applies = opt_filterFunction;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature to evaluate the filter against.
|
||||
* @return {boolean} The provided feature passes this filter.
|
||||
*/
|
||||
ol.filter.Filter.prototype.applies = goog.abstractMethod;
|
||||
@@ -1,42 +0,0 @@
|
||||
goog.provide('ol.filter.Geometry');
|
||||
goog.provide('ol.filter.GeometryType');
|
||||
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Filter features by geometry type.
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {ol.geom.GeometryType} type The geometry type.
|
||||
*/
|
||||
ol.filter.Geometry = function(type) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {ol.geom.GeometryType}
|
||||
* @private
|
||||
*/
|
||||
this.type_ = type;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Geometry, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Geometry.prototype.applies = function(feature) {
|
||||
var geometry = feature.getGeometry();
|
||||
return goog.isNull(geometry) ? false : geometry.getType() === this.type_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.geom.GeometryType} The geometry type.
|
||||
*/
|
||||
ol.filter.Geometry.prototype.getType = function() {
|
||||
return this.type_;
|
||||
};
|
||||
@@ -1,128 +0,0 @@
|
||||
goog.provide('ol.filter.Logical');
|
||||
goog.provide('ol.filter.LogicalOperator');
|
||||
goog.provide('ol.filter.and');
|
||||
goog.provide('ol.filter.not');
|
||||
goog.provide('ol.filter.or');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.filter.Filter');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A filter to group (a) subfilter(s) by a logical operator (AND/OR/NOT).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var f1 = new ol.filter.Filter(myFunc1);
|
||||
* var f2 = new ol.filter.Filter(myFunc2);
|
||||
* // match one of the two filters above
|
||||
* var logical = new ol.filter.Logical([f1, f2],
|
||||
* ol.filter.LogicalOperator.OR);
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.filter.Filter}
|
||||
* @param {Array.<ol.filter.Filter>} filters Filters to combine.
|
||||
* @param {ol.filter.LogicalOperator} operator Operator.
|
||||
*/
|
||||
ol.filter.Logical = function(filters, operator) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.filter.Filter>}
|
||||
* @private
|
||||
*/
|
||||
this.filters_ = filters;
|
||||
goog.asserts.assert(filters.length > 0, 'Must supply at least one filter');
|
||||
|
||||
/**
|
||||
* @type {ol.filter.LogicalOperator}
|
||||
*/
|
||||
this.operator = operator;
|
||||
|
||||
};
|
||||
goog.inherits(ol.filter.Logical, ol.filter.Filter);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.filter.Logical.prototype.applies = function(feature) {
|
||||
var filters = this.filters_,
|
||||
i = 0, ii = filters.length,
|
||||
result;
|
||||
switch (this.operator) {
|
||||
case ol.filter.LogicalOperator.AND:
|
||||
result = true;
|
||||
while (result && i < ii) {
|
||||
result = result && filters[i].applies(feature);
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
case ol.filter.LogicalOperator.OR:
|
||||
result = false;
|
||||
while (!result && i < ii) {
|
||||
result = result || filters[i].applies(feature);
|
||||
++i;
|
||||
}
|
||||
break;
|
||||
case ol.filter.LogicalOperator.NOT:
|
||||
result = !filters[i].applies(feature);
|
||||
break;
|
||||
default:
|
||||
goog.asserts.assert(false, 'Unsupported operation: ' + this.operator);
|
||||
}
|
||||
return !!result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.filter.Filter>} The filter's filters.
|
||||
*/
|
||||
ol.filter.Logical.prototype.getFilters = function() {
|
||||
return this.filters_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.filter.LogicalOperator = {
|
||||
AND: '&&',
|
||||
OR: '||',
|
||||
NOT: '!'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a filter that evaluates to true if all of the provided filters
|
||||
* evaluate to true.
|
||||
* @param {...ol.filter.Filter} var_args Filters.
|
||||
* @return {ol.filter.Logical} A logical AND filter.
|
||||
*/
|
||||
ol.filter.and = function(var_args) {
|
||||
var filters = Array.prototype.slice.call(arguments);
|
||||
return new ol.filter.Logical(filters, ol.filter.LogicalOperator.AND);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new filter that is the logical compliment of another.
|
||||
* @param {ol.filter.Filter} filter The filter to negate.
|
||||
* @return {ol.filter.Logical} A logical NOT filter.
|
||||
*/
|
||||
ol.filter.not = function(filter) {
|
||||
return new ol.filter.Logical([filter], ol.filter.LogicalOperator.NOT);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a filter that evaluates to true if any of the provided filters
|
||||
* evaluate to true.
|
||||
* @param {...ol.filter.Filter} var_args Filters.
|
||||
* @return {ol.filter.Logical} A logical OR filter.
|
||||
*/
|
||||
ol.filter.or = function(var_args) {
|
||||
var filters = Array.prototype.slice.call(arguments);
|
||||
return new ol.filter.Logical(filters, ol.filter.LogicalOperator.OR);
|
||||
};
|
||||
@@ -5,6 +5,10 @@ goog.require('goog.asserts');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expression');
|
||||
goog.require('ol.expression.Literal');
|
||||
goog.require('ol.expression.Logical');
|
||||
goog.require('ol.expression.LogicalOp');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
goog.require('ol.layer.Layer');
|
||||
@@ -79,35 +83,65 @@ ol.layer.FeatureCache.prototype.add = function(feature) {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expression.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
var i, features;
|
||||
if (!goog.isDef(opt_filter)) {
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_expr) {
|
||||
var features;
|
||||
if (!goog.isDef(opt_expr)) {
|
||||
features = this.idLookup_;
|
||||
} 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_.searchReturningObject(opt_filter.getExtent());
|
||||
} else if (opt_filter instanceof ol.filter.Logical &&
|
||||
opt_filter.operator === ol.filter.LogicalOperator.AND) {
|
||||
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;
|
||||
// check for geometryType or extent expression
|
||||
var name = ol.expression.isLibCall(opt_expr);
|
||||
if (name === 'geometryType') {
|
||||
var args = /** @type {ol.expression.Call} */ (opt_expr).getArgs();
|
||||
goog.asserts.assert(args.length === 1);
|
||||
goog.asserts.assert(args[0] instanceof ol.expression.Literal);
|
||||
var type = /** @type {ol.expression.Literal } */ (args[0]).evaluate();
|
||||
goog.asserts.assertString(type);
|
||||
features = this.geometryTypeIndex_[type];
|
||||
} else if (name === 'extent') {
|
||||
var args = /** @type {ol.expression.Call} */ (opt_expr).getArgs();
|
||||
goog.asserts.assert(args.length === 4);
|
||||
var extent = [];
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
goog.asserts.assert(args[i] instanceof ol.expression.Literal);
|
||||
extent[i] = /** @type {ol.expression.Literal} */ (args[i]).evaluate();
|
||||
goog.asserts.assertNumber(extent[i]);
|
||||
}
|
||||
features = this.rTree_.searchReturningObject(extent);
|
||||
} else {
|
||||
// not a call expression, check logical
|
||||
if (opt_expr instanceof ol.expression.Logical) {
|
||||
var op = /** @type {ol.expression.Logical} */ (opt_expr).getOperator();
|
||||
if (op === ol.expression.LogicalOp.AND) {
|
||||
var expressions = [opt_expr.getLeft(), opt_expr.getRight()];
|
||||
var expr, args, type, extent;
|
||||
for (var i = 0; i <= 1; ++i) {
|
||||
expr = expressions[i];
|
||||
name = ol.expression.isLibCall(expr);
|
||||
if (name === 'geometryType') {
|
||||
args = /** @type {ol.expression.Call} */ (expr).getArgs();
|
||||
goog.asserts.assert(args.length === 1);
|
||||
goog.asserts.assert(args[0] instanceof ol.expression.Literal);
|
||||
type = /** @type {ol.expression.Literal } */ (args[0]).evaluate();
|
||||
goog.asserts.assertString(type);
|
||||
} else if (name === 'extent') {
|
||||
args = /** @type {ol.expression.Call} */ (expr).getArgs();
|
||||
goog.asserts.assert(args.length === 4);
|
||||
extent = [];
|
||||
for (var j = 0; j < 4; ++j) {
|
||||
goog.asserts.assert(args[j] instanceof ol.expression.Literal);
|
||||
extent[j] =
|
||||
/** @type {ol.expression.Literal} */ (args[j]).evaluate();
|
||||
goog.asserts.assertNumber(extent[j]);
|
||||
}
|
||||
}
|
||||
if (extentFilter && geometryFilter) {
|
||||
var type = geometryFilter.getType();
|
||||
features = goog.object.isEmpty(this.geometryTypeIndex_[type]) ? {} :
|
||||
this.rTree_.searchReturningObject(extentFilter.getExtent(), type);
|
||||
}
|
||||
if (type && extent) {
|
||||
features = this.getFeaturesObjectForExtent(extent,
|
||||
/** @type {ol.geom.GeometryType} */ (type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +152,7 @@ ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
features = {};
|
||||
for (i in candidates) {
|
||||
feature = candidates[i];
|
||||
if (opt_filter.applies(feature) === true) {
|
||||
if (ol.expression.evaluateFeature(opt_expr, feature)) {
|
||||
features[i] = feature;
|
||||
}
|
||||
}
|
||||
@@ -129,12 +163,22 @@ ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Geometry} filter Geometry type filter.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesByGeometryType_ = function(filter) {
|
||||
return goog.object.getValues(this.geometryTypeIndex_[filter.getType()]);
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
opt_type) {
|
||||
var features;
|
||||
if (goog.isDef(opt_type) &&
|
||||
goog.object.isEmpty(this.geometryTypeIndex_[opt_type])) {
|
||||
features = {};
|
||||
} else {
|
||||
features = this.rTree_.searchReturningObject(extent, opt_type);
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
@@ -234,21 +278,34 @@ ol.layer.Vector.prototype.getVectorSource = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expression.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_expr) {
|
||||
return goog.object.getValues(
|
||||
this.featureCache_.getFeaturesObject(opt_filter));
|
||||
this.featureCache_.getFeaturesObject(opt_expr));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.filter.Filter=} opt_filter Optional filter.
|
||||
* @param {ol.expression.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObject = function(opt_filter) {
|
||||
return this.featureCache_.getFeaturesObject(opt_filter);
|
||||
ol.layer.Vector.prototype.getFeaturesObject = function(opt_expr) {
|
||||
return this.featureCache_.getFeaturesObject(opt_expr);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
opt_type) {
|
||||
return this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
|
||||
};
|
||||
|
||||
|
||||
@@ -415,10 +472,3 @@ ol.layer.Vector.uidTransformFeatureInfo = function(features) {
|
||||
function(feature) { return goog.getUid(feature); });
|
||||
return featureIds.join(', ');
|
||||
};
|
||||
|
||||
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
@@ -12,10 +12,6 @@ goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.renderer.canvas.Layer');
|
||||
@@ -101,18 +97,18 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
|
||||
this.tileArchetype_ = null;
|
||||
|
||||
/**
|
||||
* Geometry filters in rendering order.
|
||||
* Geometry types in rendering order.
|
||||
* TODO: these will go away shortly (in favor of one call per symbolizer type)
|
||||
* @private
|
||||
* @type {Array.<ol.filter.Geometry>}
|
||||
* @type {Array.<ol.geom.GeometryType>}
|
||||
*/
|
||||
this.geometryFilters_ = [
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.POINT),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOINT),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.LINESTRING),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTILINESTRING),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.POLYGON),
|
||||
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOLYGON)
|
||||
this.geometryTypes_ = [
|
||||
ol.geom.GeometryType.POINT,
|
||||
ol.geom.GeometryType.MULTIPOINT,
|
||||
ol.geom.GeometryType.LINESTRING,
|
||||
ol.geom.GeometryType.MULTILINESTRING,
|
||||
ol.geom.GeometryType.POLYGON,
|
||||
ol.geom.GeometryType.MULTIPOLYGON
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -251,13 +247,12 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
|
||||
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
|
||||
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
|
||||
var filter = new ol.filter.Extent(locationBbox);
|
||||
var candidates = layer.getFeatures(filter);
|
||||
var candidates = layer.getFeaturesObjectForExtent(locationBbox);
|
||||
|
||||
var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
|
||||
coordinates, j;
|
||||
for (var i = 0, ii = candidates.length; i < ii; ++i) {
|
||||
candidate = candidates[i];
|
||||
for (var id in candidates) {
|
||||
candidate = candidates[id];
|
||||
geom = candidate.getGeometry();
|
||||
type = geom.getType();
|
||||
if (type === ol.geom.GeometryType.POINT ||
|
||||
@@ -445,11 +440,11 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
var tileGutter = 15 * tileResolution;
|
||||
var tile, tileCoord, key, x, y;
|
||||
// render features by geometry type
|
||||
var filters = this.geometryFilters_,
|
||||
numFilters = filters.length,
|
||||
var types = this.geometryTypes_,
|
||||
numTypes = types.length,
|
||||
deferred = false,
|
||||
dirty = false,
|
||||
i, geomFilter, tileExtent, extentFilter, type,
|
||||
i, type, tileExtent,
|
||||
groups, group, j, numGroups, featuresObject, tileHasFeatures;
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
@@ -463,16 +458,13 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
tileExtent[1] += tileGutter;
|
||||
tileExtent[2] -= tileGutter;
|
||||
tileExtent[3] += tileGutter;
|
||||
extentFilter = new ol.filter.Extent(tileExtent);
|
||||
tileHasFeatures = false;
|
||||
for (i = 0; i < numFilters; ++i) {
|
||||
geomFilter = filters[i];
|
||||
type = geomFilter.getType();
|
||||
for (i = 0; i < numTypes; ++i) {
|
||||
type = types[i];
|
||||
if (!goog.isDef(featuresToRender[type])) {
|
||||
featuresToRender[type] = {};
|
||||
}
|
||||
featuresObject = layer.getFeaturesObject(new ol.filter.Logical(
|
||||
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND));
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent, type);
|
||||
tileHasFeatures = tileHasFeatures ||
|
||||
!goog.object.isEmpty(featuresObject);
|
||||
goog.object.extend(featuresToRender[type], featuresObject);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
goog.provide('ol.test.filter.Extent');
|
||||
|
||||
|
||||
describe('ol.filter.Extent', function() {
|
||||
|
||||
var extent, filter;
|
||||
|
||||
beforeEach(function() {
|
||||
extent = [0, 45, 0, 90];
|
||||
filter = new ol.filter.Extent(extent);
|
||||
});
|
||||
|
||||
describe('#getExtent()', function() {
|
||||
|
||||
it('returns the configured extent', function() {
|
||||
expect(filter.getExtent()).to.be(extent);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
|
||||
it('returns true if a feature intersects, false if not', function() {
|
||||
expect(filter.applies(new ol.Feature({g: new ol.geom.Point([44, 89])})))
|
||||
.to.be(true);
|
||||
expect(filter.applies(new ol.Feature({g: new ol.geom.Point([46, 91])})))
|
||||
.to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.geom.Point');
|
||||
@@ -1,51 +0,0 @@
|
||||
goog.provide('ol.test.filter.Geometry');
|
||||
|
||||
|
||||
describe('ol.filter.Geometry', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new filter', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POINT);
|
||||
expect(filter).to.be.a(ol.filter.Geometry);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getType()', function() {
|
||||
|
||||
it('works for point', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POINT);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.POINT);
|
||||
});
|
||||
|
||||
it('works for linestring', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.LINESTRING);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.LINESTRING);
|
||||
});
|
||||
|
||||
it('works for polygon', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.POLYGON);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.POLYGON);
|
||||
});
|
||||
|
||||
it('works for multi-point', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.MULTIPOINT);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTIPOINT);
|
||||
});
|
||||
|
||||
it('works for multi-linestring', function() {
|
||||
var filter = new ol.filter.Geometry(
|
||||
ol.filter.GeometryType.MULTILINESTRING);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTILINESTRING);
|
||||
});
|
||||
|
||||
it('works for multi-polygon', function() {
|
||||
var filter = new ol.filter.Geometry(ol.filter.GeometryType.MULTIPOLYGON);
|
||||
expect(filter.getType()).to.be(ol.filter.GeometryType.MULTIPOLYGON);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.GeometryType');
|
||||
@@ -1,144 +0,0 @@
|
||||
goog.provide('ol.test.filter.Logical');
|
||||
|
||||
|
||||
describe('ol.filter.Logical', function() {
|
||||
|
||||
var OR = ol.filter.LogicalOperator.OR;
|
||||
var AND = ol.filter.LogicalOperator.AND;
|
||||
var NOT = ol.filter.LogicalOperator.NOT;
|
||||
var include = new ol.filter.Filter(function() {return true;});
|
||||
var exclude = new ol.filter.Filter(function() {return false;});
|
||||
|
||||
var apple = new ol.Feature({});
|
||||
var orange = new ol.Feature({});
|
||||
var duck = new ol.Feature({});
|
||||
|
||||
var isApple = new ol.filter.Filter(function(feature) {
|
||||
return feature === apple;
|
||||
});
|
||||
var isOrange = new ol.filter.Filter(function(feature) {
|
||||
return feature === orange;
|
||||
});
|
||||
var isDuck = new ol.filter.Filter(function(feature) {
|
||||
return feature === duck;
|
||||
});
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new filter', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], OR);
|
||||
expect(filter).to.be.a(ol.filter.Logical);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#operator', function() {
|
||||
it('can be OR', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], OR);
|
||||
expect(filter.operator).to.be(OR);
|
||||
});
|
||||
|
||||
it('can be AND', function() {
|
||||
var filter = new ol.filter.Logical([include, exclude], AND);
|
||||
expect(filter.operator).to.be(AND);
|
||||
});
|
||||
|
||||
it('can be NOT', function() {
|
||||
var filter = new ol.filter.Logical([include], NOT);
|
||||
expect(filter.operator).to.be(NOT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#applies', function() {
|
||||
|
||||
it('works for OR', function() {
|
||||
var isFruit = new ol.filter.Logical([isApple, isOrange], OR);
|
||||
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isOrange.applies(apple)).to.be(false);
|
||||
expect(isFruit.applies(apple)).to.be(true);
|
||||
|
||||
expect(isApple.applies(duck)).to.be(false);
|
||||
expect(isOrange.applies(duck)).to.be(false);
|
||||
expect(isFruit.applies(duck)).to.be(false);
|
||||
});
|
||||
|
||||
it('works for AND', function() {
|
||||
expect(include.applies(apple)).to.be(true);
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
|
||||
var pass = new ol.filter.Logical([include, isApple], AND);
|
||||
expect(pass.applies(apple)).to.be(true);
|
||||
|
||||
var fail = new ol.filter.Logical([isApple, isDuck], AND);
|
||||
expect(fail.applies(apple)).to.be(false);
|
||||
});
|
||||
|
||||
it('works for NOT', function() {
|
||||
expect(isApple.applies(apple)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
expect(isDuck.applies(duck)).to.be(true);
|
||||
expect(isDuck.applies(apple)).to.be(false);
|
||||
|
||||
var notApple = new ol.filter.Logical([isApple], NOT);
|
||||
expect(notApple.applies(apple)).to.be(false);
|
||||
expect(notApple.applies(duck)).to.be(true);
|
||||
|
||||
var notDuck = new ol.filter.Logical([isDuck], NOT);
|
||||
expect(notDuck.applies(apple)).to.be(true);
|
||||
expect(notDuck.applies(duck)).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.filter.and', function() {
|
||||
it('creates the a logical AND filter', function() {
|
||||
var a = new ol.filter.Filter();
|
||||
var b = new ol.filter.Filter();
|
||||
var c = new ol.filter.Filter();
|
||||
var and = ol.filter.and(a, b, c);
|
||||
expect(and).to.be.a(ol.filter.Logical);
|
||||
expect(and.operator).to.be(ol.filter.LogicalOperator.AND);
|
||||
var filters = and.getFilters();
|
||||
expect(filters[0]).to.be(a);
|
||||
expect(filters[1]).to.be(b);
|
||||
expect(filters[2]).to.be(c);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.filter.not', function() {
|
||||
it('creates the logical compliment of another filter', function() {
|
||||
var include = new ol.filter.Filter(function() {return true;});
|
||||
var notInclude = ol.filter.not(include);
|
||||
expect(notInclude).to.be.a(ol.filter.Logical);
|
||||
expect(notInclude.applies()).to.be(false);
|
||||
|
||||
var exclude = new ol.filter.Filter(function() {return false;});
|
||||
var notExclude = ol.filter.not(exclude);
|
||||
expect(notExclude).to.be.a(ol.filter.Logical);
|
||||
expect(notExclude.applies()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.filter.or', function() {
|
||||
it('creates the a logical OR filter', function() {
|
||||
var a = new ol.filter.Filter();
|
||||
var b = new ol.filter.Filter();
|
||||
var c = new ol.filter.Filter();
|
||||
var and = ol.filter.or(a, b, c);
|
||||
expect(and).to.be.a(ol.filter.Logical);
|
||||
expect(and.operator).to.be(ol.filter.LogicalOperator.OR);
|
||||
var filters = and.getFilters();
|
||||
expect(filters[0]).to.be(a);
|
||||
expect(filters[1]).to.be(b);
|
||||
expect(filters[2]).to.be(c);
|
||||
});
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.filter.Filter');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.filter.and');
|
||||
goog.require('ol.filter.not');
|
||||
goog.require('ol.filter.or');
|
||||
@@ -50,46 +50,46 @@ describe('ol.layer.Vector', function() {
|
||||
layer.addFeatures(features);
|
||||
});
|
||||
|
||||
var geomFilter = new ol.filter.Geometry(ol.geom.GeometryType.LINESTRING);
|
||||
var extentFilter = new ol.filter.Extent([16, 16.3, 48, 48.3]);
|
||||
var geomFilter = ol.expression.parse('geometryType("linestring")');
|
||||
var extentFilter = ol.expression.parse('extent(16, 16.3, 48, 48.3)');
|
||||
|
||||
it('can filter by geometry type using its GeometryType index', function() {
|
||||
sinon.spy(geomFilter, 'applies');
|
||||
sinon.spy(geomFilter, 'evaluate');
|
||||
var lineStrings = layer.getFeatures(geomFilter);
|
||||
expect(geomFilter.applies).to.not.be.called();
|
||||
expect(geomFilter.evaluate).to.not.be.called();
|
||||
expect(lineStrings.length).to.eql(4);
|
||||
expect(lineStrings).to.contain(features[4]);
|
||||
});
|
||||
|
||||
it('can filter by extent using its RTree', function() {
|
||||
sinon.spy(extentFilter, 'applies');
|
||||
sinon.spy(extentFilter, 'evaluate');
|
||||
var subset = layer.getFeatures(extentFilter);
|
||||
expect(extentFilter.applies).to.not.be.called();
|
||||
expect(extentFilter.evaluate).to.not.be.called();
|
||||
expect(subset.length).to.eql(4);
|
||||
expect(subset).not.to.contain(features[7]);
|
||||
});
|
||||
|
||||
it('can filter by extent and geometry type using its index', function() {
|
||||
var filter1 = new ol.filter.Logical([geomFilter, extentFilter],
|
||||
ol.filter.LogicalOperator.AND);
|
||||
var filter2 = new ol.filter.Logical([extentFilter, geomFilter],
|
||||
ol.filter.LogicalOperator.AND);
|
||||
sinon.spy(filter1, 'applies');
|
||||
sinon.spy(filter2, 'applies');
|
||||
var filter1 = new ol.expression.Logical(
|
||||
ol.expression.LogicalOp.AND, geomFilter, extentFilter);
|
||||
var filter2 = new ol.expression.Logical(
|
||||
ol.expression.LogicalOp.AND, extentFilter, geomFilter);
|
||||
sinon.spy(filter1, 'evaluate');
|
||||
sinon.spy(filter2, 'evaluate');
|
||||
var subset1 = layer.getFeatures(filter1);
|
||||
var subset2 = layer.getFeatures(filter2);
|
||||
expect(filter1.applies).to.not.be.called();
|
||||
expect(filter2.applies).to.not.be.called();
|
||||
expect(filter1.evaluate).to.not.be.called();
|
||||
expect(filter2.evaluate).to.not.be.called();
|
||||
expect(subset1.length).to.eql(0);
|
||||
expect(subset2.length).to.eql(0);
|
||||
});
|
||||
|
||||
it('can handle query using the filter\'s applies function', function() {
|
||||
var filter = new ol.filter.Logical([geomFilter, extentFilter],
|
||||
ol.filter.LogicalOperator.OR);
|
||||
sinon.spy(filter, 'applies');
|
||||
it('can handle query using the filter\'s evaluate function', function() {
|
||||
var filter = new ol.expression.Logical(
|
||||
ol.expression.LogicalOp.OR, geomFilter, extentFilter);
|
||||
sinon.spy(filter, 'evaluate');
|
||||
var subset = layer.getFeatures(filter);
|
||||
expect(filter.applies).to.be.called();
|
||||
expect(filter.evaluate).to.be.called();
|
||||
expect(subset.length).to.eql(8);
|
||||
});
|
||||
|
||||
@@ -179,11 +179,8 @@ describe('ol.layer.Vector', function() {
|
||||
goog.require('goog.dispose');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expression');
|
||||
goog.require('ol.filter.Extent');
|
||||
goog.require('ol.filter.Geometry');
|
||||
goog.require('ol.filter.Logical');
|
||||
goog.require('ol.filter.LogicalOperator');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.expression.Logical');
|
||||
goog.require('ol.expression.LogicalOp');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.proj');
|
||||
|
||||
Reference in New Issue
Block a user