Search code examples
javaandroidnavigationhere-api

Here Android SDK - Navigate through "No_THROUGH_TRAFFIC" and "DIR_NO_TRUCKS" streets


A short and simple question someone hopefully has an awnser to:

How can I navigate with the Here Android SDK Premium through road elemts that have the attributes DIR_NO_CARS, NO_THROUGH_TRAFFIC, DIR_NO_TRUCKS in the TRUCK transport mode? Like I am a special car and I can drive on these roads.

My code looks like the following:

public class Scratch extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        AndroidXMapFragment mapFragment = (AndroidXMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapfragment);
        boolean success = com.here.android.mpa.common.MapSettings.setIsolatedDiskCacheRootPath(
                getApplicationContext().getExternalFilesDir(null) + File.separator + ".here-maps",
                "MainActivity");
        System.out.println(success);

        mapFragment.init(new OnEngineInitListener() {
            @Override
            public void onEngineInitializationCompleted(
                    OnEngineInitListener.Error error) {
                if (error == OnEngineInitListener.Error.NONE) {
                    // now the map is ready to be used
                    Map map = mapFragment.getMap();
                    for (String sheme : map.getMapSchemes()) {

                        Log.d("Custom", sheme);
                    }
                    map.setMapScheme("pedestrian.day");
                    map.setMapDisplayLanguage(Locale.GERMANY);

                    //Show current position marker
                    PositioningManager.getInstance().start(PositioningManager.LocationMethod.GPS_NETWORK);
                    mapFragment.getPositionIndicator().setVisible(true);

                    //Routing
                    GeoCoordinate start = new GeoCoordinate(50.992189, 10.999966);
                    GeoCoordinate target = new GeoCoordinate(51.001224, 10.990920);

                    //Start - End marker for routing
                    MapLabeledMarker markerStart = new MapLabeledMarker(start)
                            .setLabelText(map.getMapDisplayLanguage(), "Start")
                            .setIcon(IconCategory.ALL);
                    markerStart.setZIndex(12);
                    map.addMapObject(markerStart);

                    MapLabeledMarker markerTarget = new MapLabeledMarker(target)
                            .setLabelText(map.getMapDisplayLanguage(), "End")
                            .setIcon(IconCategory.ALL);
                    markerTarget.setZIndex(12);
                    map.addMapObject(markerTarget);

                    CoreRouter router = new CoreRouter();

                    router.setDynamicPenalty(NewPenaltyForStreetArea(
                            router.getDynamicPenalty(),
                            new GeoCoordinate(51.001137, 10.989901),
                            new GeoCoordinate(50.992582, 10.999338),
                            map.getMapDisplayLanguage(),
                            "Im Geströdig",
                            DrivingDirection.DIR_BOTH,
                            70
                    ));

                    RouteOptions routeOptions = new RouteOptions();
                    routeOptions.setTransportMode(RouteOptions.TransportMode.TRUCK);
                    routeOptions.setRouteType(RouteOptions.Type.FASTEST);
                    routeOptions.setCarpoolAllowed(false);
                    routeOptions.setCarShuttleTrainsAllowed(false);
                    routeOptions.setDirtRoadsAllowed(true);
                    routeOptions.setTruckLength(6.590f);
                    routeOptions.setTruckWidth(2.150f);
                    routeOptions.setTruckHeight(2.150f);
                    routeOptions.setTruckTrailersCount(0);
                    routeOptions.setTruckDifficultTurnsAllowed(true);
                    routeOptions.setRouteCount(2);

                    RoutePlan routePlan = new RoutePlan();
                    routePlan.setRouteOptions(routeOptions);
                    routePlan.addWaypoint(new RouteWaypoint(start));
                    routePlan.addWaypoint(new RouteWaypoint(target));

                    class RouteListener implements CoreRouter.Listener {

                        // Method defined in Listener
                        public void onProgress(int percentage) {
                            // Display a message indicating calculation progress
                            Log.d("Custom", percentage + "");
                        }

                        // Method defined in Listener
                        @Override
                        public void onCalculateRouteFinished(List<RouteResult> routeResult, RoutingError error) {
                            // If the route was calculated successfully
                            if (error == RoutingError.NONE) {
                                // Render the route on the map
                                Log.d("Custom", routeResult.size() + " Routes calculated");

                                for (RouteResult result : routeResult) {
                                    MapRoute mapRoute = new MapRoute(result.getRoute());
                                    mapRoute.setColor(Color.argb(100, 201, 42, 42));
                                    mapRoute.setZIndex(10);

                                    if (routeResult.indexOf(result) == 0) {
                                        //Best route
                                        mapRoute.setColor(Color.argb(255, 201, 42, 42));
                                        mapRoute.setZIndex(11);
                                    }
                                    map.addMapObject(mapRoute);
                                }
                            }
                            else {
                                // Display a message indicating route calculation failure
                            }
                        }
                    }

                    router.calculateRoute(routePlan, new RouteListener());
                } else {
                    System.out.println("ERROR: Cannot initialize AndroidXMapFragment");
                    System.out.println(error);
                }
            }
        });
    }

    private DynamicPenalty NewPenaltyForStreetArea(DynamicPenalty dynamicPenalty, GeoCoordinate cord1, GeoCoordinate cord2, String marcCode, String streetName, DrivingDirection drivingDirection, int speed){
        List<GeoCoordinate> penaltyArea = new ArrayList<>();
        penaltyArea.add(cord1);
        penaltyArea.add(cord2);

        List<RoadElement> roadElements = RoadElement.getRoadElements(GeoBoundingBox.getBoundingBoxContainingGeoCoordinates(penaltyArea), marcCode);
        for (int i = 0; i < roadElements.size(); i++) {
            //Log.d("Custom", roadElements.get(i).getRoadName());

            if (!roadElements.get(i).getRoadName().equals(streetName)){
                roadElements.remove(i);
                i--;
            }
            else
                Log.d("Custom", roadElements.get(i).getAttributes().toString());
        }

        Log.d("Custom", "Set penalty for " + roadElements.size() + " road elements - " + streetName);

        for (RoadElement road : roadElements) {
            dynamicPenalty.addRoadPenalty(road, drivingDirection, speed);
        }

        return dynamicPenalty;
    }
}

