source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorter.java@ 7005

Last change on this file since 7005 was 7005, checked in by Don-vip, 10 years ago

see #8465 - use diamond operator where applicable

File size: 6.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.relation.sort;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.Comparator;
8import java.util.LinkedHashMap;
9import java.util.LinkedList;
10import java.util.List;
11import java.util.Map;
12import java.util.Map.Entry;
13
14import org.openstreetmap.josm.data.osm.RelationMember;
15import org.openstreetmap.josm.gui.DefaultNameFormatter;
16import org.openstreetmap.josm.tools.AlphanumComparator;
17
18public class RelationSorter {
19
20 private static interface AdditionalSorter {
21 public boolean acceptsMember(RelationMember m);
22 public List<RelationMember> sortMembers(List<RelationMember> list);
23 }
24
25 private static final Collection<AdditionalSorter> additionalSorters = new ArrayList<>();
26
27 static {
28 // first adequate sorter is used, so order matters
29 additionalSorters.add(new AssociatedStreetRoleStreetSorter());
30 additionalSorters.add(new AssociatedStreetRoleAddressHouseSorter());
31 }
32
33 /**
34 * Class that sorts the {@code street} members of
35 * {@code type=associatedStreet} and {@code type=street} relations.
36 */
37 private static class AssociatedStreetRoleStreetSorter implements AdditionalSorter {
38
39 @Override
40 public boolean acceptsMember(RelationMember m) {
41 return "street".equals(m.getRole());
42 }
43
44 @Override
45 public List<RelationMember> sortMembers(List<RelationMember> list) {
46 return sortMembersByConnectivity(list);
47 }
48 }
49
50 /**
51 * Class that sorts the {@code address} and {@code house} members of
52 * {@code type=associatedStreet} and {@code type=street} relations.
53 */
54 private static class AssociatedStreetRoleAddressHouseSorter implements AdditionalSorter {
55
56 @Override
57 public boolean acceptsMember(RelationMember m) {
58 return "address".equals(m.getRole()) || "house".equals(m.getRole());
59 }
60
61 @Override
62 public List<RelationMember> sortMembers(List<RelationMember> list) {
63 Collections.sort(list, new Comparator<RelationMember>() {
64 @Override
65 public int compare(RelationMember a, RelationMember b) {
66 final int houseNumber = AlphanumComparator.getInstance().compare(
67 a.getMember().get("addr:housenumber"),
68 b.getMember().get("addr:housenumber"));
69 if (houseNumber != 0) {
70 return houseNumber;
71 }
72 final String aDisplayName = a.getMember().getDisplayName(DefaultNameFormatter.getInstance());
73 final String bDisplayName = b.getMember().getDisplayName(DefaultNameFormatter.getInstance());
74 return AlphanumComparator.getInstance().compare(aDisplayName, bDisplayName);
75 }
76 });
77 return list;
78 }
79 }
80
81 /**
82 * Sort a collection of relation members by the way they are linked.
83 *
84 * @param relationMembers collection of relation members
85 * @return sorted collection of relation members
86 */
87 public List<RelationMember> sortMembers(List<RelationMember> relationMembers) {
88 List<RelationMember> newMembers = new ArrayList<>();
89
90 // Sort members with custom mechanisms (relation-dependent)
91 List<RelationMember> defaultMembers = new ArrayList<>(relationMembers.size());
92 // Maps sorter to assigned members for sorting. Use LinkedHashMap to retain order.
93 Map<AdditionalSorter, List<RelationMember>> customMap = new LinkedHashMap<>();
94
95 // Dispatch members to the first adequate sorter
96 for (RelationMember m : relationMembers) {
97 boolean wasAdded = false;
98 for (AdditionalSorter sorter : additionalSorters) {
99 if (sorter.acceptsMember(m)) {
100 List<RelationMember> list;
101 list = customMap.get(sorter);
102 if (list == null) {
103 customMap.put(sorter, list = new LinkedList<>());
104 }
105 list.add(m);
106 wasAdded = true;
107 break;
108 }
109 }
110 if (!wasAdded) {
111 defaultMembers.add(m);
112 }
113 }
114
115 // Sort members and add them to result
116 for (Entry<AdditionalSorter, List<RelationMember>> entry : customMap.entrySet()) {
117 newMembers.addAll(entry.getKey().sortMembers(entry.getValue()));
118 }
119 newMembers.addAll(sortMembersByConnectivity(defaultMembers));
120 return newMembers;
121 }
122
123 public static List<RelationMember> sortMembersByConnectivity(List<RelationMember> defaultMembers) {
124
125 List<RelationMember> newMembers = new ArrayList<>();
126
127 RelationNodeMap map = new RelationNodeMap(defaultMembers);
128 // List of groups of linked members
129 //
130 List<LinkedList<Integer>> allGroups = new ArrayList<>();
131
132 // current group of members that are linked among each other
133 // Two successive members are always linked i.e. have a common node.
134 //
135 LinkedList<Integer> group;
136
137 Integer first;
138 while ((first = map.pop()) != null) {
139 group = new LinkedList<>();
140 group.add(first);
141
142 allGroups.add(group);
143
144 Integer next = first;
145 while ((next = map.popAdjacent(next)) != null) {
146 group.addLast(next);
147 }
148
149 // The first element need not be in front of the list.
150 // So the search goes in both directions
151 //
152 next = first;
153 while ((next = map.popAdjacent(next)) != null) {
154 group.addFirst(next);
155 }
156 }
157
158 for (LinkedList<Integer> tmpGroup : allGroups) {
159 for (Integer p : tmpGroup) {
160 newMembers.add(defaultMembers.get(p));
161 }
162 }
163
164 // Finally, add members that have not been sorted at all
165 for (Integer i : map.getNotSortableMembers()) {
166 newMembers.add(defaultMembers.get(i));
167 }
168
169 return newMembers;
170 }
171
172}
Note: See TracBrowser for help on using the repository browser.