Search code examples
androidonclickosmdroid

Android Osmdroid map polygon click unexpected delay


I have many(250+) polygons drawn on map. And I need to able to click on them. So i created custom class, that extented Polygon, where i override onSingleTapUp func(code below). The click works, but there is some delay before click action was executed: click

This delay exists both on the emulator and on the device, as well as in the release version. I assume the delay is due to the large number of polygon classes and it takes time to find the right one. What is the best solution to implement the click and remove the delay?

Custom polygon:

class CustomPolygon(geoPoints: List<GeoPoint>) : Polygon() {
    private var perimeterMarker: Marker? = null

    init {
        fillPaint.color = Color.TRANSPARENT
        this.points = geoPoints
        outlinePaint.color = Color.BLUE
        outlinePaint.strokeWidth = 5f
    }

    var isChecked = false

    private fun showPolygonPerimeterMarkers(polygon: CustomPolygon, map: MapView) {
        perimeterMarker = Marker(map)
        perimeterMarker!!.apply {
            textLabelBackgroundColor = Color.TRANSPARENT
            textLabelForegroundColor = Color.DKGRAY
            setTextIcon("P= ${(polygon.distance / 1000).toInt()} km")
            title= "P= ${(polygon.distance / 1000).toInt()} km"
            position = calculateCenter(polygon.actualPoints)
        }
    }

    override fun onSingleTapUp(e: MotionEvent?, mapView: MapView?): Boolean {
        if (e?.action == MotionEvent.ACTION_UP && contains(e) && !isChecked) {
            isChecked = true
            this.fillPaint.color = Color.BLUE
            this.fillPaint.alpha = 40

            mapView?.let{ showPolygonPerimeterMarkers(this, it)}
            perimeterMarker?.let {  mapView?.overlayManager?.add(it) }

            return true
        }
        if (e?.action == MotionEvent.ACTION_UP && contains(e) && isChecked) {
            this.fillPaint.color = Color.TRANSPARENT
            this.fillPaint.alpha = 0
            perimeterMarker?.textLabelForegroundColor = Color.TRANSPARENT
            isChecked = false
            perimeterMarker?.let {  mapView?.overlayManager?.remove(it) }
            return true
        }
        return super.onSingleTapUp(e, mapView)
    }
}

Every polygons added to map in viewmodel:

    fun getPolygons(map: MapView) {
        viewModelScope.launch {
            _isLoading.value = true

            val result = geoRepository.getPolygons()
            when (result) {
                is RepoResult.Success -> {
                    result.geoClusters.forEach { geoCluster ->
                        geoCluster.list.forEach { multiPolygon ->
                            try {
                                multiPolygon.polygons.forEach { polygon ->
                                    map.overlays.add(polygon) // here
                                    Log.e("Polygon added", "poly number")
                                }
                            } catch (e: Exception) {
                                Log.e("Point_exception", "exception $e")
                            }
                        }
                        _clusterPerimeter.value = geoCluster.perimeterLengthKm
                    }
                    _isLoading.value = false
                }
            }
        }
    }

Solution

  • You could try to simplify your polygons using the Douglas-Peucker reducer: https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/util/PointReducer.java

    More complex, if your use case is mainly based on numerous small polygons: implement a fast "no tap" check, based on non-inclusion of the tapped point inside the polygon boundingbox (precomputed boundingbox, of course). With your own PolygonCheck class, subclassing Polygon.