And this is what I get

But this is what I need

So I want to say the navigation API that the road "Im Geströdig" is accessible for my car. Road Element Attributes I need to change somehow:

[DIR_NO_CARS, DIRT_ROAD, NO_THROUGH_TRAFFIC, DIR_NO_TRUCKS]

Solution

  • The solution to the use case is not trivial. The functionality of updating Road Element attributes is available via the HERE Custom Route API, where you would need to upload an overlay with a shape, that matches the road you want to modify. The attributes which can be updated are also limited. ("VEHICLE_TYPES":"49" indicates road is open for Cars, Truck, Pedestrian)

     GET http://cre.api.here.com/2/overlays/upload.json
      ?map_name=OVERLAYBLOCKROAD
      &overlay_spec=[{"op":"override","shape":[[50.10765,8.68774],[50.10914,8.68771]],"layer":"LINK_ATTRIBUTE_FCN","data":{"VEHICLE_TYPES":"49"}}]
      &storage=readonly
      &app_id={YOUR_APP_ID}
      &app_code={YOUR_APP_CODE}
    

    Make sure to use the same AppId, Appcode as being used with HERE Premium Mobile SDK. Now this overlay can be used in HERE Premium Mobile SDK with FTCRRouter (still Beta feature)

    FTCRRouter ftcrRoute = new FTCRRouter();
    FTCRRouter.RequestParameters parmaters =new
    FTCRRouter.RequestParameters(routePlan,"OVERLAYBLOCKROAD",true);
    ftcrRoute.calculateRoute(parmaters, new FTCRRouter.Listener() {
        @Override
        public void onCalculateRouteFinished(List<FTCRRoute> list,
                        FTCRRouter.ErrorResponse errorResponse) {
            if (errorResponse.getErrorCode() == RoutingError.NONE) {
                List<GeoCoordinate> shape = list.get(0).getGeometry();
    
                MapPolyline polyline = new MapPolyline();
                polyline.setGeoPolyline(new GeoPolygon(shape));
                polyline.setLineWidth(10);
                m_map.addMapObject(polyline);
            }else{
                // Error
            }
       }
    });
    

    As the FTCRRouter is still in Beta, there are some limitation like Dynamic Penanlity is not supported and also the FTCRRouter always prefers to take the roads available in HERE Map data and uses the Roads from the overlay if necessary.