diff --git a/src/ol/render/canvas/canvasimmediate.js b/src/ol/render/canvas/canvasimmediate.js index 9736439c03..0f86efa3fa 100644 --- a/src/ol/render/canvas/canvasimmediate.js +++ b/src/ol/render/canvas/canvasimmediate.js @@ -242,7 +242,8 @@ ol.render.canvas.Immediate.prototype.drawRings_ = */ ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) { var geometry = feature.getGeometry(); - if (!ol.extent.intersects(this.extent_, geometry.getExtent())) { + if (goog.isNull(geometry) || + !ol.extent.intersects(this.extent_, geometry.getExtent())) { return; } this.setFillStrokeStyle(style.getFill(), style.getStroke()); diff --git a/src/ol/render/vector.js b/src/ol/render/vector.js index d612492422..a8e037b495 100644 --- a/src/ol/render/vector.js +++ b/src/ol/render/vector.js @@ -21,11 +21,15 @@ goog.require('ol.style.Style'); */ ol.renderer.vector.renderFeature = function( replayGroup, feature, style, squaredTolerance, data) { - var geometry = feature.getGeometry().getSimplifiedGeometry(squaredTolerance); + var geometry = feature.getGeometry(); + if (goog.isNull(geometry)) { + return; + } + var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); var geometryRenderer = - ol.renderer.vector.GEOMETRY_RENDERERS_[geometry.getType()]; + ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()]; goog.asserts.assert(goog.isDef(geometryRenderer)); - geometryRenderer(replayGroup, geometry, style, data); + geometryRenderer(replayGroup, simplifiedGeometry, style, data); }; diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index a69c70ca6d..818868ae6b 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -160,7 +160,9 @@ ol.source.Vector.prototype.forEachFeatureAtCoordinate = function(coordinate, f, opt_obj) { var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]]; return this.forEachFeatureInExtent(extent, function(feature) { - if (feature.getGeometry().containsCoordinate(coordinate)) { + var geometry = feature.getGeometry(); + goog.asserts.assert(!goog.isNull(geometry)); + if (geometry.containsCoordinate(coordinate)) { return f.call(opt_obj, feature); } else { return undefined; @@ -277,7 +279,22 @@ ol.source.Vector.prototype.getExtent = function() { */ ol.source.Vector.prototype.handleFeatureChange_ = function(event) { var feature = /** @type {ol.Feature} */ (event.target); - this.rBush_.update(feature.getGeometry().getExtent(), feature); + var featureKey = goog.getUid(feature).toString(); + var geometry = feature.getGeometry(); + if (goog.isNull(geometry)) { + if (!(featureKey in this.nullGeometryFeatures_)) { + this.rBush_.remove(feature); + this.nullGeometryFeatures_[featureKey] = feature; + } + } else { + var extent = geometry.getExtent(); + if (featureKey in this.nullGeometryFeatures_) { + delete this.nullGeometryFeatures_[featureKey]; + this.rBush_.insert(extent, feature); + } else { + this.rBush_.update(extent, feature); + } + } this.dispatchChangeEvent(); }; diff --git a/test/spec/ol/source/vectorsource.test.js b/test/spec/ol/source/vectorsource.test.js index 975a793af6..81611b0a4c 100644 --- a/test/spec/ol/source/vectorsource.test.js +++ b/test/spec/ol/source/vectorsource.test.js @@ -187,6 +187,54 @@ describe('ol.source.Vector', function() { }); + describe('tracking changes to features', function() { + + var vectorSource; + beforeEach(function() { + vectorSource = new ol.source.Vector(); + }); + + it('keeps its index up-to-date', function() { + var feature = new ol.Feature(new ol.geom.Point([1, 1])); + vectorSource.addFeature(feature); + expect(vectorSource.getAllFeaturesInExtent([0, 0, 2, 2])). + to.eql([feature]); + feature.getGeometry().setCoordinates([3, 3]); + expect(vectorSource.getAllFeaturesInExtent([0, 0, 2, 2])). + to.be.empty(); + expect(vectorSource.getAllFeaturesInExtent([2, 2, 4, 4])). + to.eql([feature]); + }); + + it('handles features with null geometries', function() { + var feature = new ol.Feature(null); + vectorSource.addFeature(feature); + expect(vectorSource.getAllFeatures()).to.eql([feature]); + }); + + it('handles features with geometries changing from null', function() { + var feature = new ol.Feature(null); + vectorSource.addFeature(feature); + expect(vectorSource.getAllFeatures()).to.eql([feature]); + feature.setGeometry(new ol.geom.Point([1, 1])); + expect(vectorSource.getAllFeaturesInExtent([0, 0, 2, 2])). + to.eql([feature]); + expect(vectorSource.getAllFeatures()).to.eql([feature]); + }); + + it('handles features with geometries changing to null', function() { + var feature = new ol.Feature(new ol.geom.Point([1, 1])); + vectorSource.addFeature(feature); + expect(vectorSource.getAllFeatures()).to.eql([feature]); + expect(vectorSource.getAllFeaturesInExtent([0, 0, 2, 2])). + to.eql([feature]); + feature.setGeometry(null); + expect(vectorSource.getAllFeaturesInExtent([0, 0, 2, 2])).to.be.empty(); + expect(vectorSource.getAllFeatures()).to.eql([feature]); + }); + + }); + });