+97
-102
@@ -12,9 +12,7 @@ import {boundingExtent, createEmpty} from '../extent.js';
|
|||||||
import {
|
import {
|
||||||
closestOnCircle,
|
closestOnCircle,
|
||||||
closestOnSegment,
|
closestOnSegment,
|
||||||
distance as coordinateDistance,
|
squaredDistance,
|
||||||
squaredDistance as squaredCoordinateDistance,
|
|
||||||
squaredDistanceToSegment,
|
|
||||||
} from '../coordinate.js';
|
} from '../coordinate.js';
|
||||||
import {fromCircle} from '../geom/Polygon.js';
|
import {fromCircle} from '../geom/Polygon.js';
|
||||||
import {
|
import {
|
||||||
@@ -68,7 +66,11 @@ function getFeatureFromEvent(evt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempSegment = [];
|
const NOT_SNAPPED = {
|
||||||
|
snapped: false,
|
||||||
|
vertex: null,
|
||||||
|
vertexPixel: null,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
@@ -424,113 +426,109 @@ class Snap extends PointerInteraction {
|
|||||||
]);
|
]);
|
||||||
const box = boundingExtent([lowerLeft, upperRight]);
|
const box = boundingExtent([lowerLeft, upperRight]);
|
||||||
|
|
||||||
let segments = this.rBush_.getInExtent(box);
|
const segments = this.rBush_.getInExtent(box);
|
||||||
|
|
||||||
// If snapping on vertices only, don't consider circles
|
const segmentsLength = segments.length;
|
||||||
if (this.vertex_ && !this.edge_) {
|
if (segmentsLength === 0) {
|
||||||
segments = segments.filter(function (segment) {
|
return NOT_SNAPPED;
|
||||||
return segment.feature.getGeometry().getType() !== GeometryType.CIRCLE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let snapped = false;
|
|
||||||
let vertex = null;
|
|
||||||
let vertexPixel = null;
|
|
||||||
|
|
||||||
if (segments.length === 0) {
|
|
||||||
return {
|
|
||||||
snapped: snapped,
|
|
||||||
vertex: vertex,
|
|
||||||
vertexPixel: vertexPixel,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const projection = map.getView().getProjection();
|
const projection = map.getView().getProjection();
|
||||||
const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection);
|
const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection);
|
||||||
|
|
||||||
let closestSegmentData;
|
let closestVertex;
|
||||||
let minSquaredDistance = Infinity;
|
let minSquaredDistance = Infinity;
|
||||||
for (let i = 0; i < segments.length; ++i) {
|
|
||||||
const segmentData = segments[i];
|
const squaredPixelTolerance = this.pixelTolerance_ * this.pixelTolerance_;
|
||||||
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
|
const getResult = () => {
|
||||||
tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
|
if (closestVertex) {
|
||||||
const delta = squaredDistanceToSegment(projectedCoordinate, tempSegment);
|
const vertexPixel = map.getPixelFromCoordinate(closestVertex);
|
||||||
if (delta < minSquaredDistance) {
|
const squaredPixelDistance = squaredDistance(pixel, vertexPixel);
|
||||||
closestSegmentData = segmentData;
|
if (squaredPixelDistance <= squaredPixelTolerance) {
|
||||||
minSquaredDistance = delta;
|
return {
|
||||||
|
snapped: true,
|
||||||
|
vertex: closestVertex,
|
||||||
|
vertexPixel: [
|
||||||
|
Math.round(vertexPixel[0]),
|
||||||
|
Math.round(vertexPixel[1]),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NOT_SNAPPED;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.vertex_) {
|
||||||
|
for (let i = 0; i < segmentsLength; ++i) {
|
||||||
|
const segmentData = segments[i];
|
||||||
|
if (
|
||||||
|
segmentData.feature.getGeometry().getType() !== GeometryType.CIRCLE
|
||||||
|
) {
|
||||||
|
segmentData.segment.forEach((vertex) => {
|
||||||
|
const tempVertexCoord = fromUserCoordinate(vertex, projection);
|
||||||
|
const delta = squaredDistance(projectedCoordinate, tempVertexCoord);
|
||||||
|
if (delta < minSquaredDistance) {
|
||||||
|
closestVertex = vertex;
|
||||||
|
minSquaredDistance = delta;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const result = getResult();
|
||||||
|
if (result.snapped) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const closestSegment = closestSegmentData.segment;
|
|
||||||
|
|
||||||
if (this.vertex_ && !this.edge_) {
|
if (this.edge_) {
|
||||||
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
|
const tempSegment = [];
|
||||||
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
|
for (let i = 0; i < segmentsLength; ++i) {
|
||||||
const squaredDist1 = squaredCoordinateDistance(pixel, pixel1);
|
let vertex = null;
|
||||||
const squaredDist2 = squaredCoordinateDistance(pixel, pixel2);
|
const segmentData = segments[i];
|
||||||
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
if (
|
||||||
if (dist <= this.pixelTolerance_) {
|
segmentData.feature.getGeometry().getType() === GeometryType.CIRCLE
|
||||||
snapped = true;
|
) {
|
||||||
vertex =
|
let circleGeometry = segmentData.feature.getGeometry();
|
||||||
squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
|
const userProjection = getUserProjection();
|
||||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
if (userProjection) {
|
||||||
}
|
circleGeometry = circleGeometry
|
||||||
} else if (this.edge_) {
|
.clone()
|
||||||
const isCircle =
|
.transform(userProjection, projection);
|
||||||
closestSegmentData.feature.getGeometry().getType() ===
|
}
|
||||||
GeometryType.CIRCLE;
|
vertex = toUserCoordinate(
|
||||||
if (isCircle) {
|
closestOnCircle(
|
||||||
let circleGeometry = closestSegmentData.feature.getGeometry();
|
projectedCoordinate,
|
||||||
const userProjection = getUserProjection();
|
/** @type {import("../geom/Circle.js").default} */ (
|
||||||
if (userProjection) {
|
circleGeometry
|
||||||
circleGeometry = circleGeometry
|
)
|
||||||
.clone()
|
),
|
||||||
.transform(userProjection, projection);
|
projection
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const [segmentStart, segmentEnd] = segmentData.segment;
|
||||||
|
// points have only one coordinate
|
||||||
|
if (segmentEnd) {
|
||||||
|
tempSegment[0] = fromUserCoordinate(segmentStart, projection);
|
||||||
|
tempSegment[1] = fromUserCoordinate(segmentEnd, projection);
|
||||||
|
vertex = closestOnSegment(projectedCoordinate, tempSegment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vertex = toUserCoordinate(
|
if (vertex) {
|
||||||
closestOnCircle(
|
const delta = squaredDistance(projectedCoordinate, vertex);
|
||||||
projectedCoordinate,
|
if (delta < minSquaredDistance) {
|
||||||
/** @type {import("../geom/Circle.js").default} */ (circleGeometry)
|
closestVertex = vertex;
|
||||||
),
|
minSquaredDistance = delta;
|
||||||
projection
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
tempSegment[0] = fromUserCoordinate(closestSegment[0], projection);
|
|
||||||
tempSegment[1] = fromUserCoordinate(closestSegment[1], projection);
|
|
||||||
vertex = toUserCoordinate(
|
|
||||||
closestOnSegment(projectedCoordinate, tempSegment),
|
|
||||||
projection
|
|
||||||
);
|
|
||||||
}
|
|
||||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
|
||||||
|
|
||||||
if (coordinateDistance(pixel, vertexPixel) <= this.pixelTolerance_) {
|
|
||||||
snapped = true;
|
|
||||||
if (this.vertex_ && !isCircle) {
|
|
||||||
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
|
|
||||||
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
|
|
||||||
const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
|
|
||||||
const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
|
|
||||||
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
|
||||||
if (dist <= this.pixelTolerance_) {
|
|
||||||
vertex =
|
|
||||||
squaredDist1 > squaredDist2
|
|
||||||
? closestSegment[1]
|
|
||||||
: closestSegment[0];
|
|
||||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = getResult();
|
||||||
|
if (result.snapped) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapped) {
|
return NOT_SNAPPED;
|
||||||
vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
snapped: snapped,
|
|
||||||
vertex: vertex,
|
|
||||||
vertexPixel: vertexPixel,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -629,15 +627,13 @@ class Snap extends PointerInteraction {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
writeMultiPointGeometry_(feature, geometry) {
|
writeMultiPointGeometry_(feature, geometry) {
|
||||||
const points = geometry.getCoordinates();
|
geometry.getCoordinates().forEach((point) => {
|
||||||
for (let i = 0, ii = points.length; i < ii; ++i) {
|
|
||||||
const coordinates = points[i];
|
|
||||||
const segmentData = {
|
const segmentData = {
|
||||||
feature: feature,
|
feature: feature,
|
||||||
segment: [coordinates, coordinates],
|
segment: [point],
|
||||||
};
|
};
|
||||||
this.rBush_.insert(geometry.getExtent(), segmentData);
|
this.rBush_.insert(geometry.getExtent(), segmentData);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -669,10 +665,9 @@ class Snap extends PointerInteraction {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
writePointGeometry_(feature, geometry) {
|
writePointGeometry_(feature, geometry) {
|
||||||
const coordinates = geometry.getCoordinates();
|
|
||||||
const segmentData = {
|
const segmentData = {
|
||||||
feature: feature,
|
feature: feature,
|
||||||
segment: [coordinates, coordinates],
|
segment: [geometry.getCoordinates()],
|
||||||
};
|
};
|
||||||
this.rBush_.insert(geometry.getExtent(), segmentData);
|
this.rBush_.insert(geometry.getExtent(), segmentData);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user