fix: eraser tool works on polygon areas and line edges, not just vertices
This commit is contained in:
@@ -983,7 +983,7 @@ export function MapView({
|
|||||||
// Eraser mode: click on/near a feature to delete it
|
// Eraser mode: click on/near a feature to delete it
|
||||||
if (mode === 'eraser') {
|
if (mode === 'eraser') {
|
||||||
const pixel = e.point
|
const pixel = e.point
|
||||||
const tolerance = 10 // px
|
const tolerance = 20 // px
|
||||||
const currentFeatures = featuresRef.current
|
const currentFeatures = featuresRef.current
|
||||||
let closestIdx = -1
|
let closestIdx = -1
|
||||||
let closestDist = Infinity
|
let closestDist = Infinity
|
||||||
@@ -992,29 +992,44 @@ export function MapView({
|
|||||||
const f = currentFeatures[i]
|
const f = currentFeatures[i]
|
||||||
const geom = f.geometry
|
const geom = f.geometry
|
||||||
|
|
||||||
// Get all coordinates to check proximity
|
|
||||||
let allCoords: number[][] = []
|
|
||||||
if (geom.type === 'Point') {
|
if (geom.type === 'Point') {
|
||||||
allCoords = [geom.coordinates as number[]]
|
const projected = m.project(geom.coordinates as [number, number])
|
||||||
} else if (geom.type === 'LineString') {
|
|
||||||
allCoords = geom.coordinates as number[][]
|
|
||||||
} else if (geom.type === 'Polygon') {
|
|
||||||
allCoords = (geom.coordinates as number[][][])[0] || []
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const c of allCoords) {
|
|
||||||
const projected = m.project([c[0], c[1]])
|
|
||||||
const dx = projected.x - pixel.x
|
const dx = projected.x - pixel.x
|
||||||
const dy = projected.y - pixel.y
|
const dy = projected.y - pixel.y
|
||||||
const dist = Math.sqrt(dx * dx + dy * dy)
|
const dist = Math.sqrt(dx * dx + dy * dy)
|
||||||
if (dist < closestDist) {
|
if (dist < closestDist) { closestDist = dist; closestIdx = i }
|
||||||
closestDist = dist
|
} else if (geom.type === 'LineString') {
|
||||||
closestIdx = i
|
const lineCoords = geom.coordinates as number[][]
|
||||||
|
for (let j = 0; j < lineCoords.length - 1; j++) {
|
||||||
|
const p1 = m.project(lineCoords[j] as [number, number])
|
||||||
|
const p2 = m.project(lineCoords[j + 1] as [number, number])
|
||||||
|
const dist = pointToSegmentDist(pixel.x, pixel.y, p1.x, p1.y, p2.x, p2.y)
|
||||||
|
if (dist < closestDist) { closestDist = dist; closestIdx = i }
|
||||||
}
|
}
|
||||||
|
} else if (geom.type === 'Polygon') {
|
||||||
|
const ring = (geom.coordinates as number[][][])[0] || []
|
||||||
|
// Check edges
|
||||||
|
for (let j = 0; j < ring.length - 1; j++) {
|
||||||
|
const p1 = m.project(ring[j] as [number, number])
|
||||||
|
const p2 = m.project(ring[j + 1] as [number, number])
|
||||||
|
const dist = pointToSegmentDist(pixel.x, pixel.y, p1.x, p1.y, p2.x, p2.y)
|
||||||
|
if (dist < closestDist) { closestDist = dist; closestIdx = i }
|
||||||
|
}
|
||||||
|
// Point-in-polygon test (screen space)
|
||||||
|
const projected = ring.map(c => m.project(c as [number, number]))
|
||||||
|
let inside = false
|
||||||
|
for (let j = 0, k = projected.length - 1; j < projected.length; k = j++) {
|
||||||
|
const xi = projected[j].x, yi = projected[j].y
|
||||||
|
const xk = projected[k].x, yk = projected[k].y
|
||||||
|
if (((yi > pixel.y) !== (yk > pixel.y)) && (pixel.x < (xk - xi) * (pixel.y - yi) / (yk - yi) + xi)) {
|
||||||
|
inside = !inside
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inside) { closestDist = 0; closestIdx = i }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closestIdx >= 0 && closestDist < tolerance * 3) {
|
if (closestIdx >= 0 && closestDist < tolerance) {
|
||||||
const deleted = currentFeatures[closestIdx]
|
const deleted = currentFeatures[closestIdx]
|
||||||
const newFeatures = currentFeatures.filter((_, i) => i !== closestIdx)
|
const newFeatures = currentFeatures.filter((_, i) => i !== closestIdx)
|
||||||
onFeaturesChangeRef.current(newFeatures)
|
onFeaturesChangeRef.current(newFeatures)
|
||||||
|
|||||||
Reference in New Issue
Block a user