Ticket #6149: multipolygon.patch

File multipolygon.patch, 10.8 KB (added by Gubaer, 15 years ago)

Patch

  • src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java

     
    77import java.util.ArrayList;
    88import java.util.Collection;
    99import java.util.List;
     10import java.util.logging.Logger;
    1011
     12import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
     14import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
    1115import org.openstreetmap.josm.data.osm.Node;
    1216import org.openstreetmap.josm.data.osm.Relation;
    1317import org.openstreetmap.josm.data.osm.RelationMember;
     
    1620import org.openstreetmap.josm.gui.NavigatableComponent;
    1721
    1822public class Multipolygon {
     23    static private final Logger logger = Logger.getLogger(Multipolygon.class.getName());
    1924
     25    /** preference key for a collection of roles which indicate that the respective member belongs to an
     26     * <em>outer</em> polygon. Default is <tt>outer</tt>.
     27     */
     28    static public final String PREF_KEY_OUTER_ROLES = "mappaint.multipolygon.outer.roles";
     29    /** preference key for collection of role prefixes which indicate that the respective
     30     *  member belongs to an <em>outer</em> polygon. Default is empty.
     31     */
     32    static public final String PREF_KEY_OUTER_ROLE_PREFIXES = "mappaint.multipolygon.outer.role-prefixes";
     33    /** preference key for a collection of roles which indicate that the respective member belongs to an
     34     * <em>inner</em> polygon. Default is <tt>inner</tt>.
     35     */
     36    static public final String PREF_KEY_INNER_ROLES = "mappaint.multipolygon.inner.roles";
     37    /** preference key for collection of role prefixes which indicate that the respective
     38     *  member belongs to an <em>inner</em> polygon. Default is empty.
     39     */
     40    static public final String PREF_KEY_INNER_ROLE_PREFIXES = "mappaint.multipolygon.inner.role-prefixes";
     41
     42    /**
     43     * <p>Kind of strategy object which is responsible for deciding whether a given
     44     * member role indicates that the member belongs to an <em>outer</em> or an
     45     * <em>inner</em> polygon.</p>
     46     *
     47     * <p>The decision is taken based on preference settings, see the four preference keys
     48     * above.</p>
     49     *
     50     */
     51    private static class MultipolygonRoleMatcher implements PreferenceChangedListener{
     52        private final List<String> outerExactRoles = new ArrayList<String>();
     53        private final List<String> outerRolePrefixes = new ArrayList<String>();
     54        private final List<String> innerExactRoles = new ArrayList<String>();
     55        private final List<String> innerRolePrefixes = new ArrayList<String>();
     56
     57        private void initDefaults() {
     58            outerExactRoles.clear();
     59            outerRolePrefixes.clear();
     60            innerExactRoles.clear();
     61            innerRolePrefixes.clear();
     62            outerExactRoles.add("outer");
     63            innerExactRoles.add("inner");
     64        }
     65
     66        private void setNormalized(Collection<String> literals, List<String> target){
     67            target.clear();
     68            for(String l: literals) {
     69                if (l == null) {
     70                    continue;
     71                }
     72                l = l.trim();
     73                if (!target.contains(l)) {
     74                    target.add(l);
     75                }
     76            }
     77        }
     78
     79        private void initFromPreferences() {
     80            initDefaults();
     81            if (Main.pref == null) return;
     82            Collection<String> literals;
     83            literals = Main.pref.getCollection(PREF_KEY_OUTER_ROLES);
     84            if (literals != null && !literals.isEmpty()){
     85                setNormalized(literals, outerExactRoles);
     86            }
     87            literals = Main.pref.getCollection(PREF_KEY_OUTER_ROLE_PREFIXES);
     88            if (literals != null && !literals.isEmpty()){
     89                setNormalized(literals, outerRolePrefixes);
     90            }
     91            literals = Main.pref.getCollection(PREF_KEY_INNER_ROLES);
     92            if (literals != null && !literals.isEmpty()){
     93                setNormalized(literals, innerExactRoles);
     94            }
     95            literals = Main.pref.getCollection(PREF_KEY_INNER_ROLE_PREFIXES);
     96            if (literals != null && !literals.isEmpty()){
     97                setNormalized(literals, innerRolePrefixes);
     98            }
     99        }
     100
     101        @Override
     102        public void preferenceChanged(PreferenceChangeEvent evt) {
     103            if (PREF_KEY_INNER_ROLE_PREFIXES.equals(evt.getKey()) ||
     104                    PREF_KEY_INNER_ROLES.equals(evt.getKey()) ||
     105                    PREF_KEY_OUTER_ROLE_PREFIXES.equals(evt.getKey()) ||
     106                    PREF_KEY_OUTER_ROLES.equals(evt.getKey())){
     107                initFromPreferences();
     108            }
     109        }
     110
     111        public boolean isOuterRole(String role){
     112            if (role == null) return false;
     113            for (String candidate: outerExactRoles) {
     114                if (role.equals(candidate)) return true;
     115            }
     116            for (String candidate: outerRolePrefixes) {
     117                if (role.startsWith(candidate)) return true;
     118            }
     119            return false;
     120        }
     121
     122        public boolean isInnerRole(String role){
     123            if (role == null) return false;
     124            for (String candidate: innerExactRoles) {
     125                if (role.equals(candidate)) return true;
     126            }
     127            for (String candidate: innerRolePrefixes) {
     128                if (role.startsWith(candidate)) return true;
     129            }
     130            return false;
     131        }
     132    }
     133
     134    /*
     135     * Init a private global matcher object which will listen to preference
     136     * changes.
     137     */
     138    private static MultipolygonRoleMatcher roleMatcher;
     139    private static MultipolygonRoleMatcher getMultipoloygonRoleMatcher() {
     140        if (roleMatcher == null) {
     141            roleMatcher = new MultipolygonRoleMatcher();
     142            if (Main.pref != null){
     143                roleMatcher.initFromPreferences();
     144                Main.pref.addPreferenceChangeListener(roleMatcher);
     145            }
     146        }
     147        return roleMatcher;
     148    }
     149
    20150    public static class JoinedWay {
    21151        private final List<Node> nodes;
    22152        private final boolean selected;
     
    122252    }
    123253
    124254    public void load(Relation r) {
     255        MultipolygonRoleMatcher matcher = getMultipoloygonRoleMatcher();
     256
    125257        // Fill inner and outer list with valid ways
    126258        for (RelationMember m : r.getMembers()) {
    127259            if (m.getMember().isDrawable()) {
     
    132264                        continue;
    133265                    }
    134266
    135                     if("inner".equals(m.getRole())) {
    136                         getInnerWays().add(w);
    137                     } else if("outer".equals(m.getRole())) {
    138                         getOuterWays().add(w);
     267                    if(matcher.isInnerRole(m.getRole())) {
     268                        innerWays.add(w);
     269                    } else if(matcher.isOuterRole(m.getRole())) {
     270                        outerWays.add(w);
    139271                    } else if (!m.hasRole()) {
    140                         getOuterWays().add(w);
     272                        outerWays.add(w);
    141273                    } // Remaining roles ignored
    142274                } // Non ways ignored
    143275            }
  • test/unit/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonTest.groovy

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.osm.visitor.paint.relations;
     3
     4import static org.junit.Assert.*;
     5import org.junit.*;
     6import org.openstreetmap.josm.Main;
     7import org.openstreetmap.josm.fixtures.JOSMFixture
     8
     9class MultipolygonTest {
     10   
     11    @BeforeClass
     12    public static void createJOSMFixture(){
     13        JOSMFixture.createUnitTestFixture().init()
     14    }
     15   
     16    @Before
     17    public void setUp() {
     18        Main.pref.put(Multipolygon.PREF_KEY_INNER_ROLE_PREFIXES, null)
     19        Main.pref.put(Multipolygon.PREF_KEY_INNER_ROLES, null)
     20        Main.pref.put(Multipolygon.PREF_KEY_OUTER_ROLE_PREFIXES, null)
     21        Main.pref.put(Multipolygon.PREF_KEY_OUTER_ROLES, null)
     22    }
     23   
     24    @Test
     25    public void matchRolesWithDefaultSettings() {
     26        def matcher = Multipolygon.getMultipoloygonRoleMatcher()
     27       
     28        /*
     29         * Default behavioiur - Only the roles "outer" and "inner" are supported.
     30         */
     31        assert matcher.isOuterRole("outer")
     32        assert !matcher.isOuterRole("outer:mask")
     33        assert matcher.isInnerRole("inner")
     34        assert !matcher.isInnerRole("inner:mask")       
     35    }
     36 
     37    @Test
     38    public void matchAdditionalOuterRoles() {
     39        Main.pref.putCollection(Multipolygon.PREF_KEY_OUTER_ROLES,["outer", "outer:mask", "outer:show"])
     40       
     41        def matcher = Multipolygon.getMultipoloygonRoleMatcher()
     42       
     43        assert matcher.isOuterRole("outer")
     44        assert matcher.isOuterRole("outer:mask")
     45        assert matcher.isOuterRole("outer:show")
     46        assert !matcher.isOuterRole("outer:something_else")
     47    }
     48   
     49    @Test
     50    public void matchAdditionalOuterRolePrefixes() {
     51        Main.pref.putCollection(Multipolygon.PREF_KEY_OUTER_ROLE_PREFIXES,["outer:"])
     52       
     53        def matcher = Multipolygon.getMultipoloygonRoleMatcher()
     54       
     55        assert matcher.isOuterRole("outer")
     56        assert matcher.isOuterRole("outer:mask")
     57        assert matcher.isOuterRole("outer:show")
     58        assert matcher.isOuterRole("outer:something_else")
     59    }
     60   
     61    @Test
     62    public void matchAdditionanInnerRoles() {
     63        Main.pref.putCollection(Multipolygon.PREF_KEY_INNER_ROLES,["inner", "inner:mask", "inner:show"])
     64       
     65        def matcher = Multipolygon.getMultipoloygonRoleMatcher()
     66       
     67        assert matcher.isInnerRole("inner")
     68        assert matcher.isInnerRole("inner:mask")
     69        assert matcher.isInnerRole("inner:show")
     70        assert !matcher.isInnerRole("inner:something_else")
     71    }
     72   
     73    @Test
     74    public void matchAdditionanInnerRolesPrefixes() {
     75        Main.pref.putCollection(Multipolygon.PREF_KEY_INNER_ROLE_PREFIXES,["inner:"])
     76       
     77        def matcher = Multipolygon.getMultipoloygonRoleMatcher()
     78       
     79        assert matcher.isInnerRole("inner")
     80        assert matcher.isInnerRole("inner:mask")
     81        assert matcher.isInnerRole("inner:show")
     82        assert matcher.isInnerRole("inner:something_else")
     83    }
     84}