return 0;
}
+ public function getNodesAtPosition(lat:Number, lon:Number):Array {
+ if (nodePositions[lat+","+lon]) {
+ return nodePositions[lat+","+lon];
+ }
+ return [];
+ }
+
// these are functions that the Connection implementation is expected to
// provide. This class has some generic helpers for the implementation.
public function loadBbox(left:Number, right:Number,
}
}
+ /**
+ * Insert this node into the list of ways, and remove dupes at the same time.
+ * Please, don't call this on a node from a vector background, chaos will ensue.
+ */
+ public function join(ways:Array, performAction:Function):void {
+ if (this.isDupe() || ways.length > 0) {
+ var connection:Connection = Connection.getConnection();
+ var nodes:Array = connection.getNodesAtPosition(lat,lon);
+ // filter the nodes array to remove any occurances of this.
+ // Pass "this" as thisObject to get "this" into the callback function
+ var dupes:Array = nodes.filter(
+ function(element:*, index:int, arr:Array):Boolean {
+ return (element != this);
+ },
+ this
+ );
+ performAction(new JoinNodeAction(this, dupes, ways));
+ }
+ }
+
+ /**
+ * Replace all occurances of this node with the given target node
+ */
+ public function replaceWith(target:Node, performAction:Function):void {
+ performAction(new ReplaceNodeAction(this, target));
+ }
+
public function isDupe():Boolean {
var connection:Connection = Connection.getConnection();
if (connection.getNode(this.id) == this // node could be part of a vector layer
--- /dev/null
+package net.systemeD.halcyon.connection.actions {
+
+ import net.systemeD.halcyon.connection.*;
+
+ public class JoinNodeAction extends CompositeUndoableAction {
+
+ private var node:Node;
+ private var nodes:Array;
+ private var ways:Array;
+
+ /**
+ * For the given node, replace all the given nodes with this node, and insert
+ * the given node into the list of ways.
+ */
+ public function JoinNodeAction(node:Node, nodes:Array, ways:Array) {
+ super("Join node "+node.id);
+ this.node = node;
+ this.nodes = nodes;
+ this.ways = ways;
+ }
+
+ public override function doAction():uint {
+
+ // don't insert the node into either a way that contains it already,
+ // nor a way that contains a dupe we're replacing.
+ var avoidWays:Array = node.parentWays;
+
+ for each (var dupe:Node in nodes) {
+ for each (var parentWay:Way in dupe.parentWays) {
+ avoidWays.push(parentWay);
+ }
+
+ dupe.replaceWith(node, push);
+ }
+
+ for each (var way:Way in ways) {
+ if (avoidWays.indexOf(way) == -1) {
+ way.insertNodeAtClosestPosition(node, false, push);
+ }
+ }
+ return super.doAction();
+ }
+
+ public override function undoAction():uint {
+ return super.undoAction();
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.systemeD.halcyon.connection.actions {
+
+ import net.systemeD.halcyon.connection.*;
+
+ public class ReplaceNodeAction extends CompositeUndoableAction {
+
+ private var node:Node;
+ private var replacement:Node;
+
+ /**
+ * @param node The node we're getting rid of
+ * @param replacement The node we want to end up with
+ */
+ public function ReplaceNodeAction(node:Node, replacement:Node) {
+ super("Replace node "+node+" with "+replacement);
+ this.node = node;
+ this.replacement = replacement;
+ }
+
+ public override function doAction():uint {
+
+ for each (var way:Way in node.parentWays) {
+ for (var x:uint=0; x<way.length; x++) {
+ if (way.getNode(x) == node) {
+ way.removeNodeByIndex(x, push);
+ way.insertNode(x, replacement, push);
+ }
+ }
+ }
+
+ for each (var relation:Relation in node.parentRelations) {
+ for (var y:uint=0; y<relation.length; y++) {
+ var member:RelationMember = relation.getMember(y);
+ if (member.entity == node) {
+ relation.removeMemberByIndex(y, push);
+ relation.insertMember(y, new RelationMember(replacement, member.role), push);
+ }
+ }
+ }
+
+ node.remove(push);
+
+ return super.doAction();
+ }
+
+ public override function undoAction():uint {
+ return super.undoAction();
+ }
+ }
+}
+
import flash.ui.Keyboard;
import flash.geom.Point;
import net.systemeD.potlatch2.EditController;
+ import net.systemeD.halcyon.WayUI;
import net.systemeD.halcyon.connection.*;
import net.systemeD.halcyon.connection.actions.*;
import net.systemeD.halcyon.Globals;
case 82: repeatTags(firstSelected); return this; // 'R'
case 87: return new SelectedWay(parentWay); // 'W'
case 191: return cycleWays(); // '/'
- case 74: if (event.shiftKey) { return unjoin() }; return this;// 'J'
+ case 74: if (event.shiftKey) { return unjoin() }; return join();// 'J'
case Keyboard.BACKSPACE: return deleteNode();
case Keyboard.DELETE: return deleteNode();
}
return this;
}
+ public function join():ControllerState {
+ // detect the ways that overlap this node
+ var p:Point = new Point(controller.map.lon2coord(Node(firstSelected).lon),
+ controller.map.latp2coord(Node(firstSelected).latp));
+ var q:Point = map.localToGlobal(p);
+ var ways:Array=[]; var w:Way;
+ for each (var wayui:WayUI in controller.map.paint.wayuis) {
+ w=wayui.hitTest(q.x, q.y);
+ if (w && w!=selectedWay) { ways.push(w); }
+ }
+
+ Node(firstSelected).join(ways,MainUndoStack.getGlobalStack().addAction);
+ return this;
+ }
}
}