Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load and display OSM elements with addr:housenumber from overpass.api.de #27

Open
4 of 12 tasks
stephan75 opened this issue Mar 16, 2021 · 38 comments
Open
4 of 12 tasks
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@stephan75
Copy link

stephan75 commented Mar 16, 2021

What about the following feature request:

When the map view of SwiftAddress is zoomed in enough, enable a button that downloads all OSM elements from overpass-api.de that contain a tagging with addr:housenumber=*

and then display each element from that data collection on the map view.

In this way, a mapper can see where buildings are present in the OSM data which already have a tag addr:housenumber, and where this tag is missing.

Maybe as a start, try this method only for OSM nodes ... and extend this method to ways and relations later.


ToDo steps moved from a following comment to have github's progress bar:

  • from current map view inside the app, determine a bounding box for the displayed area,
  • have a correct user agent string for the following overpass-api request,
  • do a query on overpass-api.de for the mentioned bounding box, for all nodes with addr:housenumber=* (ways and maybe relations should be handled later, not now.),
  • download the query result and store it
  • Parse / single out relevant parts of the XML
  • Fix DelayedMapListener issue: see DelayedMapListener onZoom() not called reliably unless using zoom Buttons. osmdroid/osmdroid#1712
  • use this to display all those housenumber on the map view similar to how housenumber are displayed so far.
  • extend the query, storing and displaying also to OSM way objects,
  • extend the query, storing and displaying also to OSM relation objects (interpolation lines of housenumbers, building multipolygons?)
  • Potentially option to edit downloaded housenumber?
  • add an option to toggle the display of this layer on/off, or even delete it completely.
  • Make downloading efficient
@IpswichMapper
Copy link
Owner

Is this worth it? You can already see all the housenumbers on the default "Osm-carto" view. Adding this might help with other views. It could also mean that you can edit existing numbers. However, implementing the ability to edit existing numbers will be more difficult I think

@IpswichMapper IpswichMapper added enhancement New feature or request help wanted Extra attention is needed labels Mar 28, 2021
@IpswichMapper
Copy link
Owner

IpswichMapper commented Mar 29, 2021

@stephan75 thoughts?

@stephan75
Copy link
Author

When writing this feature request I had in mind certain POIs where the OSM standard carto style only displays its POI icon, but NOT the house number, which is definitively tagged on that node or building.
So it is not clear for a normal user whether that POI has already its housenumber tagged in the OSM data.
Example:
image

@stephan75
Copy link
Author

stephan75 commented Apr 7, 2021

Unfortunately I have no android programming / coding skills,
but I will try to collect some needed steps for this feature:

MOVED TODO LIST TO FIRST ISSUE COMMENT

Maybe we can get some initial hints from @westnordost who is the developer of StreetComplete?

@IpswichMapper
Copy link
Owner

IpswichMapper commented Apr 7, 2021

I don't think this will be very difficult to implement (maybe it will take some time). I've already worked with Overpass API to create the "dropdown" feature when you try and manually enter a housenumber (i.e., when you click on the street name in the keypad and start typing out the street, a dropdown will show displaying the names of all the streets that are close by). I've also worked with boundingboxes already to create the "proof of concept" for downloading map tiles.

All you have to do is parse the XML and display them as markers and the map.

I have other issues though, so as if I add the ability to "edit" these, then the .osm files generated will contain already existing nodes. Will this cause issues when merging? And also, large requests to Overpass API can take relatively long to parse too.

Also, would it clutter the map?

@westnordost
Copy link

westnordost commented Apr 7, 2021 via email

@IpswichMapper
Copy link
Owner

IpswichMapper commented Apr 8, 2021

This is what I wrote for the query:

