All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.graph_builder.module.osm.OSMFilter Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
package org.opentripplanner.graph_builder.module.osm;

import org.opentripplanner.common.model.P2;
import org.opentripplanner.graph_builder.DataImportIssueStore;
import org.opentripplanner.graph_builder.issues.ConflictingBikeTags;
import org.opentripplanner.openstreetmap.model.OSMWay;
import org.opentripplanner.openstreetmap.model.OSMWithTags;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.edgetype.StreetTraversalPermission;
import org.opentripplanner.routing.graph.Graph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 */
public class OSMFilter {

    private static Logger LOG = LoggerFactory.getLogger(OSMFilter.class);

    /**
     * Determine whether any mode can or should ever traverse the given way. If not, we leave the
     * way out of the OTP graph. Potentially routable ways are those that have the tags : highway=*
     * public_transport=platform railway=platform
     * 
     * But not conveyers, proposed highways/roads or those still under construction, and raceways
     * (as well as ways where all access is specifically forbidden to the public).
     * http://wiki.openstreetmap.org/wiki/Tag:highway%3Dproposed
     */
    static boolean isWayRoutable(OSMWithTags way) {
        if (!isOsmEntityRoutable(way)) {
            return false;
        }

        String highway = way.getTag("highway");
        if (highway != null) {
            if(
                    highway.equals("conveyer") ||
                    highway.equals("proposed") ||
                    highway.equals("construction") ||
                    highway.equals("razed") ||
                    highway.equals("raceway") ||
                    highway.equals("unbuilt")
            ) {
                return false;
            }
        }

        if (way.isGeneralAccessDenied()) {
            // There are exceptions.
            return (way.isMotorcarExplicitlyAllowed() || way.isBicycleExplicitlyAllowed() || way
                    .isPedestrianExplicitlyAllowed() || way.isMotorVehicleExplicitlyAllowed());
        }
        return true;
    }

    /**
     * Determines whether this OSM way is considered routable. The majority of routable ways are
     * those with a highway= tag (which includes everything from motorways to hiking trails).
     * Anything with a public_transport=platform or railway=platform tag is also considered routable
     * even if it doesn't have a highway tag. Platforms are however filtered out if they are marked
     * usage=tourism. This prevents miniature tourist railways like the one in Portland's Zoo from
     * receiving a better score and pulling search endpoints away from real transit stops.
     */
    public static boolean isOsmEntityRoutable(OSMWithTags osmEntity) {
        if (osmEntity.hasTag("highway"))
            return true;
        if (osmEntity.isTag("public_transport", "platform")
                || osmEntity.isTag("railway", "platform")) {
            return !("tourism".equals(osmEntity.getTag("usage")));
        }
        return false;
    }

    public static StreetTraversalPermission getPermissionsForEntity(OSMWithTags entity,
            StreetTraversalPermission def) {
        StreetTraversalPermission permission = null;

        /*
         * Only a few tags are examined here, because we only care about modes supported by OTP
         * (wheelchairs are not of concern here)
         * 
         * Only a few values are checked for, all other values are presumed to be permissive (=>
         * This may not be perfect, but is closer to reality, since most people don't follow the
         * rules perfectly ;-)
         */
        if (entity.isGeneralAccessDenied()) {
            // this can actually be overridden
            permission = StreetTraversalPermission.NONE;
            if (entity.isMotorcarExplicitlyAllowed() || entity.isMotorVehicleExplicitlyAllowed()) {
                permission = permission.add(StreetTraversalPermission.CAR);
            }
            if (entity.isBicycleExplicitlyAllowed()) {
                permission = permission.add(StreetTraversalPermission.BICYCLE);
            }
            if (entity.isPedestrianExplicitlyAllowed()) {
                permission = permission.add(StreetTraversalPermission.PEDESTRIAN);
            }
        } else {
            permission = def;
        }

        if (entity.isMotorcarExplicitlyDenied() || entity.isMotorVehicleExplicitlyDenied()) {
            permission = permission.remove(StreetTraversalPermission.CAR);
        } else if (entity.isMotorcarExplicitlyAllowed() || entity.isMotorVehicleExplicitlyAllowed()) {
            permission = permission.add(StreetTraversalPermission.CAR);
        }

        if (entity.isBicycleExplicitlyDenied()) {
            permission = permission.remove(StreetTraversalPermission.BICYCLE);
        } else if (entity.isBicycleExplicitlyAllowed()) {
            permission = permission.add(StreetTraversalPermission.BICYCLE);
        }

        if (entity.isPedestrianExplicitlyDenied()) {
            permission = permission.remove(StreetTraversalPermission.PEDESTRIAN);
        } else if (entity.isPedestrianExplicitlyAllowed()) {
            permission = permission.add(StreetTraversalPermission.PEDESTRIAN);
        }

        if (entity.isUnderConstruction()) {
            permission = StreetTraversalPermission.NONE;
        }

        if (permission == null)
            return def;

        return permission;
    }

