Changeset 1690 in josm for trunk/src/org/openstreetmap/josm/data
- Timestamp:
- 2009-06-23T22:03:37+02:00 (15 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/data/osm
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r1677 r1690 8 8 import java.util.HashSet; 9 9 import java.util.HashMap; 10 import java.util.Iterator; 10 11 import java.util.LinkedList; 11 12 import java.util.List; … … 80 81 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>(); 81 82 for (OsmPrimitive osm : allPrimitives()) 82 if ( !osm.deleted) {83 if (osm.visible && !osm.deleted) { 83 84 o.add(osm); 84 85 } … … 89 90 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>(); 90 91 for (OsmPrimitive osm : allPrimitives()) 91 if ( !osm.deleted && !osm.incomplete) {92 if (osm.visible && !osm.deleted && !osm.incomplete) { 92 93 o.add(osm); 93 94 } … … 98 99 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>(); 99 100 for (OsmPrimitive osm : allPrimitives()) 100 if ( !osm.deleted && !osm.incomplete && !(osm instanceof Relation)) {101 if (osm.visible && !osm.deleted && !osm.incomplete && !(osm instanceof Relation)) { 101 102 o.add(osm); 102 103 } … … 311 312 return ret; 312 313 } 314 315 protected void deleteWay(Way way) { 316 way.nodes.clear(); 317 way.delete(true); 318 } 319 320 /** 321 * removes all references from ways in this dataset to a particular node 322 * 323 * @param node the node 324 */ 325 public void unlinkNodeFromWays(Node node) { 326 for (Way way: ways) { 327 if (way.nodes.contains(node)) { 328 way.nodes.remove(node); 329 if (way.nodes.size() < 2) { 330 deleteWay(way); 331 } 332 } 333 } 334 } 335 336 /** 337 * removes all references from relations in this dataset to this primitive 338 * 339 * @param primitive the primitive 340 */ 341 public void unlinkPrimitiveFromRelations(OsmPrimitive primitive) { 342 for (Relation relation : relations) { 343 Iterator<RelationMember> it = relation.members.iterator(); 344 while(it.hasNext()) { 345 RelationMember member = it.next(); 346 if (member.member.equals(primitive)) { 347 it.remove(); 348 } 349 } 350 } 351 } 352 353 /** 354 * removes all references from from other primitives to the 355 * referenced primitive 356 * 357 * @param referencedPrimitive the referenced primitive 358 */ 359 public void unlinkReferencesToPrimitive(OsmPrimitive referencedPrimitive) { 360 if (referencedPrimitive instanceof Node) { 361 unlinkNodeFromWays((Node)referencedPrimitive); 362 unlinkPrimitiveFromRelations(referencedPrimitive); 363 } else { 364 unlinkPrimitiveFromRelations(referencedPrimitive); 365 } 366 } 313 367 } -
trunk/src/org/openstreetmap/josm/data/osm/Node.java
r1640 r1690 31 31 32 32 public final void setEastNorth(EastNorth eastNorth) { 33 this.eastNorth = eastNorth;34 this.coor = Main.proj.eastNorth2latlon(eastNorth);33 this.eastNorth = eastNorth; 34 this.coor = Main.proj.eastNorth2latlon(eastNorth); 35 35 } 36 36 … … 87 87 } 88 88 89 /** 90 * @deprecated 91 * @see #hasEqualSemanticAttributes(OsmPrimitive) 92 * @see #hasEqualTechnicalAttributes(OsmPrimitive) 93 */ 94 @Deprecated 89 95 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 90 96 if (osm instanceof Node) { … … 99 105 } 100 106 107 @Override 108 public boolean hasEqualSemanticAttributes(OsmPrimitive other) { 109 if (other == null || ! (other instanceof Node) ) 110 return false; 111 if (! super.hasEqualSemanticAttributes(other)) 112 return false; 113 Node n = (Node)other; 114 if (coor == null && n.coor == null) 115 return true; 116 else if (coor != null && n.coor != null) 117 return coor.equals(n.coor); 118 else 119 return false; 120 } 121 101 122 public int compareTo(OsmPrimitive o) { 102 123 return o instanceof Node ? Long.valueOf(id).compareTo(o.id) : 1; 103 124 } 104 125 126 @Override 105 127 public String getName() { 106 128 String name; … … 109 131 } else { 110 132 name = get("name"); 111 if (name == null) 133 if (name == null) { 112 134 name = id == 0 ? tr("node") : ""+id; 135 } 113 136 name += " (" + coor.latToString(mCord) + ", " + coor.lonToString(mCord) + ")"; 114 137 } -
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r1530 r1690 43 43 public void putError(String text, Boolean isError) 44 44 { 45 if(errors == null) 45 if(errors == null) { 46 46 errors = new ArrayList<String>(); 47 } 47 48 String s = isError ? tr("Error: {0}", text) : tr("Warning: {0}", text); 48 49 errors.add(s); … … 91 92 * Visibility status as specified by the server. The visible attribute was 92 93 * introduced with the 0.4 API to be able to communicate deleted objects 93 * (they will have visible=false). Currently JOSM does never deal with 94 * these, so this is really for future use only. 94 * (they will have visible=false). 95 95 */ 96 96 public boolean visible = true; … … 195 195 @Override public boolean equals(Object obj) { 196 196 if (id == 0) return obj == this; 197 if (obj instanceof OsmPrimitive) { // not null too197 if (obj instanceof OsmPrimitive) 198 198 return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass(); 199 }200 199 return false; 201 200 } … … 226 225 */ 227 226 public final void put(String key, String value) { 228 if (value == null) 227 if (value == null) { 229 228 remove(key); 230 else {231 if (keys == null) 229 } else { 230 if (keys == null) { 232 231 keys = new HashMap<String, String>(); 232 } 233 233 keys.put(key, value); 234 234 } … … 241 241 if (keys != null) { 242 242 keys.remove(key); 243 if (keys.isEmpty()) 243 if (keys.isEmpty()) { 244 244 keys = null; 245 } 245 246 } 246 247 mappaintStyle = null; … … 280 281 version = osm.version; 281 282 incomplete = osm.incomplete; 283 visible = osm.visible; 282 284 clearCached(); 283 285 clearErrors(); … … 288 290 * but for the whole object (for conflict resolving) 289 291 * @param semanticOnly if <code>true</code>, modified flag and timestamp are not compared 290 */ 292 * 293 * @deprecated 294 * @see #hasEqualSemanticAttributes(OsmPrimitive) 295 * @see #hasEqualTechnicalAttributes(OsmPrimitive) 296 */ 297 @Deprecated 291 298 public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 292 299 return id == osm.id 293 300 && incomplete == osm.incomplete 294 301 && deleted == osm.deleted 295 && (semanticOnly || (modified == osm.modified 296 && timestamp == osm.timestamp 297 && version == osm.version 298 && visible == osm.visible 299 && (user == null ? osm.user==null : user==osm.user))) 302 && (semanticOnly || ( 303 modified == osm.modified 304 && timestamp == osm.timestamp 305 && version == osm.version 306 && visible == osm.visible 307 && (user == null ? osm.user==null : user==osm.user)) 308 ) 300 309 && (keys == null ? osm.keys==null : keys.equals(osm.keys)); 310 } 311 312 /** 313 * Replies true if this primitive and other are equal with respect to their 314 * semantic attributes. 315 * <ol> 316 * <li>equal id</ol> 317 * <li>both are complete or both are incomplete</li> 318 * <li>both have the same tags</li> 319 * </ol> 320 * @param other 321 * @return true if this primitive and other are equal with respect to their 322 * semantic attributes. 323 */ 324 public boolean hasEqualSemanticAttributes(OsmPrimitive other) { 325 if (id != other.id) 326 return false; 327 if (incomplete && ! other.incomplete || !incomplete && other.incomplete) 328 return false; 329 return (keys == null ? other.keys==null : keys.equals(other.keys)); 330 } 331 332 /** 333 * Replies true if this primitive and other are equal with respect to their 334 * technical attributes. The attributes: 335 * <ol> 336 * <li>deleted</ol> 337 * <li>modified</ol> 338 * <li>timestamp</ol> 339 * <li>version</ol> 340 * <li>visible</ol> 341 * <li>user</ol> 342 * </ol> 343 * have to be equal 344 * @param other the other primitive 345 * @return true if this primitive and other are equal with respect to their 346 * technical attributes 347 */ 348 public boolean hasEqualTechnicalAttributes(OsmPrimitive other) { 349 if (other == null) return false; 350 351 return 352 deleted == other.deleted 353 && modified == other.modified 354 && timestamp == other.timestamp 355 && version == other.version 356 && visible == other.visible 357 && (user == null ? other.user==null : user==other.user); 301 358 } 302 359 … … 312 369 if (keys != null) { 313 370 for (Entry<String,String> e : keys.entrySet()) { 314 if (!uninteresting.contains(e.getKey())) {371 if (!uninteresting.contains(e.getKey())) 315 372 return true; 316 }317 373 } 318 374 } … … 327 383 if (keys != null) { 328 384 for (Entry<String,String> e : keys.entrySet()) { 329 if (directionKeys.contains(e.getKey())) {385 if (directionKeys.contains(e.getKey())) 330 386 return true; 331 }332 387 } 333 388 } -
trunk/src/org/openstreetmap/josm/data/osm/Relation.java
r1677 r1690 70 70 } 71 71 72 @Deprecated 72 73 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 73 74 return osm instanceof Relation ? super.realEqual(osm, semanticOnly) && members.equals(((Relation)osm).members) : false; 75 } 76 77 @Override 78 public boolean hasEqualSemanticAttributes(OsmPrimitive other) { 79 if (other == null || ! (other instanceof Relation) ) 80 return false; 81 if (! super.hasEqualSemanticAttributes(other)) 82 return false; 83 Relation r = (Relation)other; 84 return members.equals(r.members); 74 85 } 75 86 -
trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java
r1169 r1690 33 33 34 34 @Override public boolean equals(Object other) { 35 if ( !(other instanceof RelationMember)) return false;35 if (other == null || !(other instanceof RelationMember)) return false; 36 36 RelationMember otherMember = (RelationMember) other; 37 37 return otherMember.role.equals(role) && otherMember.member.equals(member); -
trunk/src/org/openstreetmap/josm/data/osm/Way.java
r1677 r1690 39 39 public void visitNodes(Visitor v) { 40 40 if (incomplete) return; 41 for (Node n : this.nodes) 41 for (Node n : this.nodes) { 42 42 v.visit(n); 43 } 43 44 } 44 45 … … 100 101 } 101 102 103 @Deprecated 102 104 @Override public boolean realEqual(OsmPrimitive osm, boolean semanticOnly) { 103 105 return osm instanceof Way ? super.realEqual(osm, semanticOnly) && nodes.equals(((Way)osm).nodes) : false; 106 } 107 108 @Override 109 public boolean hasEqualSemanticAttributes(OsmPrimitive other) { 110 if (other == null || ! (other instanceof Way) ) 111 return false; 112 if (! super.hasEqualSemanticAttributes(other)) 113 return false; 114 Way w = (Way)other; 115 return nodes.equals(w.nodes); 104 116 } 105 117 … … 110 122 } 111 123 124 @Override 112 125 public String getName() { 113 126 String name; … … 116 129 } else { 117 130 name = get("name"); 118 if (name == null) name = get("ref"); 131 if (name == null) { 132 name = get("ref"); 133 } 119 134 if (name == null) { 120 135 name = 121 136 (get("highway") != null) ? tr("highway") : 122 (get("railway") != null) ? tr("railway") :123 (get("waterway") != null) ? tr("waterway") :124 (get("landuse") != null) ? tr("landuse") : "";137 (get("railway") != null) ? tr("railway") : 138 (get("waterway") != null) ? tr("waterway") : 139 (get("landuse") != null) ? tr("landuse") : ""; 125 140 } 126 141 … … 128 143 String nodes = trn("{0} node", "{0} nodes", nodesNo, nodesNo); 129 144 name += (name.length() > 0) ? " ("+nodes+")" : nodes; 130 if(errors != null) 145 if(errors != null) { 131 146 name = "*"+name; 147 } 132 148 } 133 149 return name; … … 138 154 boolean closed = (lastNode() == n && firstNode() == n); 139 155 int i; 140 while ((i = nodes.indexOf(n)) >= 0) 156 while ((i = nodes.indexOf(n)) >= 0) { 141 157 nodes.remove(i); 158 } 142 159 i = nodes.size(); 143 if (closed && i > 2) // close again160 if (closed && i > 2) { 144 161 addNode(firstNode()); 145 // prevent closed ways with less than 3 different nodes 146 else if (i >= 2 && i <= 3 && nodes.get(0) == nodes.get(i-1)) 162 } else if (i >= 2 && i <= 3 && nodes.get(0) == nodes.get(i-1)) { 147 163 nodes.remove(i-1); 164 } 148 165 } 149 166 … … 151 168 if (incomplete) return; 152 169 for(OsmPrimitive p : selection) { 153 if (p instanceof Node) {154 removeNode((Node)p);155 }156 }170 if (p instanceof Node) { 171 removeNode((Node)p); 172 } 173 } 157 174 } 158 175 -
trunk/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
r1677 r1690 2 2 package org.openstreetmap.josm.data.osm.visitor; 3 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 4 6 import java.util.Collection; 5 import java.util.Date;6 7 import java.util.HashMap; 7 8 import java.util.Iterator; 8 9 import java.util.LinkedList; 9 10 import java.util.Map; 11 import java.util.logging.Logger; 10 12 11 13 import org.openstreetmap.josm.data.osm.DataSet; 14 import org.openstreetmap.josm.data.osm.Node; 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 12 16 import org.openstreetmap.josm.data.osm.Relation; 13 17 import org.openstreetmap.josm.data.osm.RelationMember; 14 import org.openstreetmap.josm.data.osm.Node;15 import org.openstreetmap.josm.data.osm.OsmPrimitive;16 18 import org.openstreetmap.josm.data.osm.Way; 17 19 18 20 /** 19 * A visitor that get a data set at construction time and mergeevery visited object21 * A visitor that gets a data set at construction time and merges every visited object 20 22 * into it. 21 23 * 22 24 * @author imi 25 * @author Gubaer 23 26 */ 24 27 public class MergeVisitor extends AbstractVisitor { 28 private static Logger logger = Logger.getLogger(MergeVisitor.class.getName()); 25 29 26 30 /** … … 28 32 * round than merged) 29 33 */ 30 p ublic Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();31 32 private final DataSet ds;33 private final DataSet mergeds;34 private Map<OsmPrimitive, OsmPrimitive> conflicts; 35 36 private final DataSet myDataSet; 37 private final DataSet theirDataSet; 34 38 35 39 private final HashMap<Long, Node> nodeshash = new HashMap<Long, Node>(); … … 42 46 * in ds.nodes instead. 43 47 */ 44 private final Map<OsmPrimitive, OsmPrimitive> merged 45 = new HashMap<OsmPrimitive, OsmPrimitive>(); 46 47 public MergeVisitor(DataSet ds, DataSet mergeds) { 48 this.ds = ds; 49 this.mergeds = mergeds; 50 51 for (Node n : ds.nodes) if (n.id != 0) nodeshash.put(n.id, n); 52 for (Way w : ds.ways) if (w.id != 0) wayshash.put(w.id, w); 53 for (Relation r : ds.relations) if (r.id != 0) relshash.put(r.id, r); 54 } 55 56 private <P extends OsmPrimitive> void genMerge(P other, 57 Collection<P> myprims, Collection<P> mergeprims, 58 HashMap<Long, P> primhash) { 59 // 1. Try to find an identical prim with the same id. 60 if (mergeById(myprims, primhash, other)) 61 return; 62 63 // 2. Try to find a prim we can merge with the prim from the other ds. 64 for (P my : myprims) { 65 // LinkedList.contains calls equal, and OsmPrimitive.equal 66 // compares just the id. 67 if (match(my, other) && !mergeprims.contains(my)) { 68 merged.put(other, my); 69 mergeCommon(my, other); 48 private Map<OsmPrimitive, OsmPrimitive> merged; 49 50 /** 51 * constructor 52 * 53 * The visitor will merge <code>theirDataSet</code> onto <code>myDataSet</code> 54 * 55 * @param myDataSet dataset with my primitives 56 * @param theirDataSet dataset with their primitives. 57 */ 58 public MergeVisitor(DataSet myDataSet, DataSet theirDataSet) { 59 this.myDataSet = myDataSet; 60 this.theirDataSet = theirDataSet; 61 62 for (Node n : myDataSet.nodes) if (n.id != 0) { 63 nodeshash.put(n.id, n); 64 } 65 for (Way w : myDataSet.ways) if (w.id != 0) { 66 wayshash.put(w.id, w); 67 } 68 for (Relation r : myDataSet.relations) if (r.id != 0) { 69 relshash.put(r.id, r); 70 } 71 conflicts = new HashMap<OsmPrimitive, OsmPrimitive>(); 72 merged = new HashMap<OsmPrimitive, OsmPrimitive>(); 73 } 74 75 /** 76 * Merges a primitive <code>other</code> of type <P> onto my primitives. 77 * 78 * If other.id != 0 it tries to merge it with an corresponding primitive from 79 * my dataset with the same id. If this is not possible a conflict is remembered 80 * in {@see #conflicts}. 81 * 82 * If other.id == 0 it tries to find a primitive in my dataset with id == 0 which 83 * is semantically equal. If it finds one it merges its technical attributes onto 84 * my primitive. 85 * 86 * @param <P> the type of the other primitive 87 * @param other the other primitive 88 * @param myPrimitives the collection of my relevant primitives (i.e. only my 89 * primitives of the same type) 90 * @param otherPrimitives the collection of the other primitives 91 * @param primitivesWithDefinedIds the collection of my primitives with an 92 * assigned id (i.e. id != 0) 93 */ 94 protected <P extends OsmPrimitive> void mergePrimitive(P other, 95 Collection<P> myPrimitives, Collection<P> otherPrimitives, 96 HashMap<Long, P> primitivesWithDefinedIds) { 97 98 if (other.id > 0 ) { 99 // try to merge onto a matching primitive with the same 100 // defined id 101 // 102 if (mergeById(myPrimitives, primitivesWithDefinedIds, other)) 70 103 return; 71 } 72 } 73 74 // 3. No idea how to merge that. Simply add it unchanged. 75 myprims.add(other); 104 } else { 105 // try to merge onto a primitive with which has no id assigned 106 // yet but which is equal in its semantic attributes 107 // 108 for (P my : myPrimitives) { 109 if (my.id >0 ) { 110 continue; 111 } 112 if (my.hasEqualSemanticAttributes(other)) { 113 // copy the technical attributes from their 114 // version 115 if (other.deleted) { 116 myDataSet.unlinkReferencesToPrimitive(my); 117 my.delete(true); 118 } 119 my.visible = other.visible; 120 my.user = other.user; 121 my.setTimestamp(other.getTimestamp()); 122 my.modified = other.modified; 123 merged.put(other, my); 124 return; 125 } 126 } 127 } 128 // If we get here we didn't find a suitable primitive in 129 // my dataset. Just add other to my dataset. 130 // 131 myPrimitives.add(other); 76 132 } 77 133 78 134 public void visit(Node other) { 79 genMerge(other, ds.nodes, mergeds.nodes, nodeshash);135 mergePrimitive(other, myDataSet.nodes, theirDataSet.nodes, nodeshash); 80 136 } 81 137 82 138 public void visit(Way other) { 83 139 fixWay(other); 84 genMerge(other, ds.ways, mergeds.ways, wayshash);140 mergePrimitive(other, myDataSet.ways, theirDataSet.ways, wayshash); 85 141 } 86 142 87 143 public void visit(Relation other) { 88 144 fixRelation(other); 89 genMerge(other, ds.relations, mergeds.relations, relshash);145 mergePrimitive(other, myDataSet.relations, theirDataSet.relations, relshash); 90 146 } 91 147 … … 95 151 */ 96 152 public void fixReferences() { 97 for (Way w : ds.ways) fixWay(w); 98 for (Relation r : ds.relations) fixRelation(r); 153 for (Way w : myDataSet.ways) { 154 fixWay(w); 155 } 156 for (Relation r : myDataSet.relations) { 157 fixRelation(r); 158 } 99 159 for (OsmPrimitive osm : conflicts.values()) 100 if (osm instanceof Way) 160 if (osm instanceof Way) { 101 161 fixWay((Way)osm); 102 else if (osm instanceof Relation)162 } else if (osm instanceof Relation) { 103 163 fixRelation((Relation) osm); 164 } 104 165 } 105 166 … … 110 171 Node otherN = (Node) merged.get(n); 111 172 newNodes.add(otherN == null ? n : otherN); 112 if (otherN != null) 173 if (otherN != null) { 113 174 replacedSomething = true; 175 } 114 176 } 115 177 if (replacedSomething) { … … 139 201 } 140 202 141 private static <P extends OsmPrimitive> boolean match(P p1, P p2) {142 if ((p1.id == 0 || p2.id == 0) && !p1.incomplete && !p2.incomplete) {143 return realMatch(p1, p2);144 }145 return p1.id == p2.id;146 }147 148 /** @return true if the prims have pretty much the same data, i.e. the149 * same position, the same members, ...150 */151 // Java cannot dispatch on generics...152 private static boolean realMatch(OsmPrimitive p1, OsmPrimitive p2) {153 if (p1 instanceof Node && p2 instanceof Node) {154 return realMatch((Node) p1, (Node) p2);155 } else if (p1 instanceof Way && p2 instanceof Way) {156 return realMatch((Way) p1, (Way) p2);157 } else if (p1 instanceof Relation && p2 instanceof Relation) {158 return realMatch((Relation) p1, (Relation) p2);159 } else {160 throw new RuntimeException("arguments have unknown type");161 }162 }163 164 private static boolean realMatch(Node n1, Node n2) {165 return n1.getCoor().equalsEpsilon(n2.getCoor());166 }167 168 private static boolean realMatch(Way w1, Way w2) {169 if (w1.nodes.size() != w2.nodes.size())170 return false;171 Iterator<Node> it = w1.nodes.iterator();172 for (Node n : w2.nodes)173 if (!match(n, it.next()))174 return false;175 return true;176 }177 178 private static boolean realMatch(Relation w1, Relation w2) {179 // FIXME this is not perfect yet...180 if (w1.members.size() != w2.members.size())181 return false;182 for (RelationMember em : w1.members) {183 if (!w2.members.contains(em)) {184 return false;185 }186 }187 return true;188 }189 190 /**191 * Merge the common parts of an osm primitive.192 * @param my The object, the information gets merged into193 * @param other The object, the information gets merged from194 */195 private void mergeCommon(OsmPrimitive my, OsmPrimitive other) {196 if (other.deleted)197 my.delete(true);198 if (my.id == 0 || !my.modified || other.modified) {199 if (my.id == 0 && other.id != 0) {200 my.id = other.id;201 my.modified = other.modified; // match a new node202 my.version = other.version;203 } else if (my.id != 0 && other.id != 0 && other.modified)204 my.modified = true;205 }206 if (other.keys == null)207 return;208 if (my.keySet().containsAll(other.keys.keySet()))209 return;210 if (my.keys == null)211 my.keys = other.keys;212 else213 my.keys.putAll(other.keys);214 215 my.modified = true;216 }217 218 203 /** 219 204 * Tries to merge a primitive <code>other</code> into an existing primitive with the same id. 220 205 * 221 206 * @param myPrimitives the complete set of my primitives (potential merge targets) 222 * @param myPrimitivesWith IDthe map of primitives (potential merge targets) with an id <> 0, for faster lookup207 * @param myPrimitivesWithDefinedIds the map of primitives (potential merge targets) with an id <> 0, for faster lookup 223 208 * by id. Key is the id, value the primitive with the given value. myPrimitives.valueSet() is a 224 209 * subset of primitives. 225 * @param other the other primitive which is to be merged with a primitive in primitives if possible210 * @param other the other primitive which is to be merged onto a primitive in my primitives 226 211 * @return true, if this method was able to merge <code>other</code> with an existing node; false, otherwise 227 212 */ 228 213 private <P extends OsmPrimitive> boolean mergeById( 229 Collection<P> myPrimitives, HashMap<Long, P> myPrimitivesWith ID, P other) {214 Collection<P> myPrimitives, HashMap<Long, P> myPrimitivesWithDefinedIds, P other) { 230 215 231 216 // merge other into an existing primitive with the same id, if possible 232 217 // 233 if (myPrimitivesWithID.containsKey(other.id)) { 234 P my = myPrimitivesWithID.get(other.id); 235 if (my.realEqual(other, true /* compare semantic fields only */)) { 236 // make sure the merge target becomes the higher version number 237 // and the later timestamp 238 // 239 my.version = Math.max(other.version, my.version); 240 if (other.getTimestamp().after(my.getTimestamp())) { 241 my.setTimestamp(other.getTimestamp()); 218 if (myPrimitivesWithDefinedIds.containsKey(other.id)) { 219 P my = myPrimitivesWithDefinedIds.get(other.id); 220 if (my.version <= other.version) { 221 if (! my.visible && other.visible) { 222 // should not happen 223 // 224 logger.warning(tr("My primitive with id {0} and version {1} is visible although " 225 + "their primitive with lower version {2} is not visible. " 226 + "Can't deal with this inconsistency. Keeping my primitive. ", 227 Long.toString(my.id),Long.toString(my.version), Long.toString(other.version) 228 )); 229 merged.put(other, my); 230 } else if (my.visible && ! other.visible) { 231 // this is always a conflict because the user has to decide whether 232 // he wants to create a clone of its local primitive or whether he 233 // wants to purge my from the local dataset. He can't keep it unchanged 234 // because it was deleted on the server. 235 // 236 conflicts.put(my,other); 237 } else if (! my.modified && other.modified) { 238 // my not modified. We can assume that other is the most recent version. 239 // clone it onto my. But check first, whether other is deleted. if so, 240 // make sure that my is not references anymore in myDataSet. 241 // 242 if (other.deleted) { 243 myDataSet.unlinkReferencesToPrimitive(my); 244 } 245 my.cloneFrom(other); 246 merged.put(other, my); 247 } else if (! my.modified && !other.modified) { 248 // nothing to merge 249 // 250 merged.put(other,my); 251 } else if (my.deleted != other.deleted) { 252 // if we get here my is modified. Differences in deleted state 253 // have to be resolved manually 254 // 255 conflicts.put(my,other); 256 } else if (! my.hasEqualSemanticAttributes(other)) { 257 // my is modified and is not semantically equal with other. Can't automatically 258 // resolve the differences 259 // => create a conflict 260 conflicts.put(my,other); 261 } else { 262 // clone from other, but keep the modified flag. Clone will mainly copy 263 // technical attributes like timestamp or user information. Semantic 264 // attributes should already be equal if we get here. 265 // 266 my.cloneFrom(other); 267 my.modified = true; 268 merged.put(other, my); 242 269 } 270 } else { 271 // my.version > other.version => keep my version 243 272 merged.put(other, my); 244 return true; 245 } 246 } 247 248 // try to merge into one of the existing primitives 249 // 250 for (P my : myPrimitives) { 251 if (my.realEqual(other, false /* compare all fields */)) { 252 merged.put(other, my); 253 return true; // no merge needed. 254 } 255 if (my.realEqual(other, true)) { 256 // they differ in modified/version combination only. Auto-resolve it. 257 merged.put(other, my); 258 if (my.version < other.version) { 259 my.version = other.version; 260 my.modified = other.modified; 261 my.setTimestamp(other.getTimestamp()); 262 } 263 return true; // merge done. 264 } 265 if (my.id == other.id && my.id != 0) { 266 if (my.incomplete || other.incomplete) { 267 if (my.incomplete) { 268 my.cloneFrom(other); 269 } 270 } else if (my.modified && other.modified) { 271 conflicts.put(my, other); 272 } else if (!my.modified && !other.modified) { 273 if (my.version < other.version) { 274 my.cloneFrom(other); 275 } 276 } else if (other.modified) { 277 if (my.version > other.version) { 278 conflicts.put(my, other); 279 } else { 280 my.cloneFrom(other); 281 } 282 } else if (my.modified) { 283 if (my.version < other.version) { 284 conflicts.put(my, other); 285 } 286 } 287 merged.put(other, my); 288 return true; 289 } 273 } 274 return true; 290 275 } 291 276 return false; 292 277 } 278 279 280 /** 281 * Runs the merge operation. Successfully merged {@see OsmPrimitive}s are in 282 * {@see #getMyDataSet()}. 283 * 284 * See {@see #getConflicts()} for a map of conflicts after the merge operation. 285 */ 286 public void merge() { 287 for (final OsmPrimitive primitive : theirDataSet.allPrimitives()) { 288 primitive.visit(this); 289 } 290 fixReferences(); 291 } 292 293 /** 294 * replies my dataset 295 * 296 * @return 297 */ 298 public DataSet getMyDataSet() { 299 return myDataSet; 300 } 301 302 303 /** 304 * replies the map of conflicts 305 * 306 * @return the map of conflicts 307 */ 308 public Map<OsmPrimitive, OsmPrimitive> getConflicts() { 309 return conflicts; 310 } 293 311 }
Note:
See TracChangeset
for help on using the changeset viewer.