brouter icon indicating copy to clipboard operation
brouter copied to clipboard

No route found

Open victorlysak opened this issue 8 months ago • 6 comments

hi all.

i'm trying to develop an android satnav app for my car, android 7.0, api 24, by using mapsforge for maps and BRouter for routing.

when i run the app and try to calculate route ~30km long, by

                engine.doRun(0) // 0 for no maxRunningTime

                if (engine.getErrorMessage() != null) {
                   Log.e(TAG, "BRouter internal routing error: ${engine.getErrorMessage()}")
                   lastBRouterError = engine.getErrorMessage()
                }
                // Retrieve the result (OsmTrack)
                routeData = engine.getFoundTrack()
                Log.d(TAG, "after routeData: ${routeData}")

                if (routeData == null || routeData.nodes == null || routeData.nodes.isEmpty()) { // OsmTrack has 'nodes' not 'points'
                    lastBRouterError = "BRouter: No route found or route data is empty."
                    Log.w(TAG, lastBRouterError!!)
                } else {
                    routePath = routeData
                    // OsmTrack.nodes contains OsmPathElement, convert them to GeoPoint
                    routePath.nodes.forEach { pathElement ->
                        // OsmPathElement has getILon(), getILat() in microdegrees
                        osmdroidRoutePoints.add(GeoPoint(pathElement.getILat() / 1E7, pathElement.getILon() / 1E7))
                    }

my app gives msg: BRouter: No route found or route data is empty.

does anyone have an idea on what the problem could be? thank you

victorlysak avatar Jun 19 '25 12:06 victorlysak

Could we get some more information like position from, to, used profile Prefered in this web format

afischerdev avatar Jun 19 '25 12:06 afischerdev

ok, let's say the route is: route on brouter.de/brouter-web/#map

do you know where is it possible to find actual brouter-android.jar to work with brouter in android studio fully offline?

victorlysak avatar Jun 19 '25 13:06 victorlysak

here is my full calculateAndDisplayRoute function:

    fun calculateAndDisplayRoute(startLat: Double, startLon: Double, endLat: Double, endLon: Double, profileName: String) {
        if (!isBRouterInitialized) { // Check if data paths are valid
            Log.e(TAG, "BRouter data paths not verified or invalid.")
            bRouterStatusUpdater("Route Error: Nav Data not Ready. Please re-check BRouter data setup.")
            return
        }

        val df = DecimalFormat("#.##")
        Log.d(TAG, "Calculating route from ($startLat, $startLon) to ($endLat, $endLon) using profile '$profileName'")
        clearRouteFromMap() // Clear old route if any
        bRouterStatusUpdater("Calculating route...")

        Thread { // Route calculation is heavy, run on background thread
            var routeFound = false
            osmdroidRoutePoints.clear()
            System.setProperty("profileBaseDir", profilesDir.absolutePath)
            var routePath: btools.router.OsmTrack? = null
            var routeData: btools.router.OsmTrack? = null

            try {
                // *** CRITICAL FIX: Corrected OsmNodeNamed and OsmNode instantiation ***
                // OsmNode constructor takes ilon, ilat directly.
                // OsmNodeNamed constructor takes an OsmNode.
                // Coordinates (lon/lat) need to be converted to microdegrees (int) for OsmNode.
                val startOsmNodeRaw = OsmNode( (startLon * 1E7).toInt(), (startLat * 1E7).toInt() )
                val endOsmNodeRaw = OsmNode( (endLon * 1E7).toInt(), (endLat * 1E7).toInt() )

                val startOsmNodeNamed = OsmNodeNamed(startOsmNodeRaw).apply { name = "start" }
                val endOsmNodeNamed = OsmNodeNamed(endOsmNodeRaw).apply { name = "end" }

                // RoutingEngine takes a list of OsmNodeNamed waypoints (start and end)
                val waypoints = ArrayList<OsmNodeNamed>().apply {
                    add(startOsmNodeNamed)
                    add(endOsmNodeNamed)
                }

                Log.d(TAG, "before RoutingContext() waypoints: ${waypoints}")

                // Prepare RoutingContext
                val routingContext = RoutingContext().apply {
                    // localFunction should be the base name of the profile file (e.g., "car-fast" for "car-fast.brf")
                    localFunction = profileName
                    // DO NOT set carMode = true or turnInstructionMode = 0 here directly.
                    // These values are set *by the loaded profile script* (e.g., car-fast.brf).
                    // If you set them here, they might be overridden or conflict with the profile.
                    // The profile itself dictates these.
                    // For example, your car-fast.brf should have a line like 'assign carMode = 1'
                    // and 'assign turnInstructionMode = 0' if you want no instructions.
                }

                Log.d(TAG, "before RoutingEngine() profileName: ${profileName}")
                // Instantiate RoutingEngine per route calculation
                // RoutingEngine constructor: (outfileBase, logfileBase, segmentDir, waypoints, rc, engineMode)
                val engine = RoutingEngine(
                    null, // outfileBase (String)
                    null, // logfileBase (String)
                    segmentsDir, // segmentDir (File)
                    waypoints, // waypoints (List<OsmNodeNamed>)
                    routingContext, // rc (RoutingContext)
                    RoutingEngine.BROUTER_ENGINEMODE_ROUTING // engineMode (int) - 0 for routing
                )
                Log.d(TAG, "after RoutingEngine() waypoints: ${waypoints}")

                // Perform the routing
                engine.doRouting(0) // 0 for no maxRunningTime


                // Retrieve the result (OsmTrack)
                routeData = engine.getFoundTrack()
                Log.d(TAG, "after routeData: ${routeData}")

                if (routeData == null || routeData.nodes == null || routeData.nodes.isEmpty()) { // OsmTrack has 'nodes' not 'points'
                    lastBRouterError = "BRouter: No route found or route data is empty."
                    Log.w(TAG, lastBRouterError!!)
                } else {
                    routePath = routeData
                    // OsmTrack.nodes contains OsmPathElement, convert them to GeoPoint
                    routePath.nodes.forEach { pathElement ->
                        // OsmPathElement has getILon(), getILat() in microdegrees
                        osmdroidRoutePoints.add(GeoPoint(pathElement.getILat() / 1E7, pathElement.getILon() / 1E7))
                    }

                    if (osmdroidRoutePoints.isEmpty()) {
                        lastBRouterError = "BRouter: Route found but converted point list is empty."
                        Log.w(TAG, lastBRouterError!!)
                    } else {
                        routeFound = true
                        currentRouteOverlay = Polyline().apply {
                            setPoints(osmdroidRoutePoints)
                            getOutlinePaint().apply {
                                color = ContextCompat.getColor(context, routeColorResId)
                                strokeWidth = 12.0f
                            }
                        }
                    }
                }
            } catch (e: Exception) {
                lastBRouterError = "Exception during BRouter route calculation: ${e.message}"
                Log.e(TAG, "BRouter route calculation error", e)
            }

            // Update UI back in MainActivity via callbacks
            if (routeFound && routePath != null) {
                val distanceMeters = routePath.distance.toDouble()
                val timeSeconds = routePath.getTotalSeconds().toLong()
                distanceTimeUpdater(df.format(distanceMeters / 1000.0) + " km", formatDuration(timeSeconds))
                bRouterStatusUpdater("Route calculated.")
                routeCalculatedCallback(currentRouteOverlay)
            } else {
                distanceTimeUpdater("Dist:", "Time:")
                bRouterStatusUpdater(lastBRouterError ?: "BRouter route calculation failed (unknown).")
                routeCalculatedCallback(null)
            }
        }.start()
    }

and when i try to use it logcat gives:

BRouter not initialized. Initiating loading now. Verifying profile: /storage/emulated/0/myNavi/brouter/profiles2 BRouter data directories found and verified. /storage/emulated/0/myNavi/brouter Calculating route from (50.899731, 3.176693) to (50.800184, 3.365965) using profile 'car-fast' Route cleared from map. before RoutingContext() waypoints: [31766930,508997310,start,0.0, 33659650,508001840,end,0.0] before RoutingEngine() profileName: car-fast after RoutingEngine() waypoints: [31766930,508997310,start,0.0, 33659650,508001840,end,0.0] after routeData: btools.router.OsmTrack@8878bd BRouter: No route found or route data is empty.

victorlysak avatar Jun 19 '25 13:06 victorlysak

do you know where is it possible to find actual brouter-android.jar to work with brouter in android studio fully offline?

@victorlysak Check the Releases.

devemux86 avatar Jun 19 '25 13:06 devemux86

brouter-1.7.7.zip does not have brouter-android.jar, it has brouter-1.7.7-all.jar and this is what i'm trying to use. is there any .jar file that can be used only for android studio to develop own app with brouter routing?

victorlysak avatar Jun 19 '25 13:06 victorlysak

On Android I only know the "IPC" interface: -the Brouter-app is intalled -Your app "calls" the brouter-app using IPC (inter process communication)

(if interested I could send you an example such as the Osmand app)

EssBee59 avatar Jun 21 '25 15:06 EssBee59