Changeset 16611 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2020-06-13T06:35:37+02:00 (6 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 1 added
- 4 edited
-
actions/downloadtasks/DownloadReferrersTask.java (modified) (4 diffs)
-
gui/io/DownloadFromOverpassTask.java (added)
-
gui/io/DownloadPrimitivesWithReferrersTask.java (modified) (8 diffs)
-
io/MultiFetchOverpassObjectReader.java (modified) (2 diffs)
-
io/MultiFetchServerObjectReader.java (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java
r16405 r16611 15 15 import javax.swing.SwingUtilities; 16 16 17 import org.openstreetmap.josm.data.Bounds; 17 18 import org.openstreetmap.josm.data.osm.DataSet; 18 19 import org.openstreetmap.josm.data.osm.DataSetMerger; … … 27 28 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 28 29 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 30 import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader; 29 31 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 30 32 import org.openstreetmap.josm.io.OsmServerBackreferenceReader; 31 33 import org.openstreetmap.josm.io.OsmServerReader; 32 34 import org.openstreetmap.josm.io.OsmTransferException; 35 import org.openstreetmap.josm.io.OverpassDownloadReader; 33 36 import org.openstreetmap.josm.tools.CheckParameterUtil; 34 37 import org.openstreetmap.josm.tools.ExceptionUtil; … … 155 158 protected void realRun() throws SAXException, IOException, OsmTransferException { 156 159 try { 157 progressMonitor.setTicksCount(children.size()); 158 int i = 1; 159 for (PrimitiveId p : children) { 160 if (canceled) 161 return; 162 String msg; 163 String id = Long.toString(p.getUniqueId()); 164 switch(p.getType()) { 165 case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break; 166 case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break; 167 case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break; 168 default: throw new AssertionError(); 160 if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) { 161 String request = MultiFetchOverpassObjectReader.genOverpassQuery(children, false, true, false); 162 reader = new OverpassDownloadReader(new Bounds(0, 0, 0, 0), 163 OverpassDownloadReader.OVERPASS_SERVER.get(), request); 164 DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false)); 165 new DataSetMerger(parents, ds).merge(); 166 } else { 167 progressMonitor.setTicksCount(children.size()); 168 int i = 1; 169 for (PrimitiveId p : children) { 170 if (canceled) 171 return; 172 String msg; 173 String id = Long.toString(p.getUniqueId()); 174 switch(p.getType()) { 175 case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break; 176 case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break; 177 case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break; 178 default: throw new AssertionError(); 179 } 180 progressMonitor.subTask(msg); 181 downloadParents(p.getUniqueId(), p.getType(), progressMonitor); 182 i++; 169 183 } 170 progressMonitor.subTask(msg); 171 downloadParents(p.getUniqueId(), p.getType(), progressMonitor); 172 i++; 173 } 174 Collection<Way> ways = parents.getWays(); 175 176 if (!ways.isEmpty()) { 177 // Collect incomplete nodes of parent ways 178 Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete)) 179 .collect(Collectors.toSet()); 180 if (!nodes.isEmpty()) { 181 reader = MultiFetchServerObjectReader.create(); 182 ((MultiFetchServerObjectReader) reader).append(nodes); 183 DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false)); 184 synchronized (this) { // avoid race condition in cancel() 185 reader = null; 184 Collection<Way> ways = parents.getWays(); 185 186 if (!ways.isEmpty()) { 187 // Collect incomplete nodes of parent ways 188 Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete)) 189 .collect(Collectors.toSet()); 190 if (!nodes.isEmpty()) { 191 reader = MultiFetchServerObjectReader.create(); 192 ((MultiFetchServerObjectReader) reader).append(nodes); 193 DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false)); 194 synchronized (this) { // avoid race condition in cancel() 195 reader = null; 196 } 197 new DataSetMerger(parents, wayNodes).merge(); 186 198 } 187 new DataSetMerger(parents, wayNodes).merge();188 199 } 189 200 } … … 194 205 } 195 206 } 207 196 208 } -
trunk/src/org/openstreetmap/josm/gui/io/DownloadPrimitivesWithReferrersTask.java
r16553 r16611 10 10 import java.text.MessageFormat; 11 11 import java.util.ArrayList; 12 import java.util.Collections; 12 13 import java.util.HashSet; 14 import java.util.LinkedHashSet; 13 15 import java.util.List; 14 16 import java.util.Set; … … 32 34 import org.openstreetmap.josm.gui.widgets.HtmlPanel; 33 35 import org.openstreetmap.josm.gui.widgets.JosmTextArea; 36 import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader; 34 37 import org.openstreetmap.josm.io.OsmTransferException; 38 import org.openstreetmap.josm.io.OverpassDownloadReader; 35 39 import org.openstreetmap.josm.tools.GBC; 36 40 import org.xml.sax.SAXException; … … 51 55 /** Temporary layer where downloaded primitives are put */ 52 56 private final OsmDataLayer tmpLayer; 53 /** Reference to the task that download requested primitives */54 private DownloadPrimitivesTask mainTask;55 57 /** Flag indicated that user ask for cancel this task */ 56 58 private boolean canceled; 57 59 /** Reference to the task currently running */ 58 60 private PleaseWaitRunnable currentTask; 61 62 /** set of missing ids, with overpass API these are also deleted objects */ 63 private Set<PrimitiveId> missingPrimitives; 59 64 60 65 /** … … 102 107 @Override 103 108 protected void realRun() throws SAXException, IOException, OsmTransferException { 109 if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) { 110 useOverpassApi(); 111 } else { 112 useOSMApi(); 113 } 114 } 115 116 private void useOverpassApi() { 117 String request = MultiFetchOverpassObjectReader.genOverpassQuery(ids, true, downloadReferrers, full); 118 currentTask = new DownloadFromOverpassTask(request, tmpLayer.data, getProgressMonitor().createSubTaskMonitor(1, false)); 119 currentTask.run(); 120 missingPrimitives = ids.stream() 121 .filter(id -> tmpLayer.data.getPrimitiveById(id) == null) 122 .collect(Collectors.toSet()); 123 } 124 125 private void useOSMApi() { 104 126 getProgressMonitor().setTicksCount(ids.size()+1); 105 127 // First, download primitives 106 mainTask = new DownloadPrimitivesTask(tmpLayer, ids, full, getProgressMonitor().createSubTaskMonitor(1, false)); 128 DownloadPrimitivesTask mainTask = new DownloadPrimitivesTask(tmpLayer, ids, full, 129 getProgressMonitor().createSubTaskMonitor(1, false)); 107 130 synchronized (this) { 108 131 currentTask = mainTask; … … 113 136 } 114 137 currentTask.run(); 138 139 missingPrimitives = mainTask.getMissingPrimitives(); 140 115 141 // Then, download referrers for each primitive 116 142 if (downloadReferrers && tmpLayer.data != null) { … … 144 170 layer.mergeFrom(tmpLayer); 145 171 172 // Collect known deleted primitives 173 final Set<PrimitiveId> del = new HashSet<>(); 174 DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 175 for (PrimitiveId id : ids) { 176 OsmPrimitive osm = ds.getPrimitiveById(id); 177 if (osm != null && osm.isDeleted()) { 178 del.add(id); 179 } 180 } 181 final Set<PrimitiveId> errs; 182 if (missingPrimitives != null) { 183 errs = missingPrimitives.stream().filter(id -> !del.contains(id)).collect(Collectors.toCollection(LinkedHashSet::new)); 184 } else { 185 errs = Collections.emptySet(); 186 } 187 146 188 // Warm about missing primitives 147 final Set<PrimitiveId> errs = mainTask.getMissingPrimitives(); 148 if (errs != null && !errs.isEmpty()) 189 if (!errs.isEmpty()) { 190 final String assumedApiRC; 191 if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) { 192 assumedApiRC = trn("The server did not return data for the requested object, it was either deleted or does not exist.", 193 "The server did not return data for the requested objects, they were either deleted or do not exist.", 194 errs.size()); 195 196 } else { 197 assumedApiRC = tr("The server replied with response code 404.<br>" 198 + "This usually means, the server does not know an object with the requested id."); 199 } 149 200 GuiHelper.runInEDTAndWait(() -> reportProblemDialog(errs, 150 201 trn("Object could not be downloaded", "Some objects could not be downloaded", errs.size()), … … 153 204 errs.size(), 154 205 errs.size()) 155 + tr("The server replied with response code 404.<br>" 156 + "This usually means, the server does not know an object with the requested id."), 206 + assumedApiRC, 157 207 tr("missing objects:"), 158 208 JOptionPane.ERROR_MESSAGE 159 209 ).showDialog()); 210 } 160 211 161 212 // Warm about deleted primitives 162 final Set<PrimitiveId> del = new HashSet<>();163 DataSet ds = MainApplication.getLayerManager().getEditDataSet();164 for (PrimitiveId id : ids) {165 OsmPrimitive osm = ds.getPrimitiveById(id);166 if (osm != null && osm.isDeleted()) {167 del.add(id);168 }169 }170 213 if (!del.isEmpty()) 171 214 GuiHelper.runInEDTAndWait(() -> reportProblemDialog(del, … … 191 234 } 192 235 List<PrimitiveId> downloaded = new ArrayList<>(ids); 193 downloaded.removeAll(m ainTask.getMissingPrimitives());236 downloaded.removeAll(missingPrimitives); 194 237 return downloaded; 195 238 } -
trunk/src/org/openstreetmap/josm/io/MultiFetchOverpassObjectReader.java
r16008 r16611 2 2 package org.openstreetmap.josm.io; 3 3 4 import java.util.Map.Entry; 4 import java.util.Arrays; 5 import java.util.Collection; 6 import java.util.LinkedHashMap; 7 import java.util.List; 8 import java.util.Map; 5 9 import java.util.Set; 10 import java.util.TreeSet; 6 11 import java.util.stream.Collectors; 7 12 8 13 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 14 import org.openstreetmap.josm.data.osm.PrimitiveId; 9 15 import org.openstreetmap.josm.tools.Logging; 10 16 … … 15 21 */ 16 22 public class MultiFetchOverpassObjectReader extends MultiFetchServerObjectReader { 23 private static final List<OsmPrimitiveType> wantedOrder = Arrays.asList(OsmPrimitiveType.RELATION, 24 OsmPrimitiveType.WAY, OsmPrimitiveType.NODE); 17 25 18 26 private static String getPackageString(final OsmPrimitiveType type, Set<Long> idPackage) { 19 27 return idPackage.stream().map(String::valueOf) 20 .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ") ;"));28 .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ")")); 21 29 } 22 30 23 31 /** 24 * Create a single query for all elements 25 * @return the request string 32 * Generate single overpass query to retrieve multiple primitives. Can be used to download parents, 33 * children, the objects, or any combination of them. 34 * @param ids the collection of ids 35 * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers) 36 * @param recurseUp if true, referrers (parents) of the objects are downloaded and all nodes of parent ways 37 * @param recurseDownRelations true: yes, recurse down to retrieve complete relations 38 * @return the overpass query 39 * @since xxx 26 40 */ 27 protected String buildComplexRequestString() { 28 StringBuilder sb = new StringBuilder(); 29 int countTypes = 0; 30 for (Entry<OsmPrimitiveType, Set<Long>> e : primitivesMap.entrySet()) { 31 if (!e.getValue().isEmpty()) { 32 countTypes++; 33 String list = getPackageString(e.getKey(), e.getValue()); 34 switch (e.getKey()) { 35 case MULTIPOLYGON: 36 case RELATION: 41 public static String genOverpassQuery(Collection<? extends PrimitiveId> ids, boolean includeObjects, boolean recurseUp, 42 boolean recurseDownRelations) { 43 Map<OsmPrimitiveType, Set<Long>> primitivesMap = new LinkedHashMap<>(); 44 Arrays.asList(OsmPrimitiveType.RELATION, OsmPrimitiveType.WAY, OsmPrimitiveType.NODE) 45 .forEach(type -> primitivesMap.put(type, new TreeSet<>())); 46 for (PrimitiveId p : ids) { 47 primitivesMap.get(p.getType()).add(p.getUniqueId()); 48 } 49 return genOverpassQuery(primitivesMap, includeObjects, recurseUp, recurseDownRelations); 50 } 51 52 /** 53 * Generate single overpass query to retrieve multiple primitives. Can be used to download parents, 54 * children, the objects, or any combination of them. 55 * @param primitivesMap map containing the primitives 56 * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers) 57 * @param recurseUp if true, referrers (parents) of the objects are downloaded and all nodes of parent ways 58 * @param recurseDownRelations true: yes, recurse down to retrieve complete relations 59 * @return the overpass query 60 */ 61 protected static String genOverpassQuery(Map<OsmPrimitiveType, Set<Long>> primitivesMap, boolean includeObjects, 62 boolean recurseUp, boolean recurseDownRelations) { 63 if (!(includeObjects || recurseUp || recurseDownRelations)) 64 throw new IllegalArgumentException("At least one options must be true"); 65 StringBuilder sb = new StringBuilder(128); 66 StringBuilder setsToInclude = new StringBuilder(); 67 StringBuilder up = new StringBuilder(); 68 String down = null; 69 for (OsmPrimitiveType type : wantedOrder) { 70 Set<Long> set = primitivesMap.get(type); 71 if (!set.isEmpty()) { 72 sb.append(getPackageString(type, set)); 73 if (type == OsmPrimitiveType.NODE) { 74 sb.append("->.n;"); 75 if (includeObjects) { 76 setsToInclude.append(".n;"); 77 } 78 if (recurseUp) { 79 up.append(".n;way(bn)->.wn;.n;rel(bn)->.rn;"); 80 setsToInclude.append(".wn;node(w);.rn;"); 81 } 82 } else if (type == OsmPrimitiveType.WAY) { 83 sb.append("->.w;"); 84 if (includeObjects) { 85 setsToInclude.append(".w;>;"); 86 } 87 if (recurseUp) { 88 up.append(".w;rel(bw)->.pw;"); 89 setsToInclude.append(".pw;"); 90 } 91 } else { 92 sb.append("->.r;"); 93 if (includeObjects) { 94 setsToInclude.append(".r;"); 95 } 96 if (recurseUp) { 97 up.append(".r;rel(br)->.pr;"); 98 setsToInclude.append(".pr;"); 99 } 37 100 if (recurseDownRelations) { 38 sb.append('(').append(list); 39 sb.setLength(sb.length()-1); // remove semicolon 40 //recurse down only one level, see #18835 41 sb.append("->.r;.r;rel(r);.r;way(r);>;.r;node(r););"); 42 } else { 43 sb.append(list); 101 // get complete ways and nodes of the relation and next level of sub relations 102 down = ".r;rel(r)->.rm;"; 103 setsToInclude.append(".r;>;.rm;"); 44 104 } 45 break;46 case CLOSEDWAY:47 case WAY:48 sb.append('(').append(list).append(">;);");49 break;50 case NODE:51 sb.append(list);52 105 } 53 106 } 54 107 } 108 if (up.length() > 0) { 109 sb.append(up); 110 } 111 if (down != null) { 112 sb.append(down); 113 } 114 sb.append('(').append(setsToInclude).append(");"); 115 116 sb.append("out meta;"); 55 117 String query = sb.toString(); 56 if (countTypes > 1) {57 query = "(" + query + ");";58 }59 query += "out meta;";60 118 Logging.debug("{0} {1}", "Generated Overpass query:", query); 61 119 return query; -
trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java
r16203 r16611 383 383 if (this instanceof MultiFetchOverpassObjectReader) { 384 384 // calculate a single request for all the objects 385 String request = ((MultiFetchOverpassObjectReader) this).buildComplexRequestString();385 String request = MultiFetchOverpassObjectReader.genOverpassQuery(primitivesMap, true, false, recurseDownRelations); 386 386 if (isCanceled()) 387 387 return null; 388 388 OverpassDownloadReader reader = new OverpassDownloadReader(new Bounds(0, 0, 0, 0), getBaseUrl(), request); 389 DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor( n, false));389 DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false)); 390 390 new DataSetMerger(outputDataSet, ds).merge(); 391 391 checkMissing(outputDataSet, progressMonitor);
Note:
See TracChangeset
for help on using the changeset viewer.
