Ticket #23397: 23397-a2.patch

File 23397-a2.patch, 10.3 KB (added by GerdP, 20 months ago)

WIP patch to demonstrate what I have in mind.

  • src/org/openstreetmap/josm/actions/upload/ValidateUploadHook.java

     
    66import java.awt.Dimension;
    77import java.awt.GridBagLayout;
    88import java.util.Collection;
     9import java.util.HashSet;
    910import java.util.List;
    1011import java.util.concurrent.atomic.AtomicBoolean;
    1112
     
    1314import javax.swing.JScrollPane;
    1415
    1516import org.openstreetmap.josm.data.APIDataSet;
     17import org.openstreetmap.josm.data.osm.Node;
    1618import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1719import org.openstreetmap.josm.data.validation.OsmValidator;
    1820import org.openstreetmap.josm.data.validation.TestError;
     
    4547    @Override
    4648    public boolean checkUpload(APIDataSet apiDataSet) {
    4749        AtomicBoolean returnCode = new AtomicBoolean();
     50        Collection<OsmPrimitive> initialList = new HashSet<>(apiDataSet.getPrimitivesToAdd());
     51        initialList.addAll(apiDataSet.getPrimitivesToUpdate());
     52        // see #23397
     53        // create extended list with parent objects of modified nodes as they may mean a geometry change
     54        // maybe find a better place to do this?
     55        Collection<OsmPrimitive> extendedList = new HashSet<>(initialList);
     56        for (OsmPrimitive p : initialList) {
     57            if (p instanceof Node && !p.isNew()) {
     58                for (OsmPrimitive parent : p.getReferrers()) {
     59                    if (!parent.isDeleted()) {
     60                        extendedList.add(parent);
     61                    }
     62                }
     63            }
     64        }
    4865        AggregatePrimitivesVisitor v = new AggregatePrimitivesVisitor();
    49         v.visit(apiDataSet.getPrimitivesToAdd());
    50         Collection<OsmPrimitive> visited = v.visit(apiDataSet.getPrimitivesToUpdate());
     66        Collection<OsmPrimitive> visited = v.visit(extendedList);
    5167        OsmValidator.initializeTests();
    5268        new ValidationTask(errors -> {
    5369            if (errors.stream().allMatch(TestError::isIgnored)) {
  • src/org/openstreetmap/josm/data/validation/Test.java

     
    66import java.awt.GridBagConstraints;
    77import java.util.ArrayList;
    88import java.util.Collection;
     9import java.util.HashSet;
    910import java.util.List;
    1011import java.util.Optional;
     12import java.util.Set;
    1113import java.util.function.Predicate;
    1214import java.util.stream.Collectors;
    1315
     
    383385    public Object getSource() {
    384386        return "Java: " + this.getClass().getName();
    385387    }
     388
     389    /**
     390     * Filter the list of errors, remove all which do not concern the given list of primitives
     391     * @param given the list of primitives
     392     * @since xxx
     393     */
     394    public void removeIrrelevantErrors(Collection<? extends OsmPrimitive> given) {
     395        if (errors == null || errors.isEmpty())
     396            return;
     397        // filter errors for those which are needed, don't show errors for objects which were not in the selection
     398        final Set<? extends OsmPrimitive> relevant;
     399        if (given instanceof Set) {
     400            relevant = (Set<? extends OsmPrimitive>) given;
     401        } else {
     402            relevant = new HashSet<>(given);
     403        }
     404        errors.removeIf(e -> !e.isConcerned(relevant));
     405    }
    386406}
  • src/org/openstreetmap/josm/data/validation/TestError.java

     
    1212import java.util.List;
    1313import java.util.Locale;
    1414import java.util.Map;
     15import java.util.Set;
    1516import java.util.TreeSet;
    1617import java.util.function.Supplier;
    1718import java.util.stream.Collectors;
     
    666667                ", code=" + code + ", message=" + message + ']';
    667668    }
    668669
     670    /**
     671     * Check if any of the primitives in this error occurs in the given set of primitives.
     672     * @param given the set of primitives
     673     * @return true if any of the primitives in this error occurs in the given set of primitives, else false
     674     * @since xxx
     675     */
     676    public boolean isConcerned(Set<? extends OsmPrimitive> given) {
     677        for (OsmPrimitive p : getPrimitives()) {
     678            if (given.contains(p)) {
     679                return true;
     680            }
     681        }
     682        return false;
     683    }
    669684}
  • src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java

     
    66import java.awt.geom.Point2D;
    77import java.util.ArrayList;
    88import java.util.Arrays;
     9import java.util.Collection;
    910import java.util.HashMap;
    1011import java.util.HashSet;
    1112import java.util.List;
     
    1617
    1718import org.openstreetmap.josm.data.coor.EastNorth;
    1819import org.openstreetmap.josm.data.coor.ILatLon;
     20import org.openstreetmap.josm.data.osm.DataSet;
     21import org.openstreetmap.josm.data.osm.OsmDataManager;
    1922import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2023import org.openstreetmap.josm.data.osm.OsmUtils;
    2124import org.openstreetmap.josm.data.osm.Relation;
     
    8184    private final Map<Point2D, List<WaySegment>> cellSegments = new HashMap<>(1000);
    8285    /** The already detected ways in error */
    8386    private final Map<List<Way>, List<WaySegment>> seenWays = new HashMap<>(50);
     87    private final Set<Way> waysToTest = new HashSet<>();
    8488
    8589    protected final int code;
     90    private DataSet ds;
    8691
    8792    /**
    8893     * General crossing ways test.
     
    305310
    306311    @Override
    307312    public void endTest() {
    308         super.endTest();
     313        ds = OsmDataManager.getInstance().getActiveDataSet();
     314        if (ds == null || waysToTest.isEmpty())
     315            return;
     316        final Collection<Way> selection;
     317        if (this instanceof SelfCrossing || !partialSelection) {
     318            selection = waysToTest;
     319        } else {
     320            selection = new HashSet<>();
     321            for (Way w: waysToTest) {
     322                selection.addAll(ds.searchWays(w.getBBox()));
     323            }
     324        }
     325        for (Way w : selection) {
     326            if (!w.isDeleted() && isPrimitiveUsable(w)) {
     327                testWay(w);
     328            }
     329        }
     330        // free storage
    309331        cellSegments.clear();
    310332        seenWays.clear();
     333        if (partialSelection) {
     334            removeIrrelevantErrors(waysToTest);
     335        }
     336        super.endTest();
     337        waysToTest.clear();
     338        ds = null;
    311339    }
    312340
    313341    static boolean isCoastline(OsmPrimitive w) {
     
    344372
    345373    @Override
    346374    public void visit(Way w) {
     375        waysToTest.add(w);
     376    }
     377
     378    private void testWay(Way w) {
    347379        boolean findSelfCrossingOnly = this instanceof SelfCrossing;
    348380        if (findSelfCrossingOnly) {
    349381            // free memory, we are not interested in previous ways
     
    482514        CheckParameterUtil.ensureParameterNotNull(way, "way");
    483515        SelfCrossing test = new SelfCrossing();
    484516        test.visit(way);
     517        test.endTest();
    485518        return !test.getErrors().isEmpty();
    486519    }
    487520}
  • src/org/openstreetmap/josm/data/validation/tests/DuplicateWay.java

     
    77import java.util.Collection;
    88import java.util.Collections;
    99import java.util.HashSet;
     10import java.util.LinkedHashSet;
    1011import java.util.LinkedList;
    1112import java.util.List;
    1213import java.util.Map;
     
    103104
    104105    /** Set of known hashcodes for list of coordinates **/
    105106    private Set<Integer> knownHashCodes;
     107    private List<Way> waysToCheck;
    106108
    107109    /**
    108110     * Constructor
     
    115117    @Override
    116118    public void startTest(ProgressMonitor monitor) {
    117119        super.startTest(monitor);
     120        waysToCheck = new ArrayList<>();
    118121        ways = new MultiMap<>(1000);
    119122        waysNoTags = new MultiMap<>(1000);
    120123        knownHashCodes = new HashSet<>(1000);
     
    122125
    123126    @Override
    124127    public void endTest() {
    125         super.endTest();
     128        if (partialSelection && !waysToCheck.isEmpty()) {
     129            // make sure that we have the error candidates even if not selected
     130            Set<Way> extended = new LinkedHashSet<>(waysToCheck);
     131            for (Way w : waysToCheck) {
     132                // select a node, anyone can be used but a middle node is less likely to have many parent ways
     133                final Node n = w.getNode(w.getNodesCount()/2);
     134                // check the ways which might be in the same position
     135                for (Way other : n.getParentWays()) {
     136                    if (other != w && !other.isDeleted() && other.isUsable()
     137                            && other.getNodesCount() == w.getNodesCount())
     138                        extended.add(other);
     139                }
     140            }
     141            extended.forEach(this::checkWay);
     142        }
     143
    126144        for (Set<OsmPrimitive> duplicated : ways.values()) {
    127145            if (duplicated.size() > 1) {
    128146                TestError testError = TestError.builder(this, Severity.ERROR, DUPLICATE_WAY)
     
    162180                errors.add(testError);
    163181            }
    164182        }
     183
     184        if (partialSelection) {
     185            removeIrrelevantErrors(waysToCheck);
     186        }
     187
    165188        ways = null;
    166189        waysNoTags = null;
    167190        knownHashCodes = null;
     191        waysToCheck = null;
     192        super.endTest();
    168193    }
    169194
    170195    /**
     
    181206    public void visit(Way w) {
    182207        if (!w.isUsable())
    183208            return;
     209        if (partialSelection)
     210            waysToCheck.add(w);
     211        else
     212            checkWay(w);
     213    }
     214
     215    private void checkWay(Way w) {
    184216        List<LatLon> wLat = getOrderedNodes(w);
    185217        // If this way has not direction-dependant keys, make sure the list is ordered the same for all ways (fix #8015)
    186218        if (!w.hasDirectionKeys()) {