commons-app / apps-android-commons

The Wikimedia Commons Android app allows users to upload pictures from their Android phone/tablet to Wikimedia Commons
https://commons-app.github.io/
Apache License 2.0
998 stars 1.18k forks source link

Make Nearby show all pins that could be presented on the screen, rather than a circle #5480

Closed nicolas-raoul closed 5 months ago

nicolas-raoul commented 7 months ago

Currently Nearby shows pins in a way that often does not cover the whole screen:

Screenshot_20240127-122742~2.png

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:

Screenshot 2024-01-27 at 12 23 33

Wikishootme loads rather fast, our query is more complex but it is worth trying. We can also speed it up with some trick like #4560

shashankiitbhu commented 7 months ago

Interesting, so we have to optimise the query to speed up the loading so that more pins can be loaded in a certain radius?

nicolas-raoul commented 7 months ago

Wikishootme uses a rectangle query operation, which is probably more efficient than radius. We can use a web browser's Developer Tools to see the API calls they are using.

shashankiitbhu commented 7 months ago

This is their Request URL: https://query.wikidata.org/bigdata/namespace/wdq/sparql?query=%23TOOL%3A%20WikiShootMe%0ASELECT%20%3Fq%20%3FqLabel%20%3Flocation%20%3Fimage%20%3Freason%20%3Fdesc%20%3Fcommonscat%20%3Fstreet%20WHERE%20%7B%20SERVICE%20wikibase%3Abox%20%7B%20%3Fq%20wdt%3AP625%20%3Flocation%20.%20bd%3AserviceParam%20wikibase%3AcornerSouthWest%20%22Point(2.2610378265380864%2048.86160921192831)%22%5E%5Egeo%3AwktLiteral%20.%20bd%3AserviceParam%20wikibase%3AcornerNorthEast%20%22Point(2.327213287353516%2048.88142495734281)%22%5E%5Egeo%3AwktLiteral%20%7D%20%20OPTIONAL%20%7B%20%3Fq%20wdt%3AP18%20%3Fimage%20%7D%20%20OPTIONAL%20%7B%20%3Fq%20wdt%3AP373%20%3Fcommonscat%20%7D%20%20OPTIONAL%20%7B%20%3Fq%20wdt%3AP969%20%3Fstreet%20%7D%20%20SERVICE%20wikibase%3Alabel%20%7B%20bd%3AserviceParam%20wikibase%3Alanguage%20%22en%2Cen%2Cde%2Cfr%2Ces%2Cit%2Cnl%22%20.%20%3Fq%20schema%3Adescription%20%3Fdesc%20.%20%3Fq%20rdfs%3Alabel%20%3FqLabel%20%7D%20%7D%20LIMIT%203000

and This is the Response:

{
  "head" : {
    "vars" : [ "q", "qLabel", "location", "image", "reason", "desc", "commonscat", "street" ]
  },
  "results" : {
    "bindings" : [ {
      "q" : {
        "type" : "uri",
        "value" : "http://www.wikidata.org/entity/Q771548"
      },
      "location" : {
        "datatype" : "http://www.opengis.net/ont/geosparql#wktLiteral",
        "type" : "literal",
        "value" : "Point(2.2780859 48.8640063)"
      },
      "image" : {
        "type" : "uri",
        "value" : "http://commons.wikimedia.org/wiki/Special:FilePath/Ruedelapompe.JPG"
      },
      "commonscat" : {
        "type" : "literal",
        "value" : "Rue de la Pompe (Paris Metro)"
      },
      "desc" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Paris Métro station"
      },
      "qLabel" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Rue de la Pompe"
      }
    }, {
      "q" : {
        "type" : "uri",
        "value" : "http://www.wikidata.org/entity/Q800418"
      },
      "location" : {
        "datatype" : "http://www.opengis.net/ont/geosparql#wktLiteral",
        "type" : "literal",
        "value" : "Point(2.2753 48.8706)"
      },
      "image" : {
        "type" : "uri",
        "value" : "http://commons.wikimedia.org/wiki/Special:FilePath/Vue%20de%20trois%20quarts%20b%C3%A2timent%20voyageurs%20gare%20de%20l%27Avenue%20Foch.jpg"
      },
      "commonscat" : {
        "type" : "literal",
        "value" : "Avenue Foch (Paris)"
      },
      "desc" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "railway station"
      },
      "qLabel" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Gare de l'Avenue Foch"
      }
    }, {
      "q" : {
        "type" : "uri",
        "value" : "http://www.wikidata.org/entity/Q800418"
      },
      "location" : {
        "datatype" : "http://www.opengis.net/ont/geosparql#wktLiteral",
        "type" : "literal",
        "value" : "Point(2.2753 48.8706)"
      },
      "image" : {
        "type" : "uri",
        "value" : "http://commons.wikimedia.org/wiki/Special:FilePath/Vue%20de%20trois%20quarts%20b%C3%A2timent%20voyageurs%20gare%20de%20l%27Avenue%20Foch.jpg"
      },
      "commonscat" : {
        "type" : "literal",
        "value" : "Gare de l'avenue Foch"
      },
      "desc" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "railway station"
      },
      "qLabel" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Gare de l'Avenue Foch"
      }
    }, {
      "q" : {
        "type" : "uri",
        "value" : "http://www.wikidata.org/entity/Q1431541"
      },
      "location" : {
        "datatype" : "http://www.opengis.net/ont/geosparql#wktLiteral",
        "type" : "literal",
        "value" : "Point(2.27988889 48.86535556)"
      },
      "image" : {
        "type" : "uri",
        "value" : "http://commons.wikimedia.org/wiki/Special:FilePath/Lyc%C3%A9e%20Janson-de-Sailly%2C%20106%20rue%20de%20la%20Pompe%2C%20Paris%2016e%201.jpg"
      },
      "commonscat" : {
        "type" : "literal",
        "value" : "Lycée Janson-de-Sailly"
      },
      "desc" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "secondary education in France"
      },
      "qLabel" : {
        "xml:lang" : "en",
        "type" : "literal",
        "value" : "Lycée Janson-de-Sailly"
      }
    }...
