Ignore:
Timestamp:
2013-12-09T22:50:12+01:00 (10 years ago)
Author:
simon04
Message:

fix #9089 - improve sorting of associatedStreet/street relation members

In addition, fix a bug when more additionalSorters are adequate: This
led to duplicate relation members.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorter.java

    r6316 r6461  
    66import java.util.Collections;
    77import java.util.Comparator;
    8 import java.util.HashMap;
     8import java.util.LinkedHashMap;
    99import java.util.LinkedList;
    1010import java.util.List;
     
    1313
    1414import org.openstreetmap.josm.data.osm.RelationMember;
     15import org.openstreetmap.josm.gui.DefaultNameFormatter;
     16import org.openstreetmap.josm.tools.AlphanumComparator;
    1517
    1618public class RelationSorter {
     
    2426
    2527    static {
    26         additionalSorters.add(new AssociatedStreetSorter());
     28        // first adequate sorter is used, so order matters
     29        additionalSorters.add(new AssociatedStreetRoleStreetSorter());
     30        additionalSorters.add(new AssociatedStreetRoleAddressHouseSorter());
    2731    }
    2832
    2933    /**
    30      * Class that sorts type=associatedStreet relation's houses.
     34     * Class that sorts the {@code street} members of
     35     * {@code type=associatedStreet} and {@code type=street} relations.
    3136     */
    32     private static class AssociatedStreetSorter implements AdditionalSorter {
     37    private static class AssociatedStreetRoleStreetSorter implements AdditionalSorter {
    3338
    3439        @Override
    3540        public boolean acceptsMember(RelationMember m) {
    36             return m != null
    37                     && m.getRole() != null && m.getRole().equals("house")
    38                     && m.getMember() != null && m.getMember().get("addr:housenumber") != null;
     41            return "street".equals(m.getRole());
     42        }
     43
     44        @Override
     45        public List<RelationMember> sortMembers(List<RelationMember> list) {
     46            return sortMembersByConnectivity(list);
     47        }
     48    }
     49
     50    /**
     51     * Class that sorts the {@code address} and {@code house} members of
     52     * {@code type=associatedStreet} and {@code type=street} relations.
     53     */
     54    private static class AssociatedStreetRoleAddressHouseSorter implements AdditionalSorter {
     55
     56        public static final AlphanumComparator ALPHANUM_COMPARATOR = new AlphanumComparator();
     57
     58        @Override
     59        public boolean acceptsMember(RelationMember m) {
     60            return "address".equals(m.getRole()) || "house".equals(m.getRole());
    3961        }
    4062
     
    4466                @Override
    4567                public int compare(RelationMember a, RelationMember b) {
    46                     if (a == b || a.getMember() == b.getMember()) return 0;
    47                     String addrA = a.getMember().get("addr:housenumber").trim();
    48                     String addrB = b.getMember().get("addr:housenumber").trim();
    49                     if (addrA.equals(addrB)) return 0;
    50                     // Strip non-digits (from "1B" addresses for example)
    51                     String addrAnum = addrA.replaceAll("\\D+", "");
    52                     String addrBnum = addrB.replaceAll("\\D+", "");
    53                     // Compare only numbers
    54                     try {
    55                         Integer res = Integer.parseInt(addrAnum) - Integer.parseInt(addrBnum);
    56                         if (res != 0) return res;
    57                     } catch (NumberFormatException e) {
    58                         // Ignore NumberFormatException. If the number is not composed of digits, strings are compared next
     68                    final int houseNumber = ALPHANUM_COMPARATOR.compare(
     69                            a.getMember().get("addr:housenumber"),
     70                            b.getMember().get("addr:housenumber"));
     71                    if (houseNumber != 0) {
     72                        return houseNumber;
    5973                    }
    60                     // Same number ? Compare full strings
    61                     return addrA.compareTo(addrB);
     74                    final String aDisplayName = a.getMember().getDisplayName(DefaultNameFormatter.getInstance());
     75                    final String bDisplayName = b.getMember().getDisplayName(DefaultNameFormatter.getInstance());
     76                    return ALPHANUM_COMPARATOR.compare(aDisplayName, bDisplayName);
    6277                }
    6378            });
     
    7792        // Sort members with custom mechanisms (relation-dependent)
    7893        List<RelationMember> defaultMembers = new ArrayList<RelationMember>(relationMembers.size());
    79         Map<AdditionalSorter, List<RelationMember>> customMap = new HashMap<AdditionalSorter, List<RelationMember>>();
     94        // Maps sorter to assigned members for sorting. Use LinkedHashMap to retain order.
     95        Map<AdditionalSorter, List<RelationMember>> customMap = new LinkedHashMap<AdditionalSorter, List<RelationMember>>();
    8096
    81         // Dispatch members to correct sorters
     97        // Dispatch members to the first adequate sorter
    8298        for (RelationMember m : relationMembers) {
     99            boolean wasAdded = false;
    83100            for (AdditionalSorter sorter : additionalSorters) {
    84                 List<RelationMember> list = defaultMembers;
    85101                if (sorter.acceptsMember(m)) {
     102                    List<RelationMember> list;
    86103                    list = customMap.get(sorter);
    87104                    if (list == null) {
    88105                        customMap.put(sorter, list = new LinkedList<RelationMember>());
    89106                    }
     107                    list.add(m);
     108                    wasAdded = true;
     109                    break;
    90110                }
    91                 list.add(m);
     111            }
     112            if (!wasAdded) {
     113                defaultMembers.add(m);
    92114            }
    93115        }
     
    97119            newMembers.addAll(entry.getKey().sortMembers(entry.getValue()));
    98120        }
     121        newMembers.addAll(sortMembersByConnectivity(defaultMembers));
     122        return newMembers;
     123    }
     124
     125    public static List<RelationMember> sortMembersByConnectivity(List<RelationMember> defaultMembers) {
     126
     127        List<RelationMember> newMembers = new ArrayList<RelationMember>();
    99128
    100129        RelationNodeMap map = new RelationNodeMap(defaultMembers);
Note: See TracChangeset for help on using the changeset viewer.