Changeset 4464 in osm


Ignore:
Timestamp:
2007-09-05T23:55:17+02:00 (17 years ago)
Author:
frederik
Message:

initial changeset for 0.5 functionality. this version works with 0.5 as specified but there are some minor bugs to be fixed.

Location:
applications/editors/josm/core_0.5
Files:
13 added
11 deleted
52 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/CombineWayAction.java

    r4437 r4464  
    1010import java.util.HashMap;
    1111import java.util.LinkedList;
     12import java.util.List;
     13import java.util.ListIterator;
     14import java.util.ArrayList;
    1215import java.util.Map;
    1316import java.util.Set;
     
    1518import java.util.TreeSet;
    1619import java.util.Map.Entry;
     20import java.util.HashSet;
    1721
    1822import javax.swing.Box;
     
    3135import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3236import org.openstreetmap.josm.data.osm.Way;
     37import org.openstreetmap.josm.data.osm.Node;
     38import org.openstreetmap.josm.data.osm.NodePair;
    3339import org.openstreetmap.josm.tools.GBC;
    3440
     
    4248        public CombineWayAction() {
    4349                super(tr("Combine Way"), "combineway", tr("Combine several ways into one."), KeyEvent.VK_C, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
    44                 DataSet.listeners.add(this);
     50                DataSet.selListeners.add(this);
    4551        }
    4652
     
    6874                }
    6975               
    70                 Way oldWay = selectedWays.poll();
    71                 Way newWay = new Way(oldWay);
    72                 LinkedList<Command> cmds = new LinkedList<Command>();
     76                // Battle plan:
     77                //  1. Split the ways into small chunks of 2 nodes and weed out
     78                //         duplicates.
     79                //  2. Take a chunk and see if others could be appended or prepended,
     80                //         if so, do it and remove it from the list of remaining chunks.
     81                //         Rather, rinse, repeat.
     82                //  3. If this algorithm does not produce a single way,
     83                //     complain to the user.
     84                //  4. Profit!
    7385               
    74                 for (Way w : selectedWays)
    75                         newWay.segments.addAll(w.segments);
     86                HashSet<NodePair> chunkSet = new HashSet<NodePair>();
     87                for (Way w : selectedWays) {
     88                        if (w.nodes.size() == 0) continue;
     89                        Node lastN = null;
     90                        for (Node n : w.nodes) {
     91                                if (lastN == null) {
     92                                        lastN = n;
     93                                        continue;
     94                                }
     95                                chunkSet.add(new NodePair(lastN, n));
     96                                lastN = n;
     97                        }
     98                }
     99                LinkedList<NodePair> chunks = new LinkedList<NodePair>(chunkSet);
     100
     101                if (chunks.isEmpty()) {
     102                        JOptionPane.showMessageDialog(Main.parent, tr("All the ways were empty"));
     103                        return;
     104                }
     105
     106                List<Node> nodeList = chunks.poll().toArrayList();
     107                while (!chunks.isEmpty()) {
     108                        ListIterator<NodePair> it = chunks.listIterator();
     109                        boolean foundChunk = false;
     110                        while (it.hasNext()) {
     111                                NodePair curChunk = it.next();
     112                                if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append
     113                                        nodeList.add(curChunk.b);
     114                                        foundChunk = true;
     115                                } else if (curChunk.b == nodeList.get(0)) { // prepend
     116                                        nodeList.add(0, curChunk.a);
     117                                        foundChunk = true;
     118                                }
     119                                if (foundChunk) {
     120                                        it.remove();
     121                                        break;
     122                                }
     123                        }
     124                        if (!foundChunk) break;
     125                }
     126
     127                if (!chunks.isEmpty()) {
     128                        JOptionPane.showMessageDialog(Main.parent,
     129                                tr("Could not combine ways (Hint: ways have to point into the same direction)"));
     130                        return;
     131                }
     132
     133                Way newWay = new Way(selectedWays.get(0));
     134                newWay.nodes.clear();
     135                newWay.nodes.addAll(nodeList);
    76136               
    77137                // display conflict dialog
     
    97157                }
    98158
    99                 cmds.add(new DeleteCommand(selectedWays));
    100                 cmds.add(new ChangeCommand(oldWay, newWay));
     159                LinkedList<Command> cmds = new LinkedList<Command>();
     160                cmds.add(new DeleteCommand(selectedWays.subList(1, selectedWays.size())));
     161                cmds.add(new ChangeCommand(selectedWays.peek(), newWay));
    101162                Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds));
    102                 Main.ds.setSelected(oldWay);
     163                Main.ds.setSelected(selectedWays.peek());
    103164        }
    104165
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/SplitWayAction.java

    r4437 r4464  
    1616import java.util.LinkedList;
    1717import java.util.List;
     18import java.util.Set;
    1819import java.util.Map.Entry;
    1920
     
    2728import org.openstreetmap.josm.data.SelectionChangedListener;
    2829import org.openstreetmap.josm.data.osm.DataSet;
     30import org.openstreetmap.josm.data.osm.Relation;
    2931import org.openstreetmap.josm.data.osm.Node;
    3032import org.openstreetmap.josm.data.osm.OsmPrimitive;
    31 import org.openstreetmap.josm.data.osm.Segment;
    3233import org.openstreetmap.josm.data.osm.Way;
    3334import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
     
    3536
    3637/**
    37  * Splits a way into multiple ways (all identical except the segments
    38  * belonging to the way).
     38 * Splits a way into multiple ways (all identical except for their node list).
    3939 *
    40  * Various split modes are used depending on what is selected.
    41  *
    42  * 1. One or more NODES (and, optionally, also one way) selected:
    43  *
    44  * (All nodes must be part of the same way. If a way is also selected, that way
    45  * must contain all selected nodes.)
    46  *
    47  * Way is split AT the node(s) into contiguous ways. If the original contained
    48  * one or more parts that were not reachable from any of the nodes, they form an
    49  * extra new way. Examples (numbers are unselected nodes, letters are selected
    50  * nodes)
    51  *
    52  * 1---A---2  becomes  1---A and A---2
    53  *
    54  * 1---A---2---B---3  becomes  1---A and A---2---B and B---3
    55  * 
    56  *     2                   
    57  *     |                   
    58  * 1---A---3  becomes  1---A and 2---A and A---3
    59  *
    60  * 1---A---2  3---4  becomes  1---A and A---2 and 3---4
    61  *
    62  * If the selected node(s) do not clearly define the way that is to be split,
    63  * then the way must be selected for disambiguation (e.g. you have two ways,
    64  * 1---2---3 and 4---2---5, and select node 2, then you must also select the
    65  * way you want to split).
    66  *
    67  * This function will result in at least two ways, unless the selected node is
    68  * at the end of the way AND the way is contiguous, which will lead to an error
    69  * message.
    70  *
    71  * After executing the operation, the selection will be cleared.
    72  *
    73  * 2. One or more SEGMENTS (and, optionally, also one way) selected:
    74  *
    75  * (All segments must be part of the same way)
    76  *
    77  * The way is split in a fashion that makes a new way from the selected segments,
    78  * i.e. the selected segments are removed from the way to form a new one.
    79  *
    80  * This function will result in exactly two ways.
    81  *
    82  * If splitting the segments out of the way makes a non-contiguous part from
    83  * something that was contiguous before, the action is aborted and an error
    84  * message is shown.
    85  *
    86  * 3. Exactly one WAY selected
    87  *
    88  * If the way is contiguous, you will get an error message. If the way is not
    89  * contiguous it is split it into 2...n contiguous ways.
     40 * Ways are just split at the selected nodes.  The nodes remain in their
     41 * original order.  Selected nodes at the end of a way are ignored.
    9042 */
    9143
     
    9446        private Way selectedWay;
    9547        private List<Node> selectedNodes;
    96         private List<Segment> selectedSegments;
    9748
    9849        /**
     
    10152        public SplitWayAction() {
    10253                super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), KeyEvent.VK_P, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
    103                 DataSet.listeners.add(this);
     54                DataSet.selListeners.add(this);
    10455        }
    10556
     
    12172                selectedWay = null;
    12273                selectedNodes = null;
    123                 selectedSegments = null;
    12474
    12575                Visitor splitVisitor = new Visitor(){
     
    12979                                selectedNodes.add(n);
    13080            }
    131                         public void visit(Segment s) {
    132                                 if (selectedSegments == null)
    133                                         selectedSegments = new LinkedList<Segment>();
    134                                 selectedSegments.add(s);
    135             }
    13681                        public void visit(Way w) {
    13782                                selectedWay = w;
    13883            }
     84                        public void visit(Relation e) {
     85                                // enties are not considered
     86                        }
    13987                };
    14088               
     
    14896                        for (Node n : selectedNodes) {
    14997                                for (Way w : Main.ds.ways) {
    150                                         for (Segment s : w.segments) {
    151                                                 if (n.equals(s.from) || n.equals(s.to)) {
     98                                        for (Node wn : w.nodes) {
     99                                                if (n.equals(wn)) {
    152100                                                        Integer old = wayOccurenceCounter.get(w);
    153101                                                        wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
     
    183131
    184132                        HashSet<Node> nds = new HashSet<Node>(selectedNodes);
    185                         for (Segment s : selectedWay.segments) {
    186                                 nds.remove(s.from);
    187                                 nds.remove(s.to);
     133                        for (Node n : selectedWay.nodes) {
     134                                nds.remove(n);
    188135                        }
    189136                        if (!nds.isEmpty()) {
     
    193140                                return;
    194141                        }
    195 
    196                         // If only segments are selected, guess which way to use.
    197                 } else if (selectedWay == null && selectedSegments != null) {
    198 
    199                         HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();
    200                         for (Segment s : selectedSegments) {
    201                                 for (Way w : Main.ds.ways) {
    202                                         if (w.segments.contains(s)) {
    203                                                 Integer old = wayOccurenceCounter.get(w);
    204                                                 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);
    205                                                 break;
    206                                         }
    207                                 }
    208                         }
    209                         if (wayOccurenceCounter.isEmpty()) {
    210                                 JOptionPane.showMessageDialog(Main.parent,
    211                                                 trn("The selected segment is not part of any way.",
    212                                                                 "The selected segments are not part of any way.", selectedSegments.size()));
    213                                 return;
    214                         }
    215 
    216                         for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {
    217                                 if (entry.getValue().equals(selectedSegments.size())) {
    218                                         if (selectedWay != null) {
    219                                                 JOptionPane.showMessageDialog(Main.parent,
    220                                                                 trn("There is more than one way using the segment you selected. Please select the way also.",
    221                                                                                 "There is more than one way using the segments you selected. Please select the way also.", selectedSegments.size()));
    222                                                 return;
    223                                         }
    224                                         selectedWay = entry.getKey();
    225                                 }
    226                         }
    227 
    228                         if (selectedWay == null) {
    229                                 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments do not share the same way."));
    230                                 return;
    231                         }
    232 
    233                         // If a way and segments are selected, verify that the segments are part of the way.
    234                 } else if (selectedWay != null && selectedSegments != null) {
    235 
    236                         if (!selectedWay.segments.containsAll(selectedSegments)) {
    237                                 JOptionPane.showMessageDialog(Main.parent,
    238                                                 trn("The selected way does not contain the selected segment.",
    239                                                                 "The selected way does not contain all the selected segments.", selectedSegments.size()));
    240                                 return;
    241                         }
    242                 }
    243 
    244                 // finally check if the selected way is complete.
    245                 if (selectedWay.isIncomplete()) {
    246                         JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before splitting."));
    247                         return;
    248142                }
    249143
     
    261155        private boolean checkSelection(Collection<? extends OsmPrimitive> selection) {
    262156                boolean way = false;
    263                 boolean segment = false;
    264157                boolean node = false;
    265158                for (OsmPrimitive p : selection) {
    266                         if (p instanceof Way && !way)
     159                        if (p instanceof Way && !way) {
    267160                                way = true;
    268                         else if (p instanceof Node && !segment)
     161                        } else if (p instanceof Node) {
    269162                                node = true;
    270                         else if (p instanceof Segment && !node)
    271                                 segment = true;
    272                         else
     163                        } else {
    273164                                return false;
    274165                }
    275                 return way || segment || node;
     166                }
     167                return node;
    276168        }
    277169
     
    279171         * Split a way into two or more parts, starting at a selected node.
    280172         *
     173         * FIXME: what do the following "arguments" refer to?
    281174         * @param way the way to split
    282175         * @param nodes the node(s) to split the way at; must be part of the way.
    283176         */
    284177        private void splitWay() {
    285 
    286                 // The basic idea is to first divide all segments forming this way into
    287                 // groups, and later form new ways according to the groups. Initally,
    288                 // all segments are copied into allSegments, and then gradually removed
    289                 // from there as new groups are built.
    290 
    291                 LinkedList<Segment> allSegments = new LinkedList<Segment>();
    292                 allSegments.addAll(selectedWay.segments);
    293                 List<List<Segment>> segmentSets = new ArrayList<List<Segment>>();
    294 
    295                 if (selectedNodes != null) {
    296 
    297                         // This is the "split at node" mode.
    298 
    299                         boolean split = true;
    300                         Segment splitSeg = null;
    301                         while (split) {
    302                                 split = false;
    303 
    304                                 // Look for a "split segment". A split segment is any segment
    305                                 // that touches one of the split nodes and has not yet been
    306                                 // assigned to one of the segment groups.
    307                                 for (Segment s : allSegments) {
    308                                         for (Node node : selectedNodes) {
    309                                                 if (s.from.equals(node) || s.to.equals(node)) {
    310                                                         split = true;
    311                                                         splitSeg = s;
    312                                                         break;
    313                                                 }
    314                                         }
    315                                         if (split)
    316                                                 break;
     178                // We take our way's list of nodes and copy them to a way chunk (a
     179                // list of nodes).  Whenever we stumble upon a selected node, we start
     180                // a new way chunk.
     181
     182                Set<Node> nodeSet = new HashSet<Node>(selectedNodes);
     183                List<List<Node>> wayChunks = new LinkedList<List<Node>>();
     184                List<Node> currentWayChunk = new ArrayList<Node>();
     185                wayChunks.add(currentWayChunk);
     186
     187                Iterator<Node> it = selectedWay.nodes.iterator();
     188                while (it.hasNext()) {
     189                        Node currentNode = it.next();
     190                        boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext();
     191                        currentWayChunk.add(currentNode);
     192                        if (nodeSet.contains(currentNode) && !atEndOfWay) {
     193                                currentWayChunk = new ArrayList<Node>();
     194                                currentWayChunk.add(currentNode);
     195                                wayChunks.add(currentWayChunk);
    317196                                }
    318 
    319                                 // If a split segment was found, move this segment and all segments
    320                                 // connected to it into a new segment group, stopping only if we
    321                                 // reach another split node. Segment moving is done recursively by
    322                                 // the moveSegments method.
    323                                 if (split) {
    324                                         LinkedList<Segment> subSegments = new LinkedList<Segment>();
    325                                         moveSegments(allSegments, subSegments, splitSeg, selectedNodes);
    326                                         segmentSets.add(subSegments);
    327                                 }
    328 
    329                                 // The loop continues until no more split segments were found.
    330                                 // Nb. not all segments touching a split node are split segments;
    331                                 // e.g.
    332                                 //
    333                                 //     2       4
    334                                 //     |       |
    335                                 // 1---A---3---C---5
    336                                 //
    337                                 // This way will be split into 5 ways (1---A,2---A,A---3---C,4---C,
    338                                 // C---5). Depending on which is processed first, either A---3 becomes
    339                                 // a split segment and 3---C is moved as a connecting segment, or vice
    340                                 // versa. The result is, of course, the same but this explains why we
    341                                 // cannot simply start a new way for each segment connecting to a split
    342                                 // node.
    343                         }
    344 
    345                 } else if (selectedSegments != null) {
    346 
    347                         // This is the "split segments" mode. It is quite easy as the segments to
    348                         // remove are already explicitly selected, but some restrictions have to
    349                         // be observed to make sure that no non-contiguous parts are created.
    350 
    351                         // first create a "scratch" copy of the full segment list and move all
    352                         // segments connected to the first selected segment into a temporary list.
    353                         LinkedList<Segment> copyOfAllSegments = new LinkedList<Segment>(allSegments);
    354                         LinkedList<Segment> partThatContainsSegments = new LinkedList<Segment>();
    355                         moveSegments(copyOfAllSegments, partThatContainsSegments, selectedSegments.get(0), null);
    356 
    357                         // this list must now contain ALL selected segments; otherwise, segments
    358                         // from unconnected parts of the way have been selected and this is not allowed
    359                         // as it would create a new non-contiguous way.
    360                         if (!partThatContainsSegments.containsAll(selectedSegments)) {
    361                                 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments are not in the same contiguous part of the way."));                               
    362                                 return;         
    363                         }
    364 
    365                         // if the contiguous part that contains the segments becomes non-contiguous
    366                         // after the removal of the segments, that is also an error.
    367                         partThatContainsSegments.removeAll(selectedSegments);
    368                         if (!partThatContainsSegments.isEmpty()) {
    369                                 LinkedList<Segment> contiguousSubpart = new LinkedList<Segment>();
    370                                 moveSegments(partThatContainsSegments, contiguousSubpart, partThatContainsSegments.get(0), null);
    371                                 // if partThatContainsSegments was contiguous before, it will now be empty as all segments
    372                                 // connected to the first segment therein have been moved
    373                                 if (!partThatContainsSegments.isEmpty()) {
    374                                         JOptionPane.showMessageDialog(Main.parent, tr("Removing the selected segments would make a part of the way non-contiguous."));                         
    375                                         return;                         
    376                                 }
    377                         }
    378 
    379                         ArrayList<Segment> subSegments = new ArrayList<Segment>();
    380                         subSegments.addAll(selectedSegments);
    381                         allSegments.removeAll(selectedSegments);
    382                         segmentSets.add(subSegments);
    383 
    384                 } else {
    385 
    386                         // This is the "split way into contiguous parts" mode.
    387                         // We use a similar mechanism to splitting at nodes, but we do not
    388                         // select split segments. Instead, we randomly grab a segment out
    389                         // of the way and move all connecting segments to a new group. If
    390                         // segments remain in the original way, we repeat the procedure.
    391 
    392                         while (!allSegments.isEmpty()) {
    393                                 LinkedList<Segment> subSegments = new LinkedList<Segment>();
    394                                 moveSegments(allSegments, subSegments, allSegments.get(0), null);
    395                                 segmentSets.add(subSegments);
    396                         }                       
    397                 }
    398 
    399                 // We now have a number of segment groups.
    400 
    401                 // If segments remain in allSegments, this means that they were not reachable
    402                 // from any of the split nodes, and they will be made into an extra way.
    403                 if (!allSegments.isEmpty()) {
    404                         segmentSets.add(allSegments);
    405                 }
    406 
    407                 // If we do not have at least two parts, then the way was circular or the node(s)
    408                 // were at one end of the way. User error ;-)
    409                 if (segmentSets.size() < 2) {
    410                         if (selectedNodes != null) {
    411                                 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected node. (Hint: To split circular ways, select two nodes.)"));
    412                         } else {
    413                                 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split because it is contiguous. (Hint: To split at a node, select that node.)"));                             
    414                         }
     197                        }
     198
     199                if (wayChunks.size() < 2) {
     200                        JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)"));
    415201                        return;
    416202                }
    417203
    418                 // sort the list of segment lists according to their number of elements, so that
    419                 // the biggest part of the way comes first. That way, we will "change" the largest
    420                 // part of the way by removing a few segments, and "add" new, smaller ways; looks
    421                 // nicer.
    422                 Collections.sort(segmentSets, new Comparator<Collection<Segment>>() {
    423                         public int compare(Collection<Segment> a, Collection<Segment> b) {
    424                                 if (a.size() < b.size())
    425                                         return 1;
    426                                 if (b.size() < a.size())
    427                                         return -1;
    428                                 return 0;
    429                         }
    430                 });
    431 
    432                 // build a list of commands, and also a list of ways
    433                 Collection<Command> commandList = new ArrayList<Command>(segmentSets.size());
    434                 Collection<Way> newSelection = new ArrayList<Way>(segmentSets.size());
    435                 Iterator<List<Segment>> segsIt = segmentSets.iterator();
     204                // build a list of commands, and also a new selection list
     205                Collection<Command> commandList = new ArrayList<Command>(wayChunks.size());
     206                Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size());
    436207               
    437                 // the first is always a change to the existing way;
     208                Iterator<List<Node>> chunkIt = wayChunks.iterator();
     209               
     210                // First, change the original way
    438211                Way changedWay = new Way(selectedWay);
    439                 changedWay.segments.clear();
    440                 changedWay.segments.addAll(segsIt.next());
     212                changedWay.nodes.clear();
     213                changedWay.nodes.addAll(chunkIt.next());
    441214                commandList.add(new ChangeCommand(selectedWay, changedWay));
    442215                newSelection.add(selectedWay);
    443216
    444                 // and commands 1...n are additions of new ways.
    445                 while (segsIt.hasNext()) {
     217                // Second, create new ways
     218                while (chunkIt.hasNext()) {
    446219                        Way wayToAdd = new Way();
    447220                        if (selectedWay.keys != null)
    448221                                wayToAdd.keys = new HashMap<String, String>(selectedWay.keys);
    449                         wayToAdd.segments.clear();
    450                         wayToAdd.segments.addAll(segsIt.next());
     222                        wayToAdd.nodes.addAll(chunkIt.next());
    451223                        commandList.add(new AddCommand(wayToAdd));
    452224                        newSelection.add(wayToAdd);
     
    455227                NameVisitor v = new NameVisitor();
    456228                v.visit(selectedWay);
    457                 Main.main.undoRedo.add(new SequenceCommand(tr("Split way {0} into {1} parts",v.name, segmentSets.size()), commandList));
     229                Main.main.undoRedo.add(
     230                        new SequenceCommand(tr("Split way {0} into {1} parts",
     231                                v.name, wayChunks.size()),
     232                        commandList));
    458233                Main.ds.setSelected(newSelection);
    459234        }
     
    465240                setEnabled(checkSelection(newSelection));
    466241        }
    467 
    468         /**
    469          * Move contiguous segments from one collection to another. The given segment is moved first, and
    470          * then the procedure is recursively called for all segments that connect to the first segment at
    471          * either end.
    472          *
    473          * @param source the source collection
    474          * @param destination the destination collection
    475          * @param start the first segment to be moved
    476          * @param stopNodes collection of nodes which should be considered end points for moving (may be null).
    477          */
    478         private void moveSegments(Collection<Segment> source, LinkedList<Segment> destination, Segment start, Collection<Node> stopNodes) {
    479                 source.remove(start);
    480                 if (destination.isEmpty() || destination.iterator().next().from.equals(start.to))
    481                         destination.addFirst(start);
    482                 else
    483                         destination.addLast(start);
    484                 Segment moveSeg = start;
    485                 while(moveSeg != null) {
    486                         moveSeg = null;
    487 
    488                         for (Node node : new Node[] { start.from, start.to }) {
    489                                 if (stopNodes != null && stopNodes.contains(node))
    490                                         continue;
    491                                 for (Segment sourceSeg : source) {
    492                                         if (sourceSeg.from.equals(node) || sourceSeg.to.equals(node)) {
    493                                                 moveSeg = sourceSeg;
    494                                                 break;
    495                                         }
    496                                 }
    497                                 if (moveSeg != null)
    498                                         break;
    499                         }
    500                         if (moveSeg != null) {
    501                                 moveSegments(source, destination, moveSeg, stopNodes);
    502                         }
    503                 }
    504         }
    505242}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java

    r4437 r4464  
    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}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/AddSegmentAction.java

    r4437 r4464  
    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 node"),
    5455                                "addsegment",
    55                                 tr("Add a segment between two nodes."),
     56                                tr("Connect two nodes using ways."),
    5657                                KeyEvent.VK_G,
    5758                                mapFrame,
     
    8586                        return;
    8687
    87                 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), true);
    88                 if (clicked == null || !(clicked instanceof Node))
    89                         return;
     88                Node clicked = Main.map.mapView.getNearestNode(e.getPoint());
     89                if (clicked == null) return;
    9090
    9191                drawHint(false);
    92                 first = second = (Node)clicked;
     92                first = second = clicked;
    9393        }
    9494
     
    101101                        return;
    102102
    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;
     103                Node hovered = Main.map.mapView.getNearestNode(e.getPoint());
     104                if (hovered == null || hovered == first) return;
    106105
    107                 drawHint(false);
    108 
    109                 second = (Node)clicked;
     106                second = hovered;
    110107                drawHint(true);
    111108        }
     
    116113        @Override public void mouseReleased(MouseEvent e) {
    117114                if (e.getButton() == MouseEvent.BUTTON1) {
     115                        drawHint(false);
    118116                        makeSegment();
    119                         first = null; // release segment drawing
    120117                }
     118        }
     119
     120        /**
     121         * @return If the node is the end of exactly one way, return this.
     122         *      <code>null</code> otherwise.
     123         */
     124        private Way getWayForNode(Node n) {
     125                Way way = null;
     126                for (Way w : Main.ds.ways) {
     127                        int i = w.nodes.indexOf(n);
     128                        if (i == -1) continue;
     129                        if (i == 0 || i == w.nodes.size() - 1) {
     130                                if (way != null)
     131                                        return null;
     132                                way = w;
     133                        }
     134                }
     135                return way;
    121136        }
    122137
     
    126141         */
    127142        private void makeSegment() {
    128                 if (first == null || second == null) {
     143                Node n1 = first;
     144                Node n2 = second;
    129145                        first = null;
    130146                        second = null;
    131                         return;
     147
     148                if (n1 == null || n2 == null || n1 == n2) return;
     149               
     150                Way w = getWayForNode(n1);
     151                Way wnew;
     152                if (w == null) {
     153                        wnew = new Way();
     154                        wnew.nodes.add(n1);
     155                        wnew.nodes.add(n2);
     156                        Main.main.undoRedo.add(new AddCommand(wnew));
     157                } else {
     158                        wnew = new Way(w);
     159                        if (wnew.nodes.get(wnew.nodes.size() - 1) == n1) {
     160                                wnew.nodes.add(n2);
     161                        } else {
     162                                wnew.nodes.add(0, n2);
     163                        }
     164                        Main.main.undoRedo.add(new ChangeCommand(w, wnew));
    132165                }
    133166
    134                 drawHint(false);
    135                
    136                 Node start = first;
    137                 Node end = second;
    138                 first = second;
    139                 second = null;
    140                
    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));
    149167                        Collection<OsmPrimitive> sel = Main.ds.getSelected();
    150                         sel.add(ls);
     168                sel.add(wnew);
    151169                        Main.ds.setSelected(sel);
    152                 }
    153170
    154171                Main.map.mapView.repaint();
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java

    r4437 r4464  
    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);
     167                }
     168
     169                if (ways.size() > 1)
     170                        return tr("Used by more than one way.");
     171                Way w = ways.get(0);
     172
     173                int i = w.nodes.indexOf(n);
     174                if (w.nodes.lastIndexOf(n) != i)
     175                        return tr("Occurs more than once in the same way.");
     176                if (i == 0 || i == w.nodes.size() - 1)
     177                        return tr("Is at the end of a way");
     178
     179                Way wnew = new Way(w);
     180                wnew.nodes.remove(i);
     181
    207182                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));
    212                 }
    213                 cmds.add(new ChangeCommand(seg1, s));
    214                 cmds.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{n, seg2})));
     183                cmds.add(new ChangeCommand(w, wnew));
     184                cmds.add(new DeleteCommand(Collections.singleton(n)));
    215185                Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds));
    216186                return null;
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r4437 r4464  
    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 *
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/MoveAction.java

    r4437 r4464  
    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))
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java

    r4437 r4464  
    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}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r4437 r4464  
    99import org.openstreetmap.josm.data.osm.Node;
    1010import org.openstreetmap.josm.data.osm.OsmPrimitive;
    11 import org.openstreetmap.josm.data.osm.Segment;
    1211import org.openstreetmap.josm.data.osm.Way;
    1312
     
    112111                        if (osm instanceof Node)
    113112                                return type.equals("node");
    114                         if (osm instanceof Segment)
    115                                 return type.equals("segment");
    116113                        if (osm instanceof Way)
    117114                                return type.equals("way");
     
    137134        private static class Incomplete extends Match {
    138135                @Override public boolean match(OsmPrimitive osm) {
    139                         return osm instanceof Way && ((Way)osm).isIncomplete();
     136                        return false;
    140137                }
    141138                @Override public String toString() {return "incomplete";}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/command/AddCommand.java

    r4437 r4464  
    1212import org.openstreetmap.josm.Main;
    1313import org.openstreetmap.josm.data.osm.DataSet;
     14import org.openstreetmap.josm.data.osm.Relation;
    1415import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1516import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
     
    2223 * A command that adds an osm primitive to a dataset. Keys cannot be added this
    2324 * way. Use ChangeKeyValueCommand instead.
     25 *
     26 * See ChangeCommand for comments on relation back references.
    2427 *
    2528 * @author imi
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/command/ChangeCommand.java

    r4437 r4464  
    1313import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
    1414
     15/**
     16 * Command that basically replaces one OSM primitive by another of the
     17 * same type.
     18 * 
     19 * @author Imi
     20 */
    1521public class ChangeCommand extends Command {
    1622
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/command/Command.java

    r4437 r4464  
    1010import javax.swing.tree.MutableTreeNode;
    1111
     12import org.openstreetmap.josm.data.osm.Relation;
    1213import org.openstreetmap.josm.data.osm.Node;
    1314import org.openstreetmap.josm.data.osm.OsmPrimitive;
    14 import org.openstreetmap.josm.data.osm.Segment;
    1515import org.openstreetmap.josm.data.osm.Way;
    1616import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    3737                        orig.put(n, new Node(n));
    3838                }
    39                 public void visit(Segment s) {
    40                         orig.put(s, new Segment(s));
    41                 }
    4239                public void visit(Way w) {
    4340                        orig.put(w, new Way(w));
     41                }
     42                public void visit(Relation e) {
     43                        orig.put(e, new Relation(e));
    4444                }
    4545        }
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/command/DeleteCommand.java

    r4437 r4464  
    1111import javax.swing.tree.MutableTreeNode;
    1212
     13import org.openstreetmap.josm.data.osm.Relation;
    1314import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1415import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
     
    3233        @Override public void executeCommand() {
    3334                super.executeCommand();
    34                 for (OsmPrimitive osm : data)
     35                for (OsmPrimitive osm : data) {
    3536                        osm.delete(true);
     37                }
    3638        }
    37 
     39       
    3840        @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    3941                deleted.addAll(data);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/Preferences.java

    r4437 r4464  
    5454
    5555        /**
     56         * Override some values on read. This is intended to be used for technology previews
     57         * where we want to temporarily modify things without changing the user's preferences
     58         * file.
     59         */
     60        protected static final SortedMap<String, String> override = new TreeMap<String, String>();
     61        static {
     62                override.put("osm-server.version", "0.5");
     63                override.put("osm-server.additional-versions", "");
     64                override.put("osm-server.url", "http://openstreetmap.gryph.de/api");
     65                override.put("osm-server.username", "fred@remote.org");
     66                override.put("osm-server.password", "fredfred");
     67                override.put("plugins", null);
     68        }
     69
     70        /**
    5671         * Return the location of the user defined preferences file
    5772         */
     
    6378
    6479        /**
    65          * @return A list of all existing directories, where ressources could be stored.
     80         * @return A list of all existing directories, where resources could be stored.
    6681         */
    6782        public Collection<String> getAllPossiblePreferenceDirs() {
     
    93108
    94109        synchronized public boolean hasKey(final String key) {
    95                 return properties.containsKey(key);
     110                return override.containsKey(key) ? override.get(key) != null : properties.containsKey(key);
    96111        }
    97112        synchronized public String get(final String key) {
     113                if (override.containsKey(key))
     114                        return override.get(key);
    98115                if (!properties.containsKey(key))
    99116                        return "";
     
    101118        }
    102119        synchronized public String get(final String key, final String def) {
     120                if (override.containsKey(key))
     121                        return override.get(key);
    103122                final String prop = properties.get(key);
    104123                if (prop == null || prop.equals(""))
     
    111130                        if (e.getKey().startsWith(prefix))
    112131                                all.put(e.getKey(), e.getValue());
     132                for (final Entry<String,String> e : override.entrySet())
     133                        if (e.getKey().startsWith(prefix))
     134                                if (e.getValue() == null)
     135                                        all.remove(e.getKey());
     136                                else
     137                                        all.put(e.getKey(), e.getValue());
    113138                return all;
    114139        }
     
    117142        }
    118143        synchronized public boolean getBoolean(final String key, final boolean def) {
     144                if (override.containsKey(key))
     145                        return override.get(key) == null ? def : Boolean.parseBoolean(override.get(key));
    119146                return properties.containsKey(key) ? Boolean.parseBoolean(properties.get(key)) : def;
    120147        }
     
    148175                try {
    149176                        final PrintWriter out = new PrintWriter(new FileWriter(getPreferencesDir() + "preferences"), false);
    150                         for (final Entry<String, String> e : properties.entrySet())
     177                        for (final Entry<String, String> e : properties.entrySet()) {
    151178                                if (!e.getValue().equals(""))
    152179                                        out.println(e.getKey() + "=" + e.getValue());
     180                        }
    153181                        out.close();
    154182                } catch (final IOException e) {
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/ServerSidePreferences.java

    r4437 r4464  
    4545                public String download() {
    4646                        try {
    47                                 System.out.println("reading preferenced from "+serverUrl);
     47                                System.out.println("reading preferences from "+serverUrl);
    4848                                HttpURLConnection con = (HttpURLConnection)serverUrl.openConnection();
    4949                                addAuth(con);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/DataSet.java

    r4437 r4464  
    3131
    3232        /**
    33          * All segments goes here, even when they are in a way.
     33         * All ways (Streets etc.) in the DataSet.
     34         *
     35         * The way nodes are stored only in the way list.
    3436         */
    35         public Collection<Segment> segments = new LinkedList<Segment>();
     37        public Collection<Way> ways = new LinkedList<Way>();
    3638
    3739        /**
    38          * All ways (Streets etc.) in the DataSet.
    39          *
    40          * The nodes of the way segments of this way must be objects from
    41          * the nodes list, however the way segments are stored only in the
    42          * way list.
     40         * All relations/relationships
    4341         */
    44         public Collection<Way> ways = new LinkedList<Way>();
     42        public Collection<Relation> relations = new LinkedList<Relation>();
    4543
    4644        /**
     
    5553         * selection does only change in the active layer)
    5654         */
    57         public static Collection<SelectionChangedListener> listeners = new LinkedList<SelectionChangedListener>();
     55        public static Collection<SelectionChangedListener> selListeners = new LinkedList<SelectionChangedListener>();
    5856
    5957        /**
    6058         * @return A collection containing all primitives of the dataset. The
    61          * data is ordered after: first comes nodes, then segments, then ways.
     59         * data is ordered after: first come nodes, then ways, then relations.
    6260         * Ordering in between the categories is not guaranteed.
    6361         */
     
    6563                List<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
    6664                o.addAll(nodes);
    67                 o.addAll(segments);
    6865                o.addAll(ways);
     66                o.addAll(relations);
    6967                return o;
    7068        }
     
    8886        public void clearSelection() {
    8987                clearSelection(nodes);
    90                 clearSelection(segments);
    9188                clearSelection(ways);
     89                clearSelection(relations);
    9290                Collection<OsmPrimitive> sel = Collections.emptyList();
    9391                fireSelectionChanged(sel);
     
    10098        public Collection<OsmPrimitive> getSelected() {
    10199                Collection<OsmPrimitive> sel = getSelected(nodes);
    102                 sel.addAll(getSelected(segments));
    103100                sel.addAll(getSelected(ways));
     101                sel.addAll(getSelected(relations));
    104102                return sel;
    105103        }
     
    107105        public void setSelected(Collection<? extends OsmPrimitive> selection) {
    108106                clearSelection(nodes);
    109                 clearSelection(segments);
    110107                clearSelection(ways);
     108                clearSelection(relations);
    111109                for (OsmPrimitive osm : selection)
    112110                        osm.selected = true;
     
    120118                }
    121119                clearSelection(nodes);
    122                 clearSelection(segments);
    123120                clearSelection(ways);
     121                clearSelection(relations);
    124122                for (OsmPrimitive o : osm)
    125123                        if (o != null)
     
    158156         */
    159157        public static void fireSelectionChanged(Collection<? extends OsmPrimitive> sel) {
    160                 for (SelectionChangedListener l : listeners)
     158                for (SelectionChangedListener l : selListeners)
    161159                        l.selectionChanged(sel);
    162160        }
    163 
     161       
    164162        @Override public DataSet clone() {
    165163                DataSet ds = new DataSet();
    166164                for (Node n : nodes)
    167165                        ds.nodes.add(new Node(n));
    168                 for (Segment s : segments)
    169                         ds.segments.add(new Segment(s));
    170166                for (Way w : ways)
    171167                        ds.ways.add(new Way(w));
     168                for (Relation e : relations)
     169                        ds.relations.add(new Relation(e));
    172170                for (DataSource source : dataSources)
    173171                        ds.dataSources.add(new DataSource(source.bounds, source.origin));
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/Node.java

    r4437 r4464  
    1818        public volatile EastNorth eastNorth;
    1919
     20        /**
     21         * Create an incomplete Node object
     22         */
     23        public Node(long id) {
     24                this.id = id;
     25                incomplete = true;
     26        }
     27       
    2028        /**
    2129         * Create an identical clone of the argument (including the id)
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r4437 r4464  
    33
    44import java.text.SimpleDateFormat;
     5import java.util.ArrayList;
    56import java.util.Collection;
    67import java.util.Collections;
     
    9091
    9192        /**
     93         * If set to true, this object is incomplete, which means only the id
     94         * and type is known (type is the objects instance class)
     95         */
     96        public boolean incomplete = false;
     97
     98        /**
    9299         * Implementation of the visitor scheme. Subclases have to call the correct
    93100         * visitor function.
     
    125132                Visitor v = new Visitor(){
    126133                        public void visit(Node n) { ret[0] = 1; }
    127                         public void visit(Segment s) { ret[0] = 2; }
    128                         public void visit(Way w) { ret[0] = 3; }
     134                        public void visit(Way w) { ret[0] = 2; }
     135                        public void visit(Relation e) { ret[0] = 3; }
    129136                };
    130137                visit(v);
    131                 return id == 0 ? super.hashCode() : (int)(id<<3)+ret[0];
     138                return id == 0 ? super.hashCode() : (int)(id<<2)+ret[0];
    132139        }
    133140
     
    205212                return timestamp == null ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
    206213        }
     214       
     215       
    207216}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/Way.java

    r4437 r4464  
    99
    1010/**
    11  * One full way, consisting of several way segments chained together.
     11 * One full way, consisting of a list of way nodes.
    1212 *
    1313 * @author imi
     
    1616
    1717        /**
    18          * All way segments in this way
     18         * All way nodes in this way
    1919         */
    20         public final List<Segment> segments = new ArrayList<Segment>();
     20        public final List<Node> nodes = new ArrayList<Node>();
    2121
    2222        @Override public void visit(Visitor visitor) {
     
    3131        }
    3232       
     33        /**
     34         * Create an empty way without id. Use this only if you set meaningful
     35         * values yourself.
     36         */
    3337        public Way() {
     38        }
     39       
     40        /**
     41         * Create an incomplete Way.
     42         */
     43        public Way(long id) {
     44                this.id = id;
     45                incomplete = true;
    3446        }
    3547       
    3648        @Override public void cloneFrom(OsmPrimitive osm) {
    3749                super.cloneFrom(osm);
    38                 segments.clear();
    39                 segments.addAll(((Way)osm).segments);
     50                nodes.clear();
     51                nodes.addAll(((Way)osm).nodes);
    4052        }
    4153
    4254    @Override public String toString() {
    43         return "{Way id="+id+" segments="+Arrays.toString(segments.toArray())+"}";
     55        return "{Way id="+id+" nodes="+Arrays.toString(nodes.toArray())+"}";
    4456    }
    4557
    4658        @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) {
    47                 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && segments.equals(((Way)osm).segments) : false;
     59                return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false;
    4860    }
    4961
     
    5264    }
    5365       
     66        @Deprecated
    5467        public boolean isIncomplete() {
    55                 for (Segment s : segments)
    56                         if (s.incomplete)
    57                                 return true;
    5868                return false;
    5969        }
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/AddVisitor.java

    r4437 r4464  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    2 /**
    3  */
    42package org.openstreetmap.josm.data.osm.visitor;
    53
    64import org.openstreetmap.josm.data.osm.DataSet;
    7 import org.openstreetmap.josm.data.osm.Segment;
     5import org.openstreetmap.josm.data.osm.Relation;
    86import org.openstreetmap.josm.data.osm.Node;
    97import org.openstreetmap.josm.data.osm.Way;
     
    2725                ds.nodes.add(n);
    2826        }
    29         public void visit(Segment s) {
    30                 ds.segments.add(s);
    31         }
    3227        public void visit(Way w) {
    3328                ds.ways.add(w);
    3429        }
     30        public void visit(Relation e) {
     31                ds.relations.add(e);
     32        }
    3533}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/AllNodesVisitor.java

    r4437 r4464  
    55import java.util.HashSet;
    66
    7 import org.openstreetmap.josm.data.osm.Segment;
     7import org.openstreetmap.josm.data.osm.Relation;
     8import org.openstreetmap.josm.data.osm.RelationMember;
    89import org.openstreetmap.josm.data.osm.Node;
    910import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    3031
    3132        /**
    32          * Line segments have exactly two nodes: from and to.
     33         * Ways have their way nodes.
    3334         */
    34         public void visit(Segment ls) {
    35                 if (!ls.incomplete) {
    36                         visit(ls.from);
    37                         visit(ls.to);
    38                 }
     35        public void visit(Way w) {
     36                for (Node n : w.nodes)
     37                        visit(n);
    3938        }
    4039
    4140        /**
    42          * Ways have all nodes from their segments.
     41         * Relations may have any number of nodes.
     42         * FIXME: do we want to collect nodes from segs/ways that are relation members?
     43         * if so, use AutomatchVisitor!
    4344         */
    44         public void visit(Way w) {
    45                 for (Segment ls : w.segments)
    46                         visit(ls);
     45        public void visit(Relation e) {
     46                for (RelationMember m : e.members)
     47                        if (m.member instanceof Node) visit((Node)m.member);
    4748        }
    48 
    4949        /**
    5050         * @return All nodes the given primitive has.
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java

    r4437 r4464  
    55import org.openstreetmap.josm.data.Bounds;
    66import org.openstreetmap.josm.data.coor.EastNorth;
    7 import org.openstreetmap.josm.data.osm.Segment;
     7import org.openstreetmap.josm.data.osm.Relation;
    88import org.openstreetmap.josm.data.osm.Node;
    99import org.openstreetmap.josm.data.osm.Way;
     
    2222        }
    2323
    24         public void visit(Segment ls) {
    25                 if (!ls.incomplete) {
    26                         visit(ls.from);
    27                         visit(ls.to);
    28                 }
     24        public void visit(Way w) {
     25                for (Node n : w.nodes)
     26                        visit(n);
    2927        }
    3028
    31         public void visit(Way w) {
    32                 for (Segment ls : w.segments)
    33                         visit(ls);
     29        public void visit(Relation e) {
     30                // relations have no bounding box.
    3431        }
    3532
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java

    r4437 r4464  
    66
    77import org.openstreetmap.josm.data.osm.DataSet;
    8 import org.openstreetmap.josm.data.osm.Segment;
     8import org.openstreetmap.josm.data.osm.Relation;
     9import org.openstreetmap.josm.data.osm.RelationMember;
    910import org.openstreetmap.josm.data.osm.Node;
    1011import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    1213
    1314/**
    14  * Helper that collect all segments a node is part of, all ways
    15  * a node or segment is part of and all areas a node is part of.
     15 * Helper that collect all ways a node is part of.
    1616 *
    1717 * Deleted objects are not collected.
     
    4141                        if (w.deleted)
    4242                                continue;
    43                         for (Segment ls : w.segments) {
    44                                 if (ls.incomplete)
    45                                         continue;
    46                                 if (ls.from == n || ls.to == n) {
     43                        for (Node n2 : w.nodes) {
     44                                if (n == n2) {
    4745                                        data.add(w);
     46                                }
     47                        }
     48                }
     49                checkRelationMembership(n);
     50        }
     51       
     52        public void visit(Way w) {
     53                checkRelationMembership(w);
     54        }
     55       
     56        public void visit(Relation r) {
     57                checkRelationMembership(r);
     58        }
     59       
     60        private void checkRelationMembership(OsmPrimitive p) {
     61                // FIXME - this might be a candidate for optimisation
     62                // if OSM primitives are made to hold a list of back
     63                // references.
     64                for (Relation r : ds.relations) {
     65                        for (RelationMember m : r.members) {
     66                                if (m.member == p) {
     67                                        data.add(r);
     68                                        // move up the tree (there might be relations
     69                                        // referring to this relation)
     70                                        checkRelationMembership(r);
    4871                                        break;
    4972                                }
    5073                        }
    5174                }
    52                 for (Segment ls : ds.segments) {
    53                         if (ls.deleted || ls.incomplete)
    54                                 continue;
    55                         if (ls.from == n || ls.to == n)
    56                                 data.add(ls);
    57                 }
    5875        }
    59         public void visit(Segment ls) {
    60                 for (Way w : ds.ways) {
    61                         if (w.deleted)
    62                                 continue;
    63                         if (w.segments.contains(ls))
    64                                 data.add(w);
    65                 }
    66         }
    67         public void visit(Way w) {}
    6876}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/DeleteVisitor.java

    r4437 r4464  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    2 /**
    3  */
    42package org.openstreetmap.josm.data.osm.visitor;
    53
    64import org.openstreetmap.josm.data.osm.DataSet;
    7 import org.openstreetmap.josm.data.osm.Segment;
     5import org.openstreetmap.josm.data.osm.Relation;
    86import org.openstreetmap.josm.data.osm.Node;
    97import org.openstreetmap.josm.data.osm.Way;
     
    2725                ds.nodes.remove(n);
    2826        }
    29         public void visit(Segment ls) {
    30                 ds.segments.remove(ls);
    31         }
    3227        public void visit(Way w) {
    3328                ds.ways.remove(w);
    3429        }
     30        public void visit(Relation e) {
     31                ds.relations.remove(e);
     32        }
    3533}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java

    r4437 r4464  
    1010
    1111import org.openstreetmap.josm.data.osm.DataSet;
     12import org.openstreetmap.josm.data.osm.Relation;
     13import org.openstreetmap.josm.data.osm.RelationMember;
    1214import org.openstreetmap.josm.data.osm.Node;
    1315import org.openstreetmap.josm.data.osm.OsmPrimitive;
    14 import org.openstreetmap.josm.data.osm.Segment;
    1516import org.openstreetmap.josm.data.osm.Way;
    1617
     
    2526        /**
    2627         * Map from primitives in the database to visited primitives. (Attention: The other way
    27          * round than mergedNodes and mergedSegments)
     28         * round than mergedNodes)
    2829         */
    2930        public Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
     
    3839         */
    3940        private final Map<Node, Node> mergedNodes = new HashMap<Node, Node>();
    40         /**
    41          * A list of all segments that got replaced with others.
    42          * Key is the segment in the other's dataset and the value is the one that is now
    43          * in ds.segments.
    44          */
    45         private final Map<Segment, Segment> mergedSegments = new HashMap<Segment, Segment>();
    4641
    4742        public MergeVisitor(DataSet ds, DataSet mergeds) {
     
    8176
    8277        /**
    83          * Merge the segment if id matches or if both nodes are the same (and the
    84          * id is zero of either segment). Nodes are the "same" when they @see match
    85          */
    86         public void visit(Segment other) {
    87                 if (mergeAfterId(mergedSegments, ds.segments, other))
    88                         return;
    89 
    90                 Segment my = null;
    91                 for (Segment ls : ds.segments) {
    92                         if (match(other, ls) && ((mergeds == null) || (!mergeds.segments.contains(ls)))) {
    93                                 my = ls;
    94                                 break;
    95                         }
    96                 }
    97                
    98                 if (my == null)
    99                         ds.segments.add(other);
    100                 else if (my.incomplete && !other.incomplete) {
    101                         mergedSegments.put(other, my);
    102                         my.cloneFrom(other);
    103                 } else if (!other.incomplete) {
    104                         mergedSegments.put(other, my);
    105                         mergeCommon(my, other);
    106                         if (my.modified && !other.modified)
    107                                 return;
    108                         if (!match(my.from, other.from)) {
    109                                 my.from = other.from;
    110                                 my.modified = other.modified;
    111                         }
    112                         if (!match(my.to, other.to)) {
    113                                 my.to = other.to;
    114                                 my.modified = other.modified;
    115                         }
    116                 }
    117         }
    118 
     78         * Simply calls cloneFrom() for now.
     79         * Might be useful to keep around to facilitate merge with the relations
     80         * branch.
     81         */
    11982        private <T extends OsmPrimitive> void cloneFromExceptIncomplete(T myOsm, T otherOsm) {
    120                 if (!(myOsm instanceof Way))
    121                         myOsm.cloneFrom(otherOsm);
    122                 else {
    123                         Way my = (Way)myOsm;
    124                         Way other = (Way)otherOsm;
    125                         HashMap<Long, Segment> copy = new HashMap<Long, Segment>();
    126                         for (Segment s : my.segments)
    127                                 copy.put(s.id, s);
    128                         my.cloneFrom(other);
    129                         my.segments.clear();
    130                         for (Segment s : other.segments) {
    131                                 Segment myS = copy.get(s.id);
    132                                 if (s.incomplete && myS != null && !myS.incomplete) {
    133                                         mergedSegments.put(s, myS);
    134                                         my.segments.add(myS);
    135                                 } else
    136                                         my.segments.add(s);
    137                         }
    138                 }
     83                myOsm.cloneFrom(otherOsm);
    13984    }
    14085
    14186        /**
    142          * Merge the way if id matches or if all segments matches and the
     87         * Merge the way if id matches or if all nodes match and the
    14388         * id is zero of either way.
    14489         */
     
    155100                }
    156101                if (my == null) {
    157                         // Add the way and replace any incomplete segments that we already have
    158102                        ds.ways.add(other);
    159                         for (Segment s : other.segments) {
    160                                 if (s.incomplete) {
     103                } else {
     104                        mergeCommon(my, other);
     105                        if (my.modified && !other.modified)
     106                                return;
     107                        boolean same = true;
     108                        Iterator<Node> it = other.nodes.iterator();
     109                        for (Node n : my.nodes) {
     110                                if (!match(n, it.next()))
     111                                        same = false;
     112                        }
     113                        if (!same) {
     114                                my.nodes.clear();
     115                                my.nodes.addAll(other.nodes);
     116                                my.modified = other.modified;
     117                        }
     118                }
     119        }
     120
     121        /**
     122         * Merge the relation if id matches or if all members match and the
     123         * id of either relation is zero.
     124         */
     125        public void visit(Relation other) {
     126                if (mergeAfterId(null, ds.relations, other))
     127                        return;
     128
     129                Relation my = null;
     130                for (Relation e : ds.relations) {
     131                        if (match(other, e) && ((mergeds == null) || (!mergeds.relations.contains(e)))) {
     132                                my = e;
     133                                break;
     134                        }
     135                }
     136               
     137                if (my == null) {
     138                        // Add the relation and replace any incomplete segments that we already have
     139                        ds.relations.add(other);
     140                        // FIXME unclear!
     141                        /*
     142                        for (RelationMember em : other.getMembers()) {
     143                                if (em.member.incomplete) {
    161144                                        for (Segment ourSegment : ds.segments) {
    162145                                                if (ourSegment.id == s.id) {
     
    166149                                        }
    167150                                }
    168                         }
     151                        }*/
    169152                } else {
    170153                        mergeCommon(my, other);
     
    172155                                return;
    173156                        boolean same = true;
    174                         Iterator<Segment> it = other.segments.iterator();
    175                         for (Segment ls : my.segments) {
    176                                 if (!match(ls, it.next()))
     157                        if (other.members.size() != my.members.size()) {
    177158                                        same = false;
    178                         }
     159                        } else {
     160                                for (RelationMember em : my.members) {
     161                                        if (!other.members.contains(em)) {
     162                                                same = false;
     163                                                break;
     164                                        }
     165                                }
     166                        }
     167                        // FIXME Unclear
     168                        /*
    179169                        if (!same) {
    180170                                HashMap<Long, Segment> copy = new HashMap<Long, Segment>();
     
    192182                                my.modified = other.modified;
    193183                        }
     184                        */
    194185                }
    195186        }
     
    200191         */
    201192        public void fixReferences() {
    202                 for (Segment s : ds.segments)
    203                         fixSegment(s);
    204                 for (OsmPrimitive osm : conflicts.values())
    205                         if (osm instanceof Segment)
    206                                 fixSegment((Segment)osm);
    207193                for (Way w : ds.ways)
    208194                        fixWay(w);
     
    214200        private void fixWay(Way w) {
    215201            boolean replacedSomething = false;
    216             LinkedList<Segment> newSegments = new LinkedList<Segment>();
    217             for (Segment ls : w.segments) {
    218                 Segment otherLs = mergedSegments.get(ls);
    219                 newSegments.add(otherLs == null ? ls : otherLs);
    220                 if (otherLs != null)
     202            LinkedList<Node> newNodes = new LinkedList<Node>();
     203            for (Node n : w.nodes) {
     204                Node otherN = mergedNodes.get(n);
     205                newNodes.add(otherN == null ? n : otherN);
     206                if (otherN != null)
    221207                        replacedSomething = true;
    222208            }
    223209            if (replacedSomething) {
    224                 w.segments.clear();
    225                 w.segments.addAll(newSegments);
    226             }
    227             for (Segment ls : w.segments)
    228                 fixSegment(ls);
     210                w.nodes.clear();
     211                w.nodes.addAll(newNodes);
    229212    }
    230 
    231         private void fixSegment(Segment ls) {
    232                
    233             if (mergedNodes.containsKey(ls.from))
    234                 ls.from = mergedNodes.get(ls.from);
    235            
    236             if (mergedNodes.containsKey(ls.to)) 
    237                 ls.to = mergedNodes.get(ls.to);
    238            
    239213    }
    240214
    241215        /**
    242          * @return Whether the nodes matches (in sense of "be mergable").
     216         * @return Whether the nodes match (in sense of "be mergable").
    243217         */
    244218        private boolean match(Node n1, Node n2) {
     
    249223
    250224        /**
    251          * @return Whether the segments matches (in sense of "be mergable").
    252          */
    253         private boolean match(Segment ls1, Segment ls2) {
    254                 if (ls1.id == ls2.id && ls1.id != 0)
    255                         return true;
    256                 //if (ls1.id != 0 && ls2.id != 0)
    257                 //      return false;
    258                 if (ls1.incomplete || ls2.incomplete)
    259                         return false;
    260                 return match(ls1.from, ls2.from) && match(ls1.to, ls2.to);
    261         }
    262 
    263         /**
    264          * @return Whether the ways matches (in sense of "be mergable").
     225         * @return Whether the ways match (in sense of "be mergable").
    265226         */
    266227        private boolean match(Way w1, Way w2) {
    267228                if (w1.id == 0 || w2.id == 0) {
    268                         if (w1.segments.size() != w2.segments.size())
    269                                 return false;
    270                         Iterator<Segment> it = w1.segments.iterator();
    271                         for (Segment ls : w2.segments)
    272                                 if (!match(ls, it.next()))
     229                        if (w1.nodes.size() != w2.nodes.size())
     230                        return false;
     231                        Iterator<Node> it = w1.nodes.iterator();
     232                        for (Node n : w2.nodes)
     233                                if (!match(n, it.next()))
    273234                                        return false;
    274235                        return true;
     
    276237                return w1.id == w2.id;
    277238        }
     239        /**
     240         * @return Whether the relations match (in sense of "be mergable").
     241         */
     242        private boolean match(Relation w1, Relation w2) {
     243                // FIXME this is not perfect yet...
     244                if (w1.id == 0 || w2.id == 0) {
     245                        if (w1.members.size() != w2.members.size())
     246                                return false;
     247                        for (RelationMember em : w1.members) {
     248                                if (!w2.members.contains(em)) {
     249                                        return false;
     250                                }
     251                        }
     252                        return true;
     253                }
     254                return w1.id == w2.id;
     255        }
     256
    278257
    279258        /**
     
    327306                        }
    328307                        if (my.id == other.id && my.id != 0) {
    329                                 if (my instanceof Segment && ((Segment)my).incomplete)
    330                                         return false; // merge always over an incomplete
    331308                                if (my.modified && other.modified) {
    332309                                        conflicts.put(my, other);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/NameVisitor.java

    r4437 r4464  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    2 
    32package org.openstreetmap.josm.data.osm.visitor;
    43
     
    1312
    1413import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.data.osm.Relation;
    1515import org.openstreetmap.josm.data.osm.Node;
    1616import org.openstreetmap.josm.data.osm.OsmPrimitive;
    17 import org.openstreetmap.josm.data.osm.Segment;
    1817import org.openstreetmap.josm.data.osm.Way;
    1918import org.openstreetmap.josm.tools.ImageProvider;
     
    4140       
    4241        /**
    43          * If the segment has a key named "name", its value is displayed.
    44          * Otherwise, if it has "id", this is used. If none of these available,
    45          * "(x1,y1) -> (x2,y2)" is displayed with the nodes coordinates.
    46          */
    47         public void visit(Segment ls) {
    48                 name = ls.get("name");
    49                 if (name == null) {
    50                         if (ls.incomplete)
    51                                 name = ls.id == 0 ? tr("new") : ls.id+" ("+tr("unknown")+")";
    52                         else
    53                                 name = (ls.id==0?"":ls.id+" ")+"("+ls.from.coor.lat()+","+ls.from.coor.lon()+") -> ("+ls.to.coor.lat()+","+ls.to.coor.lon()+")";
    54                 }
    55                 addId(ls);
    56                 icon = ImageProvider.get("data", "segment");
    57                 trn("segment", "segments", 0); // no marktrn available
    58                 className = "segment";
    59         }
    60 
    61         /**
    6242         * If the node has a name-key or id-key, this is displayed. If not, (lat,lon)
    6343         * is displayed.
     
    8161                if (name == null) name = w.get("ref");
    8262                if (name == null) {
    83                         AllNodesVisitor.getAllNodes(w.segments);
    84                         Set<Node> nodes = new HashSet<Node>();
    85                         for (Segment ls : w.segments) {
    86                                 if (!ls.incomplete) {
    87                                         nodes.add(ls.from);
    88                                         nodes.add(ls.to);
    89                                 }
    90                         }
    9163                        String what = (w.get("highway") != null) ? "highway " : (w.get("railway") != null) ? "railway " : (w.get("waterway") != null) ? "waterway " : "";
    92                         name = what + trn("{0} node", "{0} nodes", nodes.size(), nodes.size());
     64                        name = what + trn("{0} node", "{0} nodes", w.nodes.size(), w.nodes.size());
    9365                }
    94                 if (w.isIncomplete())
    95                         name += " ("+tr("incomplete")+")";
    9666                addId(w);
    9767                icon = ImageProvider.get("data", "way");
    9868                trn("way", "ways", 0); // no marktrn available
    9969                className = "way";
     70        }
     71       
     72        /**
     73         */
     74        public void visit(Relation e) {
     75                name = e.get("type");
     76                // FIXME add names of members
     77                if (name == null)
     78                        name = "relation";
     79                addId(e);
     80                icon = ImageProvider.get("data", "relation");
     81                trn("relation", "relations", 0); // no marktrn available
     82                className = "relation";
    10083        }
    10184       
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java

    r4437 r4464  
    44import java.awt.Color;
    55import java.awt.Graphics;
    6 import java.awt.Graphics2D;
    76import java.awt.Point;
    8 import java.awt.Polygon;
    97import java.awt.Rectangle;
    10 import java.awt.geom.GeneralPath;
    118import java.awt.geom.Line2D;
    129
    1310import org.openstreetmap.josm.Main;
    1411import org.openstreetmap.josm.data.osm.DataSet;
     12import org.openstreetmap.josm.data.osm.Relation;
    1513import org.openstreetmap.josm.data.osm.Node;
    1614import org.openstreetmap.josm.data.osm.OsmPrimitive;
    17 import org.openstreetmap.josm.data.osm.Segment;
    1815import org.openstreetmap.josm.data.osm.Way;
    1916import org.openstreetmap.josm.gui.NavigatableComponent;
     
    3128        public final static Color darkblue = new Color(0,0,128);
    3229        public final static Color darkgreen = new Color(0,128,0);
    33        
     30
    3431        /**
    3532         * The environment to paint to.
     
    4239       
    4340        public boolean inactive;
    44        
     41
    4542        protected static final double PHI = Math.toRadians(20);
    4643
    47         /**
    48          * Preferences
    49          */
    50         protected Color inactiveColor;
    51         protected Color selectedColor;
    52         protected Color nodeColor;
    53         protected Color segmentColor;
    54         protected Color dfltWayColor;
    55         protected Color incompleteColor;
    56         protected Color backgroundColor;
    57         protected boolean showDirectionArrow;
    58         protected boolean showOrderNumber;
    59        
    60         /**
    61          * Draw subsequent segments of same color as one Path
    62          */
    63         protected Color currentColor = null;
    64         protected GeneralPath currrentPath = new GeneralPath();
    65        
    6644        public void visitAll(DataSet data) {
    67                 inactiveColor = getPreferencesColor("inactive", Color.DARK_GRAY);
    68                 selectedColor = getPreferencesColor("selected", Color.WHITE);
    69                 nodeColor = getPreferencesColor("node", Color.RED);
    70                 segmentColor = getPreferencesColor("segment", darkgreen);
    71                 dfltWayColor = getPreferencesColor("way", darkblue);
    72                 incompleteColor = getPreferencesColor("incomplete way", darkerblue);
    73                 backgroundColor = getPreferencesColor("background", Color.BLACK);
    74                 showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
    75                 showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
    76                
    77                 for (final OsmPrimitive osm : data.segments)
    78                         if (!osm.deleted && !osm.selected)
    79                                 osm.visit(this);
    8045                for (final OsmPrimitive osm : data.ways)
    8146                        if (!osm.deleted && !osm.selected)
    8247                                osm.visit(this);
    83                 displaySegments(null);  // Flush segment cache before nodes
    8448                for (final OsmPrimitive osm : data.nodes)
    8549                        if (!osm.deleted && !osm.selected)
     
    8852                        if (!osm.deleted)
    8953                                osm.visit(this);
    90                 displaySegments(null);
    9154        }
    9255
     
    10063                Color color = null;
    10164                if (inactive)
    102                         color = inactiveColor;
     65                        color = getPreferencesColor("inactive", Color.DARK_GRAY);
    10366                else if (n.selected)
    104                         color = selectedColor;
     67                        color = getPreferencesColor("selected", Color.WHITE);
    10568                else
    106                         color = nodeColor;
     69                        color = getPreferencesColor("node", Color.RED);
    10770                drawNode(n, color);
    108         }
    109 
    110         /**
    111          * Draw just a line between the points.
    112          * White if selected (as always) or green otherwise.
    113          */
    114         public void visit(Segment ls) {
    115                 Color color;
    116                 if (inactive)
    117                         color = inactiveColor;
    118                 else if (ls.selected)
    119                         color = selectedColor;
    120                 else
    121                         color = segmentColor;
    122                 drawSegment(ls, color, showDirectionArrow);
    12371        }
    12472
     
    13078                Color wayColor;
    13179                if (inactive)
    132                         wayColor = inactiveColor;
     80                        wayColor = getPreferencesColor("inactive", Color.DARK_GRAY);
    13381                else {
    134                         wayColor = dfltWayColor;
    135                         for (Segment ls : w.segments) {
    136                                 if (ls.incomplete) {
    137                                         wayColor = incompleteColor;
    138                                         break;
    139                                 }
    140                         }
     82                        wayColor = getPreferencesColor("way", darkblue);
    14183                }
    14284
     85                boolean showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
     86                boolean showOrderNumber = Main.pref.getBoolean("draw.segment.order_number");
    14387                int orderNumber = 0;
    144                 for (Segment ls : w.segments) {
     88                Node lastN = null;
     89                for (Node n : w.nodes) {
     90                        if (lastN == null) {
     91                                lastN = n;
     92                                continue;
     93                        }
    14594                        orderNumber++;
    146                         if (!ls.selected) // selected already in good color
    147                                 drawSegment(ls, w.selected && !inactive ? selectedColor : wayColor, showDirectionArrow);
    148                         if (!ls.incomplete && showOrderNumber)
    149                                 drawOrderNumber(ls, orderNumber);
     95                        drawSegment(lastN, n, w.selected && !inactive ? getPreferencesColor("selected", Color.WHITE) : wayColor, showDirectionArrow);
     96                        if (showOrderNumber)
     97                                drawOrderNumber(lastN, n, orderNumber);
     98                        lastN = n;
    15099                }
    151100        }
    152101
     102        public void visit(Relation e) {
     103                // relations are not drawn.
     104        }
    153105        /**
    154          * Draw an number of the order of the segment within the parents way
     106         * Draw an number of the order of the two consecutive nodes within the
     107         * parents way
    155108         */
    156         protected void drawOrderNumber(Segment ls, int orderNumber) {
     109        protected void drawOrderNumber(Node n1, Node n2, int orderNumber) {
    157110                int strlen = (""+orderNumber).length();
    158                 Point p1 = nc.getPoint(ls.from.eastNorth);
    159                 Point p2 = nc.getPoint(ls.to.eastNorth);
     111                Point p1 = nc.getPoint(n1.eastNorth);
     112                Point p2 = nc.getPoint(n2.eastNorth);
    160113                int x = (p1.x+p2.x)/2 - 4*strlen;
    161114                int y = (p1.y+p2.y)/2 + 4;
     
    164117                if (screen.contains(x,y)) {
    165118                        Color c = g.getColor();
    166                         g.setColor(backgroundColor);
     119                        g.setColor(getPreferencesColor("background", Color.BLACK));
    167120                        g.fillRect(x-1, y-12, 8*strlen+1, 14);
    168121                        g.setColor(c);
     
    189142         * Draw a line with the given color.
    190143         */
    191         protected void drawSegment(Segment ls, Color col, boolean showDirection) {
    192                 if (ls.incomplete)
    193                         return;
    194                 if (col != currentColor) {
    195                         displaySegments(col);
    196                 }
     144        protected void drawSegment(Node n1, Node n2, Color col, boolean showDirection) {
     145                g.setColor(col);
     146                Point p1 = nc.getPoint(n1.eastNorth);
     147                Point p2 = nc.getPoint(n2.eastNorth);
    197148               
    198                 Point p1 = nc.getPoint(ls.from.eastNorth);
    199                 Point p2 = nc.getPoint(ls.to.eastNorth);
    200                
    201                 Rectangle screen = g.getClipBounds();           
     149                Rectangle screen = g.getClipBounds();
    202150                Line2D line = new Line2D.Double(p1.x, p1.y, p2.x, p2.y);
    203151                if (screen.contains(p1.x, p1.y, p2.x, p2.y) || screen.intersectsLine(line))
    204152                {
    205                         currrentPath.moveTo(p1.x, p1.y);
    206                         currrentPath.lineTo(p2.x, p2.y);
     153                        g.drawLine(p1.x, p1.y, p2.x, p2.y);
    207154       
    208155                        if (showDirection) {
    209156                                double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
    210                                 currrentPath.lineTo((int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
    211                                 currrentPath.moveTo((int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
    212                                 currrentPath.lineTo(p2.x, p2.y);                        }
    213                 }
    214         }
    215        
    216         protected void displaySegments(Color newColor) {
    217                 if (currrentPath != null) {
    218                         g.setColor(currentColor);
    219                         ((Graphics2D) g).draw(currrentPath);
    220                         currrentPath = new GeneralPath();
    221                         currentColor = newColor;
     157                        g.drawLine(p2.x,p2.y, (int)(p2.x + 10*Math.cos(t-PHI)), (int)(p2.y + 10*Math.sin(t-PHI)));
     158                        g.drawLine(p2.x,p2.y, (int)(p2.x + 10*Math.cos(t+PHI)), (int)(p2.y + 10*Math.sin(t+PHI)));
     159                        }
    222160                }
    223161        }
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/data/osm/visitor/Visitor.java

    r4437 r4464  
    22package org.openstreetmap.josm.data.osm.visitor;
    33
     4import org.openstreetmap.josm.data.osm.Relation;
    45import org.openstreetmap.josm.data.osm.Node;
    5 import org.openstreetmap.josm.data.osm.Segment;
    66import org.openstreetmap.josm.data.osm.Way;
    77
     
    1414public interface Visitor {
    1515        void visit(Node n);
    16         void visit(Segment s);
    1716        void visit(Way w);
     17        void visit(Relation e);
    1818}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/ConflictResolver.java

    r4437 r4464  
    3838import org.openstreetmap.josm.data.conflict.ConflictItem;
    3939import org.openstreetmap.josm.data.conflict.DeleteConflict;
    40 import org.openstreetmap.josm.data.conflict.FromConflict;
    4140import org.openstreetmap.josm.data.conflict.PositionConflict;
    4241import org.openstreetmap.josm.data.conflict.PropertyConflict;
    43 import org.openstreetmap.josm.data.conflict.SegmentConflict;
    44 import org.openstreetmap.josm.data.conflict.ToConflict;
    4542import org.openstreetmap.josm.data.osm.OsmPrimitive;
    4643import org.openstreetmap.josm.tools.GBC;
     
    140137                possibleConflicts.add(new DeleteConflict());
    141138                possibleConflicts.add(new PositionConflict());
    142                 possibleConflicts.add(new FromConflict());
    143                 possibleConflicts.add(new ToConflict());
    144                 possibleConflicts.add(new SegmentConflict());
    145139                TreeSet<String> allkeys = new TreeSet<String>();
    146140                for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/GettingStarted.java

    r4437 r4464  
    4848                panel = new JPanel(new GridBagLayout());
    4949               
     50                panel.add(new JLabel("<html><h2>You are running a technology preview with support for <i>API 0.5</i>.</h2>" +
     51                                "<h3>API 0.5 supports object relationships, and segments have been removed.</h3>" +
     52                                "<h3>This version is hard-coded to use the API 0.5 running on <i>openstreetmap.gryph.de</i> which has data from a recent planet file."+
     53                                "<br>Please be gentle with that machine and request only moderate bounding boxes.<br>" +
     54                                "<br>Username and password are also hardcoded, so your real username and password are not transmitted.<br>" +
     55                "</h3>"), GBC.eol());
     56               
     57                addLine("wiki", "Read the [Wiki page on API 0.5]");
    5058                addGettingStarted();
    5159                addGettingHelp();
     
    8694                else if (e.getActionCommand().equals("help"))
    8795                        Main.main.menu.help.actionPerformed(e);
     96                else if (e.getActionCommand().equals("wiki"))
     97                        OpenBrowser.displayUrl("http://wiki.openstreetmap.org/index.php?title=OSM_Protocol_Version_0.5");
    8898                else if (e.getActionCommand().equals("tutorial"))
    8999                        OpenBrowser.displayUrl("http://josm.openstreetmap.de/wiki/TutorialVideos");
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/MainMenu.java

    r4437 r4464  
    1818import org.openstreetmap.josm.actions.CombineWayAction;
    1919import org.openstreetmap.josm.actions.DownloadAction;
    20 import org.openstreetmap.josm.actions.DownloadIncompleteAction;
    2120import org.openstreetmap.josm.actions.ExitAction;
    2221import org.openstreetmap.josm.actions.GpxExportAction;
     
    2625import org.openstreetmap.josm.actions.PreferencesAction;
    2726import org.openstreetmap.josm.actions.RedoAction;
    28 import org.openstreetmap.josm.actions.ReorderAction;
    29 import org.openstreetmap.josm.actions.ReverseSegmentAction;
     27import org.openstreetmap.josm.actions.ReverseWayAction;
    3028import org.openstreetmap.josm.actions.SaveAction;
    3129import org.openstreetmap.josm.actions.SaveAsAction;
     
    5654        public final OpenAction open = new OpenAction();
    5755        public final DownloadAction download = new DownloadAction();
    58         public final Action reverseSegment = new ReverseSegmentAction();
     56        public final Action reverseWay = new ReverseWayAction();
    5957        public final Action splitWay = new SplitWayAction();
    6058        public final Action combineWay = new CombineWayAction();
    6159        public final Action alignInCircle = new AlignInCircleAction();
    6260        public final Action alignInLine = new AlignInLineAction();
    63         public final Action reorder = new ReorderAction();
    6461        public final Action upload = new UploadAction();
    6562        public final Action save = new SaveAction(null);
     
    7067        public final HelpAction help = new HelpAction();
    7168        public final Action about = new AboutAction();
    72         public final DownloadIncompleteAction downloadIncomplete = new DownloadIncompleteAction();
    7369       
    7470        public final JMenu layerMenu = new JMenu(tr("Layer"));
     
    117113                toolsMenu.add(alignInLine);
    118114                toolsMenu.addSeparator();
    119                 toolsMenu.add(reverseSegment);
    120                 toolsMenu.add(reorder);
     115                toolsMenu.add(reverseWay);
    121116                toolsMenu.addSeparator();
    122117                toolsMenu.add(splitWay);
     
    126121                connectionMenu.setMnemonic('C');
    127122                connectionMenu.add(download);
    128                 connectionMenu.add(downloadIncomplete);
    129123                connectionMenu.add(upload);
    130124                add(connectionMenu);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/MapFrame.java

    r4437 r4464  
    1515import org.openstreetmap.josm.Main;
    1616import org.openstreetmap.josm.actions.mapmode.AddSegmentAction;
    17 import org.openstreetmap.josm.actions.mapmode.AddWayAction;
    1817import org.openstreetmap.josm.actions.mapmode.DeleteAction;
    1918import org.openstreetmap.josm.actions.mapmode.MapMode;
     
    2423import org.openstreetmap.josm.gui.dialogs.CommandStackDialog;
    2524import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
     25import org.openstreetmap.josm.gui.dialogs.RelationListDialog;
    2626import org.openstreetmap.josm.gui.dialogs.HistoryDialog;
    2727import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
     
    8585                toolBarActions.add(new IconToggleButton(new AddNodeGroup(this)));
    8686                toolBarActions.add(new IconToggleButton(new AddSegmentAction(this)));
    87                 toolBarActions.add(new IconToggleButton(new AddWayAction(this)));
    8887                toolBarActions.add(new IconToggleButton(new DeleteAction(this)));
    8988
     
    104103                addToggleDialog(conflictDialog = new ConflictDialog());
    105104                addToggleDialog(new CommandStackDialog(this));
     105                addToggleDialog(new RelationListDialog());
    106106
    107107                // status line below the map
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/MapStatus.java

    r4437 r4464  
    126126                                        OsmPrimitive osmNearest = null;
    127127                                        // Set the text label in the bottom status bar
    128                                         osmNearest = mv.getNearest(ms.mousePos, (ms.modifiers & MouseEvent.ALT_DOWN_MASK) != 0);
     128                                        osmNearest = mv.getNearest(ms.mousePos);
    129129                                        if (osmNearest != null) {
    130130                                                NameVisitor visitor = new NameVisitor();
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/MapView.java

    r4437 r4464  
    8585
    8686                // listend to selection changes to redraw the map
    87                 DataSet.listeners.add(new SelectionChangedListener(){
     87                DataSet.selListeners.add(new SelectionChangedListener(){
    8888                        public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    8989                                repaint();
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r4437 r4464  
    44import java.awt.Point;
    55import java.util.Collection;
    6 import java.util.Collections;
    76import java.util.HashSet;
    8 import java.util.List;
    97
    108import javax.swing.JComponent;
     
    1614import org.openstreetmap.josm.data.osm.Node;
    1715import org.openstreetmap.josm.data.osm.OsmPrimitive;
    18 import org.openstreetmap.josm.data.osm.Segment;
    1916import org.openstreetmap.josm.data.osm.Way;
     17import org.openstreetmap.josm.data.osm.WaySegment;
    2018import org.openstreetmap.josm.data.projection.Projection;
    2119
     
    147145
    148146        /**
    149          * @return the nearest way to the screen point given.
    150          */
    151         public final Way getNearestWay(Point p) {
     147         * @return the nearest way segment to the screen point given that is not
     148         * in ignore.
     149         *
     150         * @param p the point for which to search the nearest segment.
     151         * @param ignore a collection of segments which are not to be returned.
     152         * May be null.
     153         */
     154        public final WaySegment getNearestWaySegment(Point p, Collection<WaySegment> ignore) {
    152155                Way minPrimitive = null;
     156                int minI = 0;
    153157                double minDistanceSq = Double.MAX_VALUE;
    154158                for (Way w : Main.ds.ways) {
    155159                        if (w.deleted)
    156160                                continue;
    157                         for (Segment ls : w.segments) {
    158                                 if (ls.deleted || ls.incomplete)
     161                        Node lastN = null;
     162                        int i = -2;
     163                        for (Node n : w.nodes) {
     164                                i++;
     165                                if (n.deleted) continue;
     166                                if (lastN == null) {
     167                                        lastN = n;
    159168                                        continue;
    160                                 Point A = getPoint(ls.from.eastNorth);
    161                                 Point B = getPoint(ls.to.eastNorth);
     169                                }
     170                                if (ignore != null && ignore.contains(new WaySegment(w, i))) {
     171                                        continue;
     172                                }
     173                                Point A = getPoint(lastN.eastNorth);
     174                                Point B = getPoint(n.eastNorth);
    162175                                double c = A.distanceSq(B);
    163176                                double a = p.distanceSq(B);
     
    167180                                        minDistanceSq = perDist;
    168181                                        minPrimitive = w;
    169                                 }
     182                                        minI = i;
     183                                }
     184                                lastN = n;
    170185                        }
    171186                }
    172                 return minPrimitive;
    173         }
    174 
    175         /**
    176          * @return the nearest segment to the screen point given
    177          *
    178          * @param p the point for which to search the nearest segment.
    179          */
    180         public final Segment getNearestSegment(Point p) {
    181                 List<Segment> e = Collections.emptyList();
    182                 return getNearestSegment(p, e);
     187                return minPrimitive == null ? null : new WaySegment(minPrimitive, minI);
     188        }
     189
     190        /**
     191         * @return the nearest way segment to the screen point given.
     192         */
     193        public final WaySegment getNearestWaySegment(Point p) {
     194                return getNearestWaySegment(p, null);
    183195        }
    184196       
    185197        /**
    186          * @return the nearest segment to the screen point given that is not
    187          * in ignoreThis.
    188          *
    189          * @param p the point for which to search the nearest segment.
    190          * @param ignore a collection of segments which are not to be returned. Must not be null.
    191          */
    192         public final Segment getNearestSegment(Point p, Collection<Segment> ignore) {
    193                 Segment minPrimitive = null;
    194                 double minDistanceSq = Double.MAX_VALUE;
    195                 // segments
    196                 for (Segment ls : Main.ds.segments) {
    197                         if (ls.deleted || ls.incomplete || ignore.contains(ls))
    198                                 continue;
    199                         Point A = getPoint(ls.from.eastNorth);
    200                         Point B = getPoint(ls.to.eastNorth);
    201                         double c = A.distanceSq(B);
    202                         double a = p.distanceSq(B);
    203                         double b = p.distanceSq(A);
    204                         double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
    205                         if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
    206                                 minDistanceSq = perDist;
    207                                 minPrimitive = ls;
    208                         }
    209                 }
    210                 return minPrimitive;
     198         * @return the nearest way to the screen point given.
     199         */
     200        public final Way getNearestWay(Point p) {
     201                WaySegment nearestWaySeg = getNearestWaySegment(p);
     202                return nearestWaySeg == null ? null : nearestWaySeg.way;
    211203    }
    212204
     
    217209         * nearest node is returned.
    218210         *
    219          * If no node is found, search for pending segments.
    220          *
    221          * If no such segment is found, and a non-pending segment is
    222          * within 10 pixel to p, this segment is returned, except when
    223          * <code>wholeWay</code> is <code>true</code>, in which case the
    224          * corresponding Way is returned.
    225          *
    226          * If no segment is found and the point is within an area, return that
    227          * area.
    228          *
    229          * If no area is found, return <code>null</code>.
     211         * If no node is found, search for near ways.
     212         *
     213         * If nothing is found, return <code>null</code>.
    230214         *
    231215         * @param p                              The point on screen.
    232          * @param segmentInsteadWay Whether the segment (true) or only the whole
    233          *                                               way should be returned.
    234216         * @return      The primitive, that is nearest to the point p.
    235217         */
     218        public OsmPrimitive getNearest(Point p) {
     219                OsmPrimitive osm = getNearestNode(p);
     220                if (osm == null)
     221                        osm = getNearestWay(p);
     222                return osm;
     223        }
     224
     225        @Deprecated
    236226        public OsmPrimitive getNearest(Point p, boolean segmentInsteadWay) {
    237                 OsmPrimitive osm = getNearestNode(p);
    238                 if (osm == null && !segmentInsteadWay)
    239                         osm = getNearestWay(p);
    240                 if (osm == null)
    241                         osm = getNearestSegment(p);
    242                 return osm;
     227                return getNearest(p);
    243228        }
    244229
    245230        /**
    246231         * @return A list of all objects that are nearest to
    247          * the mouse. To do this, first the nearest object is
    248          * determined.
    249          *
    250          * If its a node, return all segments and
    251          * streets the node is part of, as well as all nodes
    252          * (with their segments and ways) with the same
    253          * location.
    254          *
    255          * If its a segment, return all ways this segment
    256          * belongs to as well as all segments that are between
    257          * the same nodes (in both direction) with all their ways.
     232         * the mouse.  Does a simple sequential scan on all the data.
    258233         *
    259234         * @return A collection of all items or <code>null</code>
     
    262237         */
    263238        public Collection<OsmPrimitive> getAllNearest(Point p) {
    264                 OsmPrimitive osm = getNearest(p, true);
    265                 if (osm == null)
    266                         return null;
    267                 Collection<OsmPrimitive> c = new HashSet<OsmPrimitive>();
    268                 c.add(osm);
    269                 if (osm instanceof Node) {
    270                         Node node = (Node)osm;
    271                         for (Node n : Main.ds.nodes)
    272                                 if (!n.deleted && n.coor.equals(node.coor))
    273                                         c.add(n);
    274                         for (Segment ls : Main.ds.segments)
    275                                 // segments never match nodes, so they are skipped by contains
    276                                 if (!ls.deleted && !ls.incomplete && (c.contains(ls.from) || c.contains(ls.to)))
    277                                         c.add(ls);
    278                 }
    279                 if (osm instanceof Segment) {
    280                         Segment line = (Segment)osm;
    281                         for (Segment ls : Main.ds.segments)
    282                                 if (!ls.deleted && ls.equalPlace(line))
    283                                         c.add(ls);
    284                 }
    285                 if (osm instanceof Node || osm instanceof Segment) {
     239                Collection<OsmPrimitive> nearest = new HashSet<OsmPrimitive>();
    286240                        for (Way w : Main.ds.ways) {
    287                                 if (w.deleted)
     241                        if (w.deleted) continue;
     242                        Node lastN = null;
     243                        for (Node n : w.nodes) {
     244                                if (n.deleted) continue;
     245                                if (lastN == null) {
     246                                        lastN = n;
    288247                                        continue;
    289                                 for (Segment ls : w.segments) {
    290                                         if (!ls.deleted && !ls.incomplete && c.contains(ls)) {
    291                                                 c.add(w);
     248                                }
     249                                Point A = getPoint(lastN.eastNorth);
     250                                Point B = getPoint(n.eastNorth);
     251                                double c = A.distanceSq(B);
     252                                double a = p.distanceSq(B);
     253                                double b = p.distanceSq(A);
     254                                double perDist = a-(a-b+c)*(a-b+c)/4/c; // perpendicular distance squared
     255                                if (perDist < 100 && a < c+100 && b < c+100) {
     256                                        nearest.add(w);
    292257                                                break;
    293258                                        }
    294                                 }
     259                                lastN = n;
     260                                }
     261                        }
     262                for (Node n : Main.ds.nodes) {
     263                        if (!n.deleted && getPoint(n.eastNorth).distanceSq(p) < 100) {
     264                                nearest.add(n);
    295265                        }
    296266                }
    297                 return c;
     267                return nearest.isEmpty() ? null : nearest;
    298268        }
    299269
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/OsmPrimitivRenderer.java

    r4437 r4464  
    55
    66import javax.swing.DefaultListCellRenderer;
     7import javax.swing.JLabel;
    78import javax.swing.JList;
     9import javax.swing.JTable;
     10import javax.swing.ListCellRenderer;
     11import javax.swing.table.DefaultTableCellRenderer;
     12import javax.swing.table.TableCellRenderer;
    813
    914import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    1217/**
    1318 * Renderer that renders the objects from an OsmPrimitive as data.
     19 *
     20 * Can be used in lists and tables.
     21 *
    1422 * @author imi
     23 * @author Frederik Ramm <frederik@remote.org>
    1524 */
    16 public class OsmPrimitivRenderer extends DefaultListCellRenderer {
     25public class OsmPrimitivRenderer implements ListCellRenderer, TableCellRenderer {
    1726
     27        /**
     28         * NameVisitor provides proper names and icons for OsmPrimitives
     29         */
    1830        private NameVisitor visitor = new NameVisitor();
    1931
    20         @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    21                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    22                 if (value != null) {
     32        /**
     33         * Default list cell renderer - delegate for ListCellRenderer operation
     34         */
     35        private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
     36       
     37        /**
     38         * Default table cell renderer - delegate for TableCellRenderer operation
     39         */
     40        private DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
     41
     42        /**
     43         * Adapter method supporting the ListCellRenderer interface.
     44         */
     45        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     46                Component def = defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     47                return renderer(def, (OsmPrimitive) value);
     48        }
     49
     50        /**
     51         * Adapter method supporting the TableCellRenderer interface.
     52         */
     53        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     54                Component def = defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     55                return renderer(def, (OsmPrimitive) value);
     56        }
     57       
     58        /**
     59         * Internal method that stuffs information into the rendering component
     60         * provided that it's a kind of JLabel.
     61         * @param def the rendering component
     62         * @param value the OsmPrimtive to render
     63         * @return the modified rendering component
     64         */
     65        private Component renderer(Component def, OsmPrimitive value) {
     66                if (def != null && value != null && def instanceof JLabel) {
    2367                        ((OsmPrimitive)value).visit(visitor);
    24                         setText(visitor.name);
    25                         setIcon(visitor.icon);
     68                        ((JLabel)def).setText(visitor.name);
     69                        ((JLabel)def).setIcon(visitor.icon);
    2670                }
    27                 return this;
     71                return def;
    2872        }
     73       
    2974}
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/SelectionManager.java

    r4437 r4464  
    2525import org.openstreetmap.josm.data.osm.Node;
    2626import org.openstreetmap.josm.data.osm.OsmPrimitive;
    27 import org.openstreetmap.josm.data.osm.Segment;
    2827import org.openstreetmap.josm.data.osm.Way;
    2928
     
    282281         * modifier.
    283282         * @param alt Whether the alt key was pressed, which means select all objects
    284          *              that are touched, instead those which are completly covered. Also
    285          *              select whole ways instead of segments.
     283         *              that are touched, instead those which are completly covered.
    286284         */
    287285        public Collection<OsmPrimitive> getObjectsInRectangle(Rectangle r, boolean alt) {
     
    293291
    294292                if (clicked) {
    295                         OsmPrimitive osm = nc.getNearest(center, alt);
     293                        OsmPrimitive osm = nc.getNearest(center);
    296294                        if (osm != null)
    297295                                selection.add(osm);
     
    303301                        }
    304302                       
    305                         // pending segments
    306                         for (Segment s : Main.ds.segments)
    307                                 if (!s.deleted && rectangleContainSegment(r, alt, s))
    308                                         selection.add(s);
    309 
    310303                        // ways
    311304                        for (Way w : Main.ds.ways) {
    312                                 if (w.deleted)
    313                                         continue;
    314                                 boolean someSelectableSegment = false;
    315                                 boolean wholeWaySelected = true;
    316                                 for (Segment s : w.segments) {
    317                                         if (s.incomplete)
     305                                if (w.deleted || w.nodes.isEmpty())
    318306                                                continue;
    319                                         someSelectableSegment = true;
    320                                         if (!rectangleContainSegment(r, alt, s)) {
    321                                                 wholeWaySelected = false;
     307                                if (alt) {
     308                                        for (Node n : w.nodes) {
     309                                                if (r.contains(nc.getPoint(n.eastNorth))) {
     310                                                        selection.add(w);
    322311                                                break;
    323312                                        }
    324313                                }
    325                                 if (someSelectableSegment && wholeWaySelected)
    326                                         selection.add(w);
     314                                } else {
     315                                        boolean allIn = true;
     316                                        for (Node n : w.nodes) {
     317                                                if (!r.contains(nc.getPoint(n.eastNorth))) {
     318                                                        allIn = false;
     319                                                        break;
    327320                        }
    328321                }
     322                                        if (allIn) selection.add(w);
     323                                }
     324        }
     325                }
    329326                return selection;
    330         }
    331 
    332         /**
    333          * Decide whether the segment is in the rectangle Return
    334          * <code>true</code>, if it is in or false if not.
    335          *
    336          * @param r                     The rectangle, in which the segment has to be.
    337          * @param alt           Whether user pressed the Alt key
    338          * @param ls            The segment.
    339          * @return <code>true</code>, if the Segment was added to the selection.
    340          */
    341         private boolean rectangleContainSegment(Rectangle r, boolean alt, Segment ls) {
    342                 if (ls.incomplete)
    343                         return false;
    344                 if (alt) {
    345                         Point p1 = nc.getPoint(ls.from.eastNorth);
    346                         Point p2 = nc.getPoint(ls.to.eastNorth);
    347                         if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
    348                                 return true;
    349                 } else {
    350                         if (r.contains(nc.getPoint(ls.from.eastNorth))
    351                                         && r.contains(nc.getPoint(ls.to.eastNorth)))
    352                                 return true;
    353                 }
    354                 return false;
    355327        }
    356328       
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java

    r4437 r4464  
    3333import org.openstreetmap.josm.data.SelectionChangedListener;
    3434import org.openstreetmap.josm.data.osm.DataSet;
     35import org.openstreetmap.josm.data.osm.Relation;
     36import org.openstreetmap.josm.data.osm.RelationMember;
    3537import org.openstreetmap.josm.data.osm.Node;
    3638import org.openstreetmap.josm.data.osm.OsmPrimitive;
    37 import org.openstreetmap.josm.data.osm.Segment;
    3839import org.openstreetmap.josm.data.osm.Way;
    3940import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
     
    8889                add(buttonPanel, BorderLayout.SOUTH);
    8990
    90                 DataSet.listeners.add(new SelectionChangedListener(){
     91                DataSet.selListeners.add(new SelectionChangedListener(){
    9192                        public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    9293                                displaylist.clearSelection();
     
    130131                                model.addElement(osm);
    131132                for (OsmPrimitive osm : this.conflicts.keySet())
    132                         if (osm instanceof Segment)
    133                                 model.addElement(osm);
    134                 for (OsmPrimitive osm : this.conflicts.keySet())
    135133                        if (osm instanceof Way)
    136134                                model.addElement(osm);
     
    155153                                g.drawRect(p.x-1, p.y-1, 2, 2);
    156154                        }
    157                         public void visit(Segment ls) {
    158                                 if (ls.incomplete)
    159                                         return;
    160                                 Point p1 = nc.getPoint(ls.from.eastNorth);
    161                                 Point p2 = nc.getPoint(ls.to.eastNorth);
     155                        public void visit(Node n1, Node n2) {
     156                                Point p1 = nc.getPoint(n1.eastNorth);
     157                                Point p2 = nc.getPoint(n2.eastNorth);
    162158                                g.drawLine(p1.x, p1.y, p2.x, p2.y);
    163159                        }
    164160                        public void visit(Way w) {
    165                                 for (Segment ls : w.segments)
    166                                         visit(ls);
     161                                Node lastN = null;
     162                                for (Node n : w.nodes) {
     163                                        if (lastN == null) {
     164                                                lastN = n;
     165                                                continue;
     166                                        }
     167                                        visit(lastN, n);
     168                                        lastN = n;
     169                                }
     170                        }
     171                        public void visit(Relation e) {
     172                                for (RelationMember em : e.members)
     173                                        em.member.visit(this);
    167174                        }
    168175                };
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java

    r4437 r4464  
    144144                revertButton.putClientProperty("help", "Dialog/History/Revert");
    145145               
    146                 DataSet.listeners.add(this);
     146                DataSet.selListeners.add(this);
    147147        }
    148148
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java

    r4437 r4464  
    4848import org.openstreetmap.josm.data.osm.DataSet;
    4949import org.openstreetmap.josm.data.osm.OsmPrimitive;
     50import org.openstreetmap.josm.data.osm.Relation;
     51import org.openstreetmap.josm.data.osm.RelationMember;
     52import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
    5053import org.openstreetmap.josm.gui.MapFrame;
    5154import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
     55import org.openstreetmap.josm.gui.tagging.ForwardActionListener;
    5256import org.openstreetmap.josm.gui.tagging.TaggingCellRenderer;
    53 import org.openstreetmap.josm.gui.tagging.ForwardActionListener;
    5457import org.openstreetmap.josm.gui.tagging.TaggingPreset;
    5558import org.openstreetmap.josm.tools.AutoCompleteComboBox;
     
    7780
    7881        /**
     82         * Used to display relation names in the membership table
     83         */
     84        private NameVisitor nameVisitor = new NameVisitor();
     85       
     86        /**
    7987         * Watches for double clicks and from editing or new property, depending on the
    8088         * location, the click was.
     
    8593                        if (e.getClickCount() < 2)
    8694                                return;
    87                         if (e.getSource() instanceof JScrollPane)
    88                                 add();
    89                         else {
     95       
     96                        if (e.getSource() == propertyTable)
     97                        {
    9098                                int row = propertyTable.rowAtPoint(e.getPoint());
    91                                 edit(row);
    92                         }
    93                 }
    94         }
    95 
    96         /**
    97          * Edit the value in the table row
    98          * @param row   The row of the table, from which the value is edited.
    99          */
    100         void edit(int row) {
    101                 String key = data.getValueAt(row, 0).toString();
     99                                if (row > -1) {
     100                                        propertyEdit(row);
     101                                        return;
     102                        }
     103                        } else if (e.getSource() == membershipTable) {
     104                                int row = membershipTable.rowAtPoint(e.getPoint());
     105                                if (row > -1) {
     106                                        membershipEdit(row);
     107                                        return;
     108                                }
     109                        }
     110                        add();
     111                }
     112        }
     113
     114        /**
     115         * Edit the value in the properties table row
     116         * @param row The row of the table from which the value is edited.
     117         */
     118        void propertyEdit(int row) {
     119                String key = propertyData.getValueAt(row, 0).toString();
    102120                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    103121                if (sel.isEmpty()) {
     
    118136                p.add(keyField, GBC.eol().fill(GBC.HORIZONTAL));
    119137                               
    120                 final JComboBox combo = (JComboBox)data.getValueAt(row, 1);
     138                final JTextField valueField = new JTextField((String)propertyData.getValueAt(row, 1));
    121139                p.add(new JLabel(tr("Value")), GBC.std());
    122140                p.add(Box.createHorizontalStrut(10), GBC.std());
    123                 p.add(combo, GBC.eol().fill(GBC.HORIZONTAL));
     141                p.add(valueField, GBC.eol().fill(GBC.HORIZONTAL));
    124142
    125143                final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
    126144                        @Override public void selectInitialValue() {
    127                                 combo.requestFocusInWindow();
    128                                 combo.getEditor().selectAll();
     145                                valueField.requestFocusInWindow();
     146                                valueField.selectAll();
    129147                        }
    130148                };
    131149                final JDialog dlg = optionPane.createDialog(Main.parent, tr("Change values?"));
    132                 combo.getEditor().addActionListener(new ActionListener(){
     150                valueField.addActionListener(new ActionListener(){
    133151                        public void actionPerformed(ActionEvent e) {
    134152                                optionPane.setValue(JOptionPane.OK_OPTION);
     
    136154                        }
    137155                });
    138                 String oldComboEntry = combo.getEditor().getItem().toString();
    139156                dlg.setVisible(true);
    140157
     
    142159                if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
    143160                                (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
    144                         combo.getEditor().setItem(oldComboEntry);
    145                         return;
    146                 }
    147 
    148                 String value = combo.getEditor().getItem().toString();
     161                        return;
     162                }
     163
     164                String value = valueField.getText();
    149165                if (value.equals(tr("<different>")))
    150166                        return;
     
    164180                }
    165181
    166                 if (!key.equals(newkey) || value == null)
    167182                        selectionChanged(sel); // update whole table
    168 
    169183                Main.parent.repaint(); // repaint all - drawing could have been changed
     184        }
     185
     186        /**
     187         * This simply fires up an relation editor for the relation shown; everything else
     188         * is the editor's business.
     189         *
     190         * @param row
     191         */
     192        void membershipEdit(int row) { 
     193                final RelationEditor editor = new RelationEditor((Relation)membershipData.getValueAt(row, 0));
     194                editor.setVisible(true);
    170195        }
    171196
     
    197222                        }
    198223                }
    199                 for (int i = 0; i < data.getRowCount(); ++i)
    200                         allData.remove(data.getValueAt(i, 0));
     224                for (int i = 0; i < propertyData.getRowCount(); ++i)
     225                        allData.remove(propertyData.getValueAt(i, 0));
    201226                final AutoCompleteComboBox keys = new AutoCompleteComboBox();
    202227                keys.setPossibleItems(allData.keySet());
     
    249274         */
    250275        private void delete(int row) {
    251                 String key = data.getValueAt(row, 0).toString();
     276                String key = propertyData.getValueAt(row, 0).toString();
    252277                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    253278                Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, null));
     
    258283         * The property data.
    259284         */
    260         private final DefaultTableModel data = new DefaultTableModel(){
     285        private final DefaultTableModel propertyData = new DefaultTableModel() {
    261286                @Override public boolean isCellEditable(int row, int column) {
    262287                        return false;
    263288                }
    264289                @Override public Class<?> getColumnClass(int columnIndex) {
    265                         return columnIndex == 1 ? JComboBox.class : String.class;
     290                        return String.class;
    266291                }
    267292        };
     293
     294        /**
     295         * The membership data.
     296         */
     297        private final DefaultTableModel membershipData = new DefaultTableModel() {
     298                @Override public boolean isCellEditable(int row, int column) {
     299                        return false;
     300                }
     301                @Override public Class<?> getColumnClass(int columnIndex) {
     302                        return columnIndex == 1 ? Relation.class : String.class;
     303                }
     304        };
     305       
    268306        /**
    269307         * The properties list.
    270308         */
    271         private final JTable propertyTable = new JTable(data);
     309        private final JTable propertyTable = new JTable(propertyData);
     310        private final JTable membershipTable = new JTable(membershipData);
     311
    272312        public JComboBox taggingPresets = new JComboBox();
    273313
     
    277317         */
    278318        public PropertiesDialog(MapFrame mapFrame) {
    279                 super(tr("Properties"), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150);
     319                super(tr("Properties/Memberships"), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150);
    280320
    281321                if (TaggingPresetPreference.taggingPresets.size() > 0) {
     
    300340                taggingPresets.setRenderer(new TaggingCellRenderer());
    301341
    302                 data.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
     342                // setting up the properties table
     343               
     344                propertyData.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
    303345                propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    304                 propertyTable.setDefaultRenderer(JComboBox.class, new DefaultTableCellRenderer(){
     346       
     347                propertyTable.getColumnModel().getColumn(1).setCellRenderer(new DefaultTableCellRenderer(){
    305348                        @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    306349                                Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
    307350                                if (c instanceof JLabel) {
    308                                         String str = ((JComboBox)value).getEditor().getItem().toString();
     351                                        String str = (String) value;
    309352                                        ((JLabel)c).setText(str);
    310353                                        if (str.equals(tr("<different>")))
     
    314357                        }
    315358                });
    316                 propertyTable.setDefaultRenderer(String.class, new DefaultTableCellRenderer(){
     359               
     360                // setting up the membership table
     361               
     362                membershipData.setColumnIdentifiers(new String[]{tr("Member Of"),tr("Role")});
     363                membershipTable.setRowSelectionAllowed(false);
     364               
     365                membershipTable.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
    317366                        @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    318                                 return super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
     367                                Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
     368                                if (c instanceof JLabel) {
     369                                        nameVisitor.visit((Relation)value);
     370                                        ((JLabel)c).setText(nameVisitor.name);
     371                                }
     372                                return c;
    319373                        }
    320374                });
     375               
     376                // combine both tables and wrap them in a scrollPane
     377                JPanel bothTables = new JPanel();
     378                bothTables.setLayout(new GridBagLayout());
     379                bothTables.add(propertyTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
     380                bothTables.add(propertyTable, GBC.eol().fill(GBC.BOTH));
     381                bothTables.add(membershipTable.getTableHeader(), GBC.eol().fill(GBC.HORIZONTAL));
     382                bothTables.add(membershipTable, GBC.eol().fill(GBC.BOTH));
     383               
    321384                DblClickWatch dblClickWatch = new DblClickWatch();
    322385                propertyTable.addMouseListener(dblClickWatch);
    323                 JScrollPane scrollPane = new JScrollPane(propertyTable);
     386                membershipTable.addMouseListener(dblClickWatch);
     387                JScrollPane scrollPane = new JScrollPane(bothTables);
    324388                scrollPane.addMouseListener(dblClickWatch);
    325389                add(scrollPane, BorderLayout.CENTER);
     
    335399                                                JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
    336400                                        else
    337                                                 edit(sel);
     401                                                propertyEdit(sel);
    338402                                } else if (e.getActionCommand().equals("Delete")) {
    339403                                        if (sel == -1)
     
    344408                        }
    345409                };
     410               
    346411                buttonPanel.add(createButton(marktr("Add"),tr("Add a new key/value pair to all objects"), KeyEvent.VK_A, buttonAction));
    347412                buttonPanel.add(createButton(marktr("Edit"),tr( "Edit the value of the selected key for all objects"), KeyEvent.VK_E, buttonAction));
     
    349414                add(buttonPanel, BorderLayout.SOUTH);
    350415
    351                 DataSet.listeners.add(this);
     416                DataSet.selListeners.add(this);
    352417        }
    353418
     
    375440                if (propertyTable.getCellEditor() != null)
    376441                        propertyTable.getCellEditor().cancelCellEditing();
    377                 data.setRowCount(0);
     442
     443                // re-load property data
     444               
     445                propertyData.setRowCount(0);
    378446
    379447                Map<String, Integer> valueCount = new HashMap<String, Integer>();
     
    391459                }
    392460                for (Entry<String, Collection<String>> e : props.entrySet()) {
    393                         JComboBox value = new JComboBox(e.getValue().toArray());
    394                         value.setEditable(true);
    395                         value.getEditor().setItem(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next());
    396                         data.addRow(new Object[]{e.getKey(), value});
     461                        String value=(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next());
     462                        propertyData.addRow(new Object[]{e.getKey(), value});
     463                }
     464               
     465                // re-load membership data
     466                // this is rather expensive since we have to walk through all members of all existing relationships.
     467                // could use back references here for speed if necessary.
     468               
     469                membershipData.setRowCount(0);
     470               
     471                Map<Relation, Integer> valueCountM = new HashMap<Relation, Integer>();
     472                TreeMap<Relation, Collection<String>> roles = new TreeMap<Relation, Collection<String>>();
     473                for (Relation r : Main.ds.relations) {
     474                        for (RelationMember m : r.members) {
     475                                if (newSelection.contains(m.member)) {
     476                                        Collection<String> value = roles.get(r);
     477                                        if (value == null) {
     478                                                value = new TreeSet<String>();
     479                                                roles.put(r, value);
     480                                        }
     481                                        value.add(m.role);
     482                                        valueCountM.put(r, valueCount.containsKey(r) ? valueCount.get(r)+1 : 1);
     483                                }
     484                        }
     485                }
     486               
     487                for (Entry<Relation, Collection<String>> e : roles.entrySet()) {
     488                        //JComboBox value = new JComboBox(e.getValue().toArray());
     489                        //value.setEditable(true);
     490                        //value.getEditor().setItem(e.getValue().size() > 1 || valueCount.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next());
     491                        String value = e.getValue().size() > 1 || valueCountM.get(e.getKey()) != newSelection.size() ? tr("<different>") : e.getValue().iterator().next();
     492                        membershipData.addRow(new Object[]{e.getKey(), value});
    397493                }
    398494        }
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java

    r4437 r4464  
    8080                selectionChanged(Main.ds.getSelected());
    8181
    82                 DataSet.listeners.add(this);
     82                DataSet.selListeners.add(this);
    8383        }
    8484
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java

    r4437 r4464  
    5454                selectionChanged(Main.ds.getSelected());
    5555               
    56                 DataSet.listeners.add(this);
     56                DataSet.selListeners.add(this);
    5757        }
    5858
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r4437 r4464  
    3434import org.openstreetmap.josm.data.osm.DataSet;
    3535import org.openstreetmap.josm.data.osm.DataSource;
     36import org.openstreetmap.josm.data.osm.Relation;
    3637import org.openstreetmap.josm.data.osm.Node;
    3738import org.openstreetmap.josm.data.osm.OsmPrimitive;
    38 import org.openstreetmap.josm.data.osm.Segment;
    3939import org.openstreetmap.josm.data.osm.Way;
    4040import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     
    6060                public final int[] normal = new int[3];         
    6161                public final int[] deleted = new int[3];
    62                 public final String[] names = {"node", "segment", "way"};
     62                public final String[] names = {"node", "way", "relation"};
    6363
    6464                private void inc(final OsmPrimitive osm, final int i) {
     
    7272                }
    7373
    74                 public void visit(final Segment ls) {
    75                         inc(ls, 1);
    76                 }
    77 
    7874                public void visit(final Way w) {
     75                        inc(w, 1);
     76                }
     77                public void visit(final Relation w) {
    7978                        inc(w, 2);
    8079                }
     
    133132         * Draw all primitives in this layer but do not draw modified ones (they
    134133         * are drawn by the edit layer).
    135          * Draw nodes last to overlap the segments they belong to.
     134         * Draw nodes last to overlap the ways they belong to.
    136135         */
    137136        @Override public void paint(final Graphics g, final MapView mv) {
     
    163162                String tool = "";
    164163                tool += undeletedSize(data.nodes)+" "+trn("node", "nodes", undeletedSize(data.nodes))+", ";
    165                 tool += undeletedSize(data.segments)+" "+trn("segment", "segments", undeletedSize(data.segments))+", ";
    166164                tool += undeletedSize(data.ways)+" "+trn("way", "ways", undeletedSize(data.ways));
    167165                if (associatedFile != null)
     
    222220                        for (final Iterator<Node> it = data.nodes.iterator(); it.hasNext();)
    223221                                cleanIterator(it, processedSet);
    224                         for (final Iterator<Segment> it = data.segments.iterator(); it.hasNext();)
    225                                 cleanIterator(it, processedSet);
    226222                        for (final Iterator<Way> it = data.ways.iterator(); it.hasNext();)
    227223                                cleanIterator(it, processedSet);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java

    r4437 r4464  
    3838import org.openstreetmap.josm.data.osm.DataSet;
    3939import org.openstreetmap.josm.data.osm.Node;
    40 import org.openstreetmap.josm.data.osm.Segment;
    4140import org.openstreetmap.josm.data.osm.Way;
    4241import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     
    7170                        for (Collection<GpsPoint> c : data) {
    7271                                Way w = new Way();
    73                                 Node start = null;
    7472                                for (GpsPoint p : c) {
    75                                         Node end = new Node(p.latlon);
    76                                         ds.nodes.add(end);
    77                                         if (start != null) {
    78                                                 Segment segment = new Segment(start,end);
    79                                                 w.segments.add(segment);
    80                                                 ds.segments.add(segment);
    81                                         }
    82                                         start = end;
     73                                        Node n = new Node(p.latlon);
     74                                        ds.nodes.add(n);
     75                                        w.nodes.add(n);
    8376                                }
    8477                                ds.ways.add(w);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java

    r4437 r4464  
    103103                Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
    104104                final DataSet data = OsmReader.parseDataSet(in, null, Main.pleaseWaitDlg);
    105                 String origin = Main.pref.get("osm-server.url")+"/"+Main.pref.get("osm-server.version", "0.4");
     105                String origin = Main.pref.get("osm-server.url")+"/"+Main.pref.get("osm-server.version", "0.5");
    106106                Bounds bounds = new Bounds(new LatLon(lat1, lon1), new LatLon(lat2, lon2));
    107107                        DataSource src = new DataSource(bounds, origin);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/GpxWriter.java

    r4437 r4464  
    1111import org.openstreetmap.josm.data.osm.Node;
    1212import org.openstreetmap.josm.data.osm.OsmPrimitive;
    13 import org.openstreetmap.josm.data.osm.Segment;
    1413import org.openstreetmap.josm.data.osm.Way;
    1514import org.openstreetmap.josm.gui.layer.RawGpsLayer.GpsPoint;
     
    3231
    3332        /**
    34          * Export the dataset to gpx. Only the physical segment structure is
    35          * exported. To do this, the list of ways is processed. If a way span a
    36          * sequence of segments, this is added as one trkseg.
    37          * Then, all remaining segments are added in one extra trk. Finally,
    38          * all remaining nodes are added as wpt.
     33         * Export the dataset to gpx.  The ways are converted to trksegs, each in
     34         * a seperate trk.  Finally, all remaining nodes are added as wpt.
    3935         */
    4036        public static final class All implements XmlWriter.OsmWriterInterface {
     
    106102                                        continue;
    107103                                out.println("  <trk>");
    108                                 Segment oldLs = null;
    109                                 for (Segment ls : w.segments) {
    110                                         if (ls.incomplete)
    111                                                 continue;
    112                                         // end old segemnt, if no longer match a chain
    113                                         if (oldLs != null && !oldLs.to.coor.equals(ls.from.coor)) {
    114                                                 out.println("    </trkseg>");
    115                                                 writer.outputNode(oldLs.to, false);
    116                                                 all.remove(oldLs.to);
    117                                                 oldLs = null;
    118                                         }
    119                                         // start new segment if necessary
    120                                         if (oldLs == null)
    121104                                                out.println("    <trkseg>");
    122                                         writer.outputNode(ls.from, false);
    123                                         all.remove(ls.from);
    124                                         oldLs = ls;
    125                                         all.remove(ls);
    126                                 }
    127                                 // write last node if there
    128                                 if (oldLs != null) {
    129                                         writer.outputNode(oldLs.to, false);
    130                                         all.remove(oldLs.to);
     105                                for (Node n : w.nodes) {
     106                                        writer.outputNode(n, false);
     107                                        all.remove(n);
     108                        }
    131109                                        out.println("    </trkseg>");
    132                                 }
    133110                                out.println("  </trk>");
    134111                                all.remove(w);
    135                         }
    136 
    137                         // add remaining segments
    138                         Collection<Segment> segments = new LinkedList<Segment>();
    139                         for (OsmPrimitive osm : all)
    140                                 if (osm instanceof Segment && !((Segment)osm).incomplete)
    141                                         segments.add((Segment)osm);
    142                         if (!segments.isEmpty()) {
    143                                 out.println("  <trk>");
    144                                 for (Segment ls : segments) {
    145                                         out.println("    <trkseg>");
    146                                         writer.outputNode(ls.from, false);
    147                                         all.remove(ls.from);
    148                                         writer.outputNode(ls.to, false);
    149                                         all.remove(ls.to);
    150                                         out.println("    </trkseg>");
    151                                         all.remove(ls);
    152                                 }
    153                                 out.println("  </trk>");
    154112                        }
    155113
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/OsmIdReader.java

    r4437 r4464  
    2828
    2929        @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
    30                 if (qName.equals("node") || qName.equals("segment") || qName.equals("way")) {
     30                if (qName.equals("node") || qName.equals("way")) {
    3131                        try {
    3232                                entries.put(Long.valueOf(atts.getValue("id")), qName);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/OsmReader.java

    r4437 r4464  
    2121import org.openstreetmap.josm.data.osm.DataSet;
    2222import org.openstreetmap.josm.data.osm.DataSource;
     23import org.openstreetmap.josm.data.osm.Relation;
     24import org.openstreetmap.josm.data.osm.RelationMember;
    2325import org.openstreetmap.josm.data.osm.Node;
    2426import org.openstreetmap.josm.data.osm.OsmPrimitive;
    25 import org.openstreetmap.josm.data.osm.Segment;
    2627import org.openstreetmap.josm.data.osm.User;
    2728import org.openstreetmap.josm.data.osm.Way;
     
    4142 * all nodes are read and stored. Other information than nodes are stored in a raw list
    4243 *
    43  * The second phase reads from the raw list all segments and create Segment objects.
    44  *
    45  * The third phase read all ways out of the remaining objects in the raw list.
     44 * The second phase read all ways out of the remaining objects in the raw list.
    4645 *
    4746 * @author Imi
     
    8887
    8988        /**
    90          * Data structure for the remaining segment objects
    91          * Maps the raw attributes to key/value pairs.
    92          */
    93         private Map<OsmPrimitiveData, long[]> segs = new HashMap<OsmPrimitiveData, long[]>();
     89         * Used as a temporary storage for relation members, before they
     90         * are resolved into pointers to real objects.
     91         */
     92        private static class RelationMemberData {
     93                public String type;
     94                public long id;
     95                public RelationMember relationMember;
     96        }
    9497
    9598        /**
     
    97100         */
    98101        private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>();
     102
     103        /**
     104         * Data structure for relation objects
     105         */
     106        private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>();
    99107
    100108        /**
     
    129137                                                ds.dataSources.add(src);
    130138                                        }
     139                                       
     140                                // ---- PARSING NODES AND WAYS ----
     141                                       
    131142                                } else if (qName.equals("node")) {
    132143                                        current = new Node(new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon")));
    133144                                        readCommon(atts, current);
    134145                                        nodes.put(current.id, (Node)current);
    135                                 } else if (qName.equals("segment")) {
    136                                         current = new OsmPrimitiveData();
    137                                         readCommon(atts, current);
    138                                         segs.put((OsmPrimitiveData)current, new long[]{getLong(atts, "from"), getLong(atts, "to")});
    139146                                } else if (qName.equals("way")) {
    140147                                        current = new OsmPrimitiveData();
    141148                                        readCommon(atts, current);
    142149                                        ways.put((OsmPrimitiveData)current, new LinkedList<Long>());
    143                                 } else if (qName.equals("seg")) {
     150                                } else if (qName.equals("nd")) {
    144151                                        Collection<Long> list = ways.get(current);
    145152                                        if (list == null)
    146                                                 throw new SAXException(tr("Found <seg> tag on non-way."));
    147                                         long id = getLong(atts, "id");
     153                                                throw new SAXException(tr("Found <nd> element in non-way."));
     154                                        long id = getLong(atts, "ref");
    148155                                        if (id == 0)
    149                                                 throw new SAXException(tr("Incomplete segment with id=0"));
     156                                                throw new SAXException(tr("<nd> has zero ref"));
    150157                                        list.add(id);
    151                                 } else if (qName.equals("tag"))
     158
     159                                // ---- PARSING ENTITIES ----                   
     160
     161                                } else if (qName.equals("relation")) {
     162                                        current = new OsmPrimitiveData();
     163                                        readCommon(atts, current);
     164                                        relations.put((OsmPrimitiveData)current, new LinkedList<RelationMemberData>());
     165                                } else if (qName.equals("member")) {
     166                                        Collection<RelationMemberData> list = relations.get(current);
     167                                        if (list == null)
     168                                                throw new SAXException(tr("Found <member> tag on non-relation."));
     169                                        RelationMemberData emd = new RelationMemberData();
     170                                        emd.relationMember = new RelationMember();
     171                                        emd.id = getLong(atts, "ref");
     172                                        emd.type=atts.getValue("type");
     173                                        emd.relationMember.role = atts.getValue("role");
     174                                       
     175                                        if (emd.id == 0)
     176                                                throw new SAXException(tr("Incomplete <member> specification with ref=0"));
     177                                       
     178                                        list.add(emd);
     179                                       
     180                                // ---- PARSING TAGS (applicable to all objects) ----
     181                                       
     182                                } else if (qName.equals("tag")) {
    152183                                        current.put(atts.getValue("k"), atts.getValue("v"));
     184                                }
    153185                        } catch (NumberFormatException x) {
    154186                                x.printStackTrace(); // SAXException does not chain correctly
     
    170202        public OsmReader() {
    171203                // first add the main server version
    172                 allowedVersions.add(Main.pref.get("osm-server.version", "0.4"));
     204                allowedVersions.add(Main.pref.get("osm-server.version", "0.5"));
    173205                // now also add all compatible versions
    174206                String[] additionalVersions =
    175                         Main.pref.get("osm-server.additional-versions", "0.3").split("/,/");
     207                        Main.pref.get("osm-server.additional-versions", "").split("/,/");
     208                if (additionalVersions.length == 1 && additionalVersions[0].length() == 0)
     209                        additionalVersions = new String[] {};
    176210                allowedVersions.addAll(Arrays.asList(additionalVersions));     
    177211        }
     
    221255                        throw new SAXException(tr("Missing required attribute \"{0}\".",value));
    222256                return Long.parseLong(s);
    223         }
    224 
    225         private void createSegments() {
    226                 for (Entry<OsmPrimitiveData, long[]> e : segs.entrySet()) {
    227                         Node from = findNode(e.getValue()[0]);
    228                         Node to = findNode(e.getValue()[1]);
    229                         if (from == null || to == null)
    230                                 continue; //TODO: implement support for incomplete nodes.
    231                         Segment s = new Segment(from, to);
    232                         e.getKey().copyTo(s);
    233                         segments.put(s.id, s);
    234                         adder.visit(s);
    235                 }
    236257        }
    237258
     
    250271    }
    251272
    252         private Segment findSegment(long id) {
    253                 Segment s = segments.get(id);
    254                 if (s != null)
    255                         return s;
    256                 for (Segment seg : references.segments)
    257                         if (seg.id == id)
    258                                 return seg;
    259                 // TODO: This has to be changed to support multiple layers.
    260                 for (Segment seg : Main.ds.segments)
    261                         if (seg.id == id)
    262                                 return new Segment(seg);
    263                 return null;
    264         }
    265 
    266273        private void createWays() {
    267274                for (Entry<OsmPrimitiveData, Collection<Long>> e : ways.entrySet()) {
    268275                        Way w = new Way();
     276                        boolean failed = false;
    269277                        for (long id : e.getValue()) {
    270                                 Segment s = findSegment(id);
    271                                 if (s == null) {
    272                                         s = new Segment(id); // incomplete line segment
    273                                         adder.visit(s);
     278                                Node n = findNode(id);
     279                                if (n == null) {
     280                                        failed = true;
     281                                        break;
    274282                                }
    275                                 w.segments.add(s);
     283                                w.nodes.add(n);
    276284                        }
     285                        if (failed) continue;
    277286                        e.getKey().copyTo(w);
    278287                        adder.visit(w);
     
    281290
    282291        /**
    283          * All read segments after phase 2.
    284          */
    285         private Map<Long, Segment> segments = new HashMap<Long, Segment>();
     292         * Return the Way object with the given id, or null if it doesn't
     293         * exist yet. This method only looks at ways stored in the data set.
     294         *
     295         * @param id
     296         * @return way object or null
     297         */
     298        private Way findWay(long id) {
     299                for (Way wy : ds.ways)
     300                        if (wy.id == id)
     301                                return wy;
     302                for (Way wy : Main.ds.ways)
     303                        if (wy.id == id)
     304                                return wy;
     305                return null;
     306        }
     307
     308        /**
     309         * Return the Relation object with the given id, or null if it doesn't
     310         * exist yet. This method only looks at relations stored in the data set.
     311         *
     312         * @param id
     313         * @return relation object or null
     314         */
     315        private Relation findRelation(long id) {
     316                for (Relation e : ds.relations)
     317                        if (e.id == id)
     318                                return e;
     319                for (Relation e : Main.ds.relations)
     320                        if (e.id == id)
     321                                return e;
     322                return null;
     323        }
     324
     325        /**
     326         * Create relations. This is slightly different than n/s/w because
     327         * unlike other objects, relations may reference other relations; it
     328         * is not guaranteed that a referenced relation will have been created
     329         * before it is referenced. So we have to create all relations first,
     330         * and populate them later.
     331         */
     332        private void createRelations() {
     333               
     334                // pass 1 - create all relations
     335                for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) {
     336                        Relation en = new Relation();
     337                        e.getKey().copyTo(en);
     338                        adder.visit(en);
     339                }
     340
     341                // pass 2 - sort out members
     342                for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) {
     343                        Relation en = findRelation(e.getKey().id);
     344                        if (en == null) throw new Error("Failed to create relation " + e.getKey().id);
     345                       
     346                        for (RelationMemberData emd : e.getValue()) {
     347                                RelationMember em = emd.relationMember;
     348                                if (emd.type.equals("node")) {
     349                                        em.member = findNode(emd.id);
     350                                        if (em.member == null) {
     351                                                em.member = new Node(emd.id);
     352                                                adder.visit((Node)em.member);
     353                                        }
     354                                } else if (emd.type.equals("way")) {
     355                                        em.member = findWay(emd.id);
     356                                        if (em.member == null) {
     357                                                em.member = new Way(emd.id);
     358                                                adder.visit((Way)em.member);
     359                                        }
     360                                } else if (emd.type.equals("relation")) {
     361                                        em.member = findRelation(emd.id);
     362                                        if (em.member == null) {
     363                                                em.member = new Relation(emd.id);
     364                                                adder.visit((Relation)em.member);
     365                                        }
     366                                } else {
     367                                        // this is an error.
     368                                }
     369                                en.members.add(em);
     370                        }
     371                }
     372        }
    286373
    287374        /**
     
    295382                osm.references = ref == null ? new DataSet() : ref;
    296383
    297                 // phase 1: Parse nodes and read in raw segments and ways
     384                // phase 1: Parse nodes and read in raw ways
    298385                osm.new Parser().parse(new InputStreamReader(source, "UTF-8"));
    299386                if (pleaseWaitDlg != null) {
     
    305392
    306393                try {
    307                         osm.createSegments();
    308394                        osm.createWays();
     395                        osm.createRelations();
    309396                } catch (NumberFormatException e) {
    310397                        e.printStackTrace();
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/OsmServerReader.java

    r4437 r4464  
    3030         */
    3131        protected InputStream getInputStream(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws IOException {
    32                 String version = Main.pref.get("osm-server.version", "0.4");
     32                String version = Main.pref.get("osm-server.version", "0.5");
    3333                urlStr = Main.pref.get("osm-server.url")+"/"+version+"/" + urlStr;
    3434                System.out.println("download: "+urlStr);
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/OsmServerWriter.java

    r4437 r4464  
    1717
    1818import org.openstreetmap.josm.Main;
     19import org.openstreetmap.josm.data.osm.Relation;
    1920import org.openstreetmap.josm.data.osm.Node;
    2021import org.openstreetmap.josm.data.osm.OsmPrimitive;
    21 import org.openstreetmap.josm.data.osm.Segment;
    2222import org.openstreetmap.josm.data.osm.Way;
    2323import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
     
    9696
    9797        /**
    98          * Upload a segment (without the nodes).
    99          */
    100         public void visit(Segment ls) {
    101                 if (ls.id == 0 && !ls.deleted && ls.get("created_by") == null) {
    102                         ls.put("created_by", "JOSM");
    103                         sendRequest("PUT", "segment", ls, true);
    104                 } else if (ls.deleted) {
    105                         sendRequest("DELETE", "segment", ls, false);
    106                 } else {
    107                         sendRequest("PUT", "segment", ls, true);
    108                 }
    109                 processed.add(ls);
    110         }
    111 
    112         /**
    113          * Upload a whole way with the complete segment id list.
     98         * Upload a whole way with the complete node id list.
    11499         */
    115100        public void visit(Way w) {
     
    125110        }
    126111
     112        /**
     113         * Upload an relation with all members.
     114         */
     115        public void visit(Relation e) {
     116                if (e.id == 0 && !e.deleted && e.get("created_by") == null) {
     117                        e.put("created_by", "JOSM");
     118                        sendRequest("PUT", "relation", e, true);
     119                } else if (e.deleted) {
     120                        sendRequest("DELETE", "relation", e, false);
     121                } else {
     122                        sendRequest("PUT", "relation", e, true);
     123                }
     124                processed.add(e);
     125        }
    127126        /**
    128127         * Read a long from the input stream and return it.
     
    154153                        OsmPrimitive osm, boolean addBody) {
    155154                try {
    156                         String version = Main.pref.get("osm-server.version", "0.4");
     155                        String version = Main.pref.get("osm-server.version", "0.5");
    157156                        URL url = new URL(
    158157                                        Main.pref.get("osm-server.url") +
    159158                                        "/" + version +
    160159                                        "/" + urlSuffix +
    161                                         "/" + ((version.equals("0.4") && osm.id==0) ? "create":osm.id));
     160                                        "/" + (osm.id==0 ? "create" : osm.id));
    162161                        System.out.println("upload to: "+url);
    163162                        activeConnection = (HttpURLConnection)url.openConnection();
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/OsmWriter.java

    r4437 r4464  
    99import org.openstreetmap.josm.data.osm.DataSet;
    1010import org.openstreetmap.josm.data.osm.DataSource;
     11import org.openstreetmap.josm.data.osm.Relation;
     12import org.openstreetmap.josm.data.osm.RelationMember;
    1113import org.openstreetmap.josm.data.osm.Node;
    1214import org.openstreetmap.josm.data.osm.OsmPrimitive;
    13 import org.openstreetmap.josm.data.osm.Segment;
    1415import org.openstreetmap.josm.data.osm.Way;
    1516import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    3738                public void header(PrintWriter out) {
    3839                        out.print("<osm version='");
    39                         out.print(Main.pref.get("osm-server.version", "0.4"));
     40                        out.print(Main.pref.get("osm-server.version", "0.5"));
    4041                        out.println("' generator='JOSM'>");
    4142                }
     
    4445                }
    4546        }
     47       
     48        // simple helper to write the object's class to the out stream
     49        private Visitor typeWriteVisitor = new Visitor() {
     50                public void visit(Node n) { out.print("node"); }
     51                public void visit(Way w) { out.print("way"); }
     52                public void visit(Relation e) { out.print("relation"); }
     53        };
    4654       
    4755        /**
     
    6977                                if (shouldWrite(n))
    7078                                        writer.visit(n);
    71                         for (Segment ls : ds.segments)
    72                                 if (shouldWrite(ls))
    73                                         writer.visit(ls);
    7479                        for (Way w : ds.ways)
    7580                                if (shouldWrite(w))
    7681                                        writer.visit(w);
     82                        for (Relation e : ds.relations)
     83                                if (shouldWrite(e))
     84                                        writer.visit(e);
    7785        }
    7886
     
    123131        }
    124132
    125         public void visit(Segment ls) {
    126                 if (ls.incomplete)
    127                         return; // Do not write an incomplete segment
    128                 addCommon(ls, "segment");
    129                 out.print(" from='"+getUsedId(ls.from)+"' to='"+getUsedId(ls.to)+"'");
    130                 addTags(ls, "segment", true);
    131         }
    132 
    133133        public void visit(Way w) {
    134134                addCommon(w, "way");
    135135                out.println(">");
    136                 for (Segment ls : w.segments)
    137                         out.println("    <seg id='"+getUsedId(ls)+"' />");
     136                for (Node n : w.nodes)
     137                        out.println("    <nd ref='"+getUsedId(n)+"' />");
    138138                addTags(w, "way", false);
    139139        }
     140
     141        public void visit(Relation e) {
     142                addCommon(e, "relation");
     143                out.println(">");
     144                for (RelationMember em : e.members) {
     145                        out.print("    <member type='");
     146                        em.member.visit(typeWriteVisitor);
     147                        out.println("' ref='"+getUsedId(em.member)+"' role='" +
     148                                XmlWriter.encode(em.role) + "' />");
     149                }
     150                addTags(e, "relation", false);
     151        }
     152       
    140153
    141154        /**
  • applications/editors/josm/core_0.5/src/org/openstreetmap/josm/io/XmlWriter.java

    r4437 r4464  
    6767        }
    6868
    69 
    70 
    7169        /**
    7270         * The output writer to save the values to.
Note: See TracChangeset for help on using the changeset viewer.