shashankiitbhu commented 7 months ago

So to Implement this we'll have to create a new List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius, final boolean shouldQueryForMonuments, final String customQuery) method which takes params for a rectangle Instead of Radius and make a query according to that ?

nicolas-raoul commented 7 months ago

Sounds right, yes!

awanishyadav967 commented 7 months ago

Hi @nicolas-raoul I want to work on this ? Please assign it to me.

shashankiitbhu commented 7 months ago

Can I work on this? Can you assisgn this to me ? @nicolas-raoul

nicolas-raoul commented 7 months ago

wow difficult situation but I guess @awanishyadav967 asked first... sorry @shashankiitbhu and thanks for your research!

shashankiitbhu commented 7 months ago

No Issue @nicolas-raoul , it's an interesting task so best of luck @awanishyadav967

awanishyadav967 commented 7 months ago

Just asking in curiosity ,If we increase the number of pins ,so that it fill all the screen ,cannot it affect the app's performance? and also we're aiming to load more pins at the default zoom level, and I am thinking it can be solve by just increasing the radius of circle. @nicolas-raoul

nicolas-raoul commented 7 months ago

@awanishyadav967

I don't think it will affecting performance in terms of CPU/memory. The bottleneck will always be network bandwidth.

We tried increasing the radius but unfortunately the query becomes too slow. As wikishootme demonstrates, rectangle queries seem to be much faster.

awanishyadav967 commented 6 months ago

Hi @nicolas-raoul I change the query from wiki around to wiki box for the rectangle query and it work perfectly for the real coordinates but when I replace with placeholder it cannot get my real coordinates.

Here is code for query:

WHERE {
  # Around given location
  SERVICE wikibase:box {
    ?item wdt:P625 ?location.
     bd:serviceParam wikibase:cornerWest "Point(${LAT_WEST} ${LONG_WEST})"^^geo:wktLiteral.
     bd:serviceParam wikibase:cornerEast "Point(${LAT_EAST} ${LONG_EAST})"^^geo:wktLiteral.
  }

Here is OkHttpJsonApiClient.java code:

@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 double diagonalDistance = 0.012;
        final double diagonalAngle = 45.0;

// Convert distance to degrees
        final double distanceInDegrees = diagonalDistance /111.32;

// Calculate diagonal distances in latitude and longitude directions
        final double deltaLat = distanceInDegrees * Math.sin(diagonalAngle);
        final double deltaLong = distanceInDegrees * Math.cos(diagonalAngle);

// Calculate bounding box coordinates
        final double westCornerLat = cur.getLatitude() - deltaLat;
        final double westCornerLong = cur.getLongitude() + deltaLong;
        final double eastCornerLat = cur.getLatitude() + deltaLat;
        final double eastCornerLong = cur.getLongitude() - deltaLong;

    /*    final double westCornerLat = 77.96077;
        final double westCornerLong = 30.30209;
        final double eastCornerLat = 78.07047;
        final double eastCornerLong = 30.25851;*/

        final String query = wikidataQuery
            .replace("${LAT_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLat))
            .replace("${LONG_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLong))
            .replace("${LAT_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLat))
            .replace("${LONG_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLong))
            .replace("${LANG}", language);
        Timber.d("Latitude: %s, Longitude: %s", cur.getLatitude(), cur.getLongitude());
        Timber.d("West Corner Lat: %s, West Corner Long: %s", westCornerLat, westCornerLong);
        Timber.d("East Corner Lat: %s, East Corner Long: %s", eastCornerLat, eastCornerLong);
    I need little help ,I thing my calculation is wrong for getting coordinates.

    Here is how it look for any random coordinates

ss

kanahia1 commented 6 months ago

Hey @awanishyadav967 , How about using this code in NearbyParentFragment.java to get LatLng for Top Right and Bottom Left, then using them as east and west. It will also help us during different zoom levels. I tried this code inside populatePlacesForAnotherLocation and populatePlacesForCurrentLocation it is working for me.

IGeoPoint screenTopRight = mapView.getProjection().fromPixels(mapView.getWidth(), 0);
IGeoPoint screenBottomLeft = mapView.getProjection().fromPixels(0, mapView.getHeight());
fr.free.nrw.commons.location.LatLng screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng(screenBottomLeft.getLatitude(),screenBottomLeft.getLongitude(),0);
fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(screenTopRight.getLatitude(),screenTopRight.getLongitude(),0);
kanahia1 commented 6 months ago

Hey @nicolas-raoul, Can I work on this issue 🙂