Merge pull request #1096 from tschaub/editable-features

Editable geometries and features.
This commit is contained in:
Tim Schaub
2013-10-03 19:22:30 -07:00
17 changed files with 480 additions and 66 deletions

View File

@@ -1,7 +1,13 @@
goog.provide('ol.Feature');
goog.provide('ol.FeatureEvent');
goog.provide('ol.FeatureEventType');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.layer.VectorLayerRenderIntent');
@@ -99,16 +105,44 @@ ol.Feature.prototype.getSymbolizers = function() {
};
/**
* Listener for geometry change events.
* @param {ol.geom.GeometryEvent} evt Geometry event.
* @private
*/
ol.Feature.prototype.handleGeometryChange_ = function(evt) {
this.dispatchEvent(new ol.FeatureEvent(
ol.FeatureEventType.CHANGE, this, evt.oldExtent));
};
/**
* @inheritDoc
* @param {string} key Key.
* @param {*} value Value.
*/
ol.Feature.prototype.set = function(key, value) {
if (!goog.isDef(this.geometryName_) && (value instanceof ol.geom.Geometry)) {
this.geometryName_ = key;
var geometry = this.getGeometry();
var oldExtent = null;
if (goog.isDefAndNotNull(geometry)) {
oldExtent = geometry.getBounds();
if (key === this.geometryName_) {
goog.events.unlisten(geometry, goog.events.EventType.CHANGE,
this.handleGeometryChange_, false, this);
}
}
if (value instanceof ol.geom.Geometry) {
if (!goog.isDef(this.geometryName_)) {
this.geometryName_ = key;
}
if (key === this.geometryName_) {
goog.events.listen(value, goog.events.EventType.CHANGE,
this.handleGeometryChange_, false, this);
}
}
goog.base(this, 'set', key, value);
this.dispatchEvent(new ol.FeatureEvent(
ol.FeatureEventType.CHANGE, this, oldExtent));
};
@@ -150,3 +184,28 @@ ol.Feature.prototype.setSymbolizers = function(symbolizers) {
* @type {string}
*/
ol.Feature.DEFAULT_GEOMETRY = 'geometry';
/**
* @enum {string}
*/
ol.FeatureEventType = {
CHANGE: 'featurechange'
};
/**
* Constructor for feature events.
* @constructor
* @extends {goog.events.Event}
* @param {string} type Event type.
* @param {ol.Feature} target The target feature.
* @param {ol.Extent} oldExtent The previous geometry extent.
*/
ol.FeatureEvent = function(type, target, oldExtent) {
goog.base(this, type, target);
this.oldExtent = oldExtent;
};
goog.inherits(ol.FeatureEvent, goog.events.Event);

View File

@@ -1,6 +1,9 @@
goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryEvent');
goog.provide('ol.geom.GeometryType');
goog.require('goog.events.Event');
goog.require('goog.events.EventTarget');
goog.require('ol.Extent');
goog.require('ol.TransformFunction');
@@ -8,8 +11,12 @@ goog.require('ol.TransformFunction');
/**
* @constructor
* @extends {goog.events.EventTarget}
*/
ol.geom.Geometry = function() {};
ol.geom.Geometry = function() {
goog.base(this);
};
goog.inherits(ol.geom.Geometry, goog.events.EventTarget);
/**
@@ -48,6 +55,23 @@ ol.geom.Geometry.prototype.getType = goog.abstractMethod;
ol.geom.Geometry.prototype.transform = goog.abstractMethod;
/**
* Constructor for geometry events.
* @constructor
* @extends {goog.events.Event}
* @param {string} type Event type.
* @param {ol.geom.Geometry} target The target geometry.
* @param {ol.Extent} oldExtent The previous geometry extent.
*/
ol.geom.GeometryEvent = function(type, target, oldExtent) {
goog.base(this, type, target);
this.oldExtent = oldExtent;
};
goog.inherits(ol.geom.GeometryEvent, goog.events.Event);
/**
* Geometry types.
*

View File

@@ -1,10 +1,12 @@
goog.provide('ol.geom.LineString');
goog.require('goog.asserts');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.extent');
goog.require('ol.geom');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
@@ -108,6 +110,19 @@ ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) {
};
/**
* Update the linestring coordinates.
* @param {ol.CoordinateArray} coordinates Coordinates array.
*/
ol.geom.LineString.prototype.setCoordinates = function(coordinates) {
var oldBounds = this.bounds_;
this.bounds_ = null;
this.coordinates_ = coordinates;
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldBounds));
};
/**
* @inheritDoc
*/
@@ -118,5 +133,5 @@ ol.geom.LineString.prototype.transform = function(transform) {
coord = coordinates[i];
transform(coord, coord, coord.length);
}
this.bounds_ = null;
this.setCoordinates(coordinates); // for change event
};

