Merge pull request #1089 from ahocevar/no-geometry-type-groups

No longer group features by geometry type
This commit is contained in:
ahocevar
2013-10-03 07:35:14 -07:00
4 changed files with 42 additions and 260 deletions

View File

@@ -6,13 +6,7 @@ goog.require('goog.asserts');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.expr');
goog.require('ol.expr.Literal');
goog.require('ol.expr.Logical');
goog.require('ol.expr.LogicalOp');
goog.require('ol.expr.functions');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.layer.Layer');
goog.require('ol.proj');
goog.require('ol.source.Vector');
@@ -34,12 +28,6 @@ ol.layer.FeatureCache = function() {
*/
this.idLookup_;
/**
* @type {Object.<string, ol.Feature>}
* @private
*/
this.geometryTypeIndex_;
/**
* @type {ol.structs.RTree}
* @private
@@ -56,11 +44,6 @@ ol.layer.FeatureCache = function() {
*/
ol.layer.FeatureCache.prototype.clear = function() {
this.idLookup_ = {};
var geometryTypeIndex = {};
for (var key in ol.geom.GeometryType) {
geometryTypeIndex[ol.geom.GeometryType[key]] = {};
}
this.geometryTypeIndex_ = geometryTypeIndex;
this.rTree_ = new ol.structs.RTree();
};
@@ -75,99 +58,18 @@ ol.layer.FeatureCache.prototype.add = function(feature) {
this.idLookup_[id] = feature;
// index by geometry type and bounding box
// index by bounding box
if (!goog.isNull(geometry)) {
var geometryType = geometry.getType();
this.geometryTypeIndex_[geometryType][id] = feature;
this.rTree_.insert(geometry.getBounds(),
feature, geometryType);
this.rTree_.insert(geometry.getBounds(), feature);
}
};
/**
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
*/
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_expr) {
var features;
if (!goog.isDef(opt_expr)) {
features = this.idLookup_;
} else {
// check for geometryType or extent expression
var name = ol.expr.isLibCall(opt_expr);
if (name === ol.expr.functions.GEOMETRY_TYPE) {
var args = /** @type {ol.expr.Call} */ (opt_expr).getArgs();
goog.asserts.assert(args.length === 1);
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
var type = /** @type {ol.expr.Literal } */ (args[0]).evaluate();
goog.asserts.assertString(type);
features = this.geometryTypeIndex_[type];
} else if (name === ol.expr.functions.EXTENT) {
var args = /** @type {ol.expr.Call} */ (opt_expr).getArgs();
goog.asserts.assert(args.length === 4);
for (var i = 0; i < 4; ++i) {
goog.asserts.assert(args[i] instanceof ol.expr.Literal);
}
var extent = [
/** @type {ol.expr.Literal} */ (args[0]).evaluate(),
/** @type {ol.expr.Literal} */ (args[1]).evaluate(),
/** @type {ol.expr.Literal} */ (args[2]).evaluate(),
/** @type {ol.expr.Literal} */ (args[3]).evaluate()
];
features = this.rTree_.searchReturningObject(extent);
} else {
// not a call expression, check logical
if (opt_expr instanceof ol.expr.Logical) {
var op = /** @type {ol.expr.Logical} */ (opt_expr).getOperator();
if (op === ol.expr.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.expr.isLibCall(expr);
if (name === ol.expr.functions.GEOMETRY_TYPE) {
args = /** @type {ol.expr.Call} */ (expr).getArgs();
goog.asserts.assert(args.length === 1);
goog.asserts.assert(args[0] instanceof ol.expr.Literal);
type = /** @type {ol.expr.Literal } */ (args[0]).evaluate();
goog.asserts.assertString(type);
} else if (name === ol.expr.functions.EXTENT) {
args = /** @type {ol.expr.Call} */ (expr).getArgs();
goog.asserts.assert(args.length === 4);
for (var j = 0; j < 4; ++j) {
goog.asserts.assert(args[j] instanceof ol.expr.Literal);
}
extent = [[
/** @type {ol.expr.Literal} */ (args[0]).evaluate(),
/** @type {ol.expr.Literal} */ (args[1]).evaluate()
], [
/** @type {ol.expr.Literal} */ (args[2]).evaluate(),
/** @type {ol.expr.Literal} */ (args[3]).evaluate()
]];
}
}
if (type && extent) {
features = this.getFeaturesObjectForExtent(extent,
/** @type {ol.geom.GeometryType} */ (type));
}
}
}
}
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 (ol.expr.evaluateFeature(opt_expr, feature)) {
features[i] = feature;
}
}
}
}
return features;
ol.layer.FeatureCache.prototype.getFeaturesObject = function() {
return this.idLookup_;
};
@@ -175,19 +77,10 @@ ol.layer.FeatureCache.prototype.getFeaturesObject = function(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.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;
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent) {
return this.rTree_.searchReturningObject(extent);
};
@@ -228,10 +121,8 @@ ol.layer.FeatureCache.prototype.remove = function(feature) {
delete this.idLookup_[id];
// index by geometry type and bounding box
// index by bounding box
if (!goog.isNull(geometry)) {
var geometryType = geometry.getType();
delete this.geometryTypeIndex_[geometryType][id];
this.rTree_.remove(geometry.getBounds(), feature);
}
};
@@ -362,18 +253,17 @@ ol.layer.Vector.prototype.getStyle = function() {
*
* @param {ol.Extent} extent Bounding extent.
* @param {ol.proj.Projection} projection Target projection.
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
* @param {Function=} opt_callback Callback to call when data is parsed.
* @return {Object.<string, ol.Feature>} Features or null if source is loading
* data for `extent`.
*/
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
projection, opt_type, opt_callback) {
projection, opt_callback) {
var source = this.getSource();
return source.prepareFeatures(this, extent, projection, opt_callback) ==
ol.source.VectorLoadState.LOADING ?
null :
this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
this.featureCache_.getFeaturesObjectForExtent(extent);
};

