From 1f3319f7b074a4e214792a1176be9dc5ab7d257b Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Thu, 24 Jan 2013 22:52:19 -0500 Subject: [PATCH] Add circularize action. Fixes #491 --- index.html | 1 + js/id/actions/circular.js | 57 +++++++++++++++++++++++++++++++++++++++ js/id/modes/select.js | 2 +- js/id/ui/radial_menu.js | 17 +++++++++++- 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 js/id/actions/circular.js diff --git a/index.html b/index.html index 25554ea27..19e7446bb 100644 --- a/index.html +++ b/index.html @@ -81,6 +81,7 @@ + diff --git a/js/id/actions/circular.js b/js/id/actions/circular.js new file mode 100644 index 000000000..ffa1b8a9e --- /dev/null +++ b/js/id/actions/circular.js @@ -0,0 +1,57 @@ +iD.actions.Circular = function(wayId, map) { + + var action = function(graph) { + var way = graph.fetch(wayId), + tags = {}, key, role; + + var points = way.nodes.map(function(n) { + return map.projection(n.loc); + }), + centroid = d3.geom.polygon(points).centroid(), + radius = d3.median(points, function(p) { + return iD.geo.dist(centroid, p); + }), + circular_nodes = []; + + for (var i = 0; i < 12; i++) { + circular_nodes.push(iD.Node({ loc: map.projection.invert([ + centroid[0] + Math.cos((i / 12) * Math.PI * 2) * radius, + centroid[1] + Math.sin((i / 12) * Math.PI * 2) * radius]) + })); + } + + circular_nodes.push(circular_nodes[0]); + + for (i = 0; i < way.nodes.length; i++) { + if (graph.parentWays(way.nodes[i]).length > 1) { + var closest, closest_dist = Infinity, dist; + for (var j = 0; j < circular_nodes.length; j++) { + dist = iD.geo.dist(circular_nodes[j].loc, way.nodes[i].loc); + if (dist < closest_dist) { + closest_dist = dist; + closest = j; + } + } + circular_nodes.splice(closest, 1, way.nodes[i]); + if (closest === 0) circular_nodes.splice(circular_nodes.length - 1, 1, way.nodes[i]); + else if (closest === circular_nodes.length - 1) circular_nodes.splice(0, 1, way.nodes[i]); + } else { + graph = graph.remove(way.nodes[i]); + } + } + + for (i = 0; i < circular_nodes.length; i++) { + graph = graph.replace(circular_nodes[i]); + } + + return graph.replace(way.update({ + nodes: _.pluck(circular_nodes, 'id') + })); + }; + + action.enabled = function(graph) { + return true; + }; + + return action; +}; diff --git a/js/id/modes/select.js b/js/id/modes/select.js index 1ab0fa3ad..de74baf78 100644 --- a/js/id/modes/select.js +++ b/js/id/modes/select.js @@ -137,7 +137,7 @@ iD.modes.Select = function(entity, initial) { }) .classed('selected', true); - radialMenu = iD.ui.RadialMenu(entity, history); + radialMenu = iD.ui.RadialMenu(entity, history, mode.map); if (d3.event && !initial) { var loc = map.mouseCoordinates(); diff --git a/js/id/ui/radial_menu.js b/js/id/ui/radial_menu.js index 3cf3b4c3f..39861f42a 100644 --- a/js/id/ui/radial_menu.js +++ b/js/id/ui/radial_menu.js @@ -1,4 +1,4 @@ -iD.ui.RadialMenu = function(entity, history) { +iD.ui.RadialMenu = function(entity, history, map) { var radialMenu = function(selection, center) { var operations, graph = history.graph(), @@ -49,6 +49,14 @@ iD.ui.RadialMenu = function(entity, history) { action: iD.actions.ReverseWay(entity.id) } ]; + if (entity.isClosed()) { + operations.push({ + id: 'circlar', + text: 'Circular', + description: 'made way circular', + action: iD.actions.Circular(entity.id, map) + }); + } } else if (geometry === 'area') { operations = [ { @@ -56,8 +64,15 @@ iD.ui.RadialMenu = function(entity, history) { text: 'Delete', description: 'deleted an area', action: iD.actions.DeleteWay(entity.id) + }, + { + id: 'circlar', + text: 'Circular', + description: 'made area circular', + action: iD.actions.Circular(entity.id, map) } ]; + } var arc = d3.svg.arc()