Merge pull request #14057 from tschaub/trace-update

Consider both tracing directions when within snap tolerance
This commit is contained in:
Tim Schaub
2022-08-25 17:25:21 +02:00
committed by GitHub
5 changed files with 56 additions and 49 deletions

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@ docs: >
The draw interaction has a <code>trace</code> option to enable tracing The draw interaction has a <code>trace</code> option to enable tracing
around existing features. This example uses the <code>traceSource</code> option around existing features. This example uses the <code>traceSource</code> option
to trace features from one source and add them to another source. The first click to trace features from one source and add them to another source. The first click
on an edge of the Idaho feature will start tracing. The second click on the edge on an edge of the target feature will start tracing. The second click on the edge
will stop tracing. will stop tracing.
tags: "draw, trace, vector, snap, topology" tags: "draw, trace, vector, snap, topology"
--- ---

View File

@@ -1,64 +1,49 @@
import Draw from '../src/ol/interaction/Draw.js'; import Draw from '../src/ol/interaction/Draw.js';
import Feature from '../src/ol/Feature.js';
import Fill from '../src/ol/style/Fill.js';
import GeoJSON from '../src/ol/format/GeoJSON.js'; import GeoJSON from '../src/ol/format/GeoJSON.js';
import LineString from '../src/ol/geom/LineString.js';
import Map from '../src/ol/Map.js'; import Map from '../src/ol/Map.js';
import Snap from '../src/ol/interaction/Snap.js'; import Snap from '../src/ol/interaction/Snap.js';
import Stroke from '../src/ol/style/Stroke.js'; import TileLayer from '../src/ol/layer/WebGLTile.js';
import Style from '../src/ol/style/Style.js'; import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import View from '../src/ol/View.js'; import View from '../src/ol/View.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js'; import XYZ from '../src/ol/source/XYZ.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
const raster = new TileLayer({ const raster = new TileLayer({
source: new OSM(), source: new XYZ({
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=get_your_own_D6rA4zTHduk6KOKTXzGB',
maxZoom: 20,
}),
}); });
// features in this layer will be snapped to // features in this layer will be snapped to
const baseVector = new VectorLayer({ const baseVector = new VectorLayer({
source: new VectorSource({ source: new VectorSource({
format: new GeoJSON(), format: new GeoJSON(),
url: "https://ahocevar.com/geoserver/wfs?service=wfs&request=getfeature&typename=topp:states&cql_filter=STATE_NAME='Idaho'&outputformat=application/json", url: 'data/geojson/fire.json',
}), }),
style: {
'fill-color': 'rgba(255, 0, 0, 0.3)',
'stroke-color': 'rgba(255, 0, 0, 0.9)',
'stroke-width': 0.5,
},
}); });
// this is were the drawn features go // this is were the drawn features go
const drawVector = new VectorLayer({ const drawVector = new VectorLayer({
source: new VectorSource(), source: new VectorSource(),
style: new Style({ style: {
stroke: new Stroke({ 'stroke-color': 'rgba(100, 255, 0, 1)',
color: 'rgba(100, 255, 0, 1)', 'stroke-width': 2,
width: 2, 'fill-color': 'rgba(100, 255, 0, 0.3)',
}), },
fill: new Fill({
color: 'rgba(100, 255, 0, 0.3)',
}),
}),
});
// this line only appears when we're tracing a feature outer ring
const previewLine = new Feature({
geometry: new LineString([]),
});
const previewVector = new VectorLayer({
source: new VectorSource({
features: [previewLine],
}),
style: new Style({
stroke: new Stroke({
color: 'rgba(255, 0, 0, 1)',
width: 2,
}),
}),
}); });
const map = new Map({ const map = new Map({
layers: [raster, baseVector, drawVector, previewVector], layers: [raster, baseVector, drawVector],
target: 'map', target: 'map',
view: new View({ view: new View({
center: [-12986427, 5678422], center: [-13378949, 5943751],
zoom: 5, zoom: 11,
}), }),
}); });
@@ -78,6 +63,13 @@ function addInteraction() {
source: drawVector.getSource(), source: drawVector.getSource(),
trace: true, trace: true,
traceSource: baseVector.getSource(), traceSource: baseVector.getSource(),
style: {
'stroke-color': 'rgba(255, 255, 100, 0.5)',
'stroke-width': 1.5,
'fill-color': 'rgba(255, 255, 100, 0.25)',
'circle-radius': 6,
'circle-fill-color': 'rgba(255, 255, 100, 0.5)',
},
}); });
map.addInteraction(drawInteraction); map.addInteraction(drawInteraction);
map.addInteraction(snapInteraction); map.addInteraction(snapInteraction);

