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()