    /**
     * Computes permissions for an OSMWay.
     * 
     * @param way
     * @param def
     * @return
     */
    public static StreetTraversalPermission getPermissionsForWay(OSMWay way,
            StreetTraversalPermission def, Graph graph, boolean banDiscouragedWalking, boolean banDiscouragedBiking,
            DataImportIssueStore issueStore) {
        StreetTraversalPermission permissions = getPermissionsForEntity(way, def);

        /*
         * pedestrian rules: everything is two-way (assuming pedestrians are allowed at all) bicycle
         * rules: default: permissions;
         * 
         * cycleway=dismount means walk your bike -- the engine will automatically try walking bikes
         * any time it is forbidden to ride them, so the only thing to do here is to remove bike
         * permissions
         * 
         * oneway=... sets permissions for cars and bikes oneway:bicycle overwrites these
         * permissions for bikes only
         * 
         * now, cycleway=opposite_lane, opposite, opposite_track can allow once oneway has been set
         * by oneway:bicycle, but should give a warning if it conflicts with oneway:bicycle
         * 
         * bicycle:backward=yes works like oneway:bicycle=no bicycle:backwards=no works like
         * oneway:bicycle=yes
         */

        // Compute pedestrian permissions.
        if (way.isPedestrianExplicitlyAllowed()) {
            permissions = permissions.add(StreetTraversalPermission.PEDESTRIAN);
        } else if (way.isPedestrianExplicitlyDenied()) {
            permissions = permissions.remove(StreetTraversalPermission.PEDESTRIAN);
        }

        // Check for foot=discouraged, if applicable
        if(banDiscouragedWalking && way.hasTag("foot") && way.getTag("foot").equals("discouraged")) {
            permissions = permissions.remove(StreetTraversalPermission.PEDESTRIAN);
        }

        // Compute bike permissions, check consistency.
        boolean forceBikes = false;
        if (way.isBicycleExplicitlyAllowed()) {
            permissions = permissions.add(StreetTraversalPermission.BICYCLE);
            forceBikes = true;
        }

        if (way.isBicycleDismountForced() ||
                (banDiscouragedBiking && way.hasTag("bicycle") && way.getTag("bicycle").equals("discouraged"))) {
            permissions = permissions.remove(StreetTraversalPermission.BICYCLE);
            if (forceBikes) {
                issueStore.add(new ConflictingBikeTags(way.getId()));
            }
        }

        return permissions;
    }

    public static StreetTraversalPermission getPermissionsForWay(OSMWay way,
            StreetTraversalPermission def, Graph graph) {
        return getPermissionsForWay(way, def, graph, false, false,
                new DataImportIssueStore(false));
    }

    /**
     * Check OSM tags for various one-way and one-way-by-mode tags and return a pair of permissions
     * for travel along and against the way.
     */
    public static P2 getPermissions(
            StreetTraversalPermission permissions, OSMWay way) {

        StreetTraversalPermission permissionsFront = permissions;
        StreetTraversalPermission permissionsBack = permissions;

        // Check driving direction restrictions.
        if (way.isOneWayForwardDriving() || way.isRoundabout()) {
            permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE_AND_CAR);
        }
        if (way.isOneWayReverseDriving()) {
            permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE_AND_CAR);
        }

        // Check bike direction restrictions.
        if (way.isOneWayForwardBicycle()) {
            permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE);
        }
        if (way.isOneWayReverseBicycle()) {
            permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE);
        }

        // TODO(flamholz): figure out what this is for.
        String oneWayBicycle = way.getTag("oneway:bicycle");
        if (OSMWithTags.isFalse(oneWayBicycle) || way.isTagTrue("bicycle:backwards")) {
            if (permissions.allows(StreetTraversalPermission.BICYCLE)) {
                permissionsFront = permissionsFront.add(StreetTraversalPermission.BICYCLE);
                permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE);
            }
        }

        //This needs to be after adding permissions for oneway:bicycle=no
        //removes bicycle permission when bicycles need to use sidepath
        //TAG: bicycle:forward=use_sidepath
        if (way.isForwardDirectionSidepath()) {
            permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE);
        }

        //TAG bicycle:backward=use_sidepath
        if (way.isReverseDirectionSidepath()) {
            permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE);
        }

        if (way.isOpposableCycleway()) {
            permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE);
        }
        return new P2(permissionsFront, permissionsBack);
    }

    public static int getStreetClasses(OSMWithTags way) {
        int link = 0;
        String highway = way.getTag("highway");
        if (highway != null && highway.endsWith(("_link"))) {
            link = StreetEdge.CLASS_LINK;
        }
        return getPlatformClass(way) | link;
    }

    public static int getPlatformClass(OSMWithTags way) {
        String highway = way.getTag("highway");
        if ("platform".equals(way.getTag("railway"))) {
            return StreetEdge.CLASS_TRAIN_PLATFORM;
        }
        if ("platform".equals(highway) || "platform".equals(way.getTag("public_transport"))) {
            if (way.isTagTrue("train") || way.isTagTrue("subway") || way.isTagTrue("tram")
                    || way.isTagTrue("monorail")) {
                return StreetEdge.CLASS_TRAIN_PLATFORM;
            }
            return StreetEdge.CLASS_OTHER_PLATFORM;
        }
        return 0;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy