Ignore:
Timestamp:
2007-09-24T01:36:24+02:00 (18 years ago)
Author:
framm
Message:

This commit is a manual merge of all changes that have been made to
the intermediate "core_0.5" branch on the main OSM repository,
bevore JOSM was moved to openstreetmap.de.

Changes incorporated here:

r4464@svn.openstreetmap.org
r4466@svn.openstreetmap.org
r4468@svn.openstreetmap.org
r4469@svn.openstreetmap.org
r4479@svn.openstreetmap.org

Location:
branch/0.5/src/org/openstreetmap/josm/actions/mapmode
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java

    r314 r329  
    2424import org.openstreetmap.josm.data.osm.Node;
    2525import org.openstreetmap.josm.data.osm.OsmPrimitive;
    26 import org.openstreetmap.josm.data.osm.Segment;
    2726import org.openstreetmap.josm.data.osm.Way;
     27import org.openstreetmap.josm.data.osm.WaySegment;
    2828import org.openstreetmap.josm.gui.MapFrame;
    2929import org.openstreetmap.josm.tools.ImageProvider;
     
    3333 * and there is it. Nothing more, nothing less.
    3434 *
     35 * FIXME: "nothing more, nothing less" is a bit out-of-date
     36 *
    3537 * Newly created nodes are selected. Shift modifier does not cancel the old
    3638 * selection as usual.
     
    4143public class AddNodeAction extends MapMode {
    4244
    43         enum Mode {node, nodesegment, autonode}
     45        enum Mode {node, nodeway, autonode}
    4446        private final Mode mode;
    4547
     
    4951                        putValue("help", "Action/AddNode");
    5052                        actions.add(new AddNodeAction(mf,tr("Add node"), Mode.node, tr("Add a new node to the map")));
    51                         actions.add(new AddNodeAction(mf, tr("Add node into segment"), Mode.nodesegment,tr( "Add a node into an existing segment")));
    52                         actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into segment; with SHIFT: re-use existing node)")));
     53                        actions.add(new AddNodeAction(mf, tr("Add node into way"), Mode.nodeway,tr( "Add a node into an existing way")));
     54                        actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into way; with SHIFT: re-use existing node)")));
    5355                        setCurrent(0);
    5456                }
     
    8385         * position.
    8486         *
    85          * If in nodesegment mode, add the node to the line segment by splitting the
    86          * segment. The new created segment will be inserted in every way the segment
    87          * was part of.
     87         * If in nodeway mode, insert the node into the way.
    8888         */
    8989        @Override public void mouseClicked(MouseEvent e) {
     
    9898
    9999                Command c = new AddCommand(n);
    100                 if (mode == Mode.nodesegment) {
    101                         Segment s = Main.map.mapView.getNearestSegment(e.getPoint());
    102                         if (s == null)
     100                if (mode == Mode.nodeway) {
     101                        WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint());
     102                        if (ws == null)
    103103                                return;
    104104                       
    105105                        // see if another segment is also near
    106                         Segment other = Main.map.mapView.getNearestSegment(e.getPoint(), Collections.singleton(s));
     106                        WaySegment other = Main.map.mapView.getNearestWaySegment(e.getPoint(),
     107                                Collections.singleton(ws));
     108
     109                        Node n1 = ws.way.nodes.get(ws.lowerIndex),
     110                                n2 = ws.way.nodes.get(ws.lowerIndex + 1);
    107111
    108112                        if (other == null && (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) == 0) {
    109113                                // moving the new point to the perpendicular point
    110                                 // FIXME: when two segments are split, should move the new point to the
     114                                // FIXME: when two way segments are split, should move the new point to the
    111115                                // intersection point!
    112                                 EastNorth A = s.from.eastNorth;
    113                                 EastNorth B = s.to.eastNorth;
     116                                EastNorth A = n1.eastNorth;
     117                                EastNorth B = n2.eastNorth;
    114118                                double ab = A.distance(B);
    115119                                double nb = n.eastNorth.distance(B);
     
    124128                       
    125129                        // split the first segment
    126                         splitSegmentAtNode(s, n, cmds);
     130                        splitWaySegmentAtNode(ws, n, cmds);
    127131                       
    128132                        // if a second segment was found, split that as well
    129                         if (other != null) splitSegmentAtNode(other, n, cmds);
     133                        if (other != null) splitWaySegmentAtNode(other, n, cmds);
    130134
    131135                        c = new SequenceCommand(tr((other == null) ?
    132                                 "Add node into segment" : "Add common node into two segments"), cmds);
     136                                "Add node into way" : "Add common node into two ways"), cmds);
    133137                }
    134138
     
    136140                if (mode == Mode.autonode) {
    137141
    138                         Segment insertInto = null;
     142                        WaySegment insertInto = null;
    139143                        Node reuseNode = null;
    140144                       
    141                         // If CTRL is held, insert the node into a potentially existing segment
     145                        // If CTRL is held, insert the node into a potentially existing way segment
    142146                        if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) {
    143                                 insertInto = Main.map.mapView.getNearestSegment(e.getPoint());
     147                                insertInto = Main.map.mapView.getNearestWaySegment(e.getPoint());
     148                                if (insertInto == null) System.err.println("Couldn't find nearby way segment");
    144149                                if (insertInto == null)
    145150                                        return;
     
    150155                        // continuation of the "add node and connect" stuff)
    151156                        else if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
    152                                 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), false);
     157                                OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint());
    153158                                if (clicked == null || !(clicked instanceof Node))
    154159                                        return;
     
    159164                        if (selection.size() == 1 && selection.iterator().next() instanceof Node) {
    160165                                Node n1 = (Node)selection.iterator().next();
     166
    161167                                Collection<Command> cmds = new LinkedList<Command>();
    162168                               
    163169                                if (reuseNode != null) {
    164170                                        // in re-use node mode, n1 must not be identical to clicked node
     171                                        if (n1 == reuseNode) System.err.println("n1 == reuseNode");
    165172                                        if (n1 == reuseNode) return;
    166173                                        // replace newly created node with existing node
     
    171178                                }
    172179                               
    173                                 Segment s = new Segment(n1, n);
    174                                
     180                                /* Keep track of the way we change, it might be the same into
     181                                 * which we insert the node.
     182                                 */
     183                                Way newInsertInto = null;
    175184                                if (insertInto != null)
    176                                         splitSegmentAtNode(insertInto, n, cmds);
    177                                
    178                                 cmds.add(new AddCommand(s));                   
     185                                        newInsertInto = splitWaySegmentAtNode(insertInto, n, cmds);
    179186
    180187                                Way way = getWayForNode(n1);
    181                                 if (way != null) {
    182                                         Way newWay = new Way(way);
    183                                         if (way.segments.get(0).from == n1) {
    184                                                 Node tmp = s.from;
    185                                                 s.from = s.to;
    186                                                 s.to = tmp;
    187                                                 newWay.segments.add(0, s);
    188                                         } else
    189                                                 newWay.segments.add(s);
    190                                         cmds.add(new ChangeCommand(way, newWay));
    191                                 }
    192 
    193                                 c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into segment and connect"), cmds);
     188                                if (way == null) {
     189                                        way = new Way();
     190                                        way.nodes.add(n1);
     191                                        cmds.add(new AddCommand(way));
     192                                } else {
     193                                        if (insertInto != null && way == insertInto.way) {
     194                                                way = newInsertInto;
     195                                        } else {
     196                                                Way wnew = new Way(way);
     197                                                cmds.add(new ChangeCommand(way, wnew));
     198                                                way = wnew;
     199                                        }
     200                                }
     201
     202                                if (way.nodes.get(way.nodes.size() - 1) == n1) {
     203                                        way.nodes.add(n);
     204                                } else {
     205                                        way.nodes.add(0, n);
     206                                }
     207
     208                                c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into way and connect"), cmds);
    194209                        }       
    195210                }               
     
    201216       
    202217        /**
    203          * @return If the node is part of exactly one way, return this.
     218         * @return If the node is the end of exactly one way, return this.
    204219         *      <code>null</code> otherwise.
    205220         */
     
    207222                Way way = null;
    208223                for (Way w : Main.ds.ways) {
    209                         for (Segment s : w.segments) {
    210                                 if (s.from == n || s.to == n) {
     224                        int i = w.nodes.indexOf(n);
     225                        if (i == -1) continue;
     226                        if (i == 0 || i == w.nodes.size() - 1) {
    211227                                        if (way != null)
    212228                                                return null;
    213                                         if (s.from == s.to)
    214                                                 return null;
    215229                                        way = w;
    216230                                }
    217231                        }
    218                 }
    219232                return way;
    220233        }
    221234       
    222         private void splitSegmentAtNode(Segment s, Node n, Collection<Command> cmds) {
    223                 Segment s1 = new Segment(s);
    224                 s1.to = n;
    225                 Segment s2 = new Segment(s.from, s.to);
    226                 s2.from = n;
    227                 if (s.keys != null)
    228                         s2.keys = new HashMap<String, String>(s.keys);
    229 
    230                 cmds.add(new ChangeCommand(s, s1));
    231                 cmds.add(new AddCommand(s2));
    232 
    233                 // Add the segment to every way
    234                 for (Way wold : Main.ds.ways) {
    235                         if (wold.segments.contains(s)) {
    236                                 Way wnew = new Way(wold);
    237                                 Collection<Segment> segs = new ArrayList<Segment>(wnew.segments);
    238                                 wnew.segments.clear();
    239                                 for (Segment waySeg : segs) {
    240                                         wnew.segments.add(waySeg);
    241                                         if (waySeg == s)
    242                                                 wnew.segments.add(s2);
    243                                 }
    244                                 cmds.add(new ChangeCommand(wold, wnew));
    245                         }
    246                 }
     235        private Way splitWaySegmentAtNode(WaySegment ws, Node n, Collection<Command> cmds) {
     236                Way wnew = new Way(ws.way);
     237                wnew.nodes.add(ws.lowerIndex + 1, n);
     238                cmds.add(new ChangeCommand(ws.way, wnew));
     239                return wnew;
    247240        }
    248241}
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddSegmentAction.java

    r301 r329  
    1515import org.openstreetmap.josm.Main;
    1616import org.openstreetmap.josm.command.AddCommand;
     17import org.openstreetmap.josm.command.ChangeCommand;
    1718import org.openstreetmap.josm.data.osm.Node;
    1819import org.openstreetmap.josm.data.osm.OsmPrimitive;
    19 import org.openstreetmap.josm.data.osm.Segment;
     20import org.openstreetmap.josm.data.osm.Way;
    2021import org.openstreetmap.josm.gui.MapFrame;
    2122import org.openstreetmap.josm.tools.ImageProvider;
     
    5152         */
    5253        public AddSegmentAction(MapFrame mapFrame) {
    53                 super(tr("Add segment"),
     54                super(tr("Connect two nodes"),
    5455                                "addsegment",
    55                                 tr("Add a segment between two nodes."),
     56                                tr("Connect two nodes using ways."),
    5657                                KeyEvent.VK_G,
    5758                                mapFrame,
     
    7273        }
    7374
    74        
     75        /**
     76         * Called when user hits space bar while dragging.
     77         */
    7578        @Override public void actionPerformed(ActionEvent e) {
    7679                super.actionPerformed(e);
     
    8588                        return;
    8689
    87                 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), true);
    88                 if (clicked == null || !(clicked instanceof Node))
    89                         return;
     90                Node clicked = Main.map.mapView.getNearestNode(e.getPoint());
     91                if (clicked == null) return;
    9092
    9193                drawHint(false);
    92                 first = second = (Node)clicked;
     94                first = second = clicked;
    9395        }
    9496
     
    101103                        return;
    102104
    103                 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
    104                 if (clicked == null || clicked == second || !(clicked instanceof Node))
    105                         return;
     105                Node hovered = Main.map.mapView.getNearestNode(e.getPoint());
     106                if (hovered == second) return;
    106107
    107108                drawHint(false);
    108 
    109                 second = (Node)clicked;
     109                second = hovered;
    110110                drawHint(true);
    111111        }
     
    116116        @Override public void mouseReleased(MouseEvent e) {
    117117                if (e.getButton() == MouseEvent.BUTTON1) {
     118                        drawHint(false);
    118119                        makeSegment();
    119                         first = null; // release segment drawing
     120                        first = null;
    120121                }
     122        }
     123
     124        /**
     125         * @return If the node is the end of exactly one way, return this.
     126         *      <code>null</code> otherwise.
     127         */
     128        private Way getWayForNode(Node n) {
     129                Way way = null;
     130                for (Way w : Main.ds.ways) {
     131                        int i = w.nodes.indexOf(n);
     132                        if (i == -1) continue;
     133                        if (i == 0 || i == w.nodes.size() - 1) {
     134                                if (way != null)
     135                                        return null;
     136                                way = w;
     137                        }
     138                }
     139                return way;
    121140        }
    122141
     
    126145         */
    127146        private void makeSegment() {
    128                 if (first == null || second == null) {
    129                         first = null;
    130                         second = null;
    131                         return;
    132                 }
    133 
    134                 drawHint(false);
     147                Node n1 = first;
     148                Node n2 = second;
    135149               
    136                 Node start = first;
    137                 Node end = second;
     150                // this is to allow continued segment drawing by hitting the space bar
     151                // at every intermediate node
    138152                first = second;
    139153                second = null;
     154
     155                if (n1 == null || n2 == null || n1 == n2) return;
     156
     157                Way w = getWayForNode(n1);
     158                Way wnew;
     159                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    140160               
    141                 if (start != end) {
    142                         // try to find a segment
    143                         for (Segment ls : Main.ds.segments)
    144                                 if (!ls.deleted && ((start == ls.from && end == ls.to) || (end == ls.from && start == ls.to)))
    145                                         return; // already a segment here - be happy, do nothing.
    146 
    147                         Segment ls = new Segment(start, end);
    148                         Main.main.undoRedo.add(new AddCommand(ls));
    149                         Collection<OsmPrimitive> sel = Main.ds.getSelected();
    150                         sel.add(ls);
     161                if (w == null) {
     162                        // create a new way and add it to the current selection.
     163                        wnew = new Way();
     164                        wnew.nodes.add(n1);
     165                        wnew.nodes.add(n2);
     166                        Main.main.undoRedo.add(new AddCommand(wnew));
     167                        sel.add(wnew);
     168                        Main.ds.setSelected(sel);
     169                } else {
     170                        // extend an existing way; only add to current selection if
     171                        // it is not already in there.
     172                        wnew = new Way(w);
     173                        if (wnew.nodes.get(wnew.nodes.size() - 1) == n1) {
     174                                wnew.nodes.add(n2);
     175                        } else {
     176                                wnew.nodes.add(0, n2);
     177                        }
     178                        Main.main.undoRedo.add(new ChangeCommand(w, wnew));
     179                        // do not use wnew below; ChangeCommand only uses wnew as a
     180                        // message about changes to be done to w but will not replace w!
     181                        if (!sel.contains(w)) {
     182                                sel.add(w);
     183                        }
     184                        // do not move this into the if block above since it also
     185                        // fires the selection change event which is desired.
    151186                        Main.ds.setSelected(sel);
    152187                }
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java

    r301 r329  
    1 // License: GPL. Copyright 2007 by Immanuel Scholz and others
    2 package org.openstreetmap.josm.actions.mapmode;
    3 
    4 import static org.openstreetmap.josm.tools.I18n.tr;
    5 import static org.openstreetmap.josm.tools.I18n.trn;
    6 
    7 import java.awt.event.KeyEvent;
    8 import java.awt.event.MouseEvent;
    9 import java.util.Arrays;
    10 import java.util.Collection;
    11 import java.util.HashSet;
    12 import java.util.LinkedList;
    13 
    14 import javax.swing.JOptionPane;
    15 
    16 import org.openstreetmap.josm.Main;
    17 import org.openstreetmap.josm.actions.ReorderAction;
    18 import org.openstreetmap.josm.command.AddCommand;
    19 import org.openstreetmap.josm.command.ChangeCommand;
    20 import org.openstreetmap.josm.command.DeleteCommand;
    21 import org.openstreetmap.josm.data.SelectionChangedListener;
    22 import org.openstreetmap.josm.data.osm.DataSet;
    23 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    24 import org.openstreetmap.josm.data.osm.Segment;
    25 import org.openstreetmap.josm.data.osm.Way;
    26 import org.openstreetmap.josm.gui.MapFrame;
    27 import org.openstreetmap.josm.tools.ImageProvider;
    28 
    29 /**
    30  * Add a new way. The action is split into the first phase, where a new way get
    31  * created or selected and the second, where this way is modified.
    32  *
    33  * Way creation mode:
    34  * If there is a selection when the mode is entered, all segments in this
    35  * selection form a new way. All non-segment objects are deselected. If there
    36  * were ways selected, the user is asked whether to select all segments of these
    37  * ways or not, except there is exactly one way selected, which enter the
    38  * edit ways mode for this way immediatly.
    39  *
    40  * If there is no selection on entering, and the user clicks on an segment,
    41  * the way editing starts the with a new way and this segment. If the user click
    42  * on a way (not holding Alt down), then this way is edited in the way edit mode.
    43  *
    44  * Way editing mode:
    45  * The user can click on subsequent segments. If the segment belonged to the way
    46  * it get removed from the way. Elsewhere it get added to the way. JOSM try to add
    47  * the segment in the correct position. This is done by searching for connections
    48  * to the segment at its 'to' node which are also in the way. The segemnt is
    49  * inserted in the way as predecessor of the found segment (or at last segment, if
    50  * nothing found).
    51  *
    52  * @author imi
    53  */
    54 public class AddWayAction extends MapMode implements SelectionChangedListener {
    55         private Way way;
    56 
    57         /**
    58          * Create a new AddWayAction.
    59          * @param mapFrame The MapFrame this action belongs to.
    60          * @param followMode The mode to go into when finished creating a way.
    61          */
    62         public AddWayAction(MapFrame mapFrame) {
    63                 super(tr("Add Way"), "addway", tr("Add a new way to the data."), KeyEvent.VK_W, mapFrame, ImageProvider.getCursor("normal", "way"));
    64                 DataSet.listeners.add(this);
    65         }
    66 
    67         @Override public void enterMode() {
    68                 super.enterMode();
    69                 way = makeWay();
    70                 Main.ds.setSelected(way);
    71                 Main.map.mapView.addMouseListener(this);
    72         }
    73 
    74         @Override public void exitMode() {
    75                 super.exitMode();
    76                 way = null;
    77                 Main.map.mapView.removeMouseListener(this);
    78         }
    79 
    80         @Override public void mouseClicked(MouseEvent e) {
    81                 if (e.getButton() != MouseEvent.BUTTON1)
    82                         return;
    83 
    84                 Segment s = Main.map.mapView.getNearestSegment(e.getPoint());
    85                 if (s == null)
    86                         return;
    87 
    88                 // special case for initial selecting one way
    89                 if (way == null && (e.getModifiers() & MouseEvent.ALT_DOWN_MASK) == 0) {
    90                         Way w = Main.map.mapView.getNearestWay(e.getPoint());
    91                         if (w != null) {
    92                                 way = w;
    93                                 Main.ds.setSelected(way);
    94                                 for (Segment seg : way.segments) {
    95                                         if (seg.incomplete) {
    96                                                 JOptionPane.showMessageDialog(Main.parent,tr("Warning: This way is incomplete. Try to download it before adding segments."));
    97                                                 return;
    98                                         }
    99                                 }
    100                                 return;
    101                         }
    102                 }
    103 
    104                 if (way != null && way.segments.contains(s)) {
    105                         Way copy = new Way(way);
    106 
    107                         copy.segments.remove(s);
    108                         if (copy.segments.isEmpty()) {
    109                                 Main.main.undoRedo.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{way})));
    110                                 way = null;
    111                         } else
    112                                 Main.main.undoRedo.add(new ChangeCommand(way, copy));
    113                 } else {
    114                         if (way == null) {
    115                                 way = new Way();
    116                                 way.segments.add(s);
    117                                 Main.main.undoRedo.add(new AddCommand(way));
    118                         } else {
    119                                 Way copy = new Way(way);
    120                                 int i;
    121                                 for (i = 0; i < way.segments.size(); ++i)
    122                                         if (way.segments.get(i).from == s.to)
    123                                                 break;
    124                                 copy.segments.add(i, s);
    125                                 Main.main.undoRedo.add(new ChangeCommand(way, copy));
    126                         }
    127                 }
    128                 Main.ds.setSelected(way);
    129         }
    130 
    131         /**
    132          * Form a way, either out of the (one) selected way or by creating a way over the selected
    133          * line segments.
    134          */
    135         private Way makeWay() {
    136                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    137                 if (selection.isEmpty())
    138                         return null;
    139 
    140                 if (selection.size() == 1 && selection.iterator().next() instanceof Way) {
    141                         Way way = (Way)selection.iterator().next();
    142                         for (Segment seg : way.segments) {
    143                                 if (seg.incomplete) {
    144                                         JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before adding segments."));
    145                                         break;
    146                                 }
    147                         }
    148                         return way;
    149                 }
    150 
    151                 HashSet<Segment> segmentSet = new HashSet<Segment>();
    152                 int numberOfSelectedWays = 0;
    153                 for (OsmPrimitive osm : selection) {
    154                         if (osm instanceof Way)
    155                                 numberOfSelectedWays++;
    156                         else if (osm instanceof Segment)
    157                                 segmentSet.add((Segment)osm);
    158                 }
    159 
    160                 Way wayToAdd = null;
    161                 boolean reordered = false;
    162                 if (numberOfSelectedWays > 0) {
    163                         int answer = JOptionPane.showConfirmDialog(Main.parent,trn("{0} way has been selected.\nDo you wish to select all segments belonging to the way instead?","{0} ways have been selected.\nDo you wish to select all segments belonging to the ways instead?",numberOfSelectedWays,numberOfSelectedWays),tr("Add segments from ways"), JOptionPane.YES_NO_OPTION);
    164                         if (answer == JOptionPane.YES_OPTION) {
    165                                 for (OsmPrimitive osm : selection)
    166                                         if (osm instanceof Way)
    167                                                 segmentSet.addAll(((Way)osm).segments);
    168                         } else if (numberOfSelectedWays == 1) {
    169                                 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Do you want to add all other selected segments to the one selected way?"),tr("Add segments to way?"), JOptionPane.YES_NO_OPTION);
    170                                 if (answer == JOptionPane.YES_OPTION) {
    171                                         for (OsmPrimitive osm : selection) {
    172                                                 if (osm instanceof Way) {
    173                                                         wayToAdd = (Way)osm;
    174                                                         answer = JOptionPane.showConfirmDialog(Main.parent,tr("Reorder all line segments?"), tr("Reorder?"), JOptionPane.YES_NO_CANCEL_OPTION);
    175                                                         if (answer == JOptionPane.CANCEL_OPTION)
    176                                                                 return wayToAdd;
    177                                                         if (answer == JOptionPane.YES_OPTION) {
    178                                                                 segmentSet.addAll(wayToAdd.segments);
    179                                                                 reordered = true;
    180                                                         } else
    181                                                                 segmentSet.removeAll(wayToAdd.segments);
    182                                                         break;
    183                                                 }
    184                                         }
    185                                 }
    186                         }
    187                 }
    188 
    189                 if (segmentSet.isEmpty())
    190                         return null;
    191 
    192                 LinkedList<Segment> rawSegments = new LinkedList<Segment>(segmentSet);
    193                 LinkedList<Segment> sortedSegments = ReorderAction.sortSegments(rawSegments, true);
    194 
    195                 if (wayToAdd != null) {
    196                         Way w = new Way(wayToAdd);
    197                         if (reordered)
    198                                 w.segments.clear();
    199                         w.segments.addAll(sortedSegments);
    200                         Main.main.undoRedo.add(new ChangeCommand(wayToAdd, w));
    201                         return wayToAdd;
    202                 }
    203 
    204                 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent,trn("Create a new way out of {0} segment?","Create a new way out of {0} segments?",sortedSegments.size(),sortedSegments.size()), tr("Create new way"), JOptionPane.YES_NO_OPTION))
    205                         return null;
    206 
    207                 Way w = new Way();
    208                 w.segments.addAll(sortedSegments);
    209                 Main.main.undoRedo.add(new AddCommand(w));
    210                 return w;
    211         }
    212 
    213         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    214                 if (newSelection.size() == 1) {
    215                         OsmPrimitive osm = newSelection.iterator().next();
    216                         way = osm instanceof Way ? (Way)osm : null;
    217                 } else
    218                         way = null;
    219     }
    220 }
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r301 r329  
    2424import org.openstreetmap.josm.data.osm.Node;
    2525import org.openstreetmap.josm.data.osm.OsmPrimitive;
    26 import org.openstreetmap.josm.data.osm.Segment;
    2726import org.openstreetmap.josm.data.osm.Way;
    2827import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
     
    3837 * @see #deleteWithReferences(OsmPrimitive)
    3938 *
    40  * Pressing Alt will select the way instead of a segment, as usual.
    41  *
    4239 * If the user did not press Ctrl and the object has any references, the user
    4340 * is informed and nothing is deleted.
     
    5754                super(tr("Delete"),
    5855                                "delete",
    59                                 tr("Delete nodes, streets or segments."),
     56                                tr("Delete nodes or ways."),
    6057                                KeyEvent.VK_D,
    6158                                mapFrame,
     
    9289                        return;
    9390               
    94                 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
     91                OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint());
    9592                if (sel == null)
    9693                        return;
     
    105102
    106103        /**
    107          * Delete the primitives and everything they references.
     104         * Delete the primitives and everything they reference.
    108105         *
    109          * If a node is deleted, the node and all segments, ways and areas
     106         * If a node is deleted, the node and all ways and relations
    110107         * the node is part of are deleted as well.
    111108         *
    112          * If a segment is deleted, all ways the segment is part of
    113          * are deleted as well. No nodes are deleted.
     109         * If a way is deleted, all relations the way is member of are also deleted.
    114110         *
    115          * If a way is deleted, only the way and no segments or nodes are
    116          * deleted.
    117          *
    118          * If an area is deleted, only the area gets deleted.
     111         * If a way is deleted, only the way and no nodes are deleted.
    119112         *
    120113         * @param selection The list of all object to be deleted.
     
    134127         * inform the user and do not delete.
    135128         *
    136          * If deleting a node which is part of exactly two segments, and both segments
    137          * have no conflicting keys, join them and remove the node.
    138          * If the two segments are part of the same way, remove the deleted segment
    139          * from the way.
     129         * If a node is to be deleted which is in the middle of exactly one way,
     130         * the node is removed from the way's node list and after that removed
     131         * itself.
    140132         *
    141133         * @param selection The objects to delete.
     
    149141                        if (!selection.containsAll(v.data)) {
    150142                                if (osm instanceof Node && joinIfPossible) {
    151                                         String reason = deleteNodeAndJoinSegment((Node)osm);
     143                                        String reason = deleteNodeAndJoinWay((Node)osm);
    152144                                        if (reason != null && msgBox) {
    153145                                                JOptionPane.showMessageDialog(Main.parent,tr("Cannot delete node.")+" "+reason);
     
    167159        }
    168160
    169         private String deleteNodeAndJoinSegment(Node n) {
    170                 ArrayList<Segment> segs = new ArrayList<Segment>(2);
    171                 for (Segment s : Main.ds.segments) {
    172                         if (!s.deleted && (s.from == n || s.to == n)) {
    173                                 if (segs.size() > 1)
    174                                         return tr("Used by more than two segments.");
    175                                 segs.add(s);
    176                         }
    177                 }
    178                 if (segs.size() != 2)
    179                         return tr("Used by only one segment.");
    180                 Segment seg1 = segs.get(0);
    181                 Segment seg2 = segs.get(1);
    182                 if (seg1.from == seg2.to) {
    183                         Segment s = seg1;
    184                         seg1 = seg2;
    185                         seg2 = s;
    186                 }
    187                 if (seg1.from == seg2.from || seg1.to == seg2.to)
    188                         return tr("Wrong direction of segments.");
    189                 for (Entry<String, String> e : seg1.entrySet())
    190                         if (seg2.keySet().contains(e.getKey()) && !seg2.get(e.getKey()).equals(e.getValue()))
    191                                 return tr("Conflicting keys");
    192                 ArrayList<Way> ways = new ArrayList<Way>(2);
     161        private String deleteNodeAndJoinWay(Node n) {
     162                ArrayList<Way> ways = new ArrayList<Way>(1);
    193163                for (Way w : Main.ds.ways) {
    194                         if (w.deleted)
    195                                 continue;
    196                         if ((w.segments.contains(seg1) && !w.segments.contains(seg2)) || (w.segments.contains(seg2) && !w.segments.contains(seg1)))
    197                                 return tr("Segments are part of different ways.");
    198                         if (w.segments.contains(seg1) && w.segments.contains(seg2))
     164                        if (!w.deleted && w.nodes.contains(n)) {
    199165                                ways.add(w);
    200166                }
    201                 Segment s = new Segment(seg1);
    202                 s.to = seg2.to;
    203                 if (s.keys == null)
    204                         s.keys = seg2.keys;
    205                 else if (seg2.keys != null)
    206                         s.keys.putAll(seg2.keys);
    207                 Collection<Command> cmds = new LinkedList<Command>();
    208                 for (Way w : ways) {
    209                         Way copy = new Way(w);
    210                         copy.segments.remove(seg2);
    211                         cmds.add(new ChangeCommand(w, copy));
    212167                }
    213                 cmds.add(new ChangeCommand(seg1, s));
    214                 cmds.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{n, seg2})));
    215                 Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds));
     168
     169                if (ways.size() > 1)
     170                        return tr("Used by more than one way.");
     171               
     172                if (ways.size() == 1) {
     173                        // node in way
     174                        Way w = ways.get(0);
     175
     176                        int i = w.nodes.indexOf(n);
     177                        if (w.nodes.lastIndexOf(n) != i)
     178                                return tr("Occurs more than once in the same way.");
     179                        if (i == 0 || i == w.nodes.size() - 1)
     180                                return tr("Is at the end of a way");
     181
     182                        Way wnew = new Way(w);
     183                        wnew.nodes.remove(i);
     184
     185                        Collection<Command> cmds = new LinkedList<Command>();
     186                        cmds.add(new ChangeCommand(w, wnew));
     187                        cmds.add(new DeleteCommand(Collections.singleton(n)));
     188                        Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds));
     189                } else {
     190                        // unwayed node
     191                        Main.main.undoRedo.add(new DeleteCommand(Collections.singleton(n)));   
     192                }
    216193                return null;
    217194    }
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r298 r329  
    1515/**
    1616 * A class implementing MapMode is able to be selected as an mode for map editing.
    17  * As example scrolling the map is a MapMode, connecting Nodes to new Segments
     17 * As example scrolling the map is a MapMode, connecting Nodes to new Ways
    1818 * is another.
    1919 *
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/MoveAction.java

    r312 r329  
    162162
    163163                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    164                 OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);
     164                OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint());
    165165                if (osm != null) {
    166166                        if (!sel.contains(osm))
  • branch/0.5/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java

    r298 r329  
    1717import org.openstreetmap.josm.data.osm.Node;
    1818import org.openstreetmap.josm.data.osm.OsmPrimitive;
    19 import org.openstreetmap.josm.data.osm.Segment;
    2019import org.openstreetmap.josm.gui.MapFrame;
    2120import org.openstreetmap.josm.gui.SelectionManager;
     
    5554 * pixel are considered "only click". If that happens, the nearest Node will
    5655 * be selected if there is any within 10 pixel range. If there is no Node within
    57  * 10 pixel, the nearest Segment (or Street, if user hold down the Alt-Key)
    58  * within 10 pixel range is selected. If there is no Segment within 10 pixel
    59  * and the user clicked in or 10 pixel away from an area, this area is selected.
    60  * If there is even no area, nothing is selected. Shift and Ctrl key applies to
    61  * this as usual. For more, @see MapView#getNearest(Point, boolean)
     56 * 10 pixel, the nearest Way within 10 pixel range is selected. If there is no
     57 * Way within 10 pixel and the user clicked in or 10 pixel away from an area,
     58 * this area is selected.  If there is even no area, nothing is selected.
     59 * Shift and Ctrl key applies to this as usual. For more,
     60 * @see MapView#getNearest(Point)
    6261 *
    6362 * @author imi
     
    6564public class SelectionAction extends MapMode implements SelectionEnded {
    6665
    67         enum Mode {select, straight}
    68         private final Mode mode;
    69 
    7066        public static class Group extends GroupAction {
    7167                public Group(MapFrame mf) {
    7268                        super(KeyEvent.VK_S,0);
    7369                        putValue("help", "Action/Selection");
    74                         actions.add(new SelectionAction(mf, tr("Selection"), Mode.select, tr("Select objects by dragging or clicking.")));
    75                         actions.add(new SelectionAction(mf, tr("Straight line"), Mode.straight, tr("Select objects in a straight line.")));
     70                        actions.add(new SelectionAction(mf, tr("Selection"), tr("Select objects by dragging or clicking.")));
    7671                        setCurrent(0);
    7772                }
     
    8479        private SelectionManager selectionManager;
    8580
    86         private Node straightStart = null;
    87         private Node lastEnd = null;
    88         private Collection<OsmPrimitive> oldSelection = null;
    89 
    90         //TODO: Implement reverse references into data objects and remove this
    91         private final Map<Node, Collection<Segment>> reverseSegmentMap = new HashMap<Node, Collection<Segment>>();
    92 
    9381        /**
    9482         * Create a new SelectionAction in the given frame.
    9583         * @param mapFrame The frame this action belongs to
    9684         */
    97         public SelectionAction(MapFrame mapFrame, String name, Mode mode, String desc) {
    98                 super(name, "selection/"+mode, desc, mapFrame, ImageProvider.getCursor("normal", "selection"));
    99                 this.mode = mode;
    100                 putValue("help", "Action/Selection/"+Character.toUpperCase(mode.toString().charAt(0))+mode.toString().substring(1));
     85        public SelectionAction(MapFrame mapFrame, String name, String desc) {
     86                super(name, "selection/select", desc, mapFrame, ImageProvider.getCursor("normal", "selection"));
     87                putValue("help", "Action/Selection");
    10188                this.selectionManager = new SelectionManager(this, false, mapFrame.mapView);
    10289        }
     
    10491        @Override public void enterMode() {
    10592                super.enterMode();
    106                 if (mode == Mode.select)
    10793                        selectionManager.register(Main.map.mapView);
    108                 else {
    109                         Main.map.mapView.addMouseMotionListener(this);
    110                         Main.map.mapView.addMouseListener(this);
    111                         for (Segment s : Main.ds.segments) {
    112                                 addBackReference(s.from, s);
    113                                 addBackReference(s.to, s);
    114                         }
    115                 }
    116         }
    117 
    118         private void addBackReference(Node n, Segment s) {
    119                 Collection<Segment> c = reverseSegmentMap.get(n);
    120                 if (c == null) {
    121                         c = new HashSet<Segment>();
    122                         reverseSegmentMap.put(n, c);
    123                 }
    124                 c.add(s);
    12594        }
    12695
    12796        @Override public void exitMode() {
    12897                super.exitMode();
    129                 if (mode == Mode.select)
    13098                        selectionManager.unregister(Main.map.mapView);
    131                 else {
    132                         Main.map.mapView.removeMouseMotionListener(this);
    133                         Main.map.mapView.removeMouseListener(this);
    134                         reverseSegmentMap.clear();
    135                 }
    13699        }
    137100
     
    163126                Main.map.mapView.repaint();
    164127    }
    165 
    166         @Override public void mouseDragged(MouseEvent e) {
    167                 Node old = lastEnd;
    168                 lastEnd = Main.map.mapView.getNearestNode(e.getPoint());
    169                 if (straightStart == null)
    170                         straightStart = lastEnd;
    171                 if (straightStart != null && lastEnd != null && straightStart != lastEnd && old != lastEnd) {
    172                         Collection<OsmPrimitive> path = new HashSet<OsmPrimitive>();
    173                         Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
    174                         path.add(straightStart);
    175                         calculateShortestPath(path, straightStart, lastEnd);
    176                         if ((e.getModifiers() & MouseEvent.CTRL_MASK) != 0) {
    177                                 sel.addAll(oldSelection);
    178                                 sel.removeAll(path);
    179                         } else if ((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0) {
    180                                 sel = path;
    181                                 sel.addAll(oldSelection);
    182                         } else
    183                                 sel = path;
    184                         Main.ds.setSelected(sel);
    185                 }
    186         }
    187 
    188         @Override public void mousePressed(MouseEvent e) {
    189                 straightStart = Main.map.mapView.getNearestNode(e.getPoint());
    190                 lastEnd = null;
    191                 oldSelection = Main.ds.getSelected();
    192         }
    193 
    194         @Override public void mouseReleased(MouseEvent e) {
    195                 straightStart = null;
    196                 lastEnd = null;
    197                 oldSelection = null;
    198         }
    199 
    200         /**
    201          * Get the shortest path by stepping through the node with a common segment with start
    202          * and nearest to the end (greedy algorithm).
    203          */
    204         private void calculateShortestPath(Collection<OsmPrimitive> path, Node start, Node end) {
    205                 for (Node pivot = start; pivot != null;)
    206                         pivot = addNearest(path, pivot, end);
    207         }
    208 
    209         private Node addNearest(Collection<OsmPrimitive> path, Node start, Node end) {
    210                 Collection<Segment> c = reverseSegmentMap.get(start);
    211                 if (c == null)
    212                         return null; // start may be a waypoint without segments
    213                 double min = Double.MAX_VALUE;
    214                 Node next = null;
    215                 Segment seg = null;
    216                 for (Segment s : c) {
    217                         Node other = s.from == start ? s.to : s.from;
    218                         if (other == end) {
    219                                 next = other;
    220                                 seg = s;
    221                                 min = 0;
    222                                 break;
    223                         }
    224                         double distance = other.eastNorth.distance(end.eastNorth);
    225                         if (distance < min) {
    226                                 min = distance;
    227                                 next = other;
    228                                 seg = s;
    229                         }
    230                 }
    231                 if (min < start.eastNorth.distance(end.eastNorth) && next != null) {
    232                         path.add(next);
    233                         path.add(seg);
    234                         return next;
    235                 }
    236                 return null;
    237         }
    238128}
Note: See TracChangeset for help on using the changeset viewer.