mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-19 23:14:47 +02:00
Merge pull request #1125 from porjo/orthotri
Orthogonalize three-node ways (addresses #1077)
This commit is contained in:
@@ -6,34 +6,48 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
var action = function(graph) {
|
||||
var way = graph.entity(wayId),
|
||||
nodes = graph.childNodes(way),
|
||||
points = nodes.map(function(n) { return projection(n.loc); }),
|
||||
best, i, j;
|
||||
corner = {i: 0, dotp: 1},
|
||||
points, i, j, score, motions;
|
||||
|
||||
var score = squareness();
|
||||
for (i = 0; i < 1000; i++) {
|
||||
var motions = points.map(stepMap);
|
||||
for (j = 0; j < motions.length; j++) {
|
||||
points[j] = addPoints(points[j],motions[j]);
|
||||
if (nodes.length === 4) {
|
||||
points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
|
||||
for (i = 0; i < 1000; i++) {
|
||||
motions = points.map(calcMotion);
|
||||
points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
|
||||
score = corner.dotp;
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var newScore = squareness();
|
||||
if (newScore < score) {
|
||||
best = _.clone(points);
|
||||
score = newScore;
|
||||
graph = graph.replace(graph.entity(nodes[corner.i].id)
|
||||
.move(projection.invert(points[corner.i])));
|
||||
} else {
|
||||
var best;
|
||||
points = nodes.map(function(n) { return projection(n.loc); });
|
||||
score = squareness();
|
||||
for (i = 0; i < 1000; i++) {
|
||||
motions = points.map(calcMotion);
|
||||
for (j = 0; j < motions.length; j++) {
|
||||
points[j] = addPoints(points[j],motions[j]);
|
||||
}
|
||||
var newScore = squareness();
|
||||
if (newScore < score) {
|
||||
best = _.clone(points);
|
||||
score = newScore;
|
||||
}
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
points = best;
|
||||
for (i = 0; i < points.length - 1; i++) {
|
||||
graph = graph.replace(graph.entity(nodes[i].id)
|
||||
.move(projection.invert(points[i])));
|
||||
}
|
||||
}
|
||||
points = best;
|
||||
|
||||
for (i = 0; i < points.length - 1; i++) {
|
||||
graph = graph.replace(graph.entity(nodes[i].id)
|
||||
.move(projection.invert(points[i])));
|
||||
}
|
||||
|
||||
return graph;
|
||||
|
||||
function stepMap(b, i, array) {
|
||||
function calcMotion(b, i, array) {
|
||||
var a = array[(i - 1 + array.length) % array.length],
|
||||
c = array[(i + 1) % array.length],
|
||||
p = subtractPoints(a, b),
|
||||
@@ -44,9 +58,17 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
q = normalizePoint(q, 1.0);
|
||||
|
||||
var dotp = p[0] * q[0] + p[1] * q[1];
|
||||
|
||||
// nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
|
||||
if (dotp < -0.707106781186547) {
|
||||
dotp += 1.0;
|
||||
if (array.length > 3) {
|
||||
if (dotp < -0.707106781186547) {
|
||||
dotp += 1.0;
|
||||
}
|
||||
} else {
|
||||
if( Math.abs(dotp) < corner.dotp){
|
||||
corner.i = i;
|
||||
corner.dotp = Math.abs(dotp);
|
||||
}
|
||||
}
|
||||
|
||||
return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
|
||||
@@ -86,7 +108,7 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
return [a[0] + b[0], a[1] + b[1]];
|
||||
}
|
||||
|
||||
function normalizePoint(point, thickness) {
|
||||
function normalizePoint(point, scale) {
|
||||
var vector = [0, 0];
|
||||
var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
|
||||
if (length !== 0) {
|
||||
@@ -94,8 +116,8 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
vector[1] = point[1] / length;
|
||||
}
|
||||
|
||||
vector[0] *= thickness;
|
||||
vector[1] *= thickness;
|
||||
vector[0] *= scale;
|
||||
vector[1] *= scale;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ iD.operations.Orthogonalize = function(selection, context) {
|
||||
operation.available = function() {
|
||||
return selection.length === 1 &&
|
||||
context.entity(entityId).type === 'way' &&
|
||||
_.uniq(context.entity(entityId).nodes).length > 3;
|
||||
_.uniq(context.entity(entityId).nodes).length > 2;
|
||||
};
|
||||
|
||||
operation.enabled = function() {
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
<script src="spec/actions/add_entity.js"></script>
|
||||
<script src="spec/actions/change_tags.js"></script>
|
||||
<script src='spec/actions/circularize.js'></script>
|
||||
<script src='spec/actions/orthogonalize.js'></script>
|
||||
<script src='spec/actions/connect.js'></script>
|
||||
<script src="spec/actions/delete_multiple.js"></script>
|
||||
<script src="spec/actions/delete_node.js"></script>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
describe("iD.actions.Orthogonalize", function () {
|
||||
var projection = d3.geo.mercator();
|
||||
|
||||
it("orthoganalizes a quad", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [4, 0]}),
|
||||
'c': iD.Node({id: 'c', loc: [3, 2]}),
|
||||
'd': iD.Node({id: 'd', loc: [0, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Orthogonalize('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.have.length(5);
|
||||
});
|
||||
|
||||
it("orthoganalizes a triangle", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [3, 0]}),
|
||||
'c': iD.Node({id: 'c', loc: [2, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'a']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Orthogonalize('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.have.length(4);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user