View File

@@ -70,7 +70,7 @@ import {getStrideForLayout} from '../geom/SimpleGeometry.js';
* that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a * that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether the drawing can be finished. Not used when drawing * boolean to indicate whether the drawing can be finished. Not used when drawing
* POINT or MULTI_POINT geometries. * POINT or MULTI_POINT geometries.
* @property {import("../style/Style.js").StyleLike} [style] * @property {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike} [style]
* Style for sketch features. * Style for sketch features.
* @property {GeometryFunction} [geometryFunction] * @property {GeometryFunction} [geometryFunction]
* Function that is called when a geometry's coordinates are updated. * Function that is called when a geometry's coordinates are updated.
@@ -355,10 +355,12 @@ const sharedUpdateInfo = {index: -1, endIndex: NaN};
/** /**
* @param {import("../coordinate.js").Coordinate} coordinate The coordinate. * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
* @param {TraceState} traceState The trace state. * @param {TraceState} traceState The trace state.
* @param {import("../Map.js").default} map The map.
* @param {number} snapTolerance The snap tolerance.
* @return {TraceTargetUpdateInfo} Information about the new trace target. The returned * @return {TraceTargetUpdateInfo} Information about the new trace target. The returned
* object is reused between calls and must not be modified by the caller. * object is reused between calls and must not be modified by the caller.
*/ */
function getTraceTargetUpdate(coordinate, traceState) { function getTraceTargetUpdate(coordinate, traceState, map, snapTolerance) {
const x = coordinate[0]; const x = coordinate[0];
const y = coordinate[1]; const y = coordinate[1];
@@ -412,14 +414,24 @@ function getTraceTargetUpdate(coordinate, traceState) {
} }
} }
if ( const newTarget = traceState.targets[newTargetIndex];
traceState.targetIndex !== newTargetIndex && let considerBothDirections = newTarget.ring;
traceState.targets[newTargetIndex].ring if (traceState.targetIndex === newTargetIndex && considerBothDirections) {
) { // only consider switching trace direction if close to the start
const target = traceState.targets[newTargetIndex]; const newCoordinate = interpolateCoordinate(
const coordinates = target.coordinates; newTarget.coordinates,
newEndIndex
);
const pixel = map.getPixelFromCoordinate(newCoordinate);
if (distance(pixel, traceState.startPx) > snapTolerance) {
considerBothDirections = false;
}
}
if (considerBothDirections) {
const coordinates = newTarget.coordinates;
const count = coordinates.length; const count = coordinates.length;
const startIndex = target.startIndex; const startIndex = newTarget.startIndex;
const endIndex = newEndIndex; const endIndex = newEndIndex;
if (startIndex < endIndex) { if (startIndex < endIndex) {
const forwardDistance = getCumulativeSquaredDistance( const forwardDistance = getCumulativeSquaredDistance(
@@ -1239,7 +1251,9 @@ class Draw extends PointerInteraction {
const updatedTraceTarget = getTraceTargetUpdate( const updatedTraceTarget = getTraceTargetUpdate(
event.coordinate, event.coordinate,
traceState traceState,
this.getMap(),
this.snapTolerance_
); );
if (traceState.targetIndex !== updatedTraceTarget.index) { if (traceState.targetIndex !== updatedTraceTarget.index) {

View File

@@ -106,7 +106,7 @@ const ModifyEventType = {
* features. Default is {@link module:ol/events/condition.always}. * features. Default is {@link module:ol/events/condition.always}.
* @property {number} [pixelTolerance=10] Pixel tolerance for considering the * @property {number} [pixelTolerance=10] Pixel tolerance for considering the
* pointer close enough to a segment or vertex for editing. * pointer close enough to a segment or vertex for editing.
* @property {import("../style/Style.js").StyleLike} [style] * @property {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike} [style]
* Style used for the modification point or vertex. For linestrings and polygons, this will * Style used for the modification point or vertex. For linestrings and polygons, this will
* be the affected vertex, for circles a point along the circle, and for points the actual * be the affected vertex, for circles a point along the circle, and for points the actual
* point. If not configured, the default edit style is used (see {@link module:ol/style/Style~Style}). * point. If not configured, the default edit style is used (see {@link module:ol/style/Style~Style}).