Skip to content

Commit

Permalink
Making consistent the evaluate method of filters. The evaluate method…
Browse files Browse the repository at this point in the history
… accepts vector features, making possible logical filters that combine spatial and comparison filters. r=ahocevar (closes #2773)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@10596 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
  • Loading branch information
tschaub committed Aug 5, 2010
1 parent c15a1a0 commit e0c3db1
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 23 deletions.
3 changes: 2 additions & 1 deletion lib/OpenLayers/Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ OpenLayers.Filter = OpenLayers.Class({
* subclasses.
*
* Parameters:
* context - {Object} Context to use in evaluating the filter.
* context - {Object} Context to use in evaluating the filter. If a vector
* feature is provided, the feature.attributes will be used as context.
*
* Returns:
* {Boolean} The filter applies.
Expand Down
26 changes: 14 additions & 12 deletions lib/OpenLayers/Filter/Comparison.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,23 @@ OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {

/**
* APIMethod: evaluate
* Evaluates this filter in a specific context. Should be implemented by
* subclasses.
* Evaluates this filter in a specific context.
*
* Parameters:
* context - {Object} Context to use in evaluating the filter.
* context - {Object} Context to use in evaluating the filter. If a vector
* feature is provided, the feature.attributes will be used as context.
*
* Returns:
* {Boolean} The filter applies.
*/
evaluate: function(context) {
if (context instanceof OpenLayers.Feature.Vector) {
context = context.attributes;
}
var result = false;
var got = context[this.property];
switch(this.type) {
case OpenLayers.Filter.Comparison.EQUAL_TO:
var got = context[this.property];
var exp = this.value;
if(!this.matchCase &&
typeof got == "string" && typeof exp == "string") {
Expand All @@ -116,7 +119,6 @@ OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
}
break;
case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
var got = context[this.property];
var exp = this.value;
if(!this.matchCase &&
typeof got == "string" && typeof exp == "string") {
Expand All @@ -126,24 +128,24 @@ OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
}
break;
case OpenLayers.Filter.Comparison.LESS_THAN:
result = context[this.property] < this.value;
result = got < this.value;
break;
case OpenLayers.Filter.Comparison.GREATER_THAN:
result = context[this.property] > this.value;
result = got > this.value;
break;
case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
result = context[this.property] <= this.value;
result = got <= this.value;
break;
case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
result = context[this.property] >= this.value;
result = got >= this.value;
break;
case OpenLayers.Filter.Comparison.BETWEEN:
result = (context[this.property] >= this.lowerBoundary) &&
(context[this.property] <= this.upperBoundary);
result = (got >= this.lowerBoundary) &&
(got <= this.upperBoundary);
break;
case OpenLayers.Filter.Comparison.LIKE:
var regexp = new RegExp(this.value, "gi");
result = regexp.test(context[this.property]);
result = regexp.test(got);
break;
}
return result;
Expand Down
7 changes: 4 additions & 3 deletions lib/OpenLayers/Filter/Logical.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {

/**
* APIMethod: evaluate
* Evaluates this filter in a specific context. Should be implemented by
* subclasses.
* Evaluates this filter in a specific context.
*
* Parameters:
* context - {Object} Context to use in evaluating the filter.
* context - {Object} Context to use in evaluating the filter. A vector
* feature may also be provided to evaluate feature attributes in
* comparison filters or geometries in spatial filters.
*
* Returns:
* {Boolean} The filter applies.
Expand Down
112 changes: 111 additions & 1 deletion tests/Filter/Comparison.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,117 @@
}

}


function test_evaluate_feature(t) {

var cases = [{
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.BETWEEN,
property: "area",
lowerBoundary: 1000,
upperBoundary: 4999
}),
context: new OpenLayers.Feature.Vector(null, {area: 999}),
expect: false
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.BETWEEN,
property: "area",
lowerBoundary: 1000,
upperBoundary: 4999
}),
context: new OpenLayers.Feature.Vector(null, {area: 1000}),
expect: true
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.BETWEEN,
property: "area",
lowerBoundary: 1000,
upperBoundary: 4999
}),
context: new OpenLayers.Feature.Vector(null, {area: 4999}),
expect: true
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.BETWEEN,
property: "area",
lowerBoundary: 1000,
upperBoundary: 4999
}),
context: new OpenLayers.Feature.Vector(null, {area: 5000}),
expect: false
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.BETWEEN,
property: "area",
lowerBoundary: 1000,
upperBoundary: 4999
}),
context: new OpenLayers.Feature.Vector(null, {area: 999}),
expect: false
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "prop",
value: "Foo"
}),
context: new OpenLayers.Feature.Vector(null, {prop: "Foo"}),
expect: true
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "prop",
value: "Foo"
}),
context: new OpenLayers.Feature.Vector(null, {prop: "foo"}),
expect: false
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
matchCase: true,
property: "prop",
value: "Foo"
}),
context: new OpenLayers.Feature.Vector(null, {prop: "foo"}),
expect: false
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
property: "prop",
value: "foo"
}),
context: {prop: "FOO"},
expect: true
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
matchCase: true,
property: "prop",
value: "foo"
}),
context: new OpenLayers.Feature.Vector(null, {prop: "FOO"}),
expect: true
}, {
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
matchCase: false,
property: "prop",
value: "foo"
}),
context: new OpenLayers.Feature.Vector(null, {prop: "FOO"}),
expect: false
}];

t.plan(cases.length);

var c;
for(var i=0; i<cases.length; ++i) {
c = cases[i];
t.eq(c.filter.evaluate(c.context), c.expect, "case " + i + ": " + c.filter.type);
}

}

function test_clone(t) {

t.plan(3);
Expand Down
69 changes: 69 additions & 0 deletions tests/Filter/Logical.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,75 @@
"feature evaluates to false correctly.");
}

function test_evaluate_feature(t) {
t.plan(6);

var feature = new OpenLayers.Feature.Vector(null, {
pop: 200,
name: "foo"
});

var smallPop = new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.LESS_THAN,
property: "pop",
value: 120
});

var bigPop = new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.GREATER_THAN,
property: "pop",
value: 120
});

var namedFoo = new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "name",
value: "foo"
});

var filter;

// test simple not
filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.NOT,
filters: [smallPop]
});
t.eq(filter.evaluate(feature), true, "not smallPop");

filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.NOT,
filters: [bigPop]
});
t.eq(filter.evaluate(feature), false, "not bigPop");

// test or
filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.OR,
filters: [smallPop, namedFoo]
});
t.eq(filter.evaluate(feature), true, "smallPop or namedFoo");

filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.OR,
filters: [bigPop, namedFoo]
});
t.eq(filter.evaluate(feature), true, "bigPop or namedFoo");

// test and
filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.AND,
filters: [smallPop, namedFoo]
});
t.eq(filter.evaluate(feature), false, "smallPop and namedFoo");

filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.AND,
filters: [bigPop, namedFoo]
});
t.eq(filter.evaluate(feature), true, "bigPop and namedFoo");

}

function test_clone(t) {

t.plan(2);
Expand Down
21 changes: 15 additions & 6 deletions tests/Filter/Spatial.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
}

function test_evaluate(t) {
t.plan(4);
t.plan(8);

var filer, feature, res, geom, bounds;

Expand All @@ -33,21 +33,25 @@
value: bounds
});

// 1 test
var not = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.NOT,
filters: [filter]
});

feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(2, 2));
res = filter.evaluate(feature);
t.eq(res, true,
"evaluates returns correct value when feature intersects bounds");

// 1 test
t.eq(not.evaluate(feature), !res, "not bbox");

feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(20, 20));
res = filter.evaluate(feature);
t.eq(res, false,
"evaluates returns correct value when feature does not intersect bounds");
t.eq(not.evaluate(feature), !res, "not outside bbox");

// 1 test
geom = bounds.toGeometry();
feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(2, 2));
Expand All @@ -58,18 +62,23 @@
res = filter.evaluate(feature);
t.eq(res, true,
"evaluates returns correct value when feature intersects bounds");
not.filters = [filter];
t.eq(not.evaluate(feature), !res, "not intersection");

// 1 test
geom = bounds.toGeometry();
feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(20, 20));
filter = new OpenLayers.Filter.Spatial({
type: OpenLayers.Filter.Spatial.INTERSECTS,
value: geom
});
not.filters = [filter];
res = filter.evaluate(feature);
t.eq(res, false,
"evaluates returns correct value when feature does not intersect bounds");
t.eq(not.evaluate(feature), !res, "not non-intersection");


}

function test_clone(t) {
Expand Down

0 comments on commit e0c3db1

Please sign in to comment.