Ignore:
Timestamp:
2016-10-24T13:44:41+02:00 (8 years ago)
Author:
bastiK
Message:

see #13307 - validator/MultipolygonTest: add check for duplicate members (extracted from patch by Gerd Petermann, minor style and javadoc changes)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java

    r11135 r11157  
    1111import java.util.Collection;
    1212import java.util.Collections;
     13import java.util.HashMap;
    1314import java.util.HashSet;
    1415import java.util.List;
     16import java.util.Map;
     17import java.util.Map.Entry;
    1518import java.util.Set;
    1619
    1720import org.openstreetmap.josm.Main;
    1821import org.openstreetmap.josm.actions.CreateMultipolygonAction;
     22import org.openstreetmap.josm.command.ChangeCommand;
     23import org.openstreetmap.josm.command.Command;
    1924import org.openstreetmap.josm.data.osm.Node;
    2025import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    6772    /** Area style on outer way */
    6873    public static final int OUTER_STYLE = 1613;
     74    /** Multipolygon member repeated (same primitive, same role */
     75    public static final int REPEATED_MEMBER_SAME_ROLE = 1614;
     76    /** Multipolygon member repeated (same primitive, different role) */
     77    public static final int REPEATED_MEMBER_DIFF_ROLE = 1615;
    6978
    7079    private static volatile ElemStyles styles;
     
    160169            checkMembersAndRoles(r);
    161170            checkOuterWay(r);
     171            checkRepeatedWayMembers(r);
    162172
    163173            // Rest of checks is only for complete multipolygons
     
    413423    }
    414424
     425    /**
     426     * Check for:<ul>
     427     * <li>{@link #REPEATED_MEMBER_DIFF_ROLE}: Multipolygon member(s) repeated with different role</li>
     428     * <li>{@link #REPEATED_MEMBER_SAME_ROLE}: Multipolygon member(s) repeated with same role</li>
     429     * </ul>
     430     * @param r relation
     431     * @return true if repeated members have been detected, false otherwise
     432     */
     433    private boolean checkRepeatedWayMembers(Relation r) {
     434        boolean hasDups = false;
     435        Map<OsmPrimitive, List<RelationMember>> seenMemberPrimitives = new HashMap<>();
     436        for (RelationMember rm : r.getMembers()) {
     437            List<RelationMember> list = seenMemberPrimitives.get(rm.getMember());
     438            if (list == null) {
     439                list = new ArrayList<>(2);
     440                seenMemberPrimitives.put(rm.getMember(), list);
     441            } else {
     442                hasDups = true;
     443            }
     444            list.add(rm);
     445        }
     446        if (hasDups) {
     447            List<OsmPrimitive> repeatedSameRole = new ArrayList<>();
     448            List<OsmPrimitive> repeatedDiffRole = new ArrayList<>();
     449            for (Entry<OsmPrimitive, List<RelationMember>> e : seenMemberPrimitives.entrySet()) {
     450                List<RelationMember> visited = e.getValue();
     451                if (e.getValue().size() == 1)
     452                    continue;
     453                // we found a duplicate member, check if the roles differ
     454                boolean rolesDiffer = false;
     455                RelationMember rm = visited.get(0);
     456                List<OsmPrimitive> primitives = new ArrayList<>();
     457                for (int i = 1; i < visited.size(); i++) {
     458                    RelationMember v = visited.get(i);
     459                    primitives.add(rm.getMember());
     460                    if (!v.getRole().equals(rm.getRole())) {
     461                        rolesDiffer = true;
     462                    }
     463                }
     464                if (rolesDiffer) {
     465                    repeatedDiffRole.addAll(primitives);
     466                } else {
     467                    repeatedSameRole.addAll(primitives);
     468                }
     469            }
     470            addRepeatedMemberError(r, repeatedDiffRole, REPEATED_MEMBER_DIFF_ROLE, tr("Multipolygon member(s) repeated with different role"));
     471            addRepeatedMemberError(r, repeatedSameRole, REPEATED_MEMBER_SAME_ROLE, tr("Multipolygon member(s) repeated with same role"));
     472        }
     473        return hasDups;
     474    }
     475
     476    private void addRepeatedMemberError(Relation r, List<OsmPrimitive> repeatedMembers, int errorCode, String msg) {
     477        if (!repeatedMembers.isEmpty()) {
     478            List<OsmPrimitive> prims = new ArrayList<>(1 + repeatedMembers.size());
     479            prims.add(r);
     480            prims.addAll(repeatedMembers);
     481            errors.add(TestError.builder(this, Severity.WARNING, errorCode)
     482                    .message(msg)
     483                    .primitives(prims)
     484                    .highlight(repeatedMembers)
     485                    .build());
     486        }
     487    }
     488
     489    @Override
     490    public Command fixError(TestError testError) {
     491        if (testError.getCode() == REPEATED_MEMBER_SAME_ROLE) {
     492            ArrayList<OsmPrimitive> primitives = new ArrayList<>(testError.getPrimitives());
     493            if (primitives.size() >= 2) {
     494                if (primitives.get(0) instanceof Relation) {
     495                    Relation oldRel = (Relation) primitives.get(0);
     496                    Relation newRel = new Relation(oldRel);
     497                    List<OsmPrimitive> repeatedPrims = primitives.subList(1, primitives.size());
     498                    List<RelationMember> oldMembers = oldRel.getMembers();
     499
     500                    List<RelationMember> newMembers = new ArrayList<>();
     501                    HashSet<OsmPrimitive> toRemove = new HashSet<>(repeatedPrims);
     502                    HashSet<OsmPrimitive> found = new HashSet<>(repeatedPrims.size());
     503                    for (RelationMember rm : oldMembers) {
     504                        if (toRemove.contains(rm.getMember())) {
     505                            if (found.contains(rm.getMember()) == false) {
     506                                found.add(rm.getMember());
     507                                newMembers.add(rm);
     508                            }
     509                        } else {
     510                            newMembers.add(rm);
     511                        }
     512                    }
     513                    newRel.setMembers(newMembers);
     514                    return new ChangeCommand (oldRel, newRel);
     515                }
     516            }
     517        }
     518        return null;
     519    }
     520
     521    @Override
     522    public boolean isFixable(TestError testError) {
     523        if (testError.getCode() == REPEATED_MEMBER_SAME_ROLE)
     524            return true;
     525        return false;
     526    }
    415527}
Note: See TracChangeset for help on using the changeset viewer.