User coordinates during modification

This commit is contained in:
Tim Schaub
2019-09-26 12:16:26 +02:00
parent 3a10476c1c
commit e0d24d3af0
3 changed files with 79 additions and 24 deletions

View File

@@ -0,0 +1,11 @@
---
layout: example.html
title: Geographic Editing
shortdesc: Editing geometries with geographic coordinates.
docs: >
Calling the <code>useGeographic</code> function in the <code>'ol/proj'</code> module
makes it so the map view uses geographic coordinates (even if the view projection is
not geographic).
tags: "geographic"
---
<div id="map" class="map"></div>

View File

@@ -0,0 +1,37 @@
import {Map, View} from '../src/ol/index.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {Modify, Select} from '../src/ol/interaction.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {useGeographic} from '../src/ol/proj.js';
useGeographic();
const vector = new VectorLayer({
source: new VectorSource({
url: 'data/geojson/countries.geojson',
format: new GeoJSON()
})
});
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}),
vector
],
view: new View({
center: [0, 0],
zoom: 2
})
});
const select = new Select();
map.addInteraction(select);
const modify = new Modify({
features: select.getFeatures()
});
map.addInteraction(modify);

View File

@@ -11,7 +11,7 @@ import {equals as coordinatesEqual, distance as coordinateDistance, squaredDista
import Event from '../events/Event.js'; import Event from '../events/Event.js';
import EventType from '../events/EventType.js'; import EventType from '../events/EventType.js';
import {always, primaryAction, altKeyOnly, singleClick} from '../events/condition.js'; import {always, primaryAction, altKeyOnly, singleClick} from '../events/condition.js';
import {boundingExtent, buffer, createOrUpdateFromCoordinate} from '../extent.js'; import {boundingExtent, buffer as bufferExtent, createOrUpdateFromCoordinate as createExtent} from '../extent.js';
import GeometryType from '../geom/GeometryType.js'; import GeometryType from '../geom/GeometryType.js';
import Point from '../geom/Point.js'; import Point from '../geom/Point.js';
import PointerInteraction from './Pointer.js'; import PointerInteraction from './Pointer.js';
@@ -20,6 +20,7 @@ import VectorSource from '../source/Vector.js';
import VectorEventType from '../source/VectorEventType.js'; import VectorEventType from '../source/VectorEventType.js';
import RBush from '../structs/RBush.js'; import RBush from '../structs/RBush.js';
import {createEditingStyle} from '../style/Style.js'; import {createEditingStyle} from '../style/Style.js';
import {fromUserExtent, toUserExtent} from '../proj.js';
/** /**
@@ -36,6 +37,7 @@ const CIRCLE_CENTER_INDEX = 0;
*/ */
const CIRCLE_CIRCUMFERENCE_INDEX = 1; const CIRCLE_CIRCUMFERENCE_INDEX = 1;
const tempExtent = [0, 0, 0, 0];
/** /**
* @enum {string} * @enum {string}
@@ -652,7 +654,7 @@ class Modify extends PointerInteraction {
const featureSegments = [centerSegmentData, circumferenceSegmentData]; const featureSegments = [centerSegmentData, circumferenceSegmentData];
centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments; centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
this.rBush_.insert(createOrUpdateFromCoordinate(coordinates), centerSegmentData); this.rBush_.insert(createExtent(coordinates), centerSegmentData);
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData); this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
} }
@@ -801,14 +803,13 @@ class Modify extends PointerInteraction {
return false; return false;
} }
this.handlePointerAtPixel_(evt.pixel, evt.map); this.handlePointerAtPixel_(evt.pixel, evt.map);
const pixelCoordinate = evt.map.getCoordinateFromPixelInternal(evt.pixel); const pixelCoordinate = evt.coordinate;
this.dragSegments_.length = 0; this.dragSegments_.length = 0;
this.modified_ = false; this.modified_ = false;
const vertexFeature = this.vertexFeature_; const vertexFeature = this.vertexFeature_;
if (vertexFeature) { if (vertexFeature) {
const insertVertices = []; const insertVertices = [];
const geometry = vertexFeature.getGeometry(); const vertex = vertexFeature.getGeometry().getCoordinates();
const vertex = geometry.getCoordinates();
const vertexExtent = boundingExtent([vertex]); const vertexExtent = boundingExtent([vertex]);
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent); const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
const componentSegments = {}; const componentSegments = {};
@@ -824,21 +825,23 @@ class Modify extends PointerInteraction {
if (!componentSegments[uid]) { if (!componentSegments[uid]) {
componentSegments[uid] = new Array(2); componentSegments[uid] = new Array(2);
} }
if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE &&
segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE && segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch); const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch);
if (coordinatesEqual(closestVertex, vertex) && !componentSegments[uid][0]) { if (coordinatesEqual(closestVertex, vertex) && !componentSegments[uid][0]) {
this.dragSegments_.push([segmentDataMatch, 0]); this.dragSegments_.push([segmentDataMatch, 0]);
componentSegments[uid][0] = segmentDataMatch; componentSegments[uid][0] = segmentDataMatch;
} }
} else if (coordinatesEqual(segment[0], vertex) && continue;
!componentSegments[uid][0]) { }
if (coordinatesEqual(segment[0], vertex) && !componentSegments[uid][0]) {
this.dragSegments_.push([segmentDataMatch, 0]); this.dragSegments_.push([segmentDataMatch, 0]);
componentSegments[uid][0] = segmentDataMatch; componentSegments[uid][0] = segmentDataMatch;
} else if (coordinatesEqual(segment[1], vertex) && continue;
!componentSegments[uid][1]) { }
if (coordinatesEqual(segment[1], vertex) && !componentSegments[uid][1]) {
// prevent dragging closed linestrings by the connecting node // prevent dragging closed linestrings by the connecting node
if ((segmentDataMatch.geometry.getType() === if ((segmentDataMatch.geometry.getType() ===
GeometryType.LINE_STRING || GeometryType.LINE_STRING ||
@@ -851,15 +854,20 @@ class Modify extends PointerInteraction {
this.dragSegments_.push([segmentDataMatch, 1]); this.dragSegments_.push([segmentDataMatch, 1]);
componentSegments[uid][1] = segmentDataMatch; componentSegments[uid][1] = segmentDataMatch;
} else if (getUid(segment) in this.vertexSegments_ && continue;
}
if (getUid(segment) in this.vertexSegments_ &&
(!componentSegments[uid][0] && !componentSegments[uid][1]) && (!componentSegments[uid][0] && !componentSegments[uid][1]) &&
this.insertVertexCondition_(evt)) { this.insertVertexCondition_(evt)) {
insertVertices.push([segmentDataMatch, vertex]); insertVertices.push([segmentDataMatch, vertex]);
} }
} }
if (insertVertices.length) { if (insertVertices.length) {
this.willModifyFeatures_(evt); this.willModifyFeatures_(evt);
} }
for (let j = insertVertices.length - 1; j >= 0; --j) { for (let j = insertVertices.length - 1; j >= 0; --j) {
this.insertVertex_.apply(this, insertVertices[j]); this.insertVertex_.apply(this, insertVertices[j]);
} }
@@ -881,7 +889,7 @@ class Modify extends PointerInteraction {
const circumferenceSegmentData = segmentData.featureSegments[1]; const circumferenceSegmentData = segmentData.featureSegments[1];
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates; centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates; circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData); this.rBush_.update(createExtent(coordinates), centerSegmentData);
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData); this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
} else { } else {
this.rBush_.update(boundingExtent(segmentData.segment), segmentData); this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
@@ -909,14 +917,16 @@ class Modify extends PointerInteraction {
* @private * @private
*/ */
handlePointerAtPixel_(pixel, map) { handlePointerAtPixel_(pixel, map) {
const pixelCoordinate = map.getCoordinateFromPixelInternal(pixel); const pixelCoordinate = map.getCoordinateFromPixel(pixel);
const sortByDistance = function(a, b) { const sortByDistance = function(a, b) {
return pointDistanceToSegmentDataSquared(pixelCoordinate, a) - return pointDistanceToSegmentDataSquared(pixelCoordinate, a) -
pointDistanceToSegmentDataSquared(pixelCoordinate, b); pointDistanceToSegmentDataSquared(pixelCoordinate, b);
}; };
const box = buffer(createOrUpdateFromCoordinate(pixelCoordinate), const projection = map.getView().getProjection();
map.getView().getResolution() * this.pixelTolerance_); const viewExtent = fromUserExtent(createExtent(pixelCoordinate, tempExtent), projection);
const buffer = map.getView().getResolution() * this.pixelTolerance_;
const box = toUserExtent(bufferExtent(viewExtent, buffer, tempExtent), projection);
const rBush = this.rBush_; const rBush = this.rBush_;
const nodes = rBush.getInExtent(box); const nodes = rBush.getInExtent(box);
@@ -925,20 +935,18 @@ class Modify extends PointerInteraction {
const node = nodes[0]; const node = nodes[0];
const closestSegment = node.segment; const closestSegment = node.segment;
let vertex = closestOnSegmentData(pixelCoordinate, node); let vertex = closestOnSegmentData(pixelCoordinate, node);
const vertexPixel = map.getPixelFromCoordinateInternal(vertex); const vertexPixel = map.getPixelFromCoordinate(vertex);
let dist = coordinateDistance(pixel, vertexPixel); let dist = coordinateDistance(pixel, vertexPixel);
if (dist <= this.pixelTolerance_) { if (dist <= this.pixelTolerance_) {
/** @type {Object<string, boolean>} */ /** @type {Object<string, boolean>} */
const vertexSegments = {}; const vertexSegments = {};
if (node.geometry.getType() === GeometryType.CIRCLE && if (node.geometry.getType() === GeometryType.CIRCLE && node.index === CIRCLE_CIRCUMFERENCE_INDEX) {
node.index === CIRCLE_CIRCUMFERENCE_INDEX) {
this.snappedToVertex_ = true; this.snappedToVertex_ = true;
this.createOrUpdateVertexFeature_(vertex); this.createOrUpdateVertexFeature_(vertex);
} else { } else {
const pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]); const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
const pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]); const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1); const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2); const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
@@ -1256,8 +1264,7 @@ function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
function closestOnSegmentData(pointCoordinates, segmentData) { function closestOnSegmentData(pointCoordinates, segmentData) {
const geometry = segmentData.geometry; const geometry = segmentData.geometry;
if (geometry.getType() === GeometryType.CIRCLE && if (geometry.getType() === GeometryType.CIRCLE && segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
return geometry.getClosestPoint(pointCoordinates); return geometry.getClosestPoint(pointCoordinates);
} }
return closestOnSegment(pointCoordinates, segmentData.segment); return closestOnSegment(pointCoordinates, segmentData.segment);