cityjson / specs

Specifications for CityJSON, a JSON-based encoding for 3D city models
https://cityjson.org
Creative Commons Zero v1.0 Universal
107 stars 25 forks source link

No attributes for boundary surfaces #1

Closed clausnagel closed 7 years ago

clausnagel commented 7 years ago

Thanks for drafting CityJSON. Just scanned the schema and examples. It seems that CityGML's concept of thematic boundary surfaces such as WallSurface or RoofSurface has been reduced to labels associated with geometric surfaces. This prevents storing attributes with individual boundary surfaces. For many CityGML models I have come across this will mean losing information when using CityJSON.

Might be worth thinking about a general pattern for representing sub-features with their spatial and non-spatial properties.

Btw, the example dataset at http://www.cityjson.org/en/0.1/_downloads/3-20-DELFSHAVEN.json uses the label "Wall" while the specification defines the label "WallSurface" (http://www.cityjson.org/en/0.1/specs/#semantics). Should be defined in the schema to enable interoperability.

hugoledoux commented 7 years ago

Thanks Claus, nice that someone dives in the details :)

I indeed made an error: boundary surfaces should be allowed to have attributes. There are two solutions to this:

  1. add another array for each attribute, eg if we wanted to have the "type of paint":
{
  "type": "MultiSurface",
  "lod": 2,
  "boundaries": [
    [[0, 3, 2, 1]], [[4, 5, 6, 7]], [[0, 1, 5, 4]]
  ],
  "semantics": [
    ["RoofSurface"], ["GroundSurface"], ["WallSurface"]
  ],
  "type-paint": [
    ["good blue paint"], ["white paint"], ["no paint"]
  ],
}

This does makes it unpractical if many attributes and (a bit) cumbersome to parse.

  1. the arrays boundaries and semantics are replaced by one array that contains json objects wrapping the indices, semantics and potentially the attributes.
{
  "type": "MultiSurface",
  "lod": 2,
  "information": [
    {[[0, 3, 2, 1]], "RoofSurface", "white paint"}, ....
  ]
}

I prefer better the former to be honest. Any opinions?


As for the Wall: oups indeed an error resulting from changing too often the specs and not updating the code. Will fix!

hugoledoux commented 7 years ago

okay I fixed the code and the dataset.

Notice all new changes are not directly visible on the website because v0.1 is the default. The master branch is where I push the new things, and this is shown online if you choose at the bottom right the 'latest' version as in the following https://dl.dropboxusercontent.com/s/h5e12xdz42zr6ha/2017-08-03%20at%2016.52.png

clausnagel commented 7 years ago

Well, good question. Solution 1 looks simpler. But it seems that each attribute array would have to have the same length as semantics. Thus, one must provide an attribute value for every entry in semantics. Well, there might be attributes that are only modelled for specific boundary surfaces, such as slope or solar energy suitability for roof surfaces. If your semantics array contains few roofs but a lot of walls, then you would have a lot of null values in this example.

Solutions 2 only stores the attribute value but not the attribute name, right? This might hinder queries such as "Give me all buildings having roof surfaces with a slope greater than...".

What about making the entries in semantics objects?

{
  "type": "MultiSurface",
  "lod": 2,
  "boundaries": [
    [[0, 3, 2, 1]], [[4, 5, 6, 7]], [[0, 1, 5, 4]]
  ],
  "semantics": [
    {
      "type": "RoofSurface",
      "attributes" : { 
        "slope": 12.5,
        "solar_suitability" : 1,
        ...
      }
    },
    {
      "type": "WallSurface",
      ...
    },
  ],
}

This would more follow your pattern of city objects.

clausnagel commented 7 years ago

I came across another question, which is somehow connected but perhaps better discussed in a separate thread.

Assume a simple LOD2 building having four sides and a gable roof. I would model this building with four WallSurface objects (one per side) and two RoofSurface elements (one for each part of the gable roof). This also complies with the SIG3D modelling guidelines.

Now assume that, due to whatever reasons, we cannot guarantee the planarity of one of the roof surfaces. One solution would be to triangulate the geometry of this roof surface. So in CityGML's GML encoding you still would be able to represent the two individual RoofSurface objects with one having a gml:MultiSurface containing the triangles. Thus, and this is my point, the semantics of the model does not change after the triangulation.

