From 42935408fb583903d1538cb790507bc9da808f7d Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 6 Mar 2014 14:05:56 +0100 Subject: [PATCH 1/4] Keep track of intersecting segments Because we have nodes sorted by segment distance from the editing vertex in #handleMouseAtPixel(), it is cheap to create a hash of intersecting segments there. Now in #handleDragStart(), we do not need to measure the distance of the vertex to the segment. Instead, we just test if the segment is in the hash. --- src/ol/interaction/modifyinteraction.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ol/interaction/modifyinteraction.js b/src/ol/interaction/modifyinteraction.js index 62a9ccc565..532b797ff7 100644 --- a/src/ol/interaction/modifyinteraction.js +++ b/src/ol/interaction/modifyinteraction.js @@ -49,6 +49,13 @@ ol.interaction.Modify = function(options) { */ this.vertexFeature_ = null; + /** + * Segments intersecting {@link this.vertexFeature_} by segment uid. + * @type {Object.} + * @private + */ + this.vertexSegments_ = null; + /** * @type {boolean} * @private @@ -379,8 +386,7 @@ ol.interaction.Modify.prototype.handleDragStart = function(evt) { this.dragSegments_.push([segmentDataMatch, 0]); } else if (ol.coordinate.equals(segment[1], vertex)) { this.dragSegments_.push([segmentDataMatch, 1]); - } else if ( - ol.coordinate.squaredDistanceToSegment(vertex, segment) === 0) { + } else if (goog.getUid(segment) in this.vertexSegments_) { insertVertices.push([segmentDataMatch, vertex]); } } @@ -518,6 +524,18 @@ ol.interaction.Modify.prototype.handleMouseAtPixel_ = function(pixel, map) { vertex = squaredDist1 > squaredDist2 ? segment[1] : segment[0]; } this.createOrUpdateVertexFeature_(vertex); + var vertexSegments = {}; + vertexSegments[goog.getUid(segment)] = true; + for (var i = 1, ii = nodes.length; i < ii; ++i) { + segment = nodes[i].segment; + if (ol.coordinate.equals(vertex, + ol.coordinate.closestOnSegment(pixelCoordinate, segment))) { + vertexSegments[goog.getUid(segment)] = true; + } else { + break; + } + } + this.vertexSegments_ = vertexSegments; this.modifiable_ = true; return; } From 97f8fdbd15d1f9e811da75c2693b3feee49f01b8 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 6 Mar 2014 14:10:39 +0100 Subject: [PATCH 2/4] Added another linestring to show shared segment editing --- examples/modify-features.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/modify-features.js b/examples/modify-features.js index 44392f260d..2b07c3a59a 100644 --- a/examples/modify-features.js +++ b/examples/modify-features.js @@ -96,7 +96,14 @@ var vectorSource = new ol.source.GeoJSON( 'type': 'Feature', 'geometry': { 'type': 'LineString', - 'coordinates': [[4e6, -2e6], [8e6, 2e6]] + 'coordinates': [[4e6, -2e6], [8e6, 2e6], [9e6, 2e6]] + } + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [[4e6, -2e6], [8e6, 2e6], [8e6, 3e6]] } }, { From bc79b89c5eab65d657e0ca101e0307b5bf41e4b9 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 6 Mar 2014 17:51:07 +0100 Subject: [PATCH 3/4] Limit shared segment editing To avoid surprises, we enable shared segment editing only on segments that have the same vertex coordinates. --- src/ol/interaction/modifyinteraction.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ol/interaction/modifyinteraction.js b/src/ol/interaction/modifyinteraction.js index 532b797ff7..6296fc8748 100644 --- a/src/ol/interaction/modifyinteraction.js +++ b/src/ol/interaction/modifyinteraction.js @@ -510,26 +510,31 @@ ol.interaction.Modify.prototype.handleMouseAtPixel_ = function(pixel, map) { if (nodes.length > 0) { nodes.sort(sortByDistance); var node = nodes[0]; - var segment = node.segment; // the closest segment - var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, segment)); + var closestSegment = node.segment; + var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate, + closestSegment)); var vertexPixel = map.getPixelFromCoordinate(vertex); if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <= this.pixelTolerance_) { - var pixel1 = map.getPixelFromCoordinate(segment[0]); - var pixel2 = map.getPixelFromCoordinate(segment[1]); + var pixel1 = map.getPixelFromCoordinate(closestSegment[0]); + var pixel2 = map.getPixelFromCoordinate(closestSegment[1]); var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1); var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2); var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); if (dist <= 10) { - vertex = squaredDist1 > squaredDist2 ? segment[1] : segment[0]; + vertex = squaredDist1 > squaredDist2 ? + closestSegment[1] : closestSegment[0]; } this.createOrUpdateVertexFeature_(vertex); var vertexSegments = {}; - vertexSegments[goog.getUid(segment)] = true; + vertexSegments[goog.getUid(closestSegment)] = true; + var segment; for (var i = 1, ii = nodes.length; i < ii; ++i) { segment = nodes[i].segment; - if (ol.coordinate.equals(vertex, - ol.coordinate.closestOnSegment(pixelCoordinate, segment))) { + if ((ol.coordinate.equals(closestSegment[0], segment[0]) && + ol.coordinate.equals(closestSegment[1], segment[1]) || + (ol.coordinate.equals(closestSegment[0], segment[1]) && + ol.coordinate.equals(closestSegment[1], segment[0])))) { vertexSegments[goog.getUid(segment)] = true; } else { break; From 6fbafef4ad6a4f42aa105a33ae31b685aa3477fd Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 6 Mar 2014 22:43:10 +0100 Subject: [PATCH 4/4] Add a layer with real data to the example --- examples/modify-features.html | 7 ++++++- examples/modify-features.js | 28 ++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/examples/modify-features.html b/examples/modify-features.html index 09cc4b912a..9be79fe94a 100644 --- a/examples/modify-features.html +++ b/examples/modify-features.html @@ -26,6 +26,10 @@
+
@@ -33,8 +37,9 @@

