mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-12 16:52:50 +00:00
136 lines
5.9 KiB
JavaScript
136 lines
5.9 KiB
JavaScript
import { prefs } from '../core/preferences';
|
|
import { t } from '../core/localizer';
|
|
//import { actionChangeTags } from '../actions/change_tags';
|
|
import { actionOrthogonalize } from '../actions/orthogonalize';
|
|
import { geoOrthoCanOrthogonalize } from '../geo/ortho';
|
|
import { utilDisplayLabel } from '../util/utilDisplayLabel';
|
|
import { validationIssue, validationIssueFix } from '../core/validation';
|
|
import { services } from '../services';
|
|
|
|
export function validationUnsquareWay(context) {
|
|
var type = 'unsquare_way';
|
|
var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
|
|
|
|
// use looser epsilon for detection to reduce warnings of buildings that are essentially square already
|
|
var epsilon = 0.05;
|
|
var nodeThreshold = 10;
|
|
|
|
function isBuilding(entity, graph) {
|
|
if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
|
|
return entity.tags.building && entity.tags.building !== 'no';
|
|
}
|
|
|
|
|
|
var validation = function checkUnsquareWay(entity, graph) {
|
|
|
|
if (!isBuilding(entity, graph)) return [];
|
|
|
|
// don't flag ways marked as physically unsquare
|
|
if (entity.tags.nonsquare === 'yes') return [];
|
|
|
|
var isClosed = entity.isClosed();
|
|
if (!isClosed) return []; // this building has bigger problems
|
|
|
|
// don't flag ways with lots of nodes since they are likely detail-mapped
|
|
var nodes = graph.childNodes(entity).slice(); // shallow copy
|
|
if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
|
|
|
|
// ignore if not all nodes are fully downloaded
|
|
var osm = services.osm;
|
|
if (!osm || nodes.some(function(node) { return !osm.isDataLoaded(node.loc); })) return [];
|
|
|
|
// don't flag connected ways to avoid unresolvable unsquare loops
|
|
var hasConnectedSquarableWays = nodes.some(function(node) {
|
|
return graph.parentWays(node).some(function(way) {
|
|
if (way.id === entity.id) return false;
|
|
if (isBuilding(way, graph)) return true;
|
|
return graph.parentRelations(way).some(function(parentRelation) {
|
|
return parentRelation.isMultipolygon() &&
|
|
parentRelation.tags.building &&
|
|
parentRelation.tags.building !== 'no';
|
|
});
|
|
});
|
|
});
|
|
if (hasConnectedSquarableWays) return [];
|
|
|
|
|
|
// user-configurable square threshold
|
|
var storedDegreeThreshold = prefs('validate-square-degrees');
|
|
var degreeThreshold = isFinite(storedDegreeThreshold) ? Number(storedDegreeThreshold) : DEFAULT_DEG_THRESHOLD;
|
|
|
|
var points = nodes.map(function(node) { return context.projection(node.loc); });
|
|
if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
|
|
|
|
var autoArgs;
|
|
// don't allow autosquaring features linked to wikidata
|
|
if (!entity.tags.wikidata) {
|
|
// use same degree threshold as for detection
|
|
var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
|
|
autoAction.transitionable = false; // when autofixing, do it instantly
|
|
autoArgs = [autoAction, t('operations.orthogonalize.annotation.feature', { n: 1 })];
|
|
}
|
|
|
|
return [new validationIssue({
|
|
type: type,
|
|
subtype: 'building',
|
|
severity: 'warning',
|
|
message: function(context) {
|
|
var entity = context.hasEntity(this.entityIds[0]);
|
|
return entity ? t.append('issues.unsquare_way.message', {
|
|
feature: utilDisplayLabel(entity, context.graph())
|
|
}) : '';
|
|
},
|
|
reference: showReference,
|
|
entityIds: [entity.id],
|
|
hash: degreeThreshold,
|
|
dynamicFixes: function() {
|
|
return [
|
|
new validationIssueFix({
|
|
icon: 'iD-operation-orthogonalize',
|
|
title: t.append('issues.fix.square_feature.title'),
|
|
autoArgs: autoArgs,
|
|
onClick: function(context, completionHandler) {
|
|
var entityId = this.issue.entityIds[0];
|
|
// use same degree threshold as for detection
|
|
context.perform(
|
|
actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold),
|
|
t('operations.orthogonalize.annotation.feature', { n: 1 })
|
|
);
|
|
// run after the squaring transition (currently 150ms)
|
|
window.setTimeout(function() { completionHandler(); }, 175);
|
|
}
|
|
}),
|
|
/*
|
|
new validationIssueFix({
|
|
title: t.append('issues.fix.tag_as_unsquare.title'),
|
|
onClick: function(context) {
|
|
var entityId = this.issue.entityIds[0];
|
|
var entity = context.entity(entityId);
|
|
var tags = Object.assign({}, entity.tags); // shallow copy
|
|
tags.nonsquare = 'yes';
|
|
context.perform(
|
|
actionChangeTags(entityId, tags),
|
|
t('issues.fix.tag_as_unsquare.annotation')
|
|
);
|
|
}
|
|
})
|
|
*/
|
|
];
|
|
}
|
|
})];
|
|
|
|
function showReference(selection) {
|
|
selection.selectAll('.issue-reference')
|
|
.data([0])
|
|
.enter()
|
|
.append('div')
|
|
.attr('class', 'issue-reference')
|
|
.call(t.append('issues.unsquare_way.buildings.reference'));
|
|
}
|
|
};
|
|
|
|
validation.type = type;
|
|
|
|
return validation;
|
|
}
|