mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-18 14:45:12 +02:00
Add layer blocker and polygon self-intersection geometry check
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
/* `.target` objects are interactive */
|
||||
/* They can be picked up, clicked, hovered, or things can connect to them */
|
||||
.layer-blocker.target,
|
||||
.node.target {
|
||||
pointer-events: fill;
|
||||
fill-opacity: 0.8;
|
||||
@@ -34,6 +35,7 @@
|
||||
}
|
||||
|
||||
/* `.target-nope` objects are explicitly forbidden to join to */
|
||||
.layer-blocker.target.target-nope,
|
||||
.node.target.target-nope,
|
||||
.way.target.target-nope {
|
||||
cursor: not-allowed;
|
||||
|
||||
@@ -12,10 +12,23 @@ import {
|
||||
actionNoop
|
||||
} from '../actions';
|
||||
|
||||
import { behaviorEdit, behaviorHover, behaviorDrag } from '../behavior';
|
||||
import { geoChooseEdge, geoVecSubtract, geoViewportEdge } from '../geo';
|
||||
import {
|
||||
behaviorEdit,
|
||||
behaviorHover,
|
||||
behaviorDrag
|
||||
} from '../behavior';
|
||||
|
||||
import {
|
||||
geoChooseEdge,
|
||||
geoLineIntersection,
|
||||
geoVecEquals,
|
||||
geoVecSubtract,
|
||||
geoViewportEdge
|
||||
} from '../geo';
|
||||
|
||||
import { modeBrowse, modeSelect } from './index';
|
||||
import { osmNode } from '../osm';
|
||||
import { svgBlocker } from '../svg';
|
||||
import { uiFlash } from '../ui';
|
||||
|
||||
|
||||
@@ -27,6 +40,7 @@ export function modeDragNode(context) {
|
||||
var hover = behaviorHover(context).altDisables(true)
|
||||
.on('hover', context.ui().sidebar.hover);
|
||||
var edit = behaviorEdit(context);
|
||||
var blocker = svgBlocker(context.projection, context);
|
||||
|
||||
var _nudgeInterval;
|
||||
var _restoreSelectedIDs = [];
|
||||
@@ -147,10 +161,63 @@ export function modeDragNode(context) {
|
||||
moveAnnotation(entity)
|
||||
);
|
||||
|
||||
|
||||
checkGeometry(entity);
|
||||
_lastLoc = loc;
|
||||
}
|
||||
|
||||
|
||||
function checkGeometry(entity) {
|
||||
var doBlock = false;
|
||||
var graph = context.graph();
|
||||
var parents = graph.parentWays(entity);
|
||||
|
||||
function checkSelfIntersections(way, activeID) {
|
||||
// check active (dragged) segments against inactive segments
|
||||
var actives = [];
|
||||
var inactives = [];
|
||||
var j, k;
|
||||
for (j = 0; j < way.nodes.length - 1; j++) {
|
||||
var n1 = graph.entity(way.nodes[j]);
|
||||
var n2 = graph.entity(way.nodes[j+1]);
|
||||
var segment = [n1.loc, n2.loc];
|
||||
if (n1.id === activeID || n2.id === activeID) {
|
||||
actives.push(segment);
|
||||
} else {
|
||||
inactives.push(segment);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < actives.length; j++) {
|
||||
for (k = 0; k < inactives.length; k++) {
|
||||
var p = actives[j];
|
||||
var q = inactives[k];
|
||||
// skip if segments share an endpoint
|
||||
if (geoVecEquals(p[1], q[0]) || geoVecEquals(p[0], q[1]) ||
|
||||
geoVecEquals(p[0], q[0]) || geoVecEquals(p[1], q[1]) ) {
|
||||
continue;
|
||||
} else if (geoLineIntersection(p, q)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
if (parent.isClosed()) { // check for self intersections
|
||||
if (checkSelfIntersections(parent, entity.id)) {
|
||||
doBlock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d3_select('.data-layer-osm')
|
||||
.call(doBlock ? blocker : blocker.off);
|
||||
}
|
||||
|
||||
|
||||
function move(entity) {
|
||||
if (_isCancelled) return;
|
||||
|
||||
@@ -270,6 +337,9 @@ export function modeDragNode(context) {
|
||||
|
||||
_activeEntity = null;
|
||||
|
||||
d3_select('.data-layer-osm')
|
||||
.call(blocker.off);
|
||||
|
||||
context.surface()
|
||||
.selectAll('.active')
|
||||
.classed('active', false);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
export function svgBlocker(projection, context) {
|
||||
|
||||
function blocker(selection) {
|
||||
var dimensions = projection.clipExtent()[1];
|
||||
var fillClass = context.getDebug('target') ? 'red ' : 'nocolor ';
|
||||
|
||||
var blocker = selection.selectAll('.layer-blocker')
|
||||
.data([{id: 'target-nope'}]);
|
||||
|
||||
blocker.enter()
|
||||
.append('rect')
|
||||
.attr('class', 'layer-blocker target target-nope ' + fillClass)
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
.merge(blocker)
|
||||
.attr('width', dimensions[0])
|
||||
.attr('height', dimensions[1]);
|
||||
}
|
||||
|
||||
blocker.off = function(selection) {
|
||||
selection.selectAll('.layer-blocker')
|
||||
.remove();
|
||||
};
|
||||
|
||||
return blocker;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export { svgAreas } from './areas.js';
|
||||
export { svgBlocker } from './blocker.js';
|
||||
export { svgDebug } from './debug.js';
|
||||
export { svgDefs } from './defs.js';
|
||||
export { svgGpx } from './gpx.js';
|
||||
|
||||
Reference in New Issue
Block a user