Changeset 24713 in osm for applications/editors/josm/plugins/terracer/src/terracer/TerracerAction.java
- Timestamp:
- 2010-12-12T11:34:30+01:00 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/terracer/src/terracer/TerracerAction.java
r24697 r24713 16 16 import java.util.Collection; 17 17 import java.util.Collections; 18 import java.util.Comparator; 19 import java.util.Iterator; 18 20 import java.util.LinkedList; 19 21 import java.util.List; 22 import java.util.Map; 23 import java.util.Set; 24 import java.util.Map.Entry; 25 import java.util.regex.Matcher; 26 import java.util.regex.Pattern; 20 27 21 28 import javax.swing.JOptionPane; … … 29 36 import org.openstreetmap.josm.command.DeleteCommand; 30 37 import org.openstreetmap.josm.command.SequenceCommand; 38 import org.openstreetmap.josm.data.osm.DataSet; 31 39 import org.openstreetmap.josm.data.osm.Node; 32 40 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 76 84 Way outline = null; 77 85 Way street = null; 86 String streetname = null; 87 ArrayList<Node> housenumbers = new ArrayList<Node>(); 78 88 Node init = null; 79 89 … … 82 92 super(message); 83 93 } 94 84 95 InvalidUserInputException() { 85 96 super(); … … 88 99 89 100 try { 90 for (OsmPrimitive osm : sel) { 91 if (osm instanceof Node) { 92 if (init != null) 101 if (sel.size() == 1) { 102 OsmPrimitive prim = sel.iterator().next(); 103 104 if (!(prim instanceof Way)) 105 throw new InvalidUserInputException(); 106 107 outline = (Way) prim; 108 } else if (sel.size() > 1) { 109 List<Way> ways = OsmPrimitive.getFilteredList(sel, Way.class); 110 Iterator<Way> wit = ways.iterator(); 111 while (wit.hasNext()) { 112 Way way = wit.next(); 113 if (way.hasKey("building")) { 114 if (outline != null) 115 // already have a building 116 throw new InvalidUserInputException(); 117 outline = way; 118 } else if (way.hasKey("highway")) { 119 if (street != null) 120 // already have a street 121 throw new InvalidUserInputException(); 122 street = way; 123 124 if ((streetname = street.get("name")) == null) 125 throw new InvalidUserInputException(); 126 } else 93 127 throw new InvalidUserInputException(); 94 init = (Node) osm; 95 } else if (osm instanceof Way) { 96 if (osm.hasKey("highway")) { 97 if (street != null) 128 } 129 130 if (outline == null) 131 throw new InvalidUserInputException(); 132 133 List<Node> nodes = OsmPrimitive.getFilteredList(sel, Node.class); 134 Iterator<Node> nit = nodes.iterator(); 135 // Actually this should test if the selected address nodes lie 136 // within the selected outline. Any ideas how to do this? 137 while (nit.hasNext()) { 138 Node node = nit.next(); 139 if (node.hasKey("addr:housenumber")) { 140 String nodesstreetname = node.get("addr:street"); 141 // if a node has a street name if must be equal 142 // to the one of the other address nodes 143 if (nodesstreetname != null) { 144 if (streetname == null) 145 streetname = nodesstreetname; 146 else if (!nodesstreetname.equals(streetname)) 147 throw new InvalidUserInputException(); 148 } 149 150 housenumbers.add(node); 151 } else { 152 // A given node might not be an address node but then 153 // it has to be part of the building to help getting 154 // the number direction right. 155 if (!outline.containsNode(node) || init != null) 98 156 throw new InvalidUserInputException(); 99 street = (Way) osm; 100 if (!street.hasKey("name")) 101 throw new InvalidUserInputException(); 102 } else { 103 if (outline != null) 104 throw new InvalidUserInputException(); 105 outline = (Way) osm; 157 init = node; 106 158 } 107 159 } 108 } 109 if (outline == null) 110 throw new InvalidUserInputException(); 111 112 if (init != null && !init.getReferrers().contains(outline)) 113 throw new InvalidUserInputException(); 114 115 if (outline.getNodesCount() < 5) 116 throw new InvalidUserInputException(); 117 118 if (!outline.isClosed()) 160 161 Collections.sort(housenumbers, new HousenumberNodeComparator()); 162 } 163 164 if (outline == null || !outline.isClosed() || outline.getNodesCount() < 5) 119 165 throw new InvalidUserInputException(); 120 166 } catch (InvalidUserInputException ex) { … … 128 174 } 129 175 130 // If we have a street, try to find a associatedStreet relation that could be reused. 176 // If we have a street, try to find an associatedStreet relation that could be reused. 131 177 Relation associatedStreet = null; 132 178 if (street != null) { … … 146 192 } 147 193 148 String title = trn("Change {0} object", "Change {0} objects", sel.size(), sel.size()); 149 // show input dialog. 150 new HouseNumberInputHandler(this, outline, init, street, associatedStreet, title); 194 if (housenumbers.size() == 1) { 195 // Special case of one outline and one address node. 196 // Don't open the dialogue, just copy the node keys 197 // to the outline, set building just in case it isn't there 198 // and remove the node. 199 Collection<Command> commands = new LinkedList<Command>(); 200 Way newOutline = new Way(outline); 201 for (Entry<String, String> entry : housenumbers.get(0).getKeys() 202 .entrySet()) { 203 newOutline.put(entry.getKey(), entry.getValue()); 204 } 205 newOutline.put("building", "yes"); 206 commands.add(new ChangeCommand(outline, newOutline)); 207 commands.add(DeleteCommand.delete(Main.main.getEditLayer(), 208 housenumbers, true, true)); 209 Main.main.undoRedo 210 .add(new SequenceCommand(tr("Terrace"), commands)); 211 Main.main.getCurrentDataSet().setSelected(newOutline); 212 } else { 213 String title = trn("Change {0} object", "Change {0} objects", sel 214 .size(), sel.size()); 215 // show input dialog. 216 new HouseNumberInputHandler(this, outline, init, street, streetname, 217 associatedStreet, housenumbers, title); 218 } 151 219 } 152 220 … … 160 228 161 229 /** 230 * Sorts the house number nodes according their numbers only 231 * 232 * @param house 233 * number nodes 234 */ 235 class HousenumberNodeComparator implements Comparator<Node> { 236 private final Pattern pat = Pattern.compile("^([0-9]+)"); 237 238 /* 239 * (non-Javadoc) 240 * 241 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 242 */ 243 @Override 244 public int compare(Node node1, Node node2) { 245 // It's necessary to strip off trailing non-numbers so we can 246 // compare the numbers itself numerically since string comparison 247 // doesn't work for numbers with different number of digits, 248 // e.g. 9 is higher than 11 249 String node1String = node1.get("addr:housenumber"); 250 String node2String = node2.get("addr:housenumber"); 251 Matcher mat = pat.matcher(node1String); 252 if (mat.find()) { 253 Integer node1Int = Integer.valueOf(mat.group(1)); 254 mat = pat.matcher(node2String); 255 if (mat.find()) { 256 Integer node2Int = Integer.valueOf(mat.group(1)); 257 258 return node1Int.compareTo(node2Int); 259 } 260 } 261 262 return node1String.compareTo(node2String); 263 } 264 } 265 266 /** 162 267 * Terraces a single, closed, quadrilateral way. 163 268 * … … 171 276 * @param street The street, the buildings belong to (may be null) 172 277 * @param associatedStreet 173 * @param From 174 * @param To 175 * @param streetName the name of a street (may be null). Used if not null and street is null. 176 * @param handleRelations If the user likes to add a relation or extend an existing relation 177 * @param deleteOutline If the outline way should be deleted, when done 278 * @param segments The number of segments to generate 279 * @param From Starting housenumber 280 * @param To Ending housenumber 281 * @param step The step width to use 282 * @param housenumbers List of housenumbers to use. From and To are ignored 283 * if this is set. 284 * @param streetName the name of the street, derived from the street line 285 * or the house numbers (may be null) 286 * @param handleRelations If the user likes to add a relation or extend an 287 * existing relation 288 * @param deleteOutline If the outline way should be deleted when done 178 289 */ 179 290 public void terraceBuilding(Way outline, … … 185 296 String To, 186 297 int step, 298 ArrayList<Node> housenumbers, 187 299 String streetName, 188 300 boolean handleRelations, 189 301 boolean deleteOutline) { 190 302 final int nb; 191 192 Integer to, from; 193 to = getNumber(To); 194 from = getNumber(From); 195 if (to != null && from != null) { 196 nb = 1 + (to.intValue() - from.intValue()) / step; 197 } else if (segments != null) { 198 nb = segments.intValue(); 303 Integer to = null, from = null; 304 if (housenumbers.isEmpty()) { 305 to = getNumber(To); 306 from = getNumber(From); 307 if (to != null && from != null) { 308 nb = 1 + (to.intValue() - from.intValue()) / step; 309 } else if (segments != null) { 310 nb = segments.intValue(); 311 } else { 312 // if we get here, there is is a bug in the input validation. 313 throw new TerracerRuntimeException( 314 "Could not determine segments from parameters, this is a bug. " 315 + "Parameters were: segments " + segments 316 + " from " + from + " to " + to + " step " 317 + step); 318 } 199 319 } else { 200 // if we get here, there is is a bug in the input validation. 201 throw new TerracerRuntimeException( 202 "Could not determine segments from parameters, this is a bug. " 203 + "Parameters were: segments " + segments 204 + " from " + from + " to " + to + " step " + step); 205 } 320 nb = housenumbers.size(); 321 } 322 323 // now find which is the longest side connecting the first node 324 Pair<Way, Way> interp = findFrontAndBack(outline); 325 326 boolean swap = false; 327 if (init != null) { 328 if (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init)) { 329 swap = true; 330 } 331 } 332 333 final double frontLength = wayLength(interp.a); 334 final double backLength = wayLength(interp.b); 206 335 207 336 // new nodes array to hold all intermediate nodes … … 211 340 Collection<Way> ways = new LinkedList<Way>(); 212 341 213 // Should this building be terraced (i.e. is there more then one section?)214 342 if (nb > 1) { 215 // create intermediate nodes by interpolating.216 217 // now find which is the longest side connecting the first node218 Pair<Way, Way> interp = findFrontAndBack(outline);219 220 boolean swap = false;221 if (init != null) {222 if (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init)) {223 swap = true;224 }225 }226 227 final double frontLength = wayLength(interp.a);228 final double backLength = wayLength(interp.b);229 230 343 for (int i = 0; i <= nb; ++i) { 231 344 int i_dir = swap ? nb - i : i; … … 249 362 250 363 String number = null; 251 if (from != null) { 252 number = Integer.toString(from + i * step); 253 } 254 terr = addressBuilding(terr, street, streetName, number); 364 Set<Entry<String, String>> additionalKeys = null; 365 if (housenumbers.isEmpty()) { 366 if (from != null) { 367 // only, if the user has specified house numbers 368 number = Integer.toString(from + i * step); 369 } 370 } else { 371 number = housenumbers.get(i).get("addr:housenumber"); 372 additionalKeys = housenumbers.get(i).getKeys().entrySet(); 373 } 374 375 terr = addressBuilding(terr, street, streetName, number, 376 additionalKeys); 255 377 256 378 ways.add(terr); … … 262 384 } 263 385 } else { 264 // Single section, just add the address details386 // Single building, just add the address details 265 387 Way newOutline; 266 newOutline = addressBuilding(outline, street, streetName, From); 388 newOutline = addressBuilding(outline, street, streetName, From, null); 267 389 ways.add(newOutline); 268 390 this.commands.add(new ChangeCommand(outline, newOutline)); … … 283 405 } 284 406 this.commands.add(new AddCommand(associatedStreet)); 285 } 286 else { // relation exists already - add new members 407 } else { // relation exists already - add new members 287 408 Relation newAssociatedStreet = new Relation(associatedStreet); 288 409 for (Way w : ways) { … … 292 413 } 293 414 } 415 416 // Remove the address node since their tags have been incorporated into 417 // the terraces. 418 // Or should removing them also be an option? 419 if (!housenumbers.isEmpty()) 420 commands.add(DeleteCommand.delete(Main.main.getEditLayer(), 421 housenumbers, true, true)); 422 294 423 Main.main.undoRedo.add(new SequenceCommand(tr("Terrace"), commands)); 295 424 if (nb > 1) { … … 309 438 * @param streetName the name of a street (may be null). Used if not null and street is null. 310 439 * @param number The house number 440 * @param additionalKeys More keys to be copied onto the new outline 311 441 * @return the way with added address details 312 442 */ 313 private Way addressBuilding(Way outline, Way street, String streetName, String number) { 443 private Way addressBuilding(Way outline, Way street, String streetName, 444 String number, Set<Entry<String, String>> additionalKeys) { 314 445 Way changedOutline = outline; 315 446 if (number != null) { 316 447 // only, if the user has specified house numbers 317 448 this.commands.add(new ChangePropertyCommand(changedOutline, "addr:housenumber", number)); 449 } 450 if (additionalKeys != null) { 451 for (Entry<String, String> entry : additionalKeys) { 452 this.commands.add(new ChangePropertyCommand(changedOutline, 453 entry.getKey(), entry.getValue())); 454 } 318 455 } 319 456 changedOutline.put("building", "yes"); … … 343 480 Pair<Node,Node> p = pairs.get(i); 344 481 final double seg_length = p.a.getCoor().greatCircleDistance(p.b.getCoor()); 345 if (l <= seg_length || 346 i == pairs.size() - 1) {// be generous on the last segment (numerical roudoff can lead to a small overshoot)482 if (l <= seg_length || i == pairs.size() - 1) { 483 // be generous on the last segment (numerical roudoff can lead to a small overshoot) 347 484 return interpolateNode(p.a, p.b, l / seg_length); 348 485 } else { … … 442 579 */ 443 580 private int positiveModulus(int a, int n) { 444 if (n <=0) 581 if (n <= 0) 445 582 throw new IllegalArgumentException(); 446 583 int res = a % n;
Note:
See TracChangeset
for help on using the changeset viewer.