View File

@@ -1,8 +1,10 @@
goog.provide('ol.geom.Point');
goog.require('goog.asserts');
goog.require('goog.events.EventType');
goog.require('ol.Coordinate');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
@@ -71,11 +73,24 @@ ol.geom.Point.prototype.getType = function() {
};
/**
* Update the point coordinates.
* @param {ol.Coordinate} coordinates Coordinates array.
*/
ol.geom.Point.prototype.setCoordinates = function(coordinates) {
var oldBounds = this.bounds_;
this.bounds_ = null;
this.coordinates_ = coordinates;
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldBounds));
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.transform = function(transform) {
var coordinates = this.getCoordinates();
transform(coordinates, coordinates, coordinates.length);
this.bounds_ = null;
this.setCoordinates(coordinates); // for change event
};

View File

@@ -1,9 +1,12 @@
goog.provide('ol.geom.Polygon');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.CoordinateArray');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryEvent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LinearRing');
@@ -35,9 +38,10 @@ ol.geom.Polygon = function(coordinates) {
/**
* @type {Array.<ol.geom.LinearRing>}
* @private
*/
this.rings = new Array(numRings);
var ringCoords;
this.rings_ = new Array(numRings);
var ringCoords, ring;
for (var i = 0; i < numRings; ++i) {
ringCoords = coordinates[i];
if (i === 0) {
@@ -51,7 +55,10 @@ ol.geom.Polygon = function(coordinates) {
ringCoords.reverse();
}
}
this.rings[i] = new ol.geom.LinearRing(ringCoords);
ring = new ol.geom.LinearRing(ringCoords);
goog.events.listen(ring, goog.events.EventType.CHANGE,
this.handleRingChange_, false, this);
this.rings_[i] = ring;
}
};
@@ -62,7 +69,7 @@ goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
* @inheritDoc
*/
ol.geom.Polygon.prototype.getBounds = function() {
return this.rings[0].getBounds();
return this.rings_[0].getBounds();
};
@@ -70,10 +77,10 @@ ol.geom.Polygon.prototype.getBounds = function() {
* @return {Array.<ol.CoordinateArray>} Coordinates array.
*/
ol.geom.Polygon.prototype.getCoordinates = function() {
var count = this.rings.length;
var count = this.rings_.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = this.rings[i].getCoordinates();
coordinates[i] = this.rings_[i].getCoordinates();
}
return coordinates;
};
@@ -87,6 +94,34 @@ ol.geom.Polygon.prototype.getType = function() {
};
/**
* Get polygon rings.
* @return {Array.<ol.geom.LinearRing>} Array of rings. The first ring is the
* exterior and any additional rings are interior.
*/
ol.geom.Polygon.prototype.getRings = function() {
return this.rings_;
};
/**
* Listener for ring change events.
* @param {ol.geom.GeometryEvent} evt Geometry event.
* @private
*/
ol.geom.Polygon.prototype.handleRingChange_ = function(evt) {
var ring = evt.target;
var oldExtent = null;
if (ring === this.rings_[0]) {
oldExtent = evt.oldExtent;
} else {
oldExtent = this.getBounds();
}
this.dispatchEvent(new ol.geom.GeometryEvent(goog.events.EventType.CHANGE,
this, oldExtent));
};
/**
* Check whether a given coordinate is inside this polygon. Note that this is a
* fast and simple check - points on an edge or vertex of the polygon or one of
@@ -96,7 +131,7 @@ ol.geom.Polygon.prototype.getType = function() {
* @return {boolean} Whether the coordinate is inside the polygon.
*/
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
var rings = this.rings;
var rings = this.rings_;
/** @type {boolean} */
var containsCoordinate;
for (var i = 0, ii = rings.length; i < ii; ++i) {
@@ -122,7 +157,7 @@ ol.geom.Polygon.prototype.getInteriorPoint = function() {
if (goog.isNull(this.labelPoint_)) {
var center = ol.extent.getCenter(this.getBounds()),
resultY = center[1],
vertices = this.rings[0].getCoordinates(),
vertices = this.rings_[0].getCoordinates(),
intersections = [],
maxLength = 0,
i, vertex1, vertex2, x, segmentLength, resultX;
@@ -163,7 +198,7 @@ ol.geom.Polygon.prototype.getInteriorPoint = function() {
* @inheritDoc
*/
ol.geom.Polygon.prototype.transform = function(transform) {
var rings = this.rings;
var rings = this.rings_;
for (var i = 0, ii = rings.length; i < ii; ++i) {
rings[i].transform(transform);
}

View File

@@ -3,9 +3,11 @@ goog.provide('ol.layer.VectorEventType');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.object');
goog.require('ol.Feature');
goog.require('ol.FeatureEventType');
goog.require('ol.extent');
goog.require('ol.layer.Layer');
goog.require('ol.proj');
@@ -114,16 +116,18 @@ ol.layer.FeatureCache.prototype.getFeatureWithUid = function(uid) {
/**
* Remove a feature from the cache.
* @param {ol.Feature} feature Feature.
* @param {ol.Extent=} opt_extent Optional extent (used when the current feature
* extent is different than the one in the index).
*/
ol.layer.FeatureCache.prototype.remove = function(feature) {
ol.layer.FeatureCache.prototype.remove = function(feature, opt_extent) {
var id = goog.getUid(feature).toString(),
geometry = feature.getGeometry();
delete this.idLookup_[id];
// index by bounding box
if (!goog.isNull(geometry)) {
this.rTree_.remove(geometry.getBounds(), feature);
var extent = goog.isDef(opt_extent) ? opt_extent : geometry.getBounds();
this.rTree_.remove(extent, feature);
}
};
@@ -181,19 +185,44 @@ ol.layer.Vector.prototype.addFeatures = function(features) {
if (!goog.isNull(geometry)) {
ol.extent.extend(extent, geometry.getBounds());
}
goog.events.listen(feature, ol.FeatureEventType.CHANGE,
this.handleFeatureChange_, false, this);
}
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.ADD,
features, [extent]));
};
/**
* Listener for feature change events.
* @param {ol.FeatureEvent} evt The feature change event.
* @private
*/
ol.layer.Vector.prototype.handleFeatureChange_ = function(evt) {
goog.asserts.assertInstanceof(evt.target, ol.Feature);
var feature = /** @type {ol.Feature} */ (evt.target);
var extents = [];
if (!goog.isNull(evt.oldExtent)) {
extents.push(evt.oldExtent);
}
var geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
this.featureCache_.remove(feature, evt.oldExtent);
this.featureCache_.add(feature);
extents.push(geometry.getBounds());
}
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE,
[feature], extents));
};
/**
* Remove all features from the layer.
*/
ol.layer.Vector.prototype.clear = function() {
this.featureCache_.clear();
this.dispatchEvent(
new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE, [], []));
new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE, [], []));
};

