mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
improve checking circularity and unit tests
This commit is contained in:
@@ -6,9 +6,10 @@ import {
|
||||
polygonCentroid as d3_polygonCentroid
|
||||
} from 'd3-polygon';
|
||||
|
||||
import { geoVecInterp, geoVecLength} from '../geo';
|
||||
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) {
|
||||
@@ -229,41 +230,44 @@ export function actionCircularize(wayId, projection, maxAngle) {
|
||||
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 sign = d3_polygonArea(points) > 0 ? 1 : -1;
|
||||
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 = d3_median(points, function(p) { return geoVecLength(centroid, p); });
|
||||
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 = geoVecLength(actualPoint, centroid);
|
||||
if (Math.abs(actualDist - radius > 1)) {
|
||||
var actualDist = geoVecLengthSquare(actualPoint, centroid);
|
||||
var diff = Math.abs(actualDist - radius);
|
||||
//compare distances with epsilon-error (5%)
|
||||
if (diff > 0.05*radius) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var startAngle = Math.atan2(hull[0][1] - centroid[1], hull[0][0] - centroid[0]);
|
||||
var endAngle = Math.atan2(hull[1][1] - centroid[1], hull[1][0] - centroid[0]);
|
||||
var eachAngle = (endAngle - startAngle);
|
||||
|
||||
//compare central angles
|
||||
//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];
|
||||
startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
|
||||
endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
|
||||
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 * sign > 0) {
|
||||
angle = -sign * (2 * Math.PI - Math.abs(angle));
|
||||
if (angle < 0) {
|
||||
angle = -angle;
|
||||
}
|
||||
if (Math.abs((angle) - eachAngle) > 0.05) {
|
||||
if (angle > Math.PI){
|
||||
angle = (2*Math.PI - angle);
|
||||
}
|
||||
|
||||
if (angle > maxAngle + epsilonAngle) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user