Changeset 26812 in osm for applications
- Timestamp:
- 2011-10-09T18:09:20+02:00 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java
r26811 r26812 11 11 import org.openstreetmap.josm.Main; 12 12 import org.openstreetmap.josm.actions.JosmAction; 13 import org.openstreetmap.josm.actions.SplitWayAction;14 13 import org.openstreetmap.josm.command.*; 15 14 import org.openstreetmap.josm.data.coor.EastNorth; 16 15 import org.openstreetmap.josm.data.osm.*; 17 16 import org.openstreetmap.josm.data.osm.MultipolygonCreate.JoinedPolygon; 18 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;19 17 import org.openstreetmap.josm.gui.DefaultNameFormatter; 20 18 import org.openstreetmap.josm.tools.GBC; … … 74 72 if( chRel != null ) 75 73 chRel.set(newRelation); 74 getCurrentDataSet().setSelected(newRelation); 76 75 return; 77 76 } … … 81 80 if( chRel != null ) 82 81 chRel.set(rels.size() == 1 ? rels.get(0) : null); 82 if( rels.size() == 1 ) 83 getCurrentDataSet().setSelected(rels); 84 else 85 getCurrentDataSet().clearSelection(); 83 86 return; 84 87 } … … 449 452 */ 450 453 private List<Relation> makeManySimpleMultipolygons( Collection<Way> selection ) { 454 System.out.println("---------------------------------------"); 455 List<TheRing> rings = new ArrayList<TheRing>(selection.size()); 456 for( Way w : selection ) 457 rings.add(new TheRing(w)); 458 for( int i = 0; i < rings.size()-1; i++ ) 459 for( int j = i+1; j < rings.size(); j++ ) 460 rings.get(i).collide(rings.get(j)); 461 redistributeSegments(rings); 462 List<Command> commands = new ArrayList<Command>(); 463 List<Relation> relations = new ArrayList<Relation>(); 464 for( TheRing r : rings ) { 465 commands.addAll(r.getCommands()); 466 relations.add(r.getRelation()); 467 } 468 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands)); 469 return relations; 470 } 471 472 /** 473 * Creates ALOT of Multipolygons and pets him gently. 474 * @return list of new relations. 475 */ 476 private List<Relation> makeManySimpleMultipolygonsOld( Collection<Way> selection ) { 451 477 List<Command> commands = new ArrayList<Command>(); 452 478 List<Way> ways = new ArrayList<Way>(selection.size()); … … 539 565 * Appends "append" to "base" so the closed polygon forms. 540 566 */ 541 private void closePolygon( List<Node> base, List<Node> append ) {567 private static void closePolygon( List<Node> base, List<Node> append ) { 542 568 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) { 543 569 List<Node> ap2 = new ArrayList<Node>(append); … … 552 578 * Checks if a middle point between two nodes is inside a polygon. Useful to check if the way is inside. 553 579 */ 554 private boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) {580 private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) { 555 581 EastNorth en1 = n1.getEastNorth(); 556 582 EastNorth en2 = n2.getEastNorth(); … … 568 594 */ 569 595 private static void collideMultipolygons( Relation r1, Relation r2, List<Command> commands, Map<Way, Way> wayDiff ) { 596 } 597 598 /** 599 * merges two ways from two multipolygons. The result is several new ways and changed old ones. 600 * But it can also remove one old way — it is returned then. 601 * @param w1 602 * @param w2 603 * @param commands 604 */ 605 private static Way collideWays( Way w1, Way w2, List<Command> commands ) { 606 return null; 570 607 } 571 608 … … 873 910 return result; 874 911 } 912 913 /** 914 * Tries to arrange segments in order for each ring to have at least one. 915 */ 916 public static void redistributeSegments( List<TheRing> rings ) { 917 // todo 918 } 919 920 public static class TheRing { 921 private Way source; 922 private List<RingSegment> segments; 923 private Relation relation = null; 924 925 public TheRing( Way source ) { 926 this.source = source; 927 segments = new ArrayList<RingSegment>(1); 928 segments.add(new RingSegment(source)); 929 } 930 931 public void collide( TheRing other ) { 932 System.out.println("Ring 1: " + this); 933 System.out.println("Ring 2: " + other); 934 List<Node> intersectionNodes = new ArrayList<Node>(); 935 List<RingSegment> segmentsList1 = new ArrayList<RingSegment>(segments); 936 List<RingSegment> segmentsList2 = new ArrayList<RingSegment>(other.segments); 937 for( int i = 0; i < segmentsList1.size(); i++ ) { 938 if( !segmentsList1.get(i).isReference() ) 939 for( int j = 0; j < segmentsList2.size(); j++ ) { 940 // not colliding referencing nodes: they've already collided, and 941 // there should be no more than two ways passing through two points. 942 if( !segmentsList1.get(i).isReference() ) { 943 intersectionNodes.clear(); 944 boolean colliding = false; 945 List<Node> nodes1 = segmentsList1.get(i).getNodes(); 946 List<Node> nodes2 = segmentsList2.get(j).getNodes(); 947 for( int ni = 0; ni < nodes2.size(); ni++ ) { 948 if( nodes1.contains(nodes2.get(ni)) != colliding ) { 949 intersectionNodes.add(nodes2.get(colliding ? ni-1 : ni)); 950 colliding = !colliding; 951 } 952 } 953 if( colliding ) 954 intersectionNodes.add(nodes2.get(nodes2.size()-1)); 955 // todo: when an intersection of two rings spans a ring's beginning 956 if( segmentsList1.get(i).isRing() && segmentsList2.get(j).isRing() && intersectionNodes.contains(nodes2.get(0)) && intersectionNodes.contains(nodes2.get(nodes2.size()-1)) ) { 957 intersectionNodes.remove(0); 958 intersectionNodes.remove(intersectionNodes.size()-1); 959 intersectionNodes.add(intersectionNodes.get(0)); 960 intersectionNodes.remove(0); 961 } 962 System.out.print("Intersection nodes for segments " + segmentsList1.get(i) + " and " + segmentsList2.get(j) + ": "); 963 for( Node inode : intersectionNodes ) 964 System.out.print(inode.getUniqueId() + ","); 965 System.out.println(); 966 // unclosed ways produce duplicate nodes 967 int ni = 1; 968 while( ni < intersectionNodes.size() ) { 969 if( intersectionNodes.get(ni-1).equals(intersectionNodes.get(ni)) ) 970 intersectionNodes.remove(ni-1); 971 else 972 ni++; 973 } 974 // boolean thisWayIsReversed = !intersectionNodes.isEmpty() && nodes1.indexOf(intersectionNodes.get(0)) > nodes1.indexOf(intersectionNodes.get(1)); 975 // now split both ways at control points and remove duplicate parts 976 ni = 0; 977 while( ni+1 < intersectionNodes.size() ) { 978 if( !segmentsList1.get(i).isReferencingEqual(segmentsList2.get(j)) ) { 979 System.out.println("Splitting segment 1: " + segmentsList1.get(i)); 980 System.out.println("Splitting segment 2: " + segmentsList2.get(j)); 981 boolean[] isarc = new boolean[] { 982 segments.size() == 1 && !segments.get(0).isRing(), 983 other.segments.size() == 1 && !other.segments.get(0).isRing() 984 }; 985 RingSegment segment = splitRingAt(i, intersectionNodes.get(ni), intersectionNodes.get(ni+1)); 986 RingSegment otherSegment = other.splitRingAt(j, intersectionNodes.get(ni), intersectionNodes.get(ni+1)); 987 if( !isarc[0] && !isarc[1] ) 988 segment.makeReference(otherSegment); 989 else { 990 // 1. A ring is an arc. It should have only 2 segments after this 991 // 2. But it has one, so add otherSegment as the second. 992 // todo: determine which segment! 993 if( isarc[0] ) { 994 if( other.segments.size() > 2 ) 995 segments.add(new RingSegment(otherSegment)); 996 else { 997 // choose between 2 segments 998 List<Node> testRing = new ArrayList<Node>(segments.get(0).getNodes()); 999 closePolygon(testRing, other.segments.get(0).getNodes()); 1000 int segmentToAdd = segmentInsidePolygon(other.segments.get(1).getNodes().get(0), 1001 other.segments.get(1).getNodes().get(1), testRing) ? 1 : 0; 1002 segments.add(new RingSegment(other.segments.get(segmentToAdd))); 1003 } 1004 } else 1005 if( segments.size() > 2 ) 1006 other.segments.add(new RingSegment(segment)); 1007 else { 1008 // choose between 2 segments 1009 List<Node> testRing = new ArrayList<Node>(other.segments.get(0).getNodes()); 1010 closePolygon(testRing, segments.get(0).getNodes()); 1011 int segmentToAdd = segmentInsidePolygon(segments.get(1).getNodes().get(0), 1012 segments.get(1).getNodes().get(1), testRing) ? 1 : 0; 1013 other.segments.add(new RingSegment(segments.get(segmentToAdd))); 1014 } 1015 } 1016 } 1017 ni += 2; 1018 } 1019 } 1020 } 1021 } 1022 System.out.println("Resulting ring 1: " + this); 1023 System.out.println("Resulting ring 2: " + other); 1024 } 1025 1026 /** 1027 * Split the segment in this ring at those nodes. 1028 * @return The segment between nodes. 1029 */ 1030 private RingSegment splitRingAt( int segmentIndex, Node n1, Node n2 ) { 1031 if( n1.equals(n2) ) 1032 throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId()); 1033 RingSegment segment = segments.get(segmentIndex); 1034 boolean isRing = segment.isRing(); 1035 System.out.println("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId()); 1036 boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1); 1037 if( reversed && !isRing ) { 1038 // order nodes 1039 Node tmp = n1; 1040 n1 = n2; 1041 n2 = tmp; 1042 } 1043 RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1); 1044 // if secondPart == null, then n1 == firstNode 1045 RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2); 1046 // if secondPart == null, then thirdPart is between n1 and n2 1047 // otherwise, thirdPart is between n2 and lastNode 1048 // if thirdPart == null, then n2 == lastNode 1049 int pos = segmentIndex + 1; 1050 if( secondPart != null ) 1051 segments.add(pos++, secondPart); 1052 if( thirdPart != null ) 1053 segments.add(pos++, thirdPart); 1054 for( int i = segmentIndex; i < pos; i++ ) 1055 System.out.println("Split result "+(i-segmentIndex+1) + ": "+segments.get(i)); 1056 RingSegment result = isRing || secondPart == null ? segment : secondPart; 1057 System.out.println("Returning segment " + result); 1058 return result; 1059 } 1060 1061 /** 1062 * Returns a list of commands to make a new relation and all newly created ways. 1063 * The first way is copied from the source one, ChangeCommand is issued in this case. 1064 */ 1065 public List<Command> getCommands() { 1066 System.out.println("Making ring " + this); 1067 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS); 1068 relation = new Relation(); 1069 relation.put("type", "multipolygon"); 1070 Way sourceCopy = new Way(source); 1071 for( String key : sourceCopy.keySet() ) { 1072 if( !linearTags.contains(key) ) { 1073 relation.put(key, sourceCopy.get(key)); 1074 sourceCopy.remove(key); 1075 } 1076 } 1077 1078 // todo: copy relations from source to all new ways 1079 1080 List<Command> commands = new ArrayList<Command>(); 1081 boolean foundOwnWay = false; 1082 Way w; 1083 for( RingSegment seg : segments ) { 1084 if( seg.isWayConstructed() || seg.isReference() || foundOwnWay ) { 1085 boolean needAdding = !seg.isWayConstructed(); 1086 w = seg.constructWay(seg.isReference() ? null : sourceCopy); 1087 if( needAdding ) 1088 commands.add(new AddCommand(w)); 1089 } else { 1090 w = source; 1091 if( segments.size() == 1 ) { 1092 // one segment means that it is a ring 1093 List<Node> segnodes = seg.getNodes(); 1094 segnodes.add(segnodes.get(0)); 1095 sourceCopy.setNodes(segnodes); 1096 } else 1097 sourceCopy.setNodes(seg.getNodes()); 1098 seg.overrideWay(source); 1099 commands.add(new ChangeCommand(source, sourceCopy)); 1100 foundOwnWay = true; 1101 } 1102 relation.addMember(new RelationMember("outer", w)); 1103 } 1104 if( !foundOwnWay ) 1105 commands.add(new DeleteCommand(source)); 1106 commands.add(new AddCommand(relation)); 1107 return commands; 1108 } 1109 1110 private List<Node> constructRing() { 1111 List<Node> result = new ArrayList<Node>(); 1112 for( RingSegment segment : segments ) 1113 result.addAll(segment.getNodes()); 1114 return result; 1115 } 1116 1117 /** 1118 * Returns the relation created in {@link #getCommands()}. 1119 */ 1120 public Relation getRelation() { 1121 return relation; 1122 } 1123 1124 @Override 1125 public String toString() { 1126 StringBuilder sb = new StringBuilder("TheRing@"); 1127 sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: "); 1128 if( segments.isEmpty() ) 1129 sb.append("empty"); 1130 else { 1131 sb.append(segments.get(0)); 1132 for( int i = 1; i < segments.size(); i++ ) 1133 sb.append(", ").append(segments.get(i)); 1134 } 1135 return sb.append(']').toString(); 1136 } 1137 } 1138 1139 private static class RingSegment { 1140 private List<Node> nodes; 1141 private RingSegment references; 1142 private Way resultingWay = null; 1143 private boolean wasTemplateApplied = false; 1144 private boolean isRing; 1145 1146 private RingSegment() {} 1147 1148 public RingSegment( Way w ) { 1149 this(w.getNodes()); 1150 } 1151 1152 public RingSegment( List<Node> nodes ) { 1153 this.nodes = nodes; 1154 isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size()-1)); 1155 if( isRing ) 1156 nodes.remove(nodes.size()-1); 1157 references = null; 1158 } 1159 1160 public RingSegment( RingSegment ref ) { 1161 this.nodes = null; 1162 this.references = ref; 1163 } 1164 1165 /** 1166 * Splits this segment at node n. Retains nodes 0..n and moves 1167 * nodes n..N to a separate segment that is returned. 1168 * @param n node at which to split. 1169 * @return new segment, {@code null} if splitting is unnecessary. 1170 */ 1171 public RingSegment split( Node n ) { 1172 if( nodes == null ) 1173 throw new IllegalArgumentException("Cannot split segment: it is a reference"); 1174 int pos = nodes.indexOf(n); 1175 if( pos <= 0 || pos >= nodes.size()-1 ) 1176 return null; 1177 List<Node> newNodes = new ArrayList<Node>(nodes.subList(pos, nodes.size())); 1178 nodes.subList(pos+1, nodes.size()).clear(); 1179 return new RingSegment(newNodes); 1180 } 1181 1182 /** 1183 * Split this segment as a way at two nodes. If one of them is null or at the end, 1184 * split as an arc. Note: order of nodes is important. 1185 * @return A new segment from n2 to n1. 1186 */ 1187 public RingSegment split( Node n1, Node n2 ) { 1188 if( nodes == null ) 1189 throw new IllegalArgumentException("Cannot split segment: it is a reference"); 1190 if( !isRing ) { 1191 if( n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size()-1).equals(n1) ) 1192 return split(n2); 1193 if( n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size()-1).equals(n2) ) 1194 return split(n1); 1195 throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this); 1196 } 1197 int pos1 = nodes.indexOf(n1); 1198 int pos2 = nodes.indexOf(n2); 1199 if( pos1 == pos2 ) 1200 return null; 1201 1202 List<Node> newNodes = new ArrayList<Node>(); 1203 if( pos2 > pos1 ) { 1204 newNodes.addAll(nodes.subList(pos2, nodes.size())); 1205 newNodes.addAll(nodes.subList(0, pos1 + 1)); 1206 if( pos2+1 < nodes.size() ) 1207 nodes.subList(pos2+1, nodes.size()).clear(); 1208 if( pos1 > 0 ) 1209 nodes.subList(0, pos1).clear(); 1210 } else { 1211 newNodes.addAll(nodes.subList(pos2, pos1+1)); 1212 nodes.addAll(new ArrayList<Node>(nodes.subList(0, pos2+1))); 1213 nodes.subList(0, pos1).clear(); 1214 } 1215 isRing = false; 1216 return new RingSegment(newNodes); 1217 } 1218 1219 public List<Node> getNodes() { 1220 return nodes == null ? references.nodes : nodes; 1221 } 1222 1223 public boolean isReference() { 1224 return nodes == null; 1225 } 1226 1227 public boolean isRing() { 1228 return isRing; 1229 } 1230 1231 public void makeReference( RingSegment segment ) { 1232 this.nodes = null; 1233 this.references = segment; 1234 } 1235 1236 public void swapReference() { 1237 this.nodes = references.nodes; 1238 references.nodes = null; 1239 references.references = this; 1240 this.references = null; 1241 } 1242 1243 public boolean isWayConstructed() { 1244 return isReference() ? references.isWayConstructed() : resultingWay != null; 1245 } 1246 1247 public Way constructWay( Way template ) { 1248 if( isReference() ) 1249 return references.constructWay(template); 1250 if( resultingWay == null ) { 1251 resultingWay = new Way(); 1252 resultingWay.setNodes(nodes); 1253 } 1254 if( template != null && !wasTemplateApplied ) { 1255 resultingWay.setKeys(template.getKeys()); 1256 wasTemplateApplied = true; 1257 } 1258 return resultingWay; 1259 } 1260 1261 public void overrideWay( Way source ) { 1262 if( isReference() ) 1263 references.overrideWay(source); 1264 else { 1265 resultingWay = source; 1266 wasTemplateApplied = true; 1267 } 1268 } 1269 1270 /** 1271 * Compares two segments with respect to referencing. 1272 * @return true if ways are equals, or one references another. 1273 */ 1274 public boolean isReferencingEqual( RingSegment other ) { 1275 return this.equals(other) || (other.isReference() && other.references == this ) || (isReference() && references == other); 1276 } 1277 1278 @Override 1279 public String toString() { 1280 StringBuilder sb = new StringBuilder("RingSegment@"); 1281 sb.append(this.hashCode()).append('['); 1282 if( isReference() ) 1283 sb.append("references ").append(references.hashCode()); 1284 else if( nodes.isEmpty() ) 1285 sb.append("empty"); 1286 else { 1287 if( isRing ) 1288 sb.append("ring:"); 1289 sb.append(nodes.get(0).getUniqueId()); 1290 for( int i = 1; i < nodes.size(); i++ ) 1291 sb.append(',').append(nodes.get(i).getUniqueId()); 1292 } 1293 return sb.append(']').toString(); 1294 } 1295 } 875 1296 }
Note:
See TracChangeset
for help on using the changeset viewer.