View File

@@ -155,7 +155,7 @@ ol.parser.GPX = function(opt_options) {
var desc = attributes['description'] || this.defaultDesc;
this.writeNode('desc', desc, undefined, node);
var geom = feature.getGeometry();
var i, ii;
var i, ii, rings;
if (geom instanceof ol.geom.LineString) {
this.writeNode('trkseg', feature.getGeometry(), undefined, node);
} else if (geom instanceof ol.geom.MultiLineString) {
@@ -163,8 +163,9 @@ ol.parser.GPX = function(opt_options) {
this.writeNode('trkseg', geom.components[i], undefined, node);
}
} else if (geom instanceof ol.geom.Polygon) {
for (i = 0, ii = geom.rings.length; i < ii; ++i) {
this.writeNode('trkseg', geom.rings[i], undefined, node);
rings = geom.getRings();
for (i = 0, ii = rings.length; i < ii; ++i) {
this.writeNode('trkseg', rings[i], undefined, node);
}
}
return node;

View File

@@ -229,9 +229,10 @@ ol.parser.WKT.prototype.encodeMultiLineString_ = function(geom) {
*/
ol.parser.WKT.prototype.encodePolygon_ = function(geom) {
var array = [];
for (var i = 0, ii = geom.rings.length; i < ii; ++i) {
var rings = geom.getRings();
for (var i = 0, ii = rings.length; i < ii; ++i) {
array.push('(' + this.encodeLineString_.apply(this,
[geom.rings[i]]) + ')');
[rings[i]]) + ')');
}
return array.join(',');
};

View File

@@ -362,7 +362,7 @@ ol.renderer.canvas.Vector.prototype.renderPolygonFeatures_ =
}
for (j = 0, jj = components.length; j < jj; ++j) {
poly = components[j];
rings = poly.rings;
rings = poly.getRings();
numRings = rings.length;
if (numRings > 0) {
// TODO: scenario 4