Skip to content

Centroid of linestrings #1771

Description

@FaFre

In some scenarios it is not possible to create a polygon (when e.g. the way has less than 4 points). But I still want to obtain the centroid.

In the documentation it is stated, that this only works with polygons/multipolygons. I gave it a shot and anyways, it is possible to obtain a centroid from linestrings like object:as_linestring():centroid(). This works in all cases, when it is not possible to create a polygon (when polygon:is_null()), with the single exception when a line(multiline has only one node (like https://www.openstreetmap.org/relation/7360610). PostGis is working in this scenario select ST_Centroid(ST_MakePoint(1, 1)).

I tried to convert the geometry into a single point via object:as_point() but the call is not possible outside node processing.

Activity

  1. joto commented on Sep 21, 2022

    @joto
    Collaborator

    Lets try to unpack this:

    1. Yes, the documentation is incomplete. Calculating the centroid is actually possible for all geometry types except GeometryCollection. We should change the docs.
    2. The centroid() of a geometry is defined as the center of gravity of that geometry. If you have an invalid geometry there is no meaning to that. osm2pgsql is more picky about invalid geometries than PostGIS is. We consider creating invalid geometries a bug, because working with invalid geometries leads to all sorts of problems.
    3. Your example select ST_Centroid(ST_MakePoint(1,1)) is wrong, this will create a point and centroids for points work in osm2pgsql also. The right example would be ST_Centroid(ST_MakeLine(ST_MakePoint(1, 1))) which indeed does work in PostGIS but not in osm2pgsql, as discussed in 2.
    4. I think the real question is: Should it be possible to create a point geometry from a way that has only a single point? If the answer is yes, we need object:as_point() to work in that case. For consistency it should probably return the null geometry if there is more than one point. (Note that there are many reasons why there can be only one point in a way, either because there is only one node, or because there are several nodes with the same ids or different ids but same locations, or because some of the nodes are not in the input data in which case osm2pgsql will just use the ones it finds.)
    5. The example you mention is a bit different, because it is a relation only containing a single node. There is nothing wrong with that. Currently, the only way to get to that node is as_geometrycollection() though, and centroid isn't supported for GeometryCollections (mostly because I am not sure what the correct semantic would be for that). From your description I understand you tried to treat that relation as a MultiLineString, which will return a null geometry, because the relation doesn't contains any lines.

    I think we should probably add (4). This would at least allow you to do whatever you want to do, although it is a bit annoying that you have to try as_polygon(), as_linestring(), and as_point() in that order for best results. But the normal use case is still that you want to be sure to always have good data and wrong data is ignored by default.

    We are already thinking about how to fix (5). There will be some way of accessing single member geometries of relations directly. (And we should probably also add an as_multipoint() for consistency.)

  2. FaFre commented on Sep 22, 2022

    @FaFre
    Author

    Sorry for my bad explanation yesterday. I was rethinking today, and maybe I can give you a complete picture.

    The spatial function set of this library is very limited, compared to PostGIS. This is completely fine, as this library has another use case. However, it trapped me in thinking I can replace this library now with PostGIS... After further investigations today, I also need to use PostGIS's ST_PointOnSurface (when the centroid is outside the surface) and ST_LineInterpolatePoint (to get the "middle" of a linestring). So this usage is far beyond the limitations.

    In fact, I want to have four tables:

    • element (contains some medtadata of an osm object)
    • node (linked node geometry of a element)
    • line (linked line geometry of a element)
    • polygon (linked polygon geometry of a element)

    In my case I don't care if it is a relation, way or node.

    A way can be a polygon (is_closed()) or just a simple line.
    A relation can be (multiple) polygon(s) (also with holes), disjoint polygons, or just straight lines.

    osm2pgsql is very oriented on node/way/relation structure and is restricting access to e.g. as_geometrycollection() outside of relation processing.

    Is there a way to do what I want without having a lot of intermediate tables and disk usage?

    I was thinking (as I use triggers anyway, to push all geom as geometrycollection into my element table and do all the processing inside a trigger, like filling my geometry tables. But as I descibed above, as_geometrycollection() is exclusive to relations. I understand geometrycollection as a universal container for several geometries. I'm not sure if this is the right thinking tho!

    So I think my demand with the centroid processing was just a side effect of an incomplete plan. You have to decide, if you want to investigate this further.

    Can you give me a suggestion on how to approach my import?

  3. locked and limited conversation to collaborators on Sep 22, 2022
  4. converted this issue into a discussion #1772 on Sep 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions