basic zoom filters are working

This commit is contained in:
Konstantin Käfer 2011-01-21 11:13:48 -05:00
parent 37f0b8c121
commit 509c260ac5
3 changed files with 132 additions and 90 deletions

View File

@ -4,7 +4,8 @@ var path = require('path'),
Step = require('step'),
_ = require('underscore')._,
sys = require('sys'),
mess = require('mess');
mess = require('mess'),
tree = require('mess/tree');
require.paths.unshift(path.join(__dirname, '..', 'lib'));
@ -211,7 +212,7 @@ mess.Renderer = function Renderer(env) {
// definitions are ordered in specificity,
// high to low
//
// basically if 'this level' has
// basically if 'this level' has
// a filter, then keep going, otherwise
// this is the final selector.
var winners = [];
@ -244,21 +245,34 @@ mess.Renderer = function Renderer(env) {
},
resolve_filters: function(definitions) {
var negated_filters = [];
var negatedFilters = [];
var negatedZoom = new tree.ZoomFilter('zoom', { value: '>=' }, '0');
for (var i = 0; i < definitions.length; i++) {
if (definitions[i].selector.filters.length) {
// array of the negation of this definition's filters
var negation = definitions[i].selector.filters.map(
function(f) { return f.negate(); });
var filters = definitions[i].selector.filters;
var normal = filters.filter(function(f) { return f instanceof tree.Filter; });
var zoom = filters.filter(function(f) { return f instanceof tree.ZoomFilter; });
// add in existing negations
// TODO: run uniq on this.
definitions[i].selector.filters =
definitions[i].selector.filters.concat(negated_filters);
var negation = normal.map(function(f) { return f.negate(); });
// add this definition's filter's negations to the list
negated_filters = negated_filters.concat(negation);
}
// add in existing negations
// TODO: run uniq on this.
normal.push.apply(normal, negatedFilters);
// add this definition's filter's negations to the list
negatedFilters.push.apply(negatedFilters, negation);
// Merge all zoom filters without overwriting existing zoom
// filters; they might be referenced in other selectors.
var currentZoom = new tree.ZoomFilter('zoom', { value: '>=' }, '0');
zoom.forEach(function(f) { currentZoom.intersection(f); });
// Only add the negated current zoom when there actually are zoom filters.
var negation = zoom.length ? currentZoom.negated() : false;
currentZoom.intersection(negatedZoom);
if (negation) negatedZoom.intersection(negation);
definitions[i].selector.filters = normal.concat([currentZoom]);
}
return definitions;
},
@ -348,14 +362,14 @@ mess.Renderer = function Renderer(env) {
* @param {Array} stylesheets the results of ruleHash().
* @return Formalized layer definition with .styles = [].
*/
var rulesets = _.flatten(stylesheets.map(function(rulesets) {
return rulesets[2].toMSS();
}));
var output = [entities(entity_list)];
// TODO: must change when background colors are available
output.push('<Map background-color="'
output.push('<Map background-color="'
+ "#ffffff"
// findBackground(stylesheets)
+ '" srs="+proj=merc +a=6378137 +b=6378137 '
@ -369,7 +383,7 @@ mess.Renderer = function Renderer(env) {
var matching = rulesets.filter(function(ruleset) {
return ruleset.selector.matches(l.id, classes);
});
// matching is an array of matching selectors,
// in order from high specificity to low.
var by_symbolizer = that.split_symbolizers(matching);
@ -391,7 +405,7 @@ mess.Renderer = function Renderer(env) {
// output.push(references(entity_list));
// output.push(stylesheet_tmpl(m));
output.push('</Map>');
callback(null, output.join('\n'));
},

View File

@ -58,11 +58,25 @@ tree.Selector.prototype.combinedFilter = function() {
return f instanceof tree.ZoomFilter;
});
return normal_filters.length ?
'<Filter>' + normal_filters.map(function(f) {
var filters = [];
if (normal_filters.length) {
filters.push('<Filter>' + normal_filters.map(function(f) {
return '(' + f.toXML().trim() + ')';
}).join(' and ') + '</Filter>'
: '<ElseFilter/>';
}).join(' and ') + '</Filter>');
}
if (zoom_filters.length) {
filters.push(zoom_filters.map(function(f) {
return f.toXML();
}));
}
if (!filters.length) {
return '<ElseFilter/>';
}
else {
return filters.join('');
}
};
})(require('mess/tree'));

View File

@ -1,11 +1,41 @@
(function(tree) {
tree.ZoomFilter = function(key, op, val, index) {
this.key = key;
this.op = op;
this.val = parseInt(val);
this.index = index;
this.zoom_range = tree.ZoomFilter.create_range(this.op.value, this.val);
tree.ZoomFilter = function(key, op, value, index) {
value = parseInt(value);
if (value > tree.ZoomFilter.maxZoom || value < 0) {
throw {
message: 'Only zoom levels between 0 and ' + tree.ZoomFilter.maxZoom + ' supported.',
index: index
};
}
this.range = tree.ZoomFilter.createRange(op.value, value);
};
tree.ZoomFilter.maxZoom = 22;
tree.ZoomFilter.ranges = {
1: 500000000,
2: 200000000,
3: 100000000,
4: 50000000,
5: 25000000,
6: 12500000,
7: 6500000,
8: 3000000,
9: 1500000,
10: 750000,
11: 400000,
12: 200000,
13: 100000,
14: 50000,
15: 25000,
16: 12500,
17: 5000,
18: 2500,
19: 1000,
20: 500,
21: 250,
22: 100
};
/**
@ -13,30 +43,46 @@ tree.ZoomFilter = function(key, op, val, index) {
* which denotes whether this filter should apply
* to each of the zoom levels from 0-22.
*/
tree.ZoomFilter.create_range = function(op, value) {
var max_zoom = 22;
var zoom_range = [];
tree.ZoomFilter.createRange = function(op, value) {
var range = [];
if (op === '>' || op === '>=') {
if (op === '>') value++;
for (var i = 0; i < max_zoom; i++) {
zoom_range[i] = (i >= value);
for (var i = 0; i < tree.ZoomFilter.maxZoom; i++) {
range[i] = (i >= value);
}
} else {
if (op === '<') value--;
for (var i = 0; i < max_zoom; i++) {
zoom_range[i] = (i <= value);
for (var i = 0; i < tree.ZoomFilter.maxZoom; i++) {
range[i] = (i <= value);
}
}
return zoom_range;
return range;
};
/**
* Returns an array of ranges that are set.
*/
tree.ZoomFilter.getRanges = function(range) {
var ranges = [], start = null;
for (var i = 0; i < range.length; i++) {
if (start == null && range[i]) {
start = i;
} else if (start != null && !range[i]) {
ranges.push([start, i - 1]);
start = null;
}
}
if (start != null) ranges.push([start, 22]);
return ranges;
}
/**
* Find the overlap of this and another set
*/
tree.ZoomFilter.prototype.intersection = function(filter) {
if (filter.zoom_range) {
for (var i = 0; i < this.max_zoom; i++) {
this.zoom_range[i] = this.zoom_range[i] && filter.zoom_range[i];
if (filter.range) {
for (var i = 0; i < this.range.length; i++) {
this.range[i] = this.range[i] && filter.range[i];
}
}
};
@ -45,9 +91,9 @@ tree.ZoomFilter.prototype.intersection = function(filter) {
* Find the union of this and another set
*/
tree.ZoomFilter.prototype.union = function(filter) {
if (filter.zoom_range) {
for (var i = 0; i < this.max_zoom; i++) {
this.zoom_range[i] = this.zoom_range[i] || filter.zoom_range[i];
if (filter.range) {
for (var i = 0; i < this.range.length; i++) {
this.range[i] = this.range[i] || filter.range[i];
}
}
};
@ -60,58 +106,26 @@ tree.ZoomFilter.prototype.union = function(filter) {
* Usage is for doing the equivalent of an ElseFilter
* for defaulting to non-zoom-filtered rules
*/
tree.ZoomFilter.prototype.negate = function() {
this.zoom_range = this.zoom_range.map(function(i) {
tree.ZoomFilter.prototype.negated = function() {
var negated = this.clone();
negated.range = this.range.map(function(i) {
return !i;
});
return this;
return negated;
};
tree.ZoomFilter.prototype.toXML = function(env) {
if (this.val > 22 || this.val < 0) {
throw {
message: 'Only zoom levels between 0 and 22 supported.',
index: this.index
};
}
var zooms = {
'1': [200000000, 500000000],
'2': [100000000, 200000000],
'3': [50000000, 100000000],
'4': [25000000, 50000000],
'5': [12500000, 25000000],
'6': [6500000, 12500000],
'7': [3000000, 6500000],
'8': [1500000, 3000000],
'9': [750000, 1500000],
'10': [400000, 750000],
'11': [200000, 400000],
'12': [100000, 200000],
'13': [50000, 100000],
'14': [25000, 50000],
'15': [12500, 25000],
'16': [5000, 12500],
'17': [2500, 5000],
'18': [1000, 2500],
'19': [500, 1000],
'20': [250, 500],
'21': [100, 250],
'22': [50, 100]};
switch (this.op.value) {
case '>':
return '<MaxScaleDenominator>' + zooms[this.val][0] +
'</MaxScaleDenominator>';
case '>=':
return '<MaxScaleDenominator>' + zooms[this.val][1] +
'</MaxScaleDenominator>';
case '<':
return '<MinScaleDenominator>' + zooms[this.val][1] +
'</MinScaleDenominator>';
case '<=':
return '<MinScaleDenominator>' + zooms[this.val][0] +
'</MinScaleDenominator>';
}
var ranges = tree.ZoomFilter.getRanges(this.range);
return ranges.map(function(range) {
return (range[0] > 0 ? '<MinScaleDenominator>' + /*tree.ZoomFilter.ranges[*/range[0]/*]*/ + '</MinScaleDenominator>' : '') +
(range[1] < 22 ? '<MaxScaleDenominator>' + /*tree.ZoomFilter.ranges[*/range[1]/*]*/ + '</MaxScaleDenominator>' : '');
});
};
tree.ZoomFilter.prototype.clone = function() {
var obj = Object.create(Object.getPrototypeOf(this));
obj.range = this.range.slice();
return obj;
}
})(require('mess/tree'));