View File

@@ -101,21 +101,6 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
*/
this.tileArchetype_ = null;
/**
* Geometry types in rendering order.
* TODO: these will go away shortly (in favor of one call per symbolizer type)
* @private
* @type {Array.<ol.geom.GeometryType>}
*/
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
];
/**
* @private
* @type {number}
@@ -464,14 +449,10 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
var tilesOnSketchCanvas = {};
// TODO make gutter configurable?
var tileGutter = 15 * tileResolution;
var tile, tileCoord, key, x, y;
// render features by geometry type
var types = this.geometryTypes_,
numTypes = types.length,
deferred = false,
dirty = false,
i, type, tileExtent,
groups, group, j, numGroups, featuresObject, tileHasFeatures;
var tile, tileCoord, key, x, y, i, type;
var deferred = false;
var dirty = false;
var tileExtent, groups, group, j, numGroups, featuresObject, tileHasFeatures;
fetchTileData:
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
@@ -486,21 +467,15 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
tileExtent[1] -= tileGutter;
tileExtent[3] += tileGutter;
tileHasFeatures = false;
for (i = 0; i < numTypes; ++i) {
type = types[i];
if (!goog.isDef(featuresToRender[type])) {
featuresToRender[type] = {};
}
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
projection, type, this.requestMapRenderFrame_);
if (goog.isNull(featuresObject)) {
deferred = true;
break fetchTileData;
}
tileHasFeatures = tileHasFeatures ||
!goog.object.isEmpty(featuresObject);
goog.object.extend(featuresToRender[type], featuresObject);
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
projection, this.requestMapRenderFrame_);
if (goog.isNull(featuresObject)) {
deferred = true;
break fetchTileData;
}
tileHasFeatures = tileHasFeatures ||
!goog.object.isEmpty(featuresObject);
goog.object.extend(featuresToRender, featuresObject);
if (tileHasFeatures) {
tilesOnSketchCanvas[key] = tileCoord;
}
@@ -511,19 +486,15 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
}
this.dirty_ = dirty;
renderByGeometryType:
for (type in featuresToRender) {
groups = layer.groupFeaturesBySymbolizerLiteral(
featuresToRender[type], tileResolution);
numGroups = groups.length;
for (j = 0; j < numGroups; ++j) {
group = groups[j];
deferred = sketchCanvasRenderer.renderFeaturesByGeometryType(
/** @type {ol.geom.GeometryType} */ (type),
group[0], group[1], group[2]);
if (deferred) {
break renderByGeometryType;
}
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender,
tileResolution);
numGroups = groups.length;
for (j = 0; j < numGroups; ++j) {
group = groups[j];
deferred = sketchCanvasRenderer.renderFeatures(group[0], group[1],
group[2]);
if (deferred) {
break;
}
}

View File

@@ -114,42 +114,21 @@ ol.renderer.canvas.Vector.prototype.getMaxSymbolSize = function() {
/**
* @param {ol.geom.GeometryType} type Geometry type.
* @param {Array.<ol.Feature>} features Array of features.
* @param {ol.style.Literal} symbolizer Symbolizer.
* @param {Array} data Additional data.
* @return {boolean} true if deferred, false if rendered.
*/
ol.renderer.canvas.Vector.prototype.renderFeaturesByGeometryType =
function(type, features, symbolizer, data) {
ol.renderer.canvas.Vector.prototype.renderFeatures =
function(features, symbolizer, data) {
var deferred = false;
if (!(symbolizer instanceof ol.style.TextLiteral)) {
switch (type) {
case ol.geom.GeometryType.POINT:
case ol.geom.GeometryType.MULTIPOINT:
goog.asserts.assert(symbolizer instanceof ol.style.PointLiteral,
'Expected point symbolizer: ' + symbolizer);
deferred = this.renderPointFeatures_(
features, /** @type {ol.style.PointLiteral} */ (symbolizer));
break;
case ol.geom.GeometryType.LINESTRING:
case ol.geom.GeometryType.MULTILINESTRING:
goog.asserts.assert(symbolizer instanceof ol.style.LineLiteral,
'Expected line symbolizer: ' + symbolizer);
this.renderLineStringFeatures_(
features, /** @type {ol.style.LineLiteral} */ (symbolizer));
break;
case ol.geom.GeometryType.POLYGON:
case ol.geom.GeometryType.MULTIPOLYGON:
goog.asserts.assert(symbolizer instanceof ol.style.PolygonLiteral,
'Expected polygon symbolizer: ' + symbolizer);
this.renderPolygonFeatures_(
features, /** @type {ol.style.PolygonLiteral} */ (symbolizer));
break;
default:
throw new Error('Rendering not implemented for geometry type: ' + type);
}
} else {
if (symbolizer instanceof ol.style.PointLiteral) {
deferred = this.renderPointFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.LineLiteral) {
this.renderLineStringFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.PolygonLiteral) {
this.renderPolygonFeatures_(features, symbolizer);
} else if (symbolizer instanceof ol.style.TextLiteral) {
this.renderText_(features, symbolizer, data);
}
return deferred;