source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeSourceBuildingVisitor.java@ 15418

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

fix #14253 - Highlight affected relation members in role validation warnings

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.visitor;
3
4import java.util.ArrayList;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8import java.util.stream.Collectors;
9
10import org.openstreetmap.josm.data.osm.DataSet;
11import org.openstreetmap.josm.data.osm.Node;
12import org.openstreetmap.josm.data.osm.NodeData;
13import org.openstreetmap.josm.data.osm.OsmPrimitive;
14import org.openstreetmap.josm.data.osm.PrimitiveData;
15import org.openstreetmap.josm.data.osm.Relation;
16import org.openstreetmap.josm.data.osm.RelationData;
17import org.openstreetmap.josm.data.osm.RelationMember;
18import org.openstreetmap.josm.data.osm.RelationMemberData;
19import org.openstreetmap.josm.data.osm.Way;
20import org.openstreetmap.josm.data.osm.WayData;
21import org.openstreetmap.josm.tools.CheckParameterUtil;
22
23/**
24 * MergeSourceBuildingVisitor helps to build the "hull" of a collection of {@link OsmPrimitive}s
25 * which shall be merged into another layer. The "hull" is slightly bigger than the original
26 * collection. It includes, for instance the nodes of a way in the original collection even though
27 * these nodes might not be present explicitly in the original collection. The "hull" also includes
28 * incomplete {@link OsmPrimitive}s which are referred to by relations in the original collection. And
29 * it turns {@link OsmPrimitive} referred to by {@link Relation}s in the original collection into
30 * incomplete {@link OsmPrimitive}s in the "hull", if they are not themselves present in the original collection.
31 * @since 1891
32 */
33public class MergeSourceBuildingVisitor implements OsmPrimitiveVisitor {
34 private final DataSet selectionBase;
35 private final DataSet hull;
36 private final Map<OsmPrimitive, PrimitiveData> mappedPrimitives;
37
38 /**
39 * Creates the visitor. The visitor starts to build the "hull" from
40 * the currently selected primitives in the dataset <code>selectionBase</code>,
41 * i.e. from {@link DataSet#getSelected()}.
42 *
43 * @param selectionBase the dataset. Must not be null.
44 * @throws IllegalArgumentException if selectionBase is null
45 */
46 public MergeSourceBuildingVisitor(DataSet selectionBase) {
47 CheckParameterUtil.ensureParameterNotNull(selectionBase, "selectionBase");
48 this.selectionBase = selectionBase;
49 this.hull = new DataSet();
50 this.mappedPrimitives = new HashMap<>();
51 }
52
53 protected boolean isInSelectionBase(OsmPrimitive primitive) {
54 return selectionBase.getAllSelected().contains(primitive);
55 }
56
57 protected boolean isAlreadyRemembered(OsmPrimitive primitive) {
58 return mappedPrimitives.containsKey(primitive);
59 }
60
61 /**
62 * Remebers a node in the "hull"
63 *
64 * @param n the node
65 */
66 protected void rememberNode(Node n) {
67 if (isAlreadyRemembered(n))
68 return;
69 mappedPrimitives.put(n, n.save());
70 }
71
72 /**
73 * remembers a way in the hull
74 *
75 * @param w the way
76 */
77 protected void rememberWay(Way w) {
78 if (isAlreadyRemembered(w))
79 return;
80 WayData clone = w.save();
81 List<Long> newNodes = new ArrayList<>(w.getNodesCount());
82 for (Node n: w.getNodes()) {
83 newNodes.add(mappedPrimitives.get(n).getUniqueId());
84 }
85 clone.setNodeIds(newNodes);
86 mappedPrimitives.put(w, clone);
87 }
88
89 /**
90 * Remembers a relation in the hull
91 *
92 * @param r the relation
93 */
94 protected void rememberRelation(Relation r) {
95 RelationData clone;
96 if (isAlreadyRemembered(r)) {
97 clone = (RelationData) mappedPrimitives.get(r);
98 } else {
99 clone = r.save();
100 mappedPrimitives.put(r, clone);
101 }
102
103 clone.setMembers(r.getMembers().stream()
104 .map(m -> new RelationMemberData(m.getRole(), mappedPrimitives.get(m.getMember())))
105 .collect(Collectors.toList()));
106 }
107
108 protected void rememberRelationPartial(Relation r) {
109 if (isAlreadyRemembered(r))
110 return;
111 RelationData clone = r.save();
112 clone.getMembers().clear();
113 mappedPrimitives.put(r, clone);
114 }
115
116 protected void rememberIncomplete(OsmPrimitive primitive) {
117 if (isAlreadyRemembered(primitive))
118 return;
119 PrimitiveData clone = primitive.save();
120 clone.setIncomplete(true);
121 mappedPrimitives.put(primitive, clone);
122 }
123
124 @Override
125 public void visit(Node n) {
126 rememberNode(n);
127 }
128
129 @Override
130 public void visit(Way w) {
131 // remember all nodes this way refers to ...
132 for (Node n: w.getNodes()) {
133 n.accept(this);
134 }
135 // ... and the way itself
136 rememberWay(w);
137 }
138
139 @Override
140 public void visit(Relation r) {
141 // first, remember all primitives members refer to (only if necessary, see below)
142 rememberRelationPartial(r);
143 for (RelationMember member: r.getMembers()) {
144 if (isAlreadyRemembered(member.getMember())) {
145 // referred primitive already remembered
146 continue;
147 }
148 if (isInSelectionBase(member.getMember()) || member.getMember().isNew()) {
149 member.getMember().accept(this);
150 } else {
151 rememberIncomplete(member.getMember());
152 }
153 }
154 rememberRelation(r);
155 }
156
157 protected void buildHull() {
158 // Create all primitives first
159 for (PrimitiveData primitive: mappedPrimitives.values()) {
160 OsmPrimitive newPrimitive = hull.getPrimitiveById(primitive);
161 boolean created = newPrimitive == null;
162 if (created) {
163 newPrimitive = primitive.getType().newInstance(primitive.getUniqueId(), true);
164 }
165 if (newPrimitive instanceof Node && !primitive.isIncomplete()) {
166 newPrimitive.load(primitive);
167 }
168 if (created) {
169 hull.addPrimitive(newPrimitive);
170 }
171 }
172 // Then ways and relations
173 for (PrimitiveData primitive : mappedPrimitives.values()) {
174 if (!(primitive instanceof NodeData) && !primitive.isIncomplete()) {
175 hull.getPrimitiveById(primitive).load(primitive);
176 }
177 }
178 }
179
180 /**
181 * Builds and returns the "hull".
182 * @return the "hull" data set
183 */
184 public DataSet build() {
185 for (OsmPrimitive primitive: selectionBase.getAllSelected()) {
186 primitive.accept(this);
187 }
188 buildHull();
189 return hull;
190 }
191}
Note: See TracBrowser for help on using the repository browser.