diff --git a/modules/actions/circularize.js b/modules/actions/circularize.js index 283cd829e..f57c10f68 100644 --- a/modules/actions/circularize.js +++ b/modules/actions/circularize.js @@ -14,8 +14,16 @@ export function actionCircularize(wayId, projection, maxAngle) { maxAngle = (maxAngle || 20) * Math.PI / 180; - var action = function(graph) { - var way = graph.entity(wayId); + var action = function(graph, t) { + if (t === null || !isFinite(t)) t = 1; + t = Math.min(Math.max(+t, 0), 1); + + var way = graph.entity(wayId), + origNodes = {}; + + graph.childNodes(way).forEach(function(node) { + if (!origNodes[node.id]) origNodes[node.id] = node; + }); if (!way.isConvex(graph)) { graph = action.makeConvex(graph); @@ -56,21 +64,27 @@ export function actionCircularize(wayId, projection, maxAngle) { endNodeIndex = nodes.indexOf(endNode), numberNewPoints = -1, indexRange = endNodeIndex - startNodeIndex, - distance, totalAngle, eachAngle, startAngle, endAngle, - angle, loc, node, j, - inBetweenNodes = []; + nearNodes = {}, + inBetweenNodes = [], + startAngle, endAngle, totalAngle, eachAngle, + angle, loc, node, origNode, j, k; if (indexRange < 0) { indexRange += nodes.length; } // position this key node - distance = geoEuclideanDistance(centroid, keyPoints[i]); + var distance = geoEuclideanDistance(centroid, keyPoints[i]); if (distance === 0) { distance = 1e-4; } keyPoints[i] = [ centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, - centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius]; - graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i]))); + centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius + ]; + loc = projection.invert(keyPoints[i]); + node = keyNodes[i]; + origNode = origNodes[node.id]; + node = node.move(geoInterp(origNode.loc, loc, t)); + graph = graph.replace(node); // figure out the between delta angle we want to match to startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]); @@ -87,14 +101,20 @@ export function actionCircularize(wayId, projection, maxAngle) { eachAngle = totalAngle / (indexRange + numberNewPoints); } while (Math.abs(eachAngle) > maxAngle); - // move existing points + + // move existing nodes for (j = 1; j < indexRange; j++) { angle = startAngle + j * eachAngle; loc = projection.invert([ - centroid[0] + Math.cos(angle)*radius, - centroid[1] + Math.sin(angle)*radius]); + centroid[0] + Math.cos(angle) * radius, + centroid[1] + Math.sin(angle) * radius + ]); - node = nodes[(j + startNodeIndex) % nodes.length].move(loc); + node = nodes[(j + startNodeIndex) % nodes.length]; + origNode = origNodes[node.id]; + nearNodes[node.id] = angle; + + node = node.move(geoInterp(origNode.loc, loc, t)); graph = graph.replace(node); } @@ -103,9 +123,21 @@ export function actionCircularize(wayId, projection, maxAngle) { angle = startAngle + (indexRange + j) * eachAngle; loc = projection.invert([ centroid[0] + Math.cos(angle) * radius, - centroid[1] + Math.sin(angle) * radius]); + centroid[1] + Math.sin(angle) * radius + ]); - node = osmNode({loc: loc}); + // choose a nearnode to use as the original + var min = Infinity; + for (var nodeId in nearNodes) { + var nearAngle = nearNodes[nodeId], + dist = Math.abs(nearAngle - angle); + if (dist < min) { + dist = min; + origNode = origNodes[nodeId]; + } + } + + node = osmNode({ loc: geoInterp(origNode.loc, loc, t) }); graph = graph.replace(node); nodes.splice(endNodeIndex + j, 0, node); @@ -195,5 +227,8 @@ export function actionCircularize(wayId, projection, maxAngle) { }; + action.transitionable = true; + + return action; }