boundingBox = mapView.boundingBox
Thread {
    val queryText = "https://overpass-api.de/api/interpreter?data=" +
                    "<query type='node'>" +
                    "<has-kv k='addr:housenumber' regv='.+'/>" +
                    "<bbox-query s='${boundingBox.latSouth}' w='${boundingBox.lonWest}' " +
                    "n='${boundingBox.latNorth}' e='${boundingBox.lonEast}' />" +
                    "</query> <print />"
            val query = URL(queryText)
            val result = query.readText()
}.start()

seems good enough, however, it isn't working reliably at the moment because osmdroid's "onZoom()" function doesn't activate properly when using a "DelayedMapListener" (which is a listener that activies only after you have finished zooming or scrolling). See osmdroid/osmdroid#1712

@westnordost

Is your library more efficient than the normal Kotlin API code I have shown above?

Another thing, how can I make this efficient / avoid redownloading housenumbers?

For example, if I were to scroll the map so that half of it still the old boundingBox, using a normal DelayedMapListener all the housenumbers would have to be downloaded (there is quite a bit of delay for this). Is there a way to only download sections that you haven't downloaded already?

@stephan75

I have checked off all the boxes that I did today and added some more detail to your checklist.

@westnordost
Copy link

Is your library more efficient than the normal Kotlin API code I have shown above?

The library is not about efficiency but convenience: It does the querying and the parsing of the data for you. If I remember correctly, it has built-in support for parsing the "out geom" result as well, so you directly get the geometry for each returned element too.

@westnordost
Copy link

val myDataHandler = object : MapDataWithGeometryHandler {
    fun handle(bounds: BoundingBox) {
        /* here you get returned the bounding box of your request */
    }

    fun handle(node: Node) {
        /* this is called for every node in the overpass result */
    }

    fun handle(way: Way, geometry: List<LatLon>) {
        /* this is called for every way in the overpass result, geometry is attached */
    }

    fun handle(relation: Relation, bounds: BoundingBox, nodeGeometries: Map<Long, LatLon>, wayGeometries: Map<Long, List<LatLon>>) {
        /* this is called for every relation in the overpass result, geometry is attached */
    }
}

// get all housenumbers on Malta
overpassApi.queryElementsWithGeometry(
    "[bbox:13.8,35.5,14.9,36.3]; nwr['addr:housenumber']; out meta geom;", 
    myDataHandler
)

What you do in myDataHandler is your choice. You could just put it all into a big list, or persist to database or whatever.

@IpswichMapper
Copy link
Owner

val myDataHandler = object : MapDataWithGeometryHandler {
    fun handle(bounds: BoundingBox) {
        /* here you get returned the bounding box of your request */
    }

    fun handle(node: Node) {
        /* this is called for every node in the overpass result */
    }

    fun handle(way: Way, geometry: List<LatLon>) {
        /* this is called for every way in the overpass result, geometry is attached */
    }

    fun handle(relation: Relation, bounds: BoundingBox, nodeGeometries: Map<Long, LatLon>, wayGeometries: Map<Long, List<LatLon>>) {
        /* this is called for every relation in the overpass result, geometry is attached */
    }
}

// get all housenumbers on Malta
overpassApi.queryElementsWithGeometry(
    "[bbox:13.8,35.5,14.9,36.3]; nwr['addr:housenumber']; out meta geom;", 
    myDataHandler
)

What you do in myDataHandler is your choice. You could just put it all into a big list, or persist to database or whatever.

How would you get the values for each node? For example, in the handler(node: Node), you could do node.position but I couldn't find any function that allowed me to get the value of specific tags. How is this possible (note: I don't know Overpass that well, I mostly stick to XML as I showed in my example).

Plus it gives me an error when building when I add this dependancy:

