Changeset 7423 in josm
- Timestamp:
- 2014-08-16T20:14:24+02:00 (10 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/CreateMultipolygonAction.java
r7392 r7423 43 43 * Create multipolygon from selected ways automatically. 44 44 * 45 * New relation with type=multipolygon is created 45 * New relation with type=multipolygon is created. 46 46 * 47 47 * If one or more of ways is already in relation with type=multipolygon or the 48 * way is not closed, then error is reported and no relation is created 48 * way is not closed, then error is reported and no relation is created. 49 49 * 50 50 * The "inner" and "outer" roles are guessed automatically. First, bbox is … … 93 93 final Relation relation = commandAndRelation.b; 94 94 95 96 95 // to avoid EDT violations 97 96 SwingUtilities.invokeLater(new Runnable() { … … 103 102 // knows about the new relation before we try to select it. 104 103 // (Yes, we are already in event dispatch thread. But DatasetEventManager 105 // uses 'SwingUtilities.invokeLater' to fire events so we have to do 106 // the same.) 104 // uses 'SwingUtilities.invokeLater' to fire events so we have to do the same.) 107 105 SwingUtilities.invokeLater(new Runnable() { 108 106 @Override … … 123 121 } 124 122 125 /**126 * The action button has been clicked127 *128 * @param e Action Event129 */130 123 @Override 131 124 public void actionPerformed(ActionEvent e) { … … 239 232 240 233 /** Enable this action only if something is selected */ 241 @Override protected void updateEnabledState() { 234 @Override 235 protected void updateEnabledState() { 242 236 if (getCurrentDataSet() == null) { 243 237 setEnabled(false); … … 252 246 * @param selection the current selection, gets tested for emptyness 253 247 */ 254 @Override protected void updateEnabledState(Collection < ? extends OsmPrimitive > selection) { 248 @Override 249 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 255 250 if (update) { 256 251 setEnabled(getSelectedMultipolygonRelation() != null); … … 265 260 * @return <code>null</code>, if there was a problem with the ways. 266 261 */ 267 private static MultipolygonBuilder analyzeWays(Collection < Way> selectedWays, boolean showNotif) {262 private static MultipolygonBuilder analyzeWays(Collection<Way> selectedWays, boolean showNotif) { 268 263 269 264 MultipolygonBuilder pol = new MultipolygonBuilder(); … … 324 319 * @return a list of commands to execute 325 320 */ 326 public static List<Command> removeTagsFromWaysIfNeeded( 321 public static List<Command> removeTagsFromWaysIfNeeded(Relation relation) { 327 322 Map<String, String> values = new HashMap<>(relation.getKeys()); 328 323 … … 342 337 outerWays.add(way); 343 338 344 for (String key : way.keySet()345 if (!values.containsKey(key)339 for (String key : way.keySet()) { 340 if (!values.containsKey(key)) { //relation values take precedence 346 341 values.put(key, way.get(key)); 347 } else if (!relation.hasKey(key) && !values.get(key).equals(way.get(key))342 } else if (!relation.hasKey(key) && !values.get(key).equals(way.get(key))) { 348 343 conflictingKeys.add(key); 349 344 } … … 353 348 354 349 // filter out empty key conflicts - we need second iteration 355 if (!Main.pref.getBoolean("multipoly.alltags", false)356 for (RelationMember m : relation.getMembers()357 if (m.hasRole() && "outer".equals(m.getRole()) && m.isWay()358 for (String key : values.keySet()359 if (!m.getWay().hasKey(key) && !relation.hasKey(key)350 if (!Main.pref.getBoolean("multipoly.alltags", false)) 351 for (RelationMember m : relation.getMembers()) 352 if (m.hasRole() && "outer".equals(m.getRole()) && m.isWay()) 353 for (String key : values.keySet()) 354 if (!m.getWay().hasKey(key) && !relation.hasKey(key)) 360 355 conflictingKeys.add(key); 361 356 362 for (String key : conflictingKeys357 for (String key : conflictingKeys) 363 358 values.remove(key); 364 359 365 for (String linearTag : Main.pref.getCollection("multipoly.lineartagstokeep", DEFAULT_LINEAR_TAGS)360 for (String linearTag : Main.pref.getCollection("multipoly.lineartagstokeep", DEFAULT_LINEAR_TAGS)) 366 361 values.remove(linearTag); 367 362 … … 402 397 if (moveTags) { 403 398 // add those tag values to the relation 404 405 399 boolean fixed = false; 406 400 Relation r2 = new Relation(relation); -
trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java
r7422 r7423 12 12 import java.util.List; 13 13 import java.util.Set; 14 import java.util.concurrent.Callable; 15 import java.util.concurrent.ExecutionException; 16 import java.util.concurrent.ExecutorService; 17 import java.util.concurrent.Future; 14 18 15 19 import org.openstreetmap.josm.tools.Geometry; 16 20 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; 17 21 import org.openstreetmap.josm.tools.MultiMap; 22 import org.openstreetmap.josm.tools.Pair; 23 import org.openstreetmap.josm.tools.Utils; 18 24 19 25 /** … … 24 30 */ 25 31 public class MultipolygonBuilder { 32 33 private static final Pair<Integer, ExecutorService> THREAD_POOL = 34 Utils.newThreadPool("multipolygon_creation.numberOfThreads"); 26 35 27 36 /** … … 237 246 */ 238 247 private String makeFromPolygons(List<JoinedPolygon> polygons) { 239 List<PolygonLevel> list = findOuterWays Recursive(0,polygons);248 List<PolygonLevel> list = findOuterWaysMultiThread(polygons); 240 249 241 250 if (list == null) { … … 258 267 } 259 268 269 private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates(JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) { 270 boolean outerGood = true; 271 List<JoinedPolygon> innerCandidates = new ArrayList<>(); 272 273 for (JoinedPolygon innerWay : boundaryWays) { 274 if (innerWay == outerWay) { 275 continue; 276 } 277 278 // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection 279 if (outerWay.bounds.intersects(innerWay.bounds)) { 280 // Bounds intersection, let's see in detail 281 PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 282 283 if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) { 284 outerGood = false; // outer is inside another polygon 285 break; 286 } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST) { 287 innerCandidates.add(innerWay); 288 } else if (intersection == PolygonIntersection.CROSSING) { 289 // ways intersect 290 return null; 291 } 292 } 293 } 294 295 return new Pair<>(outerGood, innerCandidates); 296 } 297 260 298 /** 261 299 * Collects outer way and corresponding inner ways from all boundaries. 262 * @param boundaryWays263 300 * @return the outermostWay, or {@code null} if intersection found. 264 301 */ 265 private List<PolygonLevel> findOuterWaysRecursive(int level, Collection<JoinedPolygon> boundaryWays) { 266 267 //TODO: bad performance for deep nesting... 268 List<PolygonLevel> result = new ArrayList<>(); 269 270 for (JoinedPolygon outerWay : boundaryWays) { 271 272 boolean outerGood = true; 273 List<JoinedPolygon> innerCandidates = new ArrayList<>(); 274 275 for (JoinedPolygon innerWay : boundaryWays) { 276 if (innerWay == outerWay) { 277 continue; 278 } 279 280 // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection 281 if (outerWay.bounds.intersects(innerWay.bounds)) { 282 // Bounds intersection, let's see in detail 283 PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 284 285 if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) { 286 outerGood = false; // outer is inside another polygon 287 break; 288 } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST) { 289 innerCandidates.add(innerWay); 290 } else if (intersection == PolygonIntersection.CROSSING) { 291 //ways intersect 302 private static List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) { 303 final List<PolygonLevel> result = new ArrayList<>(); 304 final List<Worker> tasks = new ArrayList<>(); 305 final int bucketsize = Math.max(32, boundaryWays.size()/THREAD_POOL.a/3); 306 final int noBuckets = (boundaryWays.size() + bucketsize - 1) / bucketsize; 307 final boolean singleThread = THREAD_POOL.a == 1 || noBuckets == 1; 308 for (int i=0; i<noBuckets; i++) { 309 int from = i*bucketsize; 310 int to = Math.min((i+1)*bucketsize, boundaryWays.size()); 311 List<PolygonLevel> target = singleThread ? result : new ArrayList<PolygonLevel>(to - from); 312 tasks.add(new Worker(boundaryWays, from, to, target)); 313 } 314 if (singleThread) { 315 try { 316 for (Worker task : tasks) { 317 if (task.call() == null) { 292 318 return null; 293 319 } 294 320 } 295 } 296 297 if (!outerGood) { 298 continue; 299 } 300 301 //add new outer polygon 302 PolygonLevel pol = new PolygonLevel(outerWay, level); 303 304 //process inner ways 305 if (!innerCandidates.isEmpty()) { 306 List<PolygonLevel> innerList = this.findOuterWaysRecursive(level + 1, innerCandidates); 307 if (innerList == null) { 308 return null; //intersection found 309 } 310 311 result.addAll(innerList); 312 313 for (PolygonLevel pl : innerList) { 314 if (pl.level == level + 1) { 315 pol.innerWays.add(pl.outerWay); 316 } 317 } 318 } 319 320 result.add(pol); 321 } 322 321 } catch (Exception ex) { 322 throw new RuntimeException(ex); 323 } 324 } else if (!tasks.isEmpty()) { 325 try { 326 for (Future<List<PolygonLevel>> future : THREAD_POOL.b.invokeAll(tasks)) { 327 List<PolygonLevel> res = future.get(); 328 if (res == null) { 329 return null; 330 } 331 result.addAll(res); 332 } 333 } catch (InterruptedException | ExecutionException ex) { 334 throw new RuntimeException(ex); 335 } 336 } 323 337 return result; 324 338 } 339 340 private static class Worker implements Callable<List<PolygonLevel>> { 341 342 private final List<JoinedPolygon> input; 343 private final int from; 344 private final int to; 345 private final List<PolygonLevel> output; 346 347 public Worker(List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output) { 348 this.input = input; 349 this.from = from; 350 this.to = to; 351 this.output = output; 352 } 353 354 /** 355 * Collects outer way and corresponding inner ways from all boundaries. 356 * @return the outermostWay, or {@code null} if intersection found. 357 */ 358 private static List<PolygonLevel> findOuterWaysRecursive(int level, List<JoinedPolygon> boundaryWays) { 359 360 final List<PolygonLevel> result = new ArrayList<>(); 361 362 for (JoinedPolygon outerWay : boundaryWays) { 363 if (processOuterWay(level, boundaryWays, result, outerWay) == null) { 364 return null; 365 } 366 } 367 368 return result; 369 } 370 371 private static List<PolygonLevel> processOuterWay(int level, List<JoinedPolygon> boundaryWays, final List<PolygonLevel> result, JoinedPolygon outerWay) { 372 Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates(outerWay, boundaryWays); 373 if (p == null) { 374 // ways intersect 375 return null; 376 } 377 378 if (p.a) { 379 //add new outer polygon 380 PolygonLevel pol = new PolygonLevel(outerWay, level); 381 382 //process inner ways 383 if (!p.b.isEmpty()) { 384 List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, p.b); 385 if (innerList == null) { 386 return null; //intersection found 387 } 388 389 result.addAll(innerList); 390 391 for (PolygonLevel pl : innerList) { 392 if (pl.level == level + 1) { 393 pol.innerWays.add(pl.outerWay); 394 } 395 } 396 } 397 398 result.add(pol); 399 } 400 return result; 401 } 402 403 @Override 404 public List<PolygonLevel> call() throws Exception { 405 for (int i = from; i<to; i++) { 406 if (processOuterWay(0, input, output, input.get(i)) == null) { 407 return null; 408 } 409 } 410 return output; 411 } 412 } 325 413 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
r7386 r7423 33 33 import java.util.concurrent.ExecutionException; 34 34 import java.util.concurrent.ExecutorService; 35 import java.util.concurrent.Executors;36 35 import java.util.concurrent.Future; 37 36 … … 73 72 import org.openstreetmap.josm.tools.CompositeList; 74 73 import org.openstreetmap.josm.tools.ImageProvider; 74 import org.openstreetmap.josm.tools.Pair; 75 75 import org.openstreetmap.josm.tools.Utils; 76 76 77 77 /** 78 * <p>A map renderer which renders a map according to style rules in a set of style sheets.</p>79 * 78 * A map renderer which renders a map according to style rules in a set of style sheets. 79 * @since 486 80 80 */ 81 81 public class StyledMapRenderer extends AbstractMapRenderer { 82 82 83 final public static int noThreads; 84 final public static ExecutorService styleCreatorPool; 85 86 static { 87 noThreads = Main.pref.getInteger( 88 "mappaint.StyledMapRenderer.style_creation.numberOfThreads", 89 Runtime.getRuntime().availableProcessors()); 90 styleCreatorPool = noThreads <= 1 ? null : Executors.newFixedThreadPool(noThreads); 91 } 83 private static final Pair<Integer, ExecutorService> THREAD_POOL = 84 Utils.newThreadPool("mappaint.StyledMapRenderer.style_creation.numberOfThreads"); 92 85 93 86 /** … … 1245 1238 Main.pref.getBoolean("mappaint.use-antialiasing", true) ? 1246 1239 RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); 1247 1240 1248 1241 highlightLineWidth = Main.pref.getInteger("mappaint.highlight.width", 4); 1249 1242 highlightPointRadius = Main.pref.getInteger("mappaint.highlight.radius", 7); … … 1441 1434 void process(List<? extends OsmPrimitive> prims) { 1442 1435 final List<ComputeStyleListWorker> tasks = new ArrayList<>(); 1443 final int bucketsize = Math.max(100, prims.size()/ noThreads/3);1436 final int bucketsize = Math.max(100, prims.size()/THREAD_POOL.a/3); 1444 1437 final int noBuckets = (prims.size() + bucketsize - 1) / bucketsize; 1445 final boolean singleThread = noThreads== 1 || noBuckets == 1;1438 final boolean singleThread = THREAD_POOL.a == 1 || noBuckets == 1; 1446 1439 for (int i=0; i<noBuckets; i++) { 1447 1440 int from = i*bucketsize; … … 1458 1451 throw new RuntimeException(ex); 1459 1452 } 1460 } else if ( tasks.size() > 1) {1453 } else if (!tasks.isEmpty()) { 1461 1454 try { 1462 for (Future<List<StyleRecord>> future : styleCreatorPool.invokeAll(tasks)) {1463 1455 for (Future<List<StyleRecord>> future : THREAD_POOL.b.invokeAll(tasks)) { 1456 allStyleElems.addAll(future.get()); 1464 1457 } 1465 1458 } catch (InterruptedException | ExecutionException ex) { -
trunk/src/org/openstreetmap/josm/tools/Utils.java
r7356 r7423 42 42 import java.util.Iterator; 43 43 import java.util.List; 44 import java.util.concurrent.ExecutorService; 45 import java.util.concurrent.Executors; 44 46 import java.util.regex.Matcher; 45 47 import java.util.regex.Pattern; … … 1064 1066 return true; 1065 1067 } 1068 1069 /** 1070 * Returns a pair containing the number of threads (n), and a thread pool (if n > 1) to perform 1071 * multi-thread computation in the context of the given preference key. 1072 * @param pref The preference key 1073 * @return a pair containing the number of threads (n), and a thread pool (if n > 1, null otherwise) 1074 * @since 7423 1075 */ 1076 public static Pair<Integer, ExecutorService> newThreadPool(String pref) { 1077 int noThreads = Main.pref.getInteger(pref, Runtime.getRuntime().availableProcessors()); 1078 ExecutorService pool = noThreads <= 1 ? null : Executors.newFixedThreadPool(noThreads); 1079 return new Pair<>(noThreads, pool); 1080 } 1066 1081 }
Note:
See TracChangeset
for help on using the changeset viewer.