osmcode / libosmium

Fast and flexible C++ library for working with OpenStreetMap data.
https://osmcode.org/libosmium/
Boost Software License 1.0
471 stars 114 forks source link

Need help, how to add altitude to libosmium #350

Closed district10 closed 2 years ago

district10 commented 2 years ago

I thought it was easy as adding z to osmium::geom::Coordinates and alt to osmium::geom::Location. But it turns out more complicated than that.

Besides adding z/alt to data structures, we need to assign them from your data, e.g. XML, so I tried:

https://github.com/district10/libosmium/commit/ff7dfe93be23ce15d39fff2b448bab384a35db09#diff-98bdd24cf8904fade7acabaa131c3b9c36ed1bd9e436a9c79b20fb66ff43fc6f

const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) {
    // ...
    check_attributes(attrs, [&location, &user, &object](const XML_Char* name, const XML_Char* value) {
        if (!std::strcmp(name, "lon")) {
            location.set_lon(value);
        } else if (!std::strcmp(name, "lat")) {
            location.set_lat(value);
        } else if (!std::strcmp(name, "user")) {
            user = value;
        } else {
            object.set_attribute(name, value);
        }
    });
    //               HERE
    //                |
    // added by me VVVVVV
    if (location.z() == 0.0) {
        auto &tags = object.tags();
        // https://wiki.openstreetmap.org/wiki/Altitude
        const char *ele = tags.get_value_by_key("ele");
        if (ele) {
            location.set_alt(ele);
        }
    }
    ...
}

This won't work, because when init_object, tags() are not set yet.

Then I tried to add caching logic to Node class directly:

https://github.com/district10/libosmium/commit/ff7dfe93be23ce15d39fff2b448bab384a35db09#diff-03c1cf399112604c393c6e324788398b97b72cf53deba9ca66b421f2446e4324

class Node {
    // ...
    osmium::Location m_location;
    mutable tl::optional<Cache> cache;
    void auto_caching() const {
        if (cache) {
            return;
        }
        cache = Cache{};
        for (auto &tag: tags()) {
            // https://wiki.openstreetmap.org/wiki/Altitude
            if (!std::strcmp(tag.key(), "ele")) {
                // <tag k="ele" v="21.228"/>
                double ele = std::atof(tag.value());
                cache->elevation = ele;
                // m_location.set_alt(ele);
            }
        }
    }

    tl::optional<double> elevation() const {
        auto_caching();
        return cache->elevation;
    }

    osmium::Location location() const noexcept {
        auto_caching(); // caching it
        return m_location;
    }
};

Code compiles and but unit tests wot't pass. Code just hangs at node.tags() function.

It seems cause by osimum memory alignment. Any suggestions?

Maybe I should just calculate on site without caching.

joto commented 2 years ago

The internal encoding of OSM objects in libosmium is somewhat magic. You have to understand how the Buffers and Items in those buffers work, do the right padding etc. It is not so easy to change that.

This is certainly not something I'd consider adding to libosmium, so I suggest you solve that outside libosmium.

district10 commented 2 years ago

@joto Yeah... I'm planning caching on the python end, that's much easier.

(Hope one day I can put more time learning the details.