Changeset 11247 in josm for trunk/src


Ignore:
Timestamp:
2016-11-13T00:29:31+01:00 (8 years ago)
Author:
Don-vip
Message:

see #9400 - see #10387 - see #12914 - initial implementation of boundaries file, replacing left-right-hand-traffic.osm, discourage contributors to use operator=RFF and operator=ERDF in France (territories rules must be manually eabled on existing installations)

Location:
trunk/src/org/openstreetmap/josm
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/Main.java

    r11213 r11247  
    108108import org.openstreetmap.josm.tools.PlatformHookUnixoid;
    109109import org.openstreetmap.josm.tools.PlatformHookWindows;
     110import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
    110111import org.openstreetmap.josm.tools.Shortcut;
     112import org.openstreetmap.josm.tools.Territories;
    111113import org.openstreetmap.josm.tools.Utils;
    112114
     
    516518                }
    517519            }));
     520
     521        tasks.add(new InitializationTask(tr("Initializing internal boundaries data"), Territories::initialize));
     522
     523        tasks.add(new InitializationTask(tr("Initializing internal traffic data"), RightAndLefthandTraffic::initialize));
    518524
    519525        tasks.add(new InitializationTask(tr("Initializing validator"), OsmValidator::initialize));
  • trunk/src/org/openstreetmap/josm/actions/SelectByInternalPointAction.java

    r11240 r11247  
    3737     */
    3838    public static Collection<OsmPrimitive> getSurroundingObjects(EastNorth internalPoint) {
    39         return getSurroundingObjects(Main.getLayerManager().getEditDataSet(), internalPoint);
     39        return getSurroundingObjects(Main.getLayerManager().getEditDataSet(), internalPoint, false);
    4040    }
    4141
     
    4646     * @param ds the data set
    4747     * @param internalPoint the internal point.
     48     * @param includeMultipolygonWays whether to include multipolygon ways in the result (false by default)
    4849     * @return the surrounding polygons/multipolygons
    49      * @since 11240
     50     * @since 11247
    5051     */
    51     public static Collection<OsmPrimitive> getSurroundingObjects(DataSet ds, EastNorth internalPoint) {
     52    public static Collection<OsmPrimitive> getSurroundingObjects(DataSet ds, EastNorth internalPoint, boolean includeMultipolygonWays) {
    5253        if (ds == null) {
    5354            return Collections.emptySet();
     
    6263        for (Relation r : ds.getRelations()) {
    6364            if (r.isUsable() && r.isMultipolygon() && r.isSelectable() && Geometry.isNodeInsideMultiPolygon(n, r, null)) {
    64                 for (RelationMember m : r.getMembers()) {
    65                     if (m.isWay() && m.getWay().isClosed()) {
    66                         found.values().remove(m.getWay());
     65                if (!includeMultipolygonWays) {
     66                    for (RelationMember m : r.getMembers()) {
     67                        if (m.isWay() && m.getWay().isClosed()) {
     68                            found.values().remove(m.getWay());
     69                        }
    6770                    }
    6871                }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java

    r10837 r11247  
    1616import java.util.Collections;
    1717import java.util.List;
     18import java.util.Locale;
    1819import java.util.Objects;
     20import java.util.Set;
    1921import java.util.TreeSet;
    2022import java.util.function.Function;
     
    2729import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
    2830import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
     31import org.openstreetmap.josm.data.coor.LatLon;
    2932import org.openstreetmap.josm.data.osm.Node;
    3033import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    4043import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
    4144import org.openstreetmap.josm.tools.SubclassFilteredCollection;
     45import org.openstreetmap.josm.tools.Territories;
    4246import org.openstreetmap.josm.tools.Utils;
    4347
     
    867871         */
    868872        public static boolean is_right_hand_traffic(Environment env) {
    869             if (env.osm instanceof Node)
    870                 return RightAndLefthandTraffic.isRightHandTraffic(((Node) env.osm).getCoor());
    871             return RightAndLefthandTraffic.isRightHandTraffic(env.osm.getBBox().getCenter());
     873            return RightAndLefthandTraffic.isRightHandTraffic(center(env));
    872874        }
    873875
     
    944946        public static Object setting(Environment env, String key) { // NO_UCD (unused code)
    945947            return env.source.settingValues.get(key);
     948        }
     949
     950        /**
     951         * Returns the center of the environment OSM primitive.
     952         * @param env the environment
     953         * @return the center of the environment OSM primitive
     954         * @since 11247
     955         */
     956        public static LatLon center(Environment env) { // NO_UCD (unused code)
     957            return env.osm instanceof Node ? ((Node) env.osm).getCoor() : env.osm.getBBox().getCenter();
     958        }
     959
     960        /**
     961         * Determines if the object is inside territories matching given ISO3166 codes.
     962         * @param env the environment
     963         * @param codes comma-separated list of ISO3166-1-alpha2 or ISO3166-2 country/subdivision codes
     964         * @return {@code true} if the object is inside territory matching given ISO3166 codes
     965         * @since 11247
     966         */
     967        public static boolean inside(Environment env, String codes) { // NO_UCD (unused code)
     968            Set<String> osmCodes = Territories.getIso3166Codes(center(env));
     969            for (String code : codes.toUpperCase(Locale.ENGLISH).split(",")) {
     970                if (osmCodes.contains(code.trim())) {
     971                    return true;
     972                }
     973            }
     974            return false;
     975        }
     976
     977        /**
     978         * Determines if the object is outside territories matching given ISO3166 codes.
     979         * @param env the environment
     980         * @param codes comma-separated list of ISO3166-1-alpha2 or ISO3166-2 country/subdivision codes
     981         * @return {@code true} if the object is outside territory matching given ISO3166 codes
     982         * @since 11247
     983         */
     984        public static boolean outside(Environment env, String codes) { // NO_UCD (unused code)
     985            return !inside(env, codes);
    946986        }
    947987    }
  • trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java

    r10378 r11247  
    154154            addDefault(def, "religion",     tr("Religion"),            tr("Checks for errors on religious objects"));
    155155            addDefault(def, "relation",     tr("Relations"),           tr("Checks for errors on relations"));
     156            addDefault(def, "territories",  tr("Territories"),         tr("Checks for territories-specific features"));
    156157            addDefault(def, "unnecessary",  tr("Unnecessary tags"),    tr("Checks for unnecessary tags"));
    157158            addDefault(def, "wikipedia",    tr("Wikipedia"),           tr("Checks for wrong wikipedia tags"));
  • trunk/src/org/openstreetmap/josm/tools/RightAndLefthandTraffic.java

    r9639 r11247  
    33
    44import java.awt.geom.Area;
     5import java.io.File;
     6import java.io.FileInputStream;
     7import java.io.FileOutputStream;
    58import java.io.IOException;
    69import java.io.InputStream;
     10import java.io.OutputStreamWriter;
     11import java.io.PrintWriter;
     12import java.io.Writer;
     13import java.nio.charset.StandardCharsets;
    714import java.util.ArrayList;
    815import java.util.Collection;
    9 
     16import java.util.Collections;
     17import java.util.List;
     18import java.util.Set;
     19
     20import org.openstreetmap.josm.Main;
     21import org.openstreetmap.josm.actions.JoinAreasAction;
     22import org.openstreetmap.josm.actions.JoinAreasAction.JoinAreasResult;
     23import org.openstreetmap.josm.actions.JoinAreasAction.Multipolygon;
     24import org.openstreetmap.josm.actions.PurgeAction;
    1025import org.openstreetmap.josm.data.coor.LatLon;
    1126import org.openstreetmap.josm.data.osm.BBox;
    1227import org.openstreetmap.josm.data.osm.DataSet;
     28import org.openstreetmap.josm.data.osm.OsmPrimitive;
     29import org.openstreetmap.josm.data.osm.Relation;
     30import org.openstreetmap.josm.data.osm.RelationMember;
    1331import org.openstreetmap.josm.data.osm.Way;
    14 import org.openstreetmap.josm.io.CachedFile;
    1532import org.openstreetmap.josm.io.IllegalDataException;
    1633import org.openstreetmap.josm.io.OsmReader;
     34import org.openstreetmap.josm.io.OsmWriter;
     35import org.openstreetmap.josm.io.OsmWriterFactory;
    1736import org.openstreetmap.josm.tools.GeoPropertyIndex.GeoProperty;
    1837import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
     
    5877     * Check if there is right-hand traffic at a certain location.
    5978     *
    60      * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex}
    61      *       as most look-ups are read-only.
    6279     * @param ll the coordinates of the point
    6380     * @return true if there is right-hand traffic, false if there is left-hand traffic
    6481     */
    6582    public static synchronized boolean isRightHandTraffic(LatLon ll) {
    66         if (leftHandTrafficPolygons == null) {
    67             initialize();
    68         }
    6983        return !rlCache.get(ll);
    7084    }
    7185
    72     private static void initialize() {
     86    /**
     87     * Initializes Right and lefthand traffic data.
     88     * TODO: Synchronization can be refined inside the {@link GeoPropertyIndex} as most look-ups are read-only.
     89     */
     90    public static synchronized void initialize() {
    7391        leftHandTrafficPolygons = new ArrayList<>();
    74         try (CachedFile cf = new CachedFile("resource://data/left-right-hand-traffic.osm");
    75                 InputStream is = cf.getInputStream()) {
    76             DataSet data = OsmReader.parseDataSet(is, null);
    77             for (Way w : data.getWays()) {
    78                 leftHandTrafficPolygons.add(Geometry.getAreaLatLon(w.getNodes()));
    79             }
    80         } catch (IOException | IllegalDataException ex) {
     92        Collection<Way> optimizedWays = loadOptimizedBoundaries();
     93        if (optimizedWays.isEmpty()) {
     94            optimizedWays = computeOptimizedBoundaries();
     95            saveOptimizedBoundaries(optimizedWays);
     96        }
     97        for (Way w : optimizedWays) {
     98            leftHandTrafficPolygons.add(Geometry.getAreaLatLon(w.getNodes()));
     99        }
     100        rlCache = new GeoPropertyIndex<>(new RLTrafficGeoProperty(), 24);
     101    }
     102
     103    private static Collection<Way> computeOptimizedBoundaries() {
     104        Collection<Way> ways = new ArrayList<>();
     105        Collection<OsmPrimitive> toPurge = new ArrayList<>();
     106        // Find all outer ways of left-driving countries. Many of them are adjacent (African and Asian states)
     107        DataSet data = Territories.getDataSet();
     108        Collection<Relation> allRelations = data.getRelations();
     109        Collection<Way> allWays = data.getWays();
     110        for (Way w : allWays) {
     111            if ("left".equals(w.get("driving_side"))) {
     112                addWayIfNotInner(ways, w);
     113            }
     114        }
     115        for (Relation r : allRelations) {
     116            if (r.isMultipolygon() && "left".equals(r.get("driving_side"))) {
     117                for (RelationMember rm : r.getMembers()) {
     118                    if (rm.isWay() && "outer".equals(rm.getRole())) {
     119                        addWayIfNotInner(ways, (Way) rm.getMember());
     120                    }
     121                }
     122            }
     123        }
     124        toPurge.addAll(allRelations);
     125        toPurge.addAll(allWays);
     126        toPurge.removeAll(ways);
     127        // Remove ways from parent relations for following optimizations
     128        for (Relation r : OsmPrimitive.getParentRelations(ways)) {
     129            r.setMembers(null);
     130        }
     131        // Remove all tags to avoid any conflict
     132        for (Way w : ways) {
     133            w.removeAll();
     134        }
     135        // Purge all other ways and relations so dataset only contains lefthand traffic data
     136        new PurgeAction().doPurge(toPurge, false);
     137        // Combine adjacent countries into a single polygon
     138        Collection<Way> optimizedWays = new ArrayList<>();
     139        List<Multipolygon> areas = JoinAreasAction.collectMultipolygons(ways);
     140        if (areas != null) {
     141            try {
     142                JoinAreasResult result = new JoinAreasAction().joinAreas(areas);
     143                if (result.hasChanges) {
     144                    for (Multipolygon mp : result.polygons) {
     145                        optimizedWays.add(mp.outerWay);
     146                    }
     147                }
     148            } catch (UserCancelException ex) {
     149                Main.warn(ex);
     150            }
     151        }
     152        if (optimizedWays.isEmpty()) {
     153            // Problem: don't optimize
     154            Main.warn("Unable to join left-driving countries polygons");
     155            optimizedWays.addAll(ways);
     156        }
     157        return optimizedWays;
     158    }
     159
     160    /**
     161     * Adds w to ways, except if it is an inner way of another lefthand driving multipolygon,
     162     * as Lesotho in South Africa and Cyprus village in British Cyprus base.
     163     * @param ways ways
     164     * @param w way
     165     */
     166    private static void addWayIfNotInner(Collection<Way> ways, Way w) {
     167        Set<Way> s = Collections.singleton(w);
     168        for (Relation r : OsmPrimitive.getParentRelations(s)) {
     169            if (r.isMultipolygon() && "left".equals(r.get("driving_side")) &&
     170                "inner".equals(r.getMembersFor(s).iterator().next().getRole())) {
     171                if (Main.isDebugEnabled()) {
     172                    Main.debug("Skipping " + w.get("name:en") + " because inner part of " + r.get("name:en"));
     173                }
     174                return;
     175            }
     176        }
     177        ways.add(w);
     178    }
     179
     180    private static void saveOptimizedBoundaries(Collection<Way> optimizedWays) {
     181        DataSet ds = optimizedWays.iterator().next().getDataSet();
     182        File file = new File(Main.pref.getCacheDirectory(), "left-right-hand-traffic.osm");
     183        try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
     184             OsmWriter w = OsmWriterFactory.createOsmWriter(new PrintWriter(writer), false, ds.getVersion())
     185            ) {
     186            w.header(false);
     187            w.writeContent(ds);
     188            w.footer();
     189        } catch (IOException ex) {
    81190            throw new RuntimeException(ex);
    82191        }
    83         rlCache = new GeoPropertyIndex<>(new RLTrafficGeoProperty(), 24);
     192    }
     193
     194    private static Collection<Way> loadOptimizedBoundaries() {
     195        try (InputStream is = new FileInputStream(new File(Main.pref.getCacheDirectory(), "left-right-hand-traffic.osm"))) {
     196           return OsmReader.parseDataSet(is, null).getWays();
     197        } catch (IllegalDataException | IOException ex) {
     198            Main.trace(ex);
     199            return Collections.emptyList();
     200        }
    84201    }
    85202}
Note: See TracChangeset for help on using the changeset viewer.