From 4eedfa8b258d7f5eda684ad4335ab8c54e55f578 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Mon, 13 May 2019 16:28:08 -0400 Subject: [PATCH] Don't allow autofixing unsquare buildings unless they are already very close to square Allow autofixing buildings with tags --- modules/geo/index.js | 1 + modules/geo/ortho.js | 27 +++++++++++++++++++++++++++ modules/validations/unsquare_way.js | 11 +++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/modules/geo/index.js b/modules/geo/index.js index 4d62211aa..88402d97a 100644 --- a/modules/geo/index.js +++ b/modules/geo/index.js @@ -45,4 +45,5 @@ export { geoVecScale } from './vector.js'; export { geoOrthoNormalizedDotProduct } from './ortho.js'; export { geoOrthoCalcScore } from './ortho.js'; +export { geoOrthoMaxOffsetAngle } from './ortho.js'; export { geoOrthoCanOrthogonalize } from './ortho.js'; diff --git a/modules/geo/ortho.js b/modules/geo/ortho.js index 3f6a14eca..31626d98b 100644 --- a/modules/geo/ortho.js +++ b/modules/geo/ortho.js @@ -45,6 +45,33 @@ export function geoOrthoCalcScore(points, isClosed, epsilon, threshold) { return score; } +// returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner +export function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) { + var max = -Infinity; + + var first = isClosed ? 0 : 1; + var last = isClosed ? coords.length : coords.length - 1; + + for (var i = first; i < last; i++) { + var a = coords[(i - 1 + coords.length) % coords.length]; + var origin = coords[i]; + var b = coords[(i + 1) % coords.length]; + var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin); + + var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI; + + if (angle > 45) angle = 90 - angle; + + if (angle >= lessThan) continue; + + if (angle > max) max = angle; + } + + if (max === -Infinity) return null; + + return max; +} + // similar to geoOrthoCalcScore, but returns quickly if there is something to do export function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) { diff --git a/modules/validations/unsquare_way.js b/modules/validations/unsquare_way.js index 1db257ae8..1450e1ce4 100644 --- a/modules/validations/unsquare_way.js +++ b/modules/validations/unsquare_way.js @@ -1,7 +1,7 @@ import { t } from '../util/locale'; import { actionChangeTags } from '../actions/change_tags'; import { actionOrthogonalize } from '../actions/orthogonalize'; -import { geoOrthoCanOrthogonalize } from '../geo'; +import { geoOrthoCanOrthogonalize, geoOrthoMaxOffsetAngle } from '../geo/ortho'; import { utilDisplayLabel } from '../util'; import { validationIssue, validationIssueFix } from '../core/validation'; @@ -9,9 +9,10 @@ import { validationIssue, validationIssueFix } from '../core/validation'; export function validationUnsquareWay() { var type = 'unsquare_way'; - // use looser epsilon for detection to reduce false positives if nearly orthogonal + // use looser epsilon for detection to reduce warnings of buildings that are essentially square already var epsilon = 0.05; var degreeThreshold = 13; + var autofixDegreeThreshold = 6.5; var nodeThreshold = 10; function isBuilding(entity, graph) { @@ -57,9 +58,10 @@ export function validationUnsquareWay() { var points = nodes.map(function(node) { return context.projection(node.loc); }); if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return []; - // only allow autofix if there are no extra tags on the building (e.g. source) - #6288 var autoArgs; - if (Object.keys(entity.tags).length === 1) { + // only allow autofixing features that are very close to square already + var maxOffsetAngle = geoOrthoMaxOffsetAngle(points, isClosed, degreeThreshold); + if (maxOffsetAngle && maxOffsetAngle < autofixDegreeThreshold) { // note: use default params for actionOrthogonalize, not relaxed epsilon var autoAction = actionOrthogonalize(entity.id, context.projection); autoAction.transitionable = false; // when autofixing, do it instantly @@ -75,6 +77,7 @@ export function validationUnsquareWay() { }, reference: showReference, entityIds: [entity.id], + hash: JSON.stringify(autoArgs !== undefined), fixes: [ new validationIssueFix({ icon: 'iD-operation-orthogonalize',