Duplicate class org.intellij.lang.annotations.Flow found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.Identifier found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$AdjustableOrientation found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$BoxLayoutAxis found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$CalendarMonth found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$CursorType found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$FlowLayoutAlignment found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$FontStyle found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$HorizontalAlignment found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$InputEventMask found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$ListSelectionMode found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$PatternFlags found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TabLayoutPolicy found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TabPlacement found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TitledBorderJustification found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TitledBorderTitlePosition found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.JdkConstants$TreeSelectionMode found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.Language found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.MagicConstant found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.Pattern found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.PrintFormat found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.PrintFormatPattern found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.RegExp found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.intellij.lang.annotations.Subst found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.Contract found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.Nls found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.NonNls found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.NotNull found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.Nullable found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.PropertyKey found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.jetbrains.annotations.TestOnly found in modules jetified-annotations-13.0 (org.jetbrains:annotations:13.0) and jetified-annotations-java5-18.0 (org.jetbrains:annotations-java5:18.0.0)
Duplicate class org.xmlpull.v1.XmlPullParser found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlPullParserException found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlPullParserFactory found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlSerializer found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)

Go to the documentation to learn how to Fix dependency resolution errors.

Here are my dependancies:

implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation 'org.osmdroid:osmdroid-android:6.1.10'
    implementation 'com.github.MKergall:osmbonuspack:6.6.0'
    implementation 'androidx.preference:preference-ktx:1.1.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
    implementation "com.github.mancj:SlideUp-Android:2.2.8"
    implementation 'ru.ztrap:RxSlideUp2:2.0.1' //optional, for reactive listeners based on RxJava-2
    implementation 'androidx.exifinterface:exifinterface:1.3.2'
    implementation 'de.westnordost:osmapi-overpass:1.3'

Even though your library isn't mentioned in the duplicate class StackTrace, removing that library fixes the problem for some reason.

@westnordost
Copy link

westnordost commented Apr 8, 2021

I don't know Overpass that well, I mostly stick to XML as I showed in my example

Should be not problem to use XML in the query. The library just passes the query string through to Overpass and does not do anything with it.

How would you get the values for each node? For example, in the handler(node: Node), you could do node.position but I couldn't find any function that allowed me to get the value of specific tags

node.tags?.get("addr:housenumber") (tags may be null if the node has no tags)

error

Right, it seems that on Android, certain classes (XmlPullParser, JetBrains annotations) are already defined, so you need to remove them from that dependency.
StreetComplete is not using the library anymore since v26, so I can't copy any configuration from the current gradle. Does this work?

implementation 'de.westnordost:osmapi-overpass:1.3' {
    // xml pull parser already included in Android
    exclude group: 'net.sf.kxml', module: 'kxml2' 
    // NonNull etc annotations are already available in Android
    exclude group: 'org.jetbrains', module: 'annotations'
    exclude group: 'com.intellij', module: 'annotations'
    exclude group: 'org.intellij', module: 'annotations'
}

@westnordost
Copy link

In an old version of StreetComplete, I found this block

configurations {
    // it's already included in Android
    all*.exclude group: 'net.sf.kxml', module: 'kxml2'

    cleanedAnnotations
    compile.exclude group: 'org.jetbrains', module:'annotations'
    compile.exclude group: 'com.intellij', module:'annotations'
    compile.exclude group: 'org.intellij', module:'annotations'
}

This excludes the given dependencies not only for the specified dependency but for all dependencies.

Please if anything of that works, let me know, then I can update the README.md in that repos.

@IpswichMapper
Copy link
Owner

I just tried using the OSMAPI library that you have for uploading/downloading OSM data (using APIv0.6). It says to add this to your code:

    compile ('de.westnordost:osmapi:3.11') {
        exclude group: 'net.sf.kxml', module: 'kxml12'
    }

(Note: compile is depreciated but I get the same bug with implementation)

Duplicate class org.xmlpull.v1.XmlPullParser found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlPullParserException found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlPullParserFactory found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)
Duplicate class org.xmlpull.v1.XmlSerializer found in modules jetified-kxml2-2.3.0 (net.sf.kxml:kxml2:2.3.0) and jetified-xmlpull-1.1.3.1 (xmlpull:xmlpull:1.1.3.1)

So it seems like kxml is giving me bugs even after I explicitaly told it to excluded from the OSMapi.

