Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider both tracing directions when within snap tolerance #14057

Merged
merged 2 commits into from Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/data/geojson/fire.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/tracing.html
Expand Up @@ -6,7 +6,7 @@
The draw interaction has a <code>trace</code> option to enable tracing
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
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.
tags: "draw, trace, vector, snap, topology"
---
Expand Down
66 changes: 29 additions & 37 deletions examples/tracing.js
@@ -1,64 +1,49 @@
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 LineString from '../src/ol/geom/LineString.js';
import Map from '../src/ol/Map.js';
import Snap from '../src/ol/interaction/Snap.js';
import Stroke from '../src/ol/style/Stroke.js';
import Style from '../src/ol/style/Style.js';
import TileLayer from '../src/ol/layer/WebGLTile.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 {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import XYZ from '../src/ol/source/XYZ.js';

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
const baseVector = new VectorLayer({
source: new VectorSource({
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
const drawVector = new VectorLayer({
source: new VectorSource(),
style: new Style({
stroke: new Stroke({
color: 'rgba(100, 255, 0, 1)',
width: 2,
}),
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,
}),
}),
style: {
'stroke-color': 'rgba(100, 255, 0, 1)',
'stroke-width': 2,
'fill-color': 'rgba(100, 255, 0, 0.3)',
},
});

const map = new Map({
layers: [raster, baseVector, drawVector, previewVector],
layers: [raster, baseVector, drawVector],
target: 'map',
view: new View({
center: [-12986427, 5678422],
zoom: 5,
center: [-13378949, 5943751],
zoom: 11,
}),
});

Expand All @@ -78,6 +63,13 @@ function addInteraction() {
source: drawVector.getSource(),
trace: true,
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(snapInteraction);
Expand Down
34 changes: 24 additions & 10 deletions src/ol/interaction/Draw.js
Expand Up @@ -70,7 +70,7 @@ import {getStrideForLayout} from '../geom/SimpleGeometry.js';
* that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
* boolean to indicate whether the drawing can be finished. Not used when drawing
* 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.
* @property {GeometryFunction} [geometryFunction]
* Function that is called when a geometry's coordinates are updated.
Expand Down Expand Up @@ -355,10 +355,12 @@ const sharedUpdateInfo = {index: -1, endIndex: NaN};
/**
* @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
* @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
* 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 y = coordinate[1];

Expand Down Expand Up @@ -412,14 +414,24 @@ function getTraceTargetUpdate(coordinate, traceState) {
}
}

if (
traceState.targetIndex !== newTargetIndex &&
traceState.targets[newTargetIndex].ring
) {
const target = traceState.targets[newTargetIndex];
const coordinates = target.coordinates;
const newTarget = traceState.targets[newTargetIndex];
let considerBothDirections = newTarget.ring;
if (traceState.targetIndex === newTargetIndex && considerBothDirections) {
// only consider switching trace direction if close to the start
const newCoordinate = interpolateCoordinate(
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 startIndex = target.startIndex;
const startIndex = newTarget.startIndex;
const endIndex = newEndIndex;
if (startIndex < endIndex) {
const forwardDistance = getCumulativeSquaredDistance(
Expand Down Expand Up @@ -1239,7 +1251,9 @@ class Draw extends PointerInteraction {

const updatedTraceTarget = getTraceTargetUpdate(
event.coordinate,
traceState
traceState,
this.getMap(),
this.snapTolerance_
);

if (traceState.targetIndex !== updatedTraceTarget.index) {
Expand Down
2 changes: 1 addition & 1 deletion src/ol/interaction/Modify.js
Expand Up @@ -106,7 +106,7 @@ const ModifyEventType = {
* features. Default is {@link module:ol/events/condition.always}.
* @property {number} [pixelTolerance=10] Pixel tolerance for considering the
* 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
* 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}).
Expand Down