Modify features example

-

Example of using the Modify interaction. Select a feature and drag the circle that appears when the cursor gets close to the selected geometry.

+

Example of using the Modify interaction.

+

Select a feature on the Test Data layer and drag the circle that appears when the cursor gets close to the selected geometry. On the Real data (topology) layer, editing adjacent countries that are selected preserves the topology.

See the modify-features.js source to see how this is done.

modify, edit, vector
diff --git a/examples/modify-features.js b/examples/modify-features.js index 2b07c3a59a..7e50855670 100644 --- a/examples/modify-features.js +++ b/examples/modify-features.js @@ -67,7 +67,7 @@ var styleFunction = (function() { }; })(); -var vectorSource = new ol.source.GeoJSON( +var testDataSource = new ol.source.GeoJSON( /** @type {olx.source.GeoJSONOptions} */ ({ object: { 'type': 'FeatureCollection', @@ -166,9 +166,18 @@ var vectorSource = new ol.source.GeoJSON( } })); +var testDataLayer = new ol.layer.Vector({ + source: testDataSource, + style: styleFunction +}); -var vectorLayer = new ol.layer.Vector({ - source: vectorSource, +var realDataSource = new ol.source.GeoJSON({ + projection: 'EPSG:3857', + url: 'data/geojson/countries.geojson' +}); + +var realDataLayer = new ol.layer.Vector({ + source: realDataSource, style: styleFunction }); @@ -246,7 +255,7 @@ var modify = new ol.interaction.Modify({ var map = new ol.Map({ interactions: ol.interaction.defaults().extend([select, modify]), - layers: [raster, vectorLayer], + layers: [raster, testDataLayer, realDataLayer], renderer: 'canvas', target: 'map', view: new ol.View2D({ @@ -254,3 +263,14 @@ var map = new ol.Map({ zoom: 2 }) }); + +$('#layer-select').change(function() { + select.getFeatures().clear(); + var index = $(this).children().index($(this).find(':selected')); + var layers = [testDataLayer, realDataLayer]; + var i, ii; + for (i = 0, ii = layers.length; i < ii; ++i) { + layers[i].setVisible(index == i); + } +}); +$('#layer-select').trigger('change');