Ticket #12303: 12303.3.patch

File 12303.3.patch, 14.5 KB (added by GerdP, 4 months ago)
  • src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java

     
    1414import javax.swing.JOptionPane;
    1515import javax.swing.SwingUtilities;
    1616
     17import org.openstreetmap.josm.data.Bounds;
    1718import org.openstreetmap.josm.data.osm.DataSet;
    1819import org.openstreetmap.josm.data.osm.DataSetMerger;
    1920import org.openstreetmap.josm.data.osm.Node;
     
    2627import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    2728import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2829import org.openstreetmap.josm.gui.progress.ProgressMonitor;
     30import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader;
    2931import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
    3032import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
    3133import org.openstreetmap.josm.io.OsmServerReader;
    3234import org.openstreetmap.josm.io.OsmTransferException;
     35import org.openstreetmap.josm.io.OverpassDownloadReader;
    3336import org.openstreetmap.josm.tools.CheckParameterUtil;
    3437import org.openstreetmap.josm.tools.ExceptionUtil;
    3538import org.xml.sax.SAXException;
     
    150153    @Override
    151154    protected void realRun() throws SAXException, IOException, OsmTransferException {
    152155        try {
    153             progressMonitor.setTicksCount(children.size());
    154             int i = 1;
    155             for (PrimitiveId p : children) {
    156                 if (canceled)
    157                     return;
    158                 String msg;
    159                 String id = Long.toString(p.getUniqueId());
    160                 switch(p.getType()) {
    161                 case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break;
    162                 case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break;
    163                 case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break;
    164                 default: throw new AssertionError();
     156            if (Boolean.TRUE.equals(OverpassDownloadReader.FOR_MULTI_FETCH.get())) {
     157                String request = MultiFetchOverpassObjectReader.genOverpassQuery(children, false, true, false);
     158                reader = new OverpassDownloadReader(new Bounds(0, 0, 0, 0),
     159                        OverpassDownloadReader.OVERPASS_SERVER.get(), request);
     160                DataSet ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
     161                new DataSetMerger(parents, ds).merge();
     162            } else {
     163                progressMonitor.setTicksCount(children.size());
     164                int i = 1;
     165                for (PrimitiveId p : children) {
     166                    if (canceled)
     167                        return;
     168                    String msg;
     169                    String id = Long.toString(p.getUniqueId());
     170                    switch(p.getType()) {
     171                    case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i, children.size(), id); break;
     172                    case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i, children.size(), id); break;
     173                    case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i, children.size(), id); break;
     174                    default: throw new AssertionError();
     175                    }
     176                    progressMonitor.subTask(msg);
     177                    downloadParents(p.getUniqueId(), p.getType(), progressMonitor);
     178                    i++;
    165179                }
    166                 progressMonitor.subTask(msg);
    167                 downloadParents(p.getUniqueId(), p.getType(), progressMonitor);
    168                 i++;
    169             }
    170             Collection<Way> ways = parents.getWays();
     180                Collection<Way> ways = parents.getWays();
    171181
    172             if (!ways.isEmpty()) {
    173                 // Collect incomplete nodes of parent ways
    174                 Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete))
    175                         .collect(Collectors.toSet());
    176                 if (!nodes.isEmpty()) {
    177                     reader = MultiFetchServerObjectReader.create();
    178                     ((MultiFetchServerObjectReader) reader).append(nodes);
    179                     DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
    180                     synchronized (this) { // avoid race condition in cancel()
    181                         reader = null;
     182                if (!ways.isEmpty()) {
     183                    // Collect incomplete nodes of parent ways
     184                    Set<Node> nodes = ways.stream().flatMap(w -> w.getNodes().stream().filter(OsmPrimitive::isIncomplete))
     185                            .collect(Collectors.toSet());
     186                    if (!nodes.isEmpty()) {
     187                        reader = MultiFetchServerObjectReader.create();
     188                        ((MultiFetchServerObjectReader) reader).append(nodes);
     189                        DataSet wayNodes = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
     190                        synchronized (this) { // avoid race condition in cancel()
     191                            reader = null;
     192                        }
     193                        new DataSetMerger(parents, wayNodes).merge();
    182194                    }
    183                     new DataSetMerger(parents, wayNodes).merge();
    184195                }
    185196            }
    186197        } catch (OsmTransferException e) {
     
    189200            lastException = e;
    190201        }
    191202    }
     203
    192204}
  • src/org/openstreetmap/josm/gui/io/DownloadPrimitivesWithReferrersTask.java

     
    3131import org.openstreetmap.josm.gui.util.GuiHelper;
    3232import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    3333import org.openstreetmap.josm.gui.widgets.JosmTextArea;
     34import org.openstreetmap.josm.io.MultiFetchOverpassObjectReader;
    3435import org.openstreetmap.josm.io.OsmTransferException;
    3536import org.openstreetmap.josm.tools.GBC;
    3637import org.xml.sax.SAXException;
     
    101102
    102103    @Override
    103104    protected void realRun() throws SAXException, IOException, OsmTransferException {
     105        MultiFetchOverpassObjectReader.genOverpassQuery(ids, true, downloadReferrers, full); // TODO: remove
    104106        getProgressMonitor().setTicksCount(ids.size()+1);
    105107        // First, download primitives
    106108        mainTask = new DownloadPrimitivesTask(tmpLayer, ids, full, getProgressMonitor().createSubTaskMonitor(1, false));
  • src/org/openstreetmap/josm/io/MultiFetchOverpassObjectReader.java

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.io;
    33
     4import java.util.Collection;
     5import java.util.Map;
    46import java.util.Map.Entry;
    57import java.util.Set;
     8import java.util.TreeMap;
     9import java.util.TreeSet;
    610import java.util.stream.Collectors;
    711
    812import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     13import org.openstreetmap.josm.data.osm.PrimitiveId;
    914import org.openstreetmap.josm.tools.Logging;
    1015
    1116/**
     
    1722
    1823    private static String getPackageString(final OsmPrimitiveType type, Set<Long> idPackage) {
    1924        return idPackage.stream().map(String::valueOf)
    20                 .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ");"));
     25                .collect(Collectors.joining(",", type.getAPIName() + (idPackage.size() == 1 ? "(" : "(id:"), ")"));
    2126    }
    2227
    2328    /**
     
    3035        for (Entry<OsmPrimitiveType, Set<Long>> e : primitivesMap.entrySet()) {
    3136            if (!e.getValue().isEmpty()) {
    3237                countTypes++;
    33                 String list = getPackageString(e.getKey(), e.getValue());
     38                String list = getPackageString(e.getKey(), e.getValue()) + ";";
    3439                switch (e.getKey()) {
    3540                case MULTIPOLYGON:
    3641                case RELATION:
     
    5661        return query;
    5762    }
    5863
     64    /**
     65     * Generate single overpass query to retrieve multiple primitives. Can be used to download parents,
     66     * children, the objects, or any combination of them.
     67     * @param ids the collection of ids
     68     * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers)
     69     * @param recurseUp if true, referrers (parents) of the objects are downloaded and all nodes of these parents
     70     * @param recurseDownRelations true: yes, recurse down to retrieve complete relations
     71     * @return the overpass query
     72     */
     73    public static String genOverpassQuery(Collection<PrimitiveId> ids, boolean includeObjects, boolean recurseUp,
     74            boolean recurseDownRelations) {
     75        Map<OsmPrimitiveType, Set<Long>> primitivesMap = new TreeMap<>();
     76        for (PrimitiveId p : ids) {
     77            primitivesMap.computeIfAbsent(p.getType(), k -> new TreeSet<>()).add(p.getUniqueId());
     78        }
     79        return genOverpassQuery(primitivesMap, includeObjects, recurseUp, recurseDownRelations);
     80    }
     81
     82    /**
     83     * Generate single overpass query to retrieve multiple primitives. Can be used to download parents,
     84     * children, the objects, or any combination of them.
     85     * @param primitivesMap map containing the primitives
     86     * @param includeObjects if false, don't retrieve the primitives (e.g. only the referrers)
     87     * @param recurseUp if true, referrers (parents) of the primitives are downloaded and all nodes of these parents
     88     * @param recurseDownRelations true: yes, recurse down to retrieve complete relations
     89     * @return the overpass query
     90     */
     91    public static String genOverpassQuery(Map<OsmPrimitiveType, Set<Long>> primitivesMap, boolean includeObjects,
     92            boolean recurseUp, boolean recurseDownRelations) {
     93        StringBuilder sb = new StringBuilder();
     94        StringBuilder setsToInclude = new StringBuilder("(");
     95        for (Entry<OsmPrimitiveType, Set<Long>> e : primitivesMap.entrySet()) {
     96            if (!e.getValue().isEmpty()) {
     97                String list = getPackageString(e.getKey(), e.getValue());
     98                switch (e.getKey()) {
     99                case NODE:
     100                    sb.append(list).append("->.n;");
     101                    if (includeObjects) {
     102                        setsToInclude.append(".n;");
     103                    }
     104                    if (recurseUp) {
     105                        sb.append(".n;way(bn)->.wn;.n;rel(bn)->.rn;");
     106                        setsToInclude.append(".wn;node(w);.rn;");
     107                    }
     108                    break;
     109                case CLOSEDWAY:
     110                case WAY:
     111                    sb.append(list).append("->.w;");
     112                    if (includeObjects) {
     113                        setsToInclude.append(".w;>;");
     114                    }
     115                    if (recurseUp) {
     116                        sb.append(".w;rel(bw)->.pw;");
     117                        setsToInclude.append(".pw;");
     118                    }
     119                    break;
     120                case MULTIPOLYGON:
     121                case RELATION:
     122                    sb.append(list).append("->.r;");
     123                    if (includeObjects) {
     124                        setsToInclude.append(".r;");
     125                    }
     126                    if (recurseUp) {
     127                        sb.append(".r;rel(br)->.pr;");
     128                        setsToInclude.append(".pr;");
     129                    }
     130                    if (recurseDownRelations) {
     131                        sb.append(".r;>>->.rm;");
     132                        setsToInclude.append(".rm;");
     133                    }
     134                    break;
     135                }
     136            }
     137        }
     138        setsToInclude.append(");");
     139        // retrieve all incomplete nodes for union of parents ?
     140        sb.append(setsToInclude);
     141        sb.append("out meta;");
     142        String query = sb.toString();
     143        Logging.debug("{0} {1}", "Possible Overpass query:", query);
     144        return query;
     145    }
     146
    59147    @Override
    60148    protected String getBaseUrl() {
    61149        return OverpassDownloadReader.OVERPASS_SERVER.get();
  • src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

     
    1212import java.util.Collections;
    1313import java.util.HashSet;
    1414import java.util.Iterator;
    15 import java.util.LinkedHashMap;
    1615import java.util.LinkedHashSet;
    1716import java.util.List;
    1817import java.util.Map;
    1918import java.util.Map.Entry;
    2019import java.util.Set;
     20import java.util.TreeMap;
    2121import java.util.concurrent.Callable;
    2222import java.util.concurrent.CompletionService;
    2323import java.util.concurrent.ExecutionException;
     
    8989        relations = new LinkedHashSet<>();
    9090        this.outputDataSet = new DataSet();
    9191        this.missingPrimitives = new LinkedHashSet<>();
    92         primitivesMap = new LinkedHashMap<>();
     92        primitivesMap = new TreeMap<>();
    9393        primitivesMap.put(OsmPrimitiveType.RELATION, relations);
    9494        primitivesMap.put(OsmPrimitiveType.WAY, ways);
    9595        primitivesMap.put(OsmPrimitiveType.NODE, nodes);
     
    382382        try {
    383383            if (this instanceof MultiFetchOverpassObjectReader) {
    384384                // calculate a single request for all the objects
    385                 String request = ((MultiFetchOverpassObjectReader) this).buildComplexRequestString();
     385                String request = MultiFetchOverpassObjectReader.genOverpassQuery(primitivesMap, true, false, recurseDownRelations);
    386386                if (isCanceled())
    387387                    return null;
    388388                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));
    390390                new DataSetMerger(outputDataSet, ds).merge();
    391391                checkMissing(outputDataSet, progressMonitor);
    392392            } else {