Changeset 30738 in osm for applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java
- Timestamp:
- 2014-10-19T01:27:04+02:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java
r30737 r30738 36 36 37 37 public TheRing( Way source ) { 38 this.source = source;39 segments = new ArrayList<>(1);40 segments.add(new RingSegment(source));38 this.source = source; 39 segments = new ArrayList<>(1); 40 segments.add(new RingSegment(source)); 41 41 } 42 42 43 43 public static boolean areAllOfThoseRings( Collection<Way> ways ) { 44 List<Way> rings = new ArrayList<>();45 for( Way way : ways ) {46 if( way.isClosed() )47 rings.add(way);48 else49 return false;50 }51 if( rings.isEmpty() || ways.size() == 1 )52 return false;53 54 // check for non-containment of rings55 for( int i = 0; i < rings.size() - 1; i++ ) {56 for( int j = i + 1; j < rings.size(); j++ ) {57 PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());58 if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )59 return false;60 }61 }62 63 return true;44 List<Way> rings = new ArrayList<>(); 45 for( Way way : ways ) { 46 if( way.isClosed() ) 47 rings.add(way); 48 else 49 return false; 50 } 51 if( rings.isEmpty() || ways.size() == 1 ) 52 return false; 53 54 // check for non-containment of rings 55 for( int i = 0; i < rings.size() - 1; i++ ) { 56 for( int j = i + 1; j < rings.size(); j++ ) { 57 PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes()); 58 if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST ) 59 return false; 60 } 61 } 62 63 return true; 64 64 } 65 65 … … 69 69 */ 70 70 public static List<Relation> makeManySimpleMultipolygons( Collection<Way> selection, List<Command> commands ) { 71 log("---------------------------------------");72 List<TheRing> rings = new ArrayList<>(selection.size());73 for( Way w : selection )74 rings.add(new TheRing(w));75 for( int i = 0; i < rings.size() - 1; i++ )76 for( int j = i + 1; j < rings.size(); j++ )77 rings.get(i).collide(rings.get(j));78 redistributeSegments(rings);79 List<Relation> relations = new ArrayList<>();80 Map<Relation, Relation> relationCache = new HashMap<>();81 for( TheRing r : rings ) {82 commands.addAll(r.getCommands(relationCache));83 relations.add(r.getRelation());84 }85 updateCommandsWithRelations(commands, relationCache);86 return relations;71 log("---------------------------------------"); 72 List<TheRing> rings = new ArrayList<>(selection.size()); 73 for( Way w : selection ) 74 rings.add(new TheRing(w)); 75 for( int i = 0; i < rings.size() - 1; i++ ) 76 for( int j = i + 1; j < rings.size(); j++ ) 77 rings.get(i).collide(rings.get(j)); 78 redistributeSegments(rings); 79 List<Relation> relations = new ArrayList<>(); 80 Map<Relation, Relation> relationCache = new HashMap<>(); 81 for( TheRing r : rings ) { 82 commands.addAll(r.getCommands(relationCache)); 83 relations.add(r.getRelation()); 84 } 85 updateCommandsWithRelations(commands, relationCache); 86 return relations; 87 87 } 88 88 89 89 public void collide( TheRing other ) { 90 boolean collideNoted = false;91 for( int i = 0; i < segments.size(); i++ ) {92 RingSegment segment1 = segments.get(i);93 if( !segment1.isReference() ) {94 for( int j = 0; j < other.segments.size(); j++ ) {95 RingSegment segment2 = other.segments.get(j);96 if( !segment2.isReference() ) {97 log("Comparing " + segment1 + " and " + segment2);98 Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());99 if( split != null ) {100 if( !collideNoted ) {101 log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");102 collideNoted = true;103 }104 RingSegment segment = splitRingAt(i, split[0], split[1]);105 RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);106 if( !areSegmentsEqual(segment, otherSegment) )107 throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);108 segment.makeReference(otherSegment);109 }110 }111 if( segment1.isReference() )112 break;113 }114 }115 }90 boolean collideNoted = false; 91 for( int i = 0; i < segments.size(); i++ ) { 92 RingSegment segment1 = segments.get(i); 93 if( !segment1.isReference() ) { 94 for( int j = 0; j < other.segments.size(); j++ ) { 95 RingSegment segment2 = other.segments.get(j); 96 if( !segment2.isReference() ) { 97 log("Comparing " + segment1 + " and " + segment2); 98 Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing()); 99 if( split != null ) { 100 if( !collideNoted ) { 101 log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide."); 102 collideNoted = true; 103 } 104 RingSegment segment = splitRingAt(i, split[0], split[1]); 105 RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]); 106 if( !areSegmentsEqual(segment, otherSegment) ) 107 throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment); 108 segment.makeReference(otherSegment); 109 } 110 } 111 if( segment1.isReference() ) 112 break; 113 } 114 } 115 } 116 116 } 117 117 … … 120 120 */ 121 121 public static Node[] getSplitNodes( List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2 ) { 122 int pos = 0;123 while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )124 pos++;125 boolean collideFound = pos == nodes1.size();126 if( pos == 0 && isRing1 ) {127 // rewind a bit128 pos = nodes1.size() - 1;129 while( pos > 0 && nodes2.contains(nodes1.get(pos)) )130 pos--;131 if( pos == 0 && nodes1.size() == nodes2.size() ) {132 JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);133 return null;134 }135 pos = pos == nodes1.size() - 1 ? 0 : pos + 1;136 }137 int firstPos = isRing1 ? pos : nodes1.size();138 while( !collideFound ) {139 log("pos=" + pos);140 int start1 = pos;141 int start2 = nodes2.indexOf(nodes1.get(start1));142 int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);143 int last2 = start2;144 int increment2 = 0;145 if( last1 >= 0 ) {146 last2 = incrementBy(start2, -1, nodes2.size(), isRing2);147 if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )148 increment2 = -1;149 else {150 last2 = incrementBy(start2, 1, nodes2.size(), isRing2);151 if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )152 increment2 = 1;153 }154 }155 log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);156 if( increment2 != 0 ) {157 // find the first nodes158 boolean reachedEnd = false;159 while( !reachedEnd ) {160 int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);161 int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);162 if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )163 reachedEnd = true;164 else {165 last1 = newLast1;166 last2 = newLast2;167 }168 }169 log("last1=" + last1 + " last2=" + last2);170 if( increment2 < 0 ) {171 int tmp = start2;172 start2 = last2;173 last2 = tmp;174 }175 return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};176 } else {177 pos = last1;178 while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )179 pos = incrementBy(pos, 1, nodes1.size(), isRing1);180 if( pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) )181 collideFound = true;182 }183 }184 return null;122 int pos = 0; 123 while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) ) 124 pos++; 125 boolean collideFound = pos == nodes1.size(); 126 if( pos == 0 && isRing1 ) { 127 // rewind a bit 128 pos = nodes1.size() - 1; 129 while( pos > 0 && nodes2.contains(nodes1.get(pos)) ) 130 pos--; 131 if( pos == 0 && nodes1.size() == nodes2.size() ) { 132 JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE); 133 return null; 134 } 135 pos = pos == nodes1.size() - 1 ? 0 : pos + 1; 136 } 137 int firstPos = isRing1 ? pos : nodes1.size(); 138 while( !collideFound ) { 139 log("pos=" + pos); 140 int start1 = pos; 141 int start2 = nodes2.indexOf(nodes1.get(start1)); 142 int last1 = incrementBy(start1, 1, nodes1.size(), isRing1); 143 int last2 = start2; 144 int increment2 = 0; 145 if( last1 >= 0 ) { 146 last2 = incrementBy(start2, -1, nodes2.size(), isRing2); 147 if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) 148 increment2 = -1; 149 else { 150 last2 = incrementBy(start2, 1, nodes2.size(), isRing2); 151 if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) 152 increment2 = 1; 153 } 154 } 155 log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2); 156 if( increment2 != 0 ) { 157 // find the first nodes 158 boolean reachedEnd = false; 159 while( !reachedEnd ) { 160 int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1); 161 int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2); 162 if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) ) 163 reachedEnd = true; 164 else { 165 last1 = newLast1; 166 last2 = newLast2; 167 } 168 } 169 log("last1=" + last1 + " last2=" + last2); 170 if( increment2 < 0 ) { 171 int tmp = start2; 172 start2 = last2; 173 last2 = tmp; 174 } 175 return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)}; 176 } else { 177 pos = last1; 178 while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) ) 179 pos = incrementBy(pos, 1, nodes1.size(), isRing1); 180 if( pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) ) 181 collideFound = true; 182 } 183 } 184 return null; 185 185 } 186 186 187 187 private static int incrementBy( int value, int increment, int limit1, boolean isRing ) { 188 int result = value + increment;189 if( result < 0 )190 return isRing ? result + limit1 : -1;191 else if( result >= limit1 )192 return isRing ? result - limit1 : -1;193 else194 return result;188 int result = value + increment; 189 if( result < 0 ) 190 return isRing ? result + limit1 : -1; 191 else if( result >= limit1 ) 192 return isRing ? result - limit1 : -1; 193 else 194 return result; 195 195 } 196 196 197 197 private boolean areSegmentsEqual( RingSegment seg1, RingSegment seg2 ) { 198 List<Node> nodes1 = seg1.getNodes();199 List<Node> nodes2 = seg2.getNodes();200 int size = nodes1.size();201 if( size != nodes2.size() )202 return false;203 boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0));204 for( int i = 0; i < size; i++ )205 if( !nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) )206 return false;207 return true;198 List<Node> nodes1 = seg1.getNodes(); 199 List<Node> nodes2 = seg2.getNodes(); 200 int size = nodes1.size(); 201 if( size != nodes2.size() ) 202 return false; 203 boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0)); 204 for( int i = 0; i < size; i++ ) 205 if( !nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) ) 206 return false; 207 return true; 208 208 } 209 209 … … 213 213 */ 214 214 private RingSegment splitRingAt( int segmentIndex, Node n1, Node n2 ) { 215 if( n1.equals(n2) )216 throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());217 RingSegment segment = segments.get(segmentIndex);218 boolean isRing = segment.isRing();219 log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());220 boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);221 if( reversed && !isRing ) {222 // order nodes223 Node tmp = n1;224 n1 = n2;225 n2 = tmp;226 }227 RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1);228 // if secondPart == null, then n1 == firstNode229 RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);230 // if secondPart == null, then thirdPart is between n1 and n2231 // otherwise, thirdPart is between n2 and lastNode232 // if thirdPart == null, then n2 == lastNode233 int pos = segmentIndex + 1;234 if( secondPart != null )235 segments.add(pos++, secondPart);236 if( thirdPart != null )237 segments.add(pos++, thirdPart);238 return isRing || secondPart == null ? segment : secondPart;215 if( n1.equals(n2) ) 216 throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId()); 217 RingSegment segment = segments.get(segmentIndex); 218 boolean isRing = segment.isRing(); 219 log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId()); 220 boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1); 221 if( reversed && !isRing ) { 222 // order nodes 223 Node tmp = n1; 224 n1 = n2; 225 n2 = tmp; 226 } 227 RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1); 228 // if secondPart == null, then n1 == firstNode 229 RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2); 230 // if secondPart == null, then thirdPart is between n1 and n2 231 // otherwise, thirdPart is between n2 and lastNode 232 // if thirdPart == null, then n2 == lastNode 233 int pos = segmentIndex + 1; 234 if( secondPart != null ) 235 segments.add(pos++, secondPart); 236 if( thirdPart != null ) 237 segments.add(pos++, thirdPart); 238 return isRing || secondPart == null ? segment : secondPart; 239 239 } 240 240 … … 246 246 */ 247 247 public static void redistributeSegments( List<TheRing> rings ) { 248 // build segments map249 Map<RingSegment, TheRing> segmentMap = new HashMap<>();250 for( TheRing ring : rings )251 for( RingSegment seg : ring.segments )252 if( !seg.isReference() )253 segmentMap.put(seg, ring);254 255 // rearrange references256 for( int i = 0; i < rings.size(); i++ ) {257 TheRing ring = rings.get(i);258 if( ring.countNonReferenceSegments() == 0 ) {259 // need to find one non-reference segment260 for( RingSegment seg : ring.segments ) {261 TheRing otherRing = segmentMap.get(seg.references);262 if( otherRing.countNonReferenceSegments() > 1 ) {263 // we could check for >0, but it is prone to deadlocking264 seg.swapReference();265 }266 }267 }268 }269 270 // initializing source way for each ring271 for( TheRing ring : rings )272 ring.putSourceWayFirst();248 // build segments map 249 Map<RingSegment, TheRing> segmentMap = new HashMap<>(); 250 for( TheRing ring : rings ) 251 for( RingSegment seg : ring.segments ) 252 if( !seg.isReference() ) 253 segmentMap.put(seg, ring); 254 255 // rearrange references 256 for( int i = 0; i < rings.size(); i++ ) { 257 TheRing ring = rings.get(i); 258 if( ring.countNonReferenceSegments() == 0 ) { 259 // need to find one non-reference segment 260 for( RingSegment seg : ring.segments ) { 261 TheRing otherRing = segmentMap.get(seg.references); 262 if( otherRing.countNonReferenceSegments() > 1 ) { 263 // we could check for >0, but it is prone to deadlocking 264 seg.swapReference(); 265 } 266 } 267 } 268 } 269 270 // initializing source way for each ring 271 for( TheRing ring : rings ) 272 ring.putSourceWayFirst(); 273 273 } 274 274 275 275 private int countNonReferenceSegments() { 276 int count = 0;277 for( RingSegment seg : segments )278 if( !seg.isReference() )279 count++;280 return count;276 int count = 0; 277 for( RingSegment seg : segments ) 278 if( !seg.isReference() ) 279 count++; 280 return count; 281 281 } 282 282 283 283 public void putSourceWayFirst() { 284 for( RingSegment seg : segments ) {285 if( !seg.isReference() ) {286 seg.overrideWay(source);287 return;288 }289 }284 for( RingSegment seg : segments ) { 285 if( !seg.isReference() ) { 286 seg.overrideWay(source); 287 return; 288 } 289 } 290 290 } 291 291 292 292 public List<Command> getCommands() { 293 return getCommands(true, null);293 return getCommands(true, null); 294 294 } 295 295 296 296 public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) { 297 return getCommands(true, relationChangeMap);297 return getCommands(true, relationChangeMap); 298 298 } 299 299 … … 303 303 */ 304 304 public List<Command> getCommands( boolean createMultipolygon, Map<Relation, Relation> relationChangeMap ) { 305 Way sourceCopy = new Way(source);306 if( createMultipolygon ) {307 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);308 relation = new Relation();309 relation.put("type", "multipolygon");310 for( String key : sourceCopy.keySet() ) {305 Way sourceCopy = new Way(source); 306 if( createMultipolygon ) { 307 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS); 308 relation = new Relation(); 309 relation.put("type", "multipolygon"); 310 for( String key : sourceCopy.keySet() ) { 311 311 if( linearTags.contains(key) ) continue; 312 312 if( key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) continue; 313 313 relation.put(key, sourceCopy.get(key)); 314 314 sourceCopy.remove(key); 315 }316 }317 318 // build a map of referencing relations319 Map<Relation, Integer> referencingRelations = new HashMap<>();320 List<Command> relationCommands = new ArrayList<>();321 for( OsmPrimitive p : source.getReferrers() ) {322 if( p instanceof Relation ) {323 Relation rel = null;324 if( relationChangeMap != null ) {325 if( relationChangeMap.containsKey((Relation)p) )326 rel = relationChangeMap.get((Relation)p);327 else {328 rel = new Relation((Relation)p);329 relationChangeMap.put((Relation)p, rel);330 }331 } else {332 rel = new Relation((Relation)p);333 relationCommands.add(new ChangeCommand((Relation)p, rel));334 }335 for( int i = 0; i < rel.getMembersCount(); i++ )336 if( rel.getMember(i).getMember().equals(source) )337 referencingRelations.put(rel, Integer.valueOf(i));338 }339 }340 // todo: когда два кольца менÑ�ÑŽÑ‚ одно и то же отношение, в Ñ�пиÑ�ок команд добавлÑ�етÑ�Ñ�341 // изменение базового отношениÑ� на новое, а не предыдущего342 // поÑ�тому Ñ�охранÑ�етÑ�Ñ� только первое изменение343 344 List<Command> commands = new ArrayList<>();345 boolean foundOwnWay = false;346 for( RingSegment seg : segments ) {347 boolean needAdding = !seg.isWayConstructed();348 Way w = seg.constructWay(seg.isReference() ? null : sourceCopy);349 if( needAdding )350 commands.add(new AddCommand(w));351 if( w.equals(source) ) {352 if( createMultipolygon || !seg.getWayNodes().equals(source.getNodes()) ) {353 sourceCopy.setNodes(seg.getWayNodes());354 commands.add(new ChangeCommand(source, sourceCopy));355 }356 foundOwnWay = true;357 } else {358 for( Relation rel : referencingRelations.keySet() ) {359 int relIndex = referencingRelations.get(rel);360 rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w));361 }362 }363 if( createMultipolygon )364 relation.addMember(new RelationMember("outer", w));365 }366 if( !foundOwnWay )367 commands.add(new DeleteCommand(source));368 commands.addAll(relationCommands);369 if( createMultipolygon )370 commands.add(new AddCommand(relation));371 return commands;315 } 316 } 317 318 // build a map of referencing relations 319 Map<Relation, Integer> referencingRelations = new HashMap<>(); 320 List<Command> relationCommands = new ArrayList<>(); 321 for( OsmPrimitive p : source.getReferrers() ) { 322 if( p instanceof Relation ) { 323 Relation rel = null; 324 if( relationChangeMap != null ) { 325 if( relationChangeMap.containsKey((Relation)p) ) 326 rel = relationChangeMap.get((Relation)p); 327 else { 328 rel = new Relation((Relation)p); 329 relationChangeMap.put((Relation)p, rel); 330 } 331 } else { 332 rel = new Relation((Relation)p); 333 relationCommands.add(new ChangeCommand((Relation)p, rel)); 334 } 335 for( int i = 0; i < rel.getMembersCount(); i++ ) 336 if( rel.getMember(i).getMember().equals(source) ) 337 referencingRelations.put(rel, Integer.valueOf(i)); 338 } 339 } 340 // todo: когда два кольца менÑ�ÑŽÑ‚ одно и то же отношение, в Ñ�пиÑ�ок команд добавлÑ�етÑ�Ñ� 341 // изменение базового отношениÑ� на новое, а не предыдущего 342 // поÑ�тому Ñ�охранÑ�етÑ�Ñ� только первое изменение 343 344 List<Command> commands = new ArrayList<>(); 345 boolean foundOwnWay = false; 346 for( RingSegment seg : segments ) { 347 boolean needAdding = !seg.isWayConstructed(); 348 Way w = seg.constructWay(seg.isReference() ? null : sourceCopy); 349 if( needAdding ) 350 commands.add(new AddCommand(w)); 351 if( w.equals(source) ) { 352 if( createMultipolygon || !seg.getWayNodes().equals(source.getNodes()) ) { 353 sourceCopy.setNodes(seg.getWayNodes()); 354 commands.add(new ChangeCommand(source, sourceCopy)); 355 } 356 foundOwnWay = true; 357 } else { 358 for( Relation rel : referencingRelations.keySet() ) { 359 int relIndex = referencingRelations.get(rel); 360 rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w)); 361 } 362 } 363 if( createMultipolygon ) 364 relation.addMember(new RelationMember("outer", w)); 365 } 366 if( !foundOwnWay ) 367 commands.add(new DeleteCommand(source)); 368 commands.addAll(relationCommands); 369 if( createMultipolygon ) 370 commands.add(new AddCommand(relation)); 371 return commands; 372 372 } 373 373 374 374 public static void updateCommandsWithRelations( List<Command> commands, Map<Relation, Relation> relationCache ) { 375 for( Relation src : relationCache.keySet() )376 commands.add(new ChangeCommand(src, relationCache.get(src)));375 for( Relation src : relationCache.keySet() ) 376 commands.add(new ChangeCommand(src, relationCache.get(src))); 377 377 } 378 378 … … 381 381 */ 382 382 public Relation getRelation() { 383 return relation;383 return relation; 384 384 } 385 385 386 386 @Override 387 387 public String toString() { 388 StringBuilder sb = new StringBuilder("TheRing@");389 sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: ");390 if( segments.isEmpty() )391 sb.append("empty");392 else {393 sb.append(segments.get(0));394 for( int i = 1; i < segments.size(); i++ )395 sb.append(", ").append(segments.get(i));396 }397 return sb.append(']').toString();388 StringBuilder sb = new StringBuilder("TheRing@"); 389 sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: "); 390 if( segments.isEmpty() ) 391 sb.append("empty"); 392 else { 393 sb.append(segments.get(0)); 394 for( int i = 1; i < segments.size(); i++ ) 395 sb.append(", ").append(segments.get(i)); 396 } 397 return sb.append(']').toString(); 398 398 } 399 399 … … 402 402 */ 403 403 /*private static void closePolygon( List<Node> base, List<Node> append ) { 404 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {405 List<Node> ap2 = new ArrayList<Node>(append);406 Collections.reverse(ap2);407 append = ap2;408 }409 base.remove(base.size() - 1);410 base.addAll(append);404 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) { 405 List<Node> ap2 = new ArrayList<Node>(append); 406 Collections.reverse(ap2); 407 append = ap2; 408 } 409 base.remove(base.size() - 1); 410 base.addAll(append); 411 411 }*/ 412 412 … … 415 415 */ 416 416 /*private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) { 417 EastNorth en1 = n1.getEastNorth();418 EastNorth en2 = n2.getEastNorth();419 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));420 return Geometry.nodeInsidePolygon(testNode, polygon);417 EastNorth en1 = n1.getEastNorth(); 418 EastNorth en2 = n2.getEastNorth(); 419 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0)); 420 return Geometry.nodeInsidePolygon(testNode, polygon); 421 421 }*/ 422 422 423 423 private static void log( String s ) { 424 // System.out.println(s);424 // System.out.println(s); 425 425 } 426 426 427 427 private static class RingSegment { 428 private List<Node> nodes;429 private RingSegment references;430 private Way resultingWay = null;431 private boolean wasTemplateApplied = false;432 private boolean isRing;433 434 /*private RingSegment() {435 }*/436 437 public RingSegment( Way w ) {438 this(w.getNodes());439 }440 441 public RingSegment( List<Node> nodes ) {442 this.nodes = nodes;443 isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size() - 1));444 if( isRing )445 nodes.remove(nodes.size() - 1);446 references = null;447 }448 449 /*public RingSegment( RingSegment ref ) {450 this.nodes = null;451 this.references = ref;452 }*/453 454 /**455 * Splits this segment at node n. Retains nodes 0..n and moves456 * nodes n..N to a separate segment that is returned.457 * @param n node at which to split.458 * @return new segment, {@code null} if splitting is unnecessary.459 */460 public RingSegment split( Node n ) {461 if( nodes == null )462 throw new IllegalArgumentException("Cannot split segment: it is a reference");463 int pos = nodes.indexOf(n);464 if( pos <= 0 || pos >= nodes.size() - 1 )465 return null;466 List<Node> newNodes = new ArrayList<>(nodes.subList(pos, nodes.size()));467 nodes.subList(pos + 1, nodes.size()).clear();468 return new RingSegment(newNodes);469 }470 471 /**472 * Split this segment as a way at two nodes. If one of them is null or at the end,473 * split as an arc. Note: order of nodes is important.474 * @return A new segment from n2 to n1.475 */476 public RingSegment split( Node n1, Node n2 ) {477 if( nodes == null )478 throw new IllegalArgumentException("Cannot split segment: it is a reference");479 if( !isRing ) {480 if( n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size() - 1).equals(n1) )481 return split(n2);482 if( n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size() - 1).equals(n2) )483 return split(n1);484 throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this);485 }486 int pos1 = nodes.indexOf(n1);487 int pos2 = nodes.indexOf(n2);488 if( pos1 == pos2 )489 return null;490 491 List<Node> newNodes = new ArrayList<>();492 if( pos2 > pos1 ) {493 newNodes.addAll(nodes.subList(pos2, nodes.size()));494 newNodes.addAll(nodes.subList(0, pos1 + 1));495 if( pos2 + 1 < nodes.size() )496 nodes.subList(pos2 + 1, nodes.size()).clear();497 if( pos1 > 0 )498 nodes.subList(0, pos1).clear();499 } else {500 newNodes.addAll(nodes.subList(pos2, pos1 + 1));501 nodes.addAll(new ArrayList<>(nodes.subList(0, pos2 + 1)));502 nodes.subList(0, pos1).clear();503 }504 isRing = false;505 return new RingSegment(newNodes);506 }507 508 public List<Node> getNodes() {509 return nodes == null ? references.nodes : nodes;510 }511 512 public List<Node> getWayNodes() {513 if( nodes == null )514 throw new IllegalArgumentException("Won't give you wayNodes: it is a reference");515 List<Node> wayNodes = new ArrayList<>(nodes);516 if( isRing )517 wayNodes.add(wayNodes.get(0));518 return wayNodes;519 }520 521 public boolean isReference() {522 return nodes == null;523 }524 525 public boolean isRing() {526 return isRing;527 }528 529 public void makeReference( RingSegment segment ) {530 log(this + " was made a reference to " + segment);531 this.nodes = null;532 this.references = segment;533 }534 535 public void swapReference() {536 this.nodes = references.nodes;537 references.nodes = null;538 references.references = this;539 this.references = null;540 }541 542 public boolean isWayConstructed() {543 return isReference() ? references.isWayConstructed() : resultingWay != null;544 }545 546 public Way constructWay( Way template ) {547 if( isReference() )548 return references.constructWay(template);549 if( resultingWay == null ) {550 resultingWay = new Way();551 resultingWay.setNodes(getWayNodes());552 }553 if( template != null && !wasTemplateApplied ) {554 resultingWay.setKeys(template.getKeys());555 wasTemplateApplied = true;556 }557 return resultingWay;558 }559 560 public void overrideWay( Way source ) {561 if( isReference() )562 references.overrideWay(source);563 else {564 resultingWay = source;565 wasTemplateApplied = true;566 }567 }568 569 /**570 * Compares two segments with respect to referencing.571 * @return true if ways are equals, or one references another.572 */573 /*public boolean isReferencingEqual( RingSegment other ) {574 return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other);575 }*/576 577 @Override578 public String toString() {579 StringBuilder sb = new StringBuilder("RingSegment@");580 sb.append(this.hashCode()).append('[');581 if( isReference() )582 sb.append("references ").append(references.hashCode());583 else if( nodes.isEmpty() )584 sb.append("empty");585 else {586 if( isRing )587 sb.append("ring:");588 sb.append(nodes.get(0).getUniqueId());589 for( int i = 1; i < nodes.size(); i++ )590 sb.append(',').append(nodes.get(i).getUniqueId());591 }592 return sb.append(']').toString();593 }428 private List<Node> nodes; 429 private RingSegment references; 430 private Way resultingWay = null; 431 private boolean wasTemplateApplied = false; 432 private boolean isRing; 433 434 /*private RingSegment() { 435 }*/ 436 437 public RingSegment( Way w ) { 438 this(w.getNodes()); 439 } 440 441 public RingSegment( List<Node> nodes ) { 442 this.nodes = nodes; 443 isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size() - 1)); 444 if( isRing ) 445 nodes.remove(nodes.size() - 1); 446 references = null; 447 } 448 449 /*public RingSegment( RingSegment ref ) { 450 this.nodes = null; 451 this.references = ref; 452 }*/ 453 454 /** 455 * Splits this segment at node n. Retains nodes 0..n and moves 456 * nodes n..N to a separate segment that is returned. 457 * @param n node at which to split. 458 * @return new segment, {@code null} if splitting is unnecessary. 459 */ 460 public RingSegment split( Node n ) { 461 if( nodes == null ) 462 throw new IllegalArgumentException("Cannot split segment: it is a reference"); 463 int pos = nodes.indexOf(n); 464 if( pos <= 0 || pos >= nodes.size() - 1 ) 465 return null; 466 List<Node> newNodes = new ArrayList<>(nodes.subList(pos, nodes.size())); 467 nodes.subList(pos + 1, nodes.size()).clear(); 468 return new RingSegment(newNodes); 469 } 470 471 /** 472 * Split this segment as a way at two nodes. If one of them is null or at the end, 473 * split as an arc. Note: order of nodes is important. 474 * @return A new segment from n2 to n1. 475 */ 476 public RingSegment split( Node n1, Node n2 ) { 477 if( nodes == null ) 478 throw new IllegalArgumentException("Cannot split segment: it is a reference"); 479 if( !isRing ) { 480 if( n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size() - 1).equals(n1) ) 481 return split(n2); 482 if( n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size() - 1).equals(n2) ) 483 return split(n1); 484 throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this); 485 } 486 int pos1 = nodes.indexOf(n1); 487 int pos2 = nodes.indexOf(n2); 488 if( pos1 == pos2 ) 489 return null; 490 491 List<Node> newNodes = new ArrayList<>(); 492 if( pos2 > pos1 ) { 493 newNodes.addAll(nodes.subList(pos2, nodes.size())); 494 newNodes.addAll(nodes.subList(0, pos1 + 1)); 495 if( pos2 + 1 < nodes.size() ) 496 nodes.subList(pos2 + 1, nodes.size()).clear(); 497 if( pos1 > 0 ) 498 nodes.subList(0, pos1).clear(); 499 } else { 500 newNodes.addAll(nodes.subList(pos2, pos1 + 1)); 501 nodes.addAll(new ArrayList<>(nodes.subList(0, pos2 + 1))); 502 nodes.subList(0, pos1).clear(); 503 } 504 isRing = false; 505 return new RingSegment(newNodes); 506 } 507 508 public List<Node> getNodes() { 509 return nodes == null ? references.nodes : nodes; 510 } 511 512 public List<Node> getWayNodes() { 513 if( nodes == null ) 514 throw new IllegalArgumentException("Won't give you wayNodes: it is a reference"); 515 List<Node> wayNodes = new ArrayList<>(nodes); 516 if( isRing ) 517 wayNodes.add(wayNodes.get(0)); 518 return wayNodes; 519 } 520 521 public boolean isReference() { 522 return nodes == null; 523 } 524 525 public boolean isRing() { 526 return isRing; 527 } 528 529 public void makeReference( RingSegment segment ) { 530 log(this + " was made a reference to " + segment); 531 this.nodes = null; 532 this.references = segment; 533 } 534 535 public void swapReference() { 536 this.nodes = references.nodes; 537 references.nodes = null; 538 references.references = this; 539 this.references = null; 540 } 541 542 public boolean isWayConstructed() { 543 return isReference() ? references.isWayConstructed() : resultingWay != null; 544 } 545 546 public Way constructWay( Way template ) { 547 if( isReference() ) 548 return references.constructWay(template); 549 if( resultingWay == null ) { 550 resultingWay = new Way(); 551 resultingWay.setNodes(getWayNodes()); 552 } 553 if( template != null && !wasTemplateApplied ) { 554 resultingWay.setKeys(template.getKeys()); 555 wasTemplateApplied = true; 556 } 557 return resultingWay; 558 } 559 560 public void overrideWay( Way source ) { 561 if( isReference() ) 562 references.overrideWay(source); 563 else { 564 resultingWay = source; 565 wasTemplateApplied = true; 566 } 567 } 568 569 /** 570 * Compares two segments with respect to referencing. 571 * @return true if ways are equals, or one references another. 572 */ 573 /*public boolean isReferencingEqual( RingSegment other ) { 574 return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other); 575 }*/ 576 577 @Override 578 public String toString() { 579 StringBuilder sb = new StringBuilder("RingSegment@"); 580 sb.append(this.hashCode()).append('['); 581 if( isReference() ) 582 sb.append("references ").append(references.hashCode()); 583 else if( nodes.isEmpty() ) 584 sb.append("empty"); 585 else { 586 if( isRing ) 587 sb.append("ring:"); 588 sb.append(nodes.get(0).getUniqueId()); 589 for( int i = 1; i < nodes.size(); i++ ) 590 sb.append(',').append(nodes.get(i).getUniqueId()); 591 } 592 return sb.append(']').toString(); 593 } 594 594 } 595 595 }
Note:
See TracChangeset
for help on using the changeset viewer.
