How to make Nearby show all pins that could be presented on the screen in rectangle, rather than a circle

41 Views Asked by At

Currently Nearby shows pins in a way that often does not cover the whole screen, at least at default zoom level, I feel that it should be possible to load more pins, enough to fill all areas of the screen, similar to how Wikishootme loads pins. Wikishootme uses a rectangle query operation, which is probably more efficient than radius. We tried increasing the radius but unfortunately the query becomes too slow. As wikishootme demonstrates, rectangle queries seem to be much faster.

Here is code:

/**
 * Make API Call to get Nearby Places
 *
 * @param cur                     Search lat long
 * @param language                Language
 * @param radius                  Search Radius
 * @param shouldQueryForMonuments : Should we query for monuments
 * @return
 * @throws Exception
 */
@Nullable
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
        final boolean shouldQueryForMonuments, final String customQuery) throws Exception {

    Timber.d("Fetching nearby items at radius %s", radius);
    Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
    final String wikidataQuery;
    if (customQuery != null) {
        wikidataQuery = customQuery;
    } else if (!shouldQueryForMonuments) {
        wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
    } else {
        wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
    }
    final String query = wikidataQuery
            .replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
            .replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude()))
            .replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude()))
            .replace("${LANG}", language);

    final HttpUrl.Builder urlBuilder = HttpUrl
            .parse(sparqlQueryUrl)
            .newBuilder()
            .addQueryParameter("query", query)
            .addQueryParameter("format", "json");

    final Request request = new Request.Builder()
            .url(urlBuilder.build())
            .build();

    final Response response = okHttpClient.newCall(request).execute();
    if (response.body() != null && response.isSuccessful()) {
        final String json = response.body().string();
        final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
        final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
        final List<Place> places = new ArrayList<>();
        for (final NearbyResultItem item : bindings) {
            final Place placeFromNearbyItem = Place.from(item);
            if (shouldQueryForMonuments && item.getMonument() != null) {
                placeFromNearbyItem.setMonument(true);
            } else {
                placeFromNearbyItem.setMonument(false);
            }
            places.add(placeFromNearbyItem);
        }
        return places;
    }
    throw new Exception(response.message());
}

/**
 * Make API Call to get Nearby Places Implementation does not expects a custom query
 *
 * @param cur                     Search lat long
 * @param language                Language
 * @param radius                  Search Radius
 * @param shouldQueryForMonuments : Should we query for monuments
 * @return
 * @throws Exception
 */
@Nullable
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
        final boolean shouldQueryForMonuments) throws Exception {
    return getNearbyPlaces(cur, language, radius, shouldQueryForMonuments, null);
}

here is SPARQL query..

SELECT
  ?item
  (SAMPLE(?location) as ?location)
  (SAMPLE(?label) AS ?label)
  (SAMPLE(?description) AS ?description)
  (SAMPLE(?class) AS ?class)
  (SAMPLE(?classLabel) AS ?classLabel)
  (SAMPLE(?pic) AS ?pic)
  (SAMPLE(?destroyed) AS ?destroyed)
  (SAMPLE(?endTime) AS ?endTime)
  (SAMPLE(?wikipediaArticle) AS ?wikipediaArticle)
  (SAMPLE(?commonsArticle) AS ?commonsArticle)
  (SAMPLE(?commonsCategory) AS ?commonsCategory)
WHERE {
  # Around given location
  SERVICE wikibase:around {
     ?item wdt:P625 ?location.
     bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. # Longitude latitude
     bd:serviceParam wikibase:radius "${RAD}". # Radius in kilometers.
}

here is calculation

 /**
 * Creates a series of points that create a circle on the map.
 * Takes the center latitude, center longitude of the circle,
 * the radius in meter and the number of nodes of the circle.
 *
 * @return List List of LatLng points of the circle.
 */
public static List<com.mapbox.mapboxsdk.geometry.LatLng> createCircleArray(
        double centerLat, double centerLong, float radius, int nodes) {
    List<com.mapbox.mapboxsdk.geometry.LatLng> circle = new ArrayList<>();
    float radiusKilometer = radius / 1000;
    double radiusLong = radiusKilometer
            / (111.320 * Math.cos(centerLat * Math.PI / 180));
    double radiusLat = radiusKilometer / 110.574;

    for (int i = 0; i < nodes; i++) {
        double theta = ((double) i / (double) nodes) * (2 * Math.PI);

        double nodeLongitude = centerLong + radiusLong * Math.cos(theta);

        double nodeLatitude = centerLat + radiusLat * Math.sin(theta);

        circle.add(new com.mapbox.mapboxsdk.geometry.LatLng(nodeLatitude, nodeLongitude));
    }
    return circle;
}

enter image description here

Can anyone help me to know about how to implement rectangular query instead of circular query?

0

There are 0 best solutions below