Also, another thing that is confusing me is branches. I made the above compile ('de.westnordost:osmapi:3.11') in the uploadToOsm branch, but when I checkout the main branch, the changes appear in the main branch too??? I thought the advantages of branches was that you code write code in one branch and not affect another one until you merge? So why is this happening? (Sorry if this is something basic I am missing out, I've not used branches in git before this).

@westnordost
Copy link

westnordost commented Apr 8, 2021

but when I checkout the main branch, the changes appear in the main branch too???

This does not happen. What made you think this is what happened? If you switch branches, I recommend re-sync the project with the gradle files and running hte clean task.

I just tried using the OSMAPI library that you have for uploading/downloading OSM data (using APIv0.6). It says to add this to your code:

Okay, just as a test, what about only

    implementation 'de.westnordost:osmapi-core:1.4' {
        exclude group: 'net.sf.kxml', module: 'kxml12'
    }

?

And if this gives an error, what about

dependencies {
    implementation 'de.westnordost:osmapi-core:1.4'
}

configurations {
    all*.exclude group: 'net.sf.kxml', module: 'kxml2'
}

@IpswichMapper
Copy link
Owner

This does not happen. What made you think this is what happened?

Turns out you have to commit changes in order for them to be tied to that branch. (Other option is to use git stash of course). Sorry about that, that was a really simple thing.

implementation 'de.westnordost:osmapi-core:1.4' {
   exclude group: 'net.sf.kxml', module: 'kxml12'
}

Note, even with implementation the actual library needs to be in brackets if you want to do that:

implementation ('de.westnordost:osmapi-core:1.4') {
    exclude group: 'net.sf.kxml', module: 'kxml12'
}

That didn't work, however, the bug still showed up.

This, however, even with implementation the actual library needs to be in brackets if you want to do that:

implementation ('de.westnordost:osmapi-core:1.4') {
    exclude group: 'net.sf.kxml', module: 'kxml12'
}

That didn't work, however, the bug still showed up.

This, however, worked fine:

dependancies {
    implementation 'de.westnordost:osmapi-core:1.4'
}
configurations {
    all*.exclude group: 'net.sf.kxml', module: 'kxml2'
}

@IpswichMapper
Copy link
Owner

IpswichMapper commented Apr 8, 2021

Seems like, in your documention, this:

compile ('de.westnordost:osmapi:3.11')
{
	exclude group: 'net.sf.kxml', module: 'kxml2' // already included in Android
}

needs to be replaced with this:

dependancies {
    implementation 'de.westnordost:osmapi:3.11'
}
configurations {
    all*.exclude group: 'net.sf.kxml', module: 'kxml2'
}

@westnordost
Copy link

Hm?

@IpswichMapper
Copy link
Owner

In the documentation for OSMAPI (the api v0.6 version), it says to use the "exclude" command to remove the kxml library.

However, that doesn't work, but rather configuration{} works. So the documentatino should be updated to show this

@IpswichMapper
Copy link
Owner

Got it working. However, on my first run, I got rate limited (it says Too Many Requests (429)). Is there a user agent that I need to enter to be able to do more requests?

Not only this, but the downloading really lagged the app. I changed the zoomLevel from 14 to 17 and this was fixed, however I am still getting the Too Many Requests message

@IpswichMapper
Copy link
Owner

@stephan75 I don't think continuous download of housenumbers when you are zoomed in is possible. Not only would it send far too many requests to the server, it would also lead to duplication of markers and would lag the app. I think a better solution is to be able to download already existing markers in the "DownloadTilesFragment". This can be accessed from the Imagery icon in the top right of the map. When downloading tiles, I could add an option to also download existing housenumbers in that area.

@westnordost
Copy link

Got it working. However, on my first run, I got rate limited (it says Too Many Requests (429)). Is there a user agent that I need to enter to be able to do more requests?

On your first request? Well, the request limiting is per IP. So if you made requests earlier, you have to wait. Note the other methods of the OverpassMapDataDao. You can actually query how long more you have to wait until you are allowed to do the next request. But in any way, you should specify the correct user agent (in this case, "SwiftAddress")

Anyway, check how many requests you do. Maybe you do too many requests.

Not only this, but the downloading really lagged the app.

You are downloading in a background thread, right? OverpassMapDataDao doesn't do any threading on its own.

@IpswichMapper
Copy link
Owner

On your first request?

Sorry, I meant my first run of the app. I was using a "DelayedMapListener" to call the function. That means that everytime I stop scrolling or stop zooming, it calls the function.

Not only this, but the downloading really lagged the app.

You are downloading in a background thread, right? OverpassMapDataDao doesn't do any threading on its own.

Placing the markers has to happen on a main thread, however. Since then I increased the zoom level, and that issue went away.

That being said, do you think it is possible to have a continuous download like @stephan75 wants?

Streetcomplete only downloads data when you tell it to. Would it be possible to use the overpass API to download data continuously when you scroll the map?

@westnordost
Copy link

That means that everytime I stop scrolling or stop zooming, it calls the function.

That's too much. You should memorize which areas you already downloaded and memorize the results. StreetComplete does this like this:

iD does it the same, and I assume that every other proper editor that allows free scrolling (OsmInEdit, Osm Go, .... for example) does it the same. Maybe not persisting it into a DB, but at least persisting the information into memory.

Streetcomplete only downloads data when you tell it to.

No, StreetComplete downloads automatically areas around the user's current location. The logic is functionally the same as the "download everything that comes into view" as it is done for iD etc.

@westnordost
Copy link

Though in all fairness, I have to tell you that it is almost certain that I will implement a view that looks something like this

in StreetComplete within the next 3-4 months or so, as described in detail here streetcomplete/StreetComplete#2461

@IpswichMapper
Copy link
Owner

No, StreetComplete downloads automatically areas around the user's current location. The logic is functionally the same as the "download everything that comes into view" as it is done for iD etc.

So tasks are downloaded automatically? I think I got confused there because when I used to use it, I would always tell it to download manually tasks in an area.

When they are downloaded automatically, isn't it in the area surrounding your current location? I'm pretty sure it doesn't start downloading tasks when you zoom in. Could you create code where housenumbers are downloaded when you zoom in enough using the techniques you have shown?

@westnordost
Copy link

So tasks are downloaded automatically?

Yes, around your GPS location. You can additionally download areas manually, if you want to download areas not around your location in advance.

When they are downloaded automatically, isn't it in the area surrounding your current location

Correct.

Could you create code where housenumbers are downloaded when you zoom in enough using the techniques you have shown?

What do you mean exactly? If I can theoretically?

@IpswichMapper
Copy link
Owner

Could you create code where housenumbers are downloaded when you zoom in enough using the techniques you have shown?

Sorry, bad phrasing. I essentially meant, "can it be done". I'm not asking you to do it for me 😅.

@westnordost
Copy link

westnordost commented Apr 8, 2021

Yes, of course.

val downloadedTiles = HashSet<Tile>()

@Synchronized fun download(bbox: Bounds) {
    val  tiles = bbox.asTilesAtZoomLevel(16)
    if (downloadedTiles.containsAll(tiles)) return

    val bboxExpandedToTileEdges = tiles.toBbox()
    doTheDownloadNow(bboxExpandedToTileEdges )
    
    downloadedTiles.putAll(tiles)
}

fun onMapViewHasChangedInAnyWay() {
    val bbox = getDisplayedBoundingBox()
    download(bbox)
}

@IpswichMapper
Copy link
Owner

IpswichMapper commented Apr 8, 2021

Thanks for all the help.

Currently I'm trying to login to the "sandbox api". How do you get an OAuthConsumer?

        val provider: OAuthProvider = DefaultOAuthProvider(
            "https://api06.dev.openstreetmap.org/oauth/request_token",
            "https://api06.dev.openstreetmap.org/oauth/access_token",
            "https://api06.dev.openstreetmap.org/oauth/authorize"
        )

        

        val connection = OsmConnection("https://api06.dev.openstreetmap.org/", null, null)

You do you get this "consumer" after the user has entered a username and password?

https://github.com/mttkay/signpost/blob/master/docs/GettingStarted.md

This guide does not mention what role the username and password play.

@westnordost
Copy link

Not as simple as that. You need to go through the OAuth process. The Sandbox Api is the same as the normal api. So you'd need to create an account on the dev instance of openstreetmap.

Have a look at:
https://github.com/streetcomplete/StreetComplete/blob/master/app/src/main/java/de/westnordost/streetcomplete/settings/OAuthFragment.kt

However, you don't need to be logged in at OpenStreetMap.org to do an overpass query. So the "OsmConnection" you use for the overpass-api can have null for the OAuth stuff.

@IpswichMapper
Copy link
Owner

IpswichMapper commented Apr 8, 2021

However, you don't need to be logged in at OpenStreetMap.org to do an overpass query. So the "OsmConnection" you use for the overpass-api can have null for the OAuth stuff.

This is for uploading data to OSM. Which is something I was the app to eventually do.

Have a look at:
https://github.com/streetcomplete/StreetComplete/blob/master/app/src/main/java/de/westnordost/streetcomplete/settings/OAuthFragment.kt

I did, but I'm still confused as to where this consumer is coming from:

        if (inState != null) {
            consumer = inState.getSerializable(CONSUMER) as OAuthConsumer
            authorizeUrl = inState.getString(AUTHORIZE_URL)
            oAuthVerifier = inState.getString(OAUTH_VERIFIER)
        } else {
            consumer = consumerProvider.get()
            authorizeUrl = null
            oAuthVerifier = null
        }

What is inState, what is inState.getSerializable(CONSUMER) , is it a PreferenceManager (can't find inState being defined anywhere)?

@IpswichMapper

This comment has been minimized.

@IpswichMapper
Copy link
Owner

Oh wait - You sign in through the OSM Website. That makes sense then, you are just opening the URL and getting back the oauth tokens

@westnordost
Copy link

westnordost commented Apr 8, 2021

It is not entered in the app. If you want to know the details, read up on how OAuth 1 works.

The @Inject stuff is from Dagger2, a dependency injection framework. It is resolved to the following:

private const val BASE_OAUTH_URL = "https://www.openstreetmap.org/oauth/"
private const val CONSUMER_KEY = "[your oauth consumer key for your app]"
private const val CONSUMER_SECRET = "[your oauth consumer secret for your app]"
// you can create the above two in your account preferences on openstreetmap.org

consumerProvider = OkHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET)
provider = OkHttpOAuthProvider(
        BASE_OAUTH_URL + "request_token",
        BASE_OAUTH_URL + "access_token",
        BASE_OAUTH_URL + "authorize"
    )
callbackScheme = "streetcomplete"
callbackHost = "oauth"

@stephan75
Copy link
Author

@stephan75 I don't think continuous download of housenumbers when you are zoomed in is possible. ...

Having a continuous download from overpass-api when dragging or zooming the map view was not my my prime aim, to be honest. I was indeed more thinking about how StreetComplete does it. Most minimalistic solution: only download housenumbers when the user has done a certain action, maybe by pressing a button like "download housenumber data" or similar.

Maybe there are also some users who want to use the SwiftAddress app in the fields without an online connection.
Please don't make that download mandatory.

PS: I am really very very amazed about the efforts of you two concerning this feature request. Many thanks! This coding things are really out of my scope. But keep on!

@IpswichMapper
Copy link
Owner

@stephan75 Is it okay if I only add a "download housenumbers" dialog in the "imagery" tab? Trying to implement this automatically will be a lot of effort.

@stephan75
Copy link
Author

Yes it is okay when that download starts by a user action.

No need for automatic download, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants