Fix issue #6816
This commit is contained in:
Bryan Housel
2019-10-29 21:29:24 -04:00
committed by GitHub
5 changed files with 79 additions and 1 deletions
+1
View File
@@ -100,6 +100,7 @@ en:
too_large: This can't be made circular because not enough of it is currently visible.
connected_to_hidden: This can't be made circular because it is connected to a hidden feature.
not_downloaded: This can't be made circular because parts of it have not yet been downloaded.
already_circular: This can't be made circular because it's already circular.
orthogonalize:
title: Square
description:
+44
View File
@@ -9,6 +9,7 @@ import {
import { geoVecInterp, geoVecLength } from '../geo';
import { osmNode } from '../osm/node';
import { utilArrayUniq } from '../util';
import { geoVecLengthSquare } from '../geo/vector';
export function actionCircularize(wayId, projection, maxAngle) {
@@ -228,6 +229,49 @@ export function actionCircularize(wayId, projection, maxAngle) {
if (!graph.entity(wayId).isClosed()) {
return 'not_closed';
}
//disable when already circular
var way = graph.entity(wayId);
var nodes = utilArrayUniq(graph.childNodes(way));
var points = nodes.map(function(n) { return projection(n.loc); });
var hull = d3_polygonHull(points);
var epsilonAngle = Math.PI / 180;
if (hull.length !== points.length || hull.length < 3){
return false;
}
var centroid = d3_polygonCentroid(points);
var radius = geoVecLengthSquare(centroid, points[0]);
// compare distances between centroid and points
for (var i = 0; i<hull.length; i++){
var actualPoint = hull[i];
var actualDist = geoVecLengthSquare(actualPoint, centroid);
var diff = Math.abs(actualDist - radius);
//compare distances with epsilon-error (5%)
if (diff > 0.05*radius) {
return false;
}
}
//check if central angles are smaller than maxAngle
for (i = 0; i<hull.length; i++){
actualPoint = hull[i];
var nextPoint = hull[(i+1)%hull.length];
var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
var angle = endAngle - startAngle;
if (angle < 0) {
angle = -angle;
}
if (angle > Math.PI){
angle = (2*Math.PI - angle);
}
if (angle > maxAngle + epsilonAngle) {
return false;
}
}
return 'already_circular';
};
+1
View File
@@ -37,6 +37,7 @@ export { geoVecEqual } from './vector.js';
export { geoVecFloor } from './vector.js';
export { geoVecInterp } from './vector.js';
export { geoVecLength } from './vector.js';
export { geoVecLengthSquare } from '/vector.js';
export { geoVecNormalize } from './vector.js';
export { geoVecNormalizedDot } from './vector.js';
export { geoVecProject } from './vector.js';
+6 -1
View File
@@ -37,10 +37,15 @@ export function geoVecInterp(a, b, t) {
// http://jsperf.com/id-dist-optimization
export function geoVecLength(a, b) {
return Math.sqrt(geoVecLengthSquare(a,b));
}
// length of vector raised to the power two
export function geoVecLengthSquare(a, b) {
b = b || [0, 0];
var x = a[0] - b[0];
var y = a[1] - b[1];
return Math.sqrt((x * x) + (y * y));
return (x * x) + (y * y);
}
// get a unit vector
+27
View File
@@ -288,6 +288,33 @@ describe('iD.actionCircularize', function () {
expect(isCircular('-', graph)).to.be.ok;
});
it('not disable circularize when its not circular', function(){
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [2, 0]}),
iD.osmNode({id: 'c', loc: [2, 2]}),
iD.osmNode({id: 'd', loc: [0, 2]}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
var result = iD.actionCircularize('-', projection).disabled(graph);
expect(result).to.be.false;
});
it('disable circularize twice', function(){
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [2, 0]}),
iD.osmNode({id: 'c', loc: [2, 2]}),
iD.osmNode({id: 'd', loc: [0, 2]}),
iD.osmWay({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionCircularize('-', projection)(graph);
var result = iD.actionCircularize('-', projection).disabled(graph);
expect(result).to.eql('already_circular');
});
describe('transitions', function () {
it('is transitionable', function() {