In CityJSON the semantics array is more strictly coupled with the surface members of a geometry. Correct me if I'm wrong, but for the above example every triangle would receive the label "RoofSurface". So ultimately, with CityJSON you can only distinguish all wall polygons from all roof polygons. But you cannot identify separate semantic RoofSurface or WallSurface objects anymore.

Well, this of course is a design decision. And keeping CityJSON simple might speak in favor of the label approach. But as a consequence, the original CityGML model cannot be reproduced after it has been exchanged with CityJSON. Is this understanding correct?

hugoledoux commented 7 years ago

Your solution is better than my two, already one advantage of releasing publicly CityJSON. I am a bit against having lists of objects, but these can't be avoided, I guess.

I'll implement this next week (schema + specs).

Re: the other point, this is something that I had identified and did not see personally as a major issue. Your understanding is correct. One can break the face into triangles, and give each the same ID (as you put above); this would allow us to reconstruct the CityGML. Optimal it is not, and rather "hacky", but it'd word. I'll think of it more...

clausnagel commented 7 years ago

Great, thanks. Yes, using the same ID would work. I think b3dm even works similar.

hugoledoux commented 7 years ago

As a side issue, triangulating unplanar faces is perhaps not the best solution (the easiest it is though), see this new paper: https://link.springer.com/chapter/10.1007/978-3-319-55702-1_78

On Fri, 4 Aug 2017 at 12:53, Claus Nagel notifications@github.com wrote:

Great, thanks. Yes, using the same ID would work. I think b3dm even works similar.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/tudelft3d/cityjson/issues/1#issuecomment-320219917, or mute the thread https://github.com/notifications/unsubscribe-auth/ABeZFqVsdz9iTdnvD2e6K7n9i3B7iKQzks5sUvgQgaJpZM4OrdSx .

clausnagel commented 7 years ago

Well, to avoid a list of objects, you could possibly draw the proposed RoofSurface, WallSurface, etc. JSON objects outside the semantics array. If you make sure that they have a mandory id attribute, then you could use this as reference in your semantics array.

For example, at some place you define:

"id-1": {
  "type": "RoofSurface",
  "attributes": {
    "solar_suitability": 1
  }
},
"id-2": {
  "type": "WallSurface"
},

Then, within the geometry, you can reference the id values very much like referencing vertices by their indices in the boundaries array or like referencing building parts in your Parts array.

{
  "type": "MultiSurface",
  "lod": 2,
  "boundaries": [
    [[0, 3, 2, 1]], [[4, 5, 6, 7]], [[0, 1, 5, 4]]
  ],
  "semantics": [
    ["id-1"], ["id-1"], ["id-2"]
  ],
}

The benefit is that you can easily and clearly assign mutliple surfaces to the same feature. And the representation of the boundary surface JSON objects even more follows the layout of the other feature types such as Building.

You could even allow the use of either an id value or of one of your predefined labels within the semantics array. For instance, if someone does not care about semantic roof or wall objects and does neither require additional attributes, then he or she could simply go for the predefined labels:

{
  "type": "MultiSurface",
  "lod": 2,
  "boundaries": [
    [[0, 3, 2, 1]], [[4, 5, 6, 7]], [[0, 1, 5, 4]]
  ],
  "semantics": [
    ["RoofSurface"], ["RoofSurface"], ["WallSurface"]
  ],
}

So all existing example datasets would still be valid.

And let me propose even one more step. Assume you make semantics a multi-dimensional array. Then you could even assign a surface to multiple features. For instance, you could express that a surface belongs to a RoofSurface and a BuildingInstallation (which is also possible in CityGML). As a consequence, only the top-level Building would require a geometry attribute. For all nested sub-features, the assigment of surfaces would happen via semantics.

A benefit would be that this would result in a general pattern for sub-features as mentioned in my initial post. A drawback, however, would be that you cannot make any assumption about the geometry type of a sub-feature anymore. Since only surfaces are tagged with the id of the sub-feature, all you could say is that it is a MultiSurface, but not necessarily a Solid. Hm, not so nice...

I will stop here. Please remember when reading all these proposals that I actually have no experience in designing a proper JSON data structure :-)

hugoledoux commented 7 years ago

@clausnagel I implemented your proposal, and updated the example (dummy values) but not the code yet. The more complex ones where one reuses the surfaces are too complex I believe. But I could be convinced otherwise.

f29be7f477ac41f08cf45907b2ed188433d69138