1

I am trying to filter out my clusters/markers based on a user's location with a predefined Circle for the radius. I would like it so that clusters/markers are invisible outside that radius.

I have tried creating an array and putting my lat and longs such as this: Android - display in the map only the markers included in a determinate area

and this: How to show markers only inside of radius (circle) on maps?

However, I am not sure how to approach this problem using ClusterManager

Here I get my data from Firebase and store it in ClusterManager:

    private fun loadMarkersFromDB() {

        mCompanies.child("data/results").addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {
                if (dataSnapshot.exists()) {
                    for (s in dataSnapshot.children) {
                        var company = s.getValue(Company::class.java)
                        val infoWindow =
                            MyItem(company!!.latitude, company!!.longitude, company.name)
                        mClusterManager.setAnimation(false)
                        mClusterManager.addItem(infoWindow)

                        Log.d("onDataChange", company.toString())
                    }
                }
            }

            override fun onCancelled(databaseError: DatabaseError) {
                Log.w("MapsActivity", databaseError.toException())
            }
        })
    }

Setting up Cluster function:

    private fun setUpCluster() {
        // Initialize the manager with the context and the map.
        // (Activity extends context, so we can pass 'this' in the constructor.)
        mClusterManager = ClusterManager(this, mMap)
        // Point the map's listeners at the listeners implemented by the cluster
        // manager.
        mMap.setOnCameraIdleListener(mClusterManager)
        mMap.setOnMarkerClickListener(mClusterManager)

        // Add cluster items (markers) to the cluster manager.
        loadMarkersFromDB()
    }

What I call inside onMapReady:

 setUpCluster()

        mClusterManager = ClusterManager(this, mMap)
        val customRenderer = CustomClusterRenderer(this, mMap, mClusterManager, mMap.getCameraPosition().zoom, 20f)
        mClusterManager.renderer = customRenderer
        mMap.setOnCameraMoveListener(customRenderer)
        mMap.setOnCameraIdleListener(mClusterManager)
        mMap.setOnMarkerClickListener(mClusterManager)

Here is a Circle code that I got from StackOverflow:

circle = mMap.addCircle(
                    CircleOptions()
                        .center(currentLatLng)
                        .radius(400.0) //The radius of the circle, specified in meters. It should be zero or greater.
                        .strokeColor(Color.rgb(0, 136, 255))
                        .fillColor(Color.argb(20, 0, 136, 255))
                )

My Cluster Item Class:

class MyItem : ClusterItem {
    private val position: LatLng
    private var title: String = ""
    private var snippet: String = ""

    constructor(lat: Double, lng: Double, title: String) {
        position = LatLng(lat, lng)
        this.title = title
    }

    override fun getSnippet(): String {
        return snippet
    }

    override fun getTitle(): String {
        return title
    }

    override fun getPosition(): LatLng {
        return position
    }

}

I got the Clusters working, and the data has loaded as intended, however, because I have over 3000 locations, I am trying to make it as optimized as possible, so that the user can only see the markers within the given Radius, but I would also like the option to unhide the markers outside the Radius with a click of a button.

Shashin Bhayani
  • 1,551
  • 3
  • 16
  • 37
jjjj-unit
  • 25
  • 7
  • You can use geofire for firebase that can give you locations with radius. And on "unhide" you can change radius and make new request. https://github.com/firebase/geofire-java – Vadim Eksler Mar 25 '19 at 06:40
  • @VadimEksler Adding full lib to do a simple calculation is not the right way. – Ibrahim Ali Mar 25 '19 at 07:00
  • @IbrahimAli totally not agree. If we think about future, now in he's db 3000 locations, and he need to bring all of them (not sure that user need it), when db will be 30 000 locations? it will bad solution to bring all of them and sort. – Vadim Eksler Mar 25 '19 at 07:23
  • did you fixed ur issue?? – Ramesh kumar May 29 '19 at 06:55

1 Answers1

-1

I think you really need only simple condition to check if the coming location is inside radius, i.e:

if(company!!.longitude < useLocation.longitude + radius && company!!.longitude > useLocation.longitude - radius)
   mClusterManager.addItem(infoWindow)

Note: You may need to do the same with latitude.

I guess the radius value will something equal to 0.00578 it's depending in your needs of course.

While the best way is write a query to get only the location within the range you specified.

Ibrahim Ali
  • 1,237
  • 9
  • 20
  • Thanks! I have tried this code using the following: if (company!!.longitude < circle.center.longitude + circle.radius && company!!.longitude > circle.center.longitude - circle.radius) mClusterManager.addItem(infoWindow) Just wondering, is my circle.center.longitude supposed to be the 'useLocation.longitude'? I have also applied the equivalent latitude but I didn't get any changes, however when I removed the 'radius' part I started to get some changes – jjjj-unit Mar 25 '19 at 07:44
  • Wrong example. Lets try with center of Paris: lat - 48.856180, long - 2.346505, our radius 5 km. You trying to add kilometers to degrees. Le Jardin du Luxembourg 2 km from my position lat - 48.8457545, long - 2.3526363. if (2.346505 < 2.3526363 + 5 && 2.346505 > 2.3526363 - 5) false – Vadim Eksler Mar 25 '19 at 08:00
  • look at this formula how to define distance from lat long https://stackoverflow.com/a/12440017/7917629 – Vadim Eksler Mar 25 '19 at 08:06
  • @LVXIV Yes `circle.center.longitude` equal to `userLocation.longitude` but the `circle.radius` not correct. Because circle.radius may equal to `5.0` which will produce not correct result, because 1 from longitude is equal to **40075 km** and 1 from latitude is equal to **111.32 km**, so you need to add few meters as I demonstrated above, it should be smth like `0.000123`. – Ibrahim Ali Mar 25 '19 at 10:49
  • @VadimEksler I don't think you understand my answer as well! – Ibrahim Ali Mar 25 '19 at 10:51
  • @IbrahimAli Thanks! I got it working as intended now – jjjj-unit Mar 25 '19 at 18:56