@cityjson/cj-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,296 @@
1
+ ## 8\. Extensions[](#extensions)
2
+
3
+ CityJSON uses [JSON Schemas](http://json-schema.org/) to document and validate its data model, including its Extensions. Schemas offer a way to validate the syntax of a JSON document, and thus the possibility to require certain JSON members. Therefore, for writing more complex Extensions, a basic familiarity with [JSON Schemas](http://json-schema.org/) is advised.
4
+
5
+ A CityJSON _Extension_ is a JSON file that documents how the core data model of CityJSON is extended, and it is also used for validating the CityJSON files. This is conceptually akin to, but not conformant with, the [Application Domain Extensions (ADEs)](https://docs.ogc.org/is/20-010/20-010.html#toc66) in CityGML.
6
+
7
+ A CityJSON Extension can extend the core data model in four ways:
8
+
9
+ 1. Defining new properties at the root of a document
10
+
11
+ 2. Defining attributes on existing City Objects
12
+
13
+ 3. Defining a new Semantic Object
14
+
15
+ 4. Defining a new City Object, or "extending" one of the existing City Objects
16
+
17
+
18
+ > **Note:** While Extensions are less flexible than CityGML ADEs (inheritance and namespaces are for instance not supported, and less customisation is possible), it should be noted that the flexibility of ADEs comes at a price: the software processing an extended CityGML file will not necessarily know what structure to expect.
19
+
20
+ There is ongoing work on using the ADE schemas to automatically do this, but this is currently not supported by most software. Viewers might not be affected by ADEs because the geometries are usually not changed by an ADE (although they can!). However, software parsing the XML to extract attributes and features might not work directly (and thus specific code would need to be written).
21
+
22
+ CityJSON Extensions are designed in a way that they can be read and processed by standard CityJSON software, often without requiring any changes in the parsing code. This is achieved by enforcing a set of 6 simple rules (see [§ 8.7 Rules to follow to define new City Objects](#rules-to-follow-to-define-new-city-objects)) when adding new City Objects. If these are followed, then a CityJSON file containing Extensions will be seen as a "standard" CityJSON file.
23
+
24
+ One of the philosophies of JSON is being "schema-less", which means that one is allowed to define new properties for the JSON objects without documenting them in a JSON schema (watch out: this does _not_ mean that JSON does not have schemas!). While this is in contrast to CityGML (and GML as a whole) where the schemas are central, the schemas of CityJSON are (partly) following that philosophy.
25
+
26
+ If one wants to document the parcel area in square-meters for a `"Building"` (`"area-parcel": {"value": 437, "uom": "m2"}`), the easiest way is just to add a new member to the City Object attributes:
27
+
28
+ {
29
+ "type": "Building",
30
+ "attributes": {
31
+ "storeysAboveGround": 2,
32
+ "area-parcel": {
33
+ "value": 437,
34
+ "uom": "m2"
35
+ }
36
+ },
37
+ "geometry": \[...\]
38
+ }
39
+
40
+ However, a regular attribute (without the `"+"` prefix) cannot be made mandatory in the core CityJSON schema. Only with an Extension can an attribute be made mandatory (see [](#case-2-defining-attributes-on-existing-city-objects)).
41
+
42
+ Therefore, an _Extension_ is used for enforcing certain properties, attributes, or City Object types in CityJSON objects. An _Extension_ makes sense if it is expected that different data producers and consumers in the target domain need to exchange data, or if an additional City Object or Semantic type is required for accurately modelling the data.
43
+
44
+ ### 8.1. Using an Extension in a CityJSON file[](#using-an-extension-in-a-cityjson-file)
45
+
46
+ An Extension should be given a name (eg "Noise") and the URL of the Extension file should be defined, including the version of the Extension that is used for this file. It is expected that the Extension is publicly available at the URL, and can be downloaded.
47
+
48
+ Several Extensions can be used in a single CityJSON Object, each one is indexed by its name in the `"extensions"` JSON object. In the example below we have two Extensions: one named "Noise" and one named "Solar\_Potential".
49
+
50
+ {
51
+ "type": "CityJSON",
52
+ "version": "2.0",
53
+ "extensions": {
54
+ "Noise": {
55
+ "url" : "https://someurl.org/noise.json",
56
+ "version": "2.0"
57
+ },
58
+ "Solar\_Potential": {
59
+ "url" : "https://someurl.org/solar.json",
60
+ "version": "0.8"
61
+ }
62
+ },
63
+ "CityObjects": {},
64
+ "vertices": \[\]
65
+ }
66
+
67
+ ### 8.2. The Extension file[](#the-extension-file)
68
+
69
+ A CityJSON Extension is a JSON object, and it **must** have the following 8 members:
70
+
71
+ 1. one member with the name `"type"`. The value must be `"CityJSONExtension"`.
72
+
73
+ 2. one member with the name `"name"`. The value must be a string identifying the extension.
74
+
75
+ 3. one member with the name `"url"`. The value must be a string with the HTTP URL of the location of the schema where the JSON object is located.
76
+
77
+ 4. one member with the name `"version"`. The value must be a string identifying the version of the Extension.
78
+
79
+ 5. one member with the name `"versionCityJSON"`. The value must be a string (X.Y) identifying the version of CityJSON that uses the Extension.
80
+
81
+ 6. one member with the name `"extraAttributes"`. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object.
82
+
83
+ 7. one member with the name `"extraCityObjects"`. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object.
84
+
85
+ 8. one member with the name `"extraRootProperties"`. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object.
86
+
87
+ 9. one member with the name `"extraSemanticSurfaces"`. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object.
88
+
89
+
90
+ {
91
+ "type": "CityJSONExtension",
92
+ "name": "Noise",
93
+ "description": "Extension to model the noise",
94
+ "url": "https://someurl.org/noise.ext.json",
95
+ "version": "0.5",
96
+ "versionCityJSON": "2.0",
97
+ "extraAttributes": {},
98
+ "extraCityObjects": {},
99
+ "extraRootProperties": {},
100
+ "extraSemanticSurfaces": {},
101
+ }
102
+
103
+ > **Note:** If an element of the Extension reuses, or references, structures and/or objects defined in the schemas of CityJSON, then assume that the Extension is in the same folder as the schemas. An example would be to reuse the Solid type:
104
+
105
+ "items": {
106
+ "oneOf": \[
107
+ {"$ref": "geomprimitives.json#/Solid"}
108
+ \]
109
+ }
110
+
111
+ ### 8.3. Case 1: Adding new properties at the root of a document[](#case-1-adding-new-properties-at-the-root-of-a-document)
112
+
113
+ It is allowed to add a new member at the root of a CityJSON file, but if one wants to document it in a schema, then the member’s name must start with a `"+"`. Imagine we wanted to store some census data for a given neighbourhood for which we have a CityJSON file, then we could define the extra root member `"+census"` as follows:
114
+
115
+ "extraRootProperties": {
116
+ "+census": {
117
+ "type": "object",
118
+ "properties": {
119
+ "percent\_men": {
120
+ "type": "number",
121
+ "minimum": 0.0,
122
+ "maximum": 100.0
123
+ },
124
+ "percent\_women": {
125
+ "type": "number",
126
+ "minimum": 0.0,
127
+ "maximum": 100.0
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ And a CityJSON file would look like this:
134
+
135
+ {
136
+ "type": "CityJSON",
137
+ "version": "2.0",
138
+ "extensions": {
139
+ "Census": {
140
+ "url": "https://someurl.org/census.ext.json",
141
+ "version": "0.7"
142
+ }
143
+ },
144
+ "CityObjects": {...},
145
+ "vertices": \[...\],
146
+ "+census": {
147
+ "percent\_men": 49.5,
148
+ "percent\_women": 51.5
149
+ }
150
+ }
151
+
152
+ ### 8.4. Case 2: Defining attributes for existing City Objects[](#case-2-defining-attributes-for-existing-city-objects)
153
+
154
+ It is also possible to add, and document in a schema, specific attributes, for example if we wanted to have the colour of the buildings as a RGBA value (red-green-blue-alpha):
155
+
156
+ {
157
+ "type": "Building",
158
+ "attributes": {
159
+ "storeysAboveGround": 2,
160
+ "+colour": {
161
+ "rgba": \[255, 255, 255, 1\]
162
+ }
163
+ },
164
+ "geometry": \[...\]
165
+ }
166
+
167
+ Another example would be to store the area of the parcel of a building, and also to document the unit of measurement (UoM):
168
+
169
+ {
170
+ "type": "Building",
171
+ "attributes": {
172
+ "storeysAboveGround": 2,
173
+ "+area-parcel": {
174
+ "value": 437,
175
+ "uom": "m2"
176
+ }
177
+ },
178
+ "geometry": \[...\]
179
+ }
180
+
181
+ For these two cases, the CityJSON Extension object would look like the snippet below. Notice that `"extraAttributes"` may have several properties (the types of the City Objects are the possibilities) and then each of these has as properties the new attributes (there can be several).
182
+
183
+ An extra attribute must start with a `"+"`; it is good practice to prepend the attribute with the name of the Extension, to avoid that 2 attributes from 2 different Extensions have the same name.
184
+
185
+ The value of the member is a JSON schema, this schema can reference and reuse JSON objects already defined in the CityJSON schemas. Thus, the keywords of the member values are defined by the JSON Schema specification. For instance, `"additionalProperties"` is a JSON-schema keyword stating that one is not allowed to add properties to this JSON object, beyond the ones defined in the schema (eg `"value", "uom"`).
186
+
187
+ "extraAttributes": {
188
+ "Building": {
189
+ "+colour": {
190
+ "type": "object",
191
+ "properties": {
192
+ "rgba": {
193
+ "type": "array",
194
+ "items": {"type": "number"},
195
+ "minItems": 4,
196
+ "maxItems": 4
197
+ }
198
+ },
199
+ "required": \["rgba"\],
200
+ "additionalProperties": false
201
+ },
202
+ "+area-parcel": {
203
+ "type": "object",
204
+ "properties": {
205
+ "value": { "type": "number" },
206
+ "uom": { "type": "string", "enum": \["m2", "feet2"\] }
207
+ },
208
+ "required": \["value", "uom"\],
209
+ "additionalProperties": false
210
+ }
211
+ }
212
+ }
213
+
214
+ ### 8.5. Case 3: Defining a new Semantic Object[](#case-3-defining-a-new-semantic-object)
215
+
216
+ It is possible to define a new Semantic Object (besides the ones prescribed, see [§ 3.3 Semantics of geometric primitives](#semantics-of-geometric-primitives)), and document it in the Extension.
217
+
218
+ New Semantic Objects must have a `"+"` as their first character, and other attributes/properties can be defined.
219
+
220
+ "extraSemanticSurfaces": {
221
+ "+ThermalSurface": {
222
+ "type": "object",
223
+ "properties": {
224
+ "type": { "enum": \[ "+ThermalSurface" \] },
225
+ "azimuth": {"type": "number"}
226
+ },
227
+ "required": \[ "type", "azimuth" \],
228
+ "additionalProperties": false
229
+ }
230
+ }
231
+
232
+ ### 8.6. Case 4: Creating and/or extending new City Objects[](#case-4-creating-and-or-extending-new-city-objects)
233
+
234
+ The creation of a new City Object is done by defining it in the CityJSON Extension object in the `"extraCityObjects"` member:
235
+
236
+ "extraCityObjects": {
237
+ "+NoiseBuilding": {
238
+ "allOf": \[
239
+ { "$ref": "cityobjects.json#/\_AbstractBuilding" },
240
+ {
241
+ "properties": {
242
+ "type": { "enum": \["+NoiseBuilding"\] },
243
+ "attributes": {
244
+ "properties": {
245
+ "buildingLDenMin": {"type": "number"}
246
+ }
247
+ }
248
+ },
249
+ "required": \["type"\]
250
+ }
251
+ \]
252
+ }
253
+ }
254
+
255
+ "extraCityObjects": {
256
+ "+NoiseBuildingPart": {
257
+ "allOf": \[
258
+ { "$ref": "cityobjects.json#/\_AbstractBuilding" },
259
+ {
260
+ "properties": {
261
+ "type": { "enum": \["+NoiseBuildingPart"\] },
262
+ "attributes": {
263
+ "properties": {
264
+ "buildingLDenMin": {"type": "number"}
265
+ }
266
+ }
267
+ },
268
+ "required": \["type", "parents"\]
269
+ }
270
+ \]
271
+ }
272
+ }
273
+
274
+ Since all City Objects are documented in the [schemas of CityJSON](https://www.cityjson.org/schemas/) (in `cityobjects.schema.json`), it is basically a matter of copying the parts needed in a new file and modifying its content.
275
+
276
+ A new name for the City Object must be given and it must begin with a `"+"`.
277
+
278
+ Because City Objects can be of different levels (1st-level ones can exist by themselves; 2nd-level ones need to have a parent), we need to explicitly define that the `"parents"` member is mandatory for 2nd-level objects.
279
+
280
+ Please note that since JSON schemas do not allow inheritance, the only way to extend a City Object is to define an entirely new one (with a new name, eg `"+NoiseBuilding"`). This is done by copying the schema of the parent City Object and extending it.
281
+
282
+ ### 8.7. Rules to follow to define new City Objects[](#rules-to-follow-to-define-new-city-objects)
283
+
284
+ The challenge when creating Extensions to the core model is that we do not want to break the software packages (viewers, spatial analysis, etc) that already read and process CityJSON files. While one could define a new City Object and document it, if this new object does not follow the rules below then it will mean that new specific software needs to be built for it (and this would go against the fundamental ideas behind CityJSON).
285
+
286
+ 1. The name of a new City Object must begin with a `"+"`, eg `"+NoiseBuilding"`.
287
+
288
+ 2. A new City Object must conform to the rules of CityJSON, ie it must contain a member `"type"`.
289
+
290
+ 3. Existing City Objects cannot be extended and have new types as children, eg it is not allowed to add a new City Object `"+Balcony"` to a `"Building"`. Instead, a new type, eg `"+FancyBuilding"`, should be created and it can have a `"+Balcony"` as a potential child.
291
+
292
+ 4. All the geometries must be in the member `"geometry"`, and cannot be located somewhere else deep in a hierarchy of a new member.
293
+
294
+ 5. The Geometry object’s boundary must be one of the eight types described in [§ 3 Geometry Objects](#geometry-objects). Similarly, the geometry appearances and templates must follow the core specification. This ensures that all the code written to process, manipulate, and view CityJSON files will be working without modifications.
295
+
296
+ 6. The reuse of types defined in CityJSON, eg `"Solid"` or semantic surfaces, is allowed.
@@ -0,0 +1,362 @@
1
+ ## 3\. Geometry Objects[](#geometry-objects)
2
+
3
+ CityJSON defines the following 3D geometric primitives, all of which are embedded in 3D space (and therefore their vertices have _(x, y, z)_ coordinates). Similarly to the indexing mechanism of the format [Wavefront OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file), the geometry object does not store the locations of its vertices, but points instead to a vertex in a list (member `"vertices"` in the CityJSON Object).
4
+
5
+ As is the case in CityGML, only linear and planar primitives are allowed; no curves or parametric surfaces can be represented.
6
+
7
+ A Geometry object is a JSON object for which the type member’s value is one of the following:
8
+
9
+ 1. `"MultiPoint"`
10
+
11
+ 2. `"MultiLineString"`
12
+
13
+ 3. `"MultiSurface"`
14
+
15
+ 4. `"CompositeSurface"`
16
+
17
+ 5. `"Solid"`
18
+
19
+ 6. `"MultiSolid"`
20
+
21
+ 7. `"CompositeSolid"`
22
+
23
+ 8. `"GeometryInstance"` (this is another type with different properties, see [§ 3.4 Geometry templates](#geometry-templates))
24
+
25
+
26
+ A Geometry object:
27
+
28
+ * **must** have one member with the name `"type"`. The value must be a string with one of the 8 allowed Geometry types, as defined above.
29
+
30
+ * **must** have one member with the name `"lod"`. The value must be a string with the LoD identifying the level-of-detail (LoD) of the geometry. This can be either a single digit (following the CityGML standards), or "X.Y"-formatted if the [improved LoDs by TU Delft](https://3d.bk.tudelft.nl/lod) are used.
31
+
32
+ * **must** have one member with the name `"boundaries"`. The value is a hierarchy of arrays (the depth depends on the Geometry object) with integers. Each integer refers to an index in the `"vertices"` array of the CityJSON object, and it is 0-based (ie the first element in the array has the index "0", the second one "1", etc.).
33
+
34
+ * **may** have one member with the name `"semantics"`. The value is a JSON Object, as defined below.
35
+
36
+ * **may** have one member with the name `"material"`. The value is a JSON Object, as defined below.
37
+
38
+ * **may** have one member with the name `"texture"`. The value is a JSON Object, as defined below.
39
+
40
+
41
+ > **Note:** There is _no_ Geometry Object for MultiGeometry. Instead, for the `"geometry"` member of a CityObject, the different geometries may be enumerated in the array (all with the same value for the member `"lod"`).
42
+
43
+ ### 3.1. Coordinates of the vertices[](#coordinates-of-the-vertices)
44
+
45
+ A CityJSON Object must have one member named `"vertices"`. The value is an array of arrays of 3 integers representing the coordinates of each vertex of the city model. The position of a vertex in this array (0-based) is used to represent the `"boundaries"` of Geometry Objects.
46
+
47
+ * one vertex **must** be an array with exactly 3 integers, representing the _(x,y,z)_ location of the vertex before it is transformed to its real-world coordinates (with the [§ 4 Transform Object](#transform-object)).
48
+
49
+ * the array of vertices may be empty.
50
+
51
+ * vertices may be repeated.
52
+
53
+
54
+ "vertices": \[
55
+ \[102, 103, 1\],
56
+ \[11, 910, 43\],
57
+ \[25, 744, 22\],
58
+ ...
59
+ \[23, 88, 5\],
60
+ \[8523, 487, 22\]
61
+ \]
62
+
63
+ ### 3.2. Arrays to represent boundaries[](#arrays-to-represent-boundaries)
64
+
65
+ The depth of the hierarchy of arrays depends on the Geometry object, and is as follows.
66
+
67
+ * A `"MultiPoint"` has an array with the indices of the vertices; this array can be empty.
68
+
69
+ * A `"MultiLineString"` has an array of arrays, each containing the indices of a LineString.
70
+
71
+ * A `"MultiSurface"`, or a `"CompositeSurface"`, has an array containing surfaces, each surface is modelled by an array of arrays, the first array being the exterior boundary of the surface, and the others the interior boundaries.
72
+
73
+ * A `"Solid"` has an array of shells, the first shell being the exterior shell of the solid, and the others the interior shells. Each shell has an array of surfaces, modelled in the exact same way as a MultiSurface/CompositeSurface.
74
+
75
+ * A `"MultiSolid"`, or a `"CompositeSolid"`, has an array containing solids. Each solid is modelled as above.
76
+
77
+
78
+ > **Note:** JSON does not allow comments, the comments in the example below (C++ style: `//-- my comments`) are only to explain the cases, and should be removed.
79
+
80
+ {
81
+ "type": "MultiPoint",
82
+ "lod": "1",
83
+ "boundaries": \[2, 44, 0, 7\]
84
+ }
85
+
86
+ {
87
+ "type": "MultiLineString",
88
+ "lod": "1",
89
+ "boundaries": \[
90
+ \[2, 3, 5\], \[77, 55, 212\]
91
+ \]
92
+ }
93
+
94
+ {
95
+ "type": "MultiSurface",
96
+ "lod": "2",
97
+ "boundaries": \[
98
+ \[\[0, 3, 2, 1\]\], \[\[4, 5, 6, 7\]\], \[\[0, 1, 5, 4\]\]
99
+ \]
100
+ }
101
+
102
+ {
103
+ "type": "Solid",
104
+ "lod": "2",
105
+ "boundaries": \[
106
+ //-- exterior shell
107
+ \[ \[\[0, 3, 2, 1, 22\]\], \[\[4, 5, 6, 7\]\], \[\[0, 1, 5, 4\]\], \[\[1, 2, 6, 5\]\] \],
108
+ //-- interior shell
109
+ \[ \[\[240, 243, 124\]\], \[\[244, 246, 724\]\], \[\[34, 414, 45\]\], \[\[111, 246, 5\]\] \]
110
+ \]
111
+ }
112
+
113
+ {
114
+ "type": "CompositeSolid",
115
+ "lod": "3",
116
+ "boundaries": \[
117
+ \[ //-- 1st Solid
118
+ \[ \[\[0, 3, 2, 1, 22\]\], \[\[4, 5, 6, 7\]\], \[\[0, 1, 5, 4\]\], \[\[1, 2, 6, 5\]\] \],
119
+ \[ \[\[240, 243, 124\]\], \[\[244, 246, 724\]\], \[\[34, 414, 45\]\], \[\[111, 246, 5\]\] \]
120
+ \],
121
+ \[ //-- 2nd Solid
122
+ \[ \[\[666, 667, 668\]\], \[\[74, 75, 76\]\], \[\[880, 881, 885\]\], \[\[111, 122, 226\]\] \]
123
+ \]
124
+ \]
125
+ }
126
+
127
+ > **Note:** See [this tutorial](https://www.cityjson.org/dev/geom-arrays/) for further explanation on the depth of arrays of Geometry objects.
128
+
129
+ ### 3.3. Semantics of geometric primitives[](#semantics-of-geometric-primitives)
130
+
131
+ A Semantic Object is a JSON object representing the semantics of a primitive of a geometry (e.g. a surface of a building). A Semantic Object may also represent other attributes of the primitive (e.g. the slope of the roof, or the solar potential). For surface and volumetric geometries (e.g. `MultiSurface`, `Solid` and `MultiSolid`), a primitive is a surface. If a geometry is a `MultiPoint` or a `MultiLineString`, then the primitives are its respective sub-parts: points and linestrings.
132
+
133
+ A Semantic Object:
134
+
135
+ * **must** have one member with the name `"type"`. The value is one of the allowed values. These depend on the City Object (see below).
136
+
137
+ * **may** have one member with the name `"parent"`. The value is an integer pointing to another Semantic Object of the same geometry (index of it, 0-based). This is used to explicitly represent to which wall or roof a window or door belongs to; there can be only one parent.
138
+
139
+ * **may** have one member with the name `"children"`. The value is an array of integers pointing to other Semantic Objects of the same geometry (index of it, 0-based). This is used to explicitly represent the openings (windows and doors) of walls and roofs.
140
+
141
+ * **may** have other members in the form of a JSON key-value pair, where the value must not be a JSON object (but a string/number/integer/boolean).
142
+
143
+
144
+ {
145
+ "type": "RoofSurface",
146
+ "slope": 16.4,
147
+ "children": \[2, 37\],
148
+ "solar-potential": 5
149
+ }
150
+
151
+ {
152
+ "type": "Window",
153
+ "parent": 2,
154
+ "type-glass": "HR++"
155
+ }
156
+
157
+ `"Building"`, `"BuildingPart"`, `"BuildingRoom"`, `"BuildingStorey"`, `"BuildingUnit"`, and `"BuildingInstallation"` can have the following semantics:
158
+
159
+ * `"RoofSurface"`
160
+
161
+ * `"GroundSurface"`
162
+
163
+ * `"WallSurface"`
164
+
165
+ * `"ClosureSurface"`
166
+
167
+ * `"OuterCeilingSurface"`
168
+
169
+ * `"OuterFloorSurface"`
170
+
171
+ * `"Window"`
172
+
173
+ * `"Door"`
174
+
175
+ * `"InteriorWallSurface"`
176
+
177
+ * `"CeilingSurface"`
178
+
179
+ * `"FloorSurface"`
180
+
181
+
182
+ For `"WaterBody"`:
183
+
184
+ * `"WaterSurface"`
185
+
186
+ * `"WaterGroundSurface"`
187
+
188
+ * `"WaterClosureSurface"`
189
+
190
+
191
+ For Transportation (`"Road"`, `"Railway"`, `"TransportSquare"`):
192
+
193
+ * `"TrafficArea"`
194
+
195
+ * `"AuxiliaryTrafficArea"`
196
+
197
+ * `"TransportationMarking"`
198
+
199
+ * `"TransportationHole"`
200
+
201
+
202
+ It is possible to define and use other semantics, but these have to start with a `"+"`, inline with the rules defined in the [§ 8 Extensions](#extensions).
203
+
204
+ {
205
+ "type": "+SupportingWall"
206
+ }
207
+
208
+ Because in a given City Object (say a `"Building"`) several primitives can have the same semantics (think of a complex building that has been triangulated, there can be dozens of triangles used to represent one planar surface), a Semantic Object can be declared once, and each of the primitives that are represented by it should point to it. This is achieved by first declaring all the Semantic Objects in an array, and then having an array where each primitive links to a Semantic Object (position in the array).
209
+
210
+ If a Geometry object has semantics, then the Geometry object:
211
+
212
+ * **must** have one member with the name `"semantics"`, whose values are two properties: `"surfaces"` and `"values"`. Both **must** be present.
213
+
214
+
215
+ Also:
216
+
217
+ * the value of `"surfaces"` is an array of Semantic Objects.
218
+
219
+ * the value of `"values"` is a hierarchy of arrays with integers. The depth depends on the Geometry object: for `MultiPoint` and `MultiLineString` this is a simple array of integers; for any other geometry type it is two less than the array `"boundaries"`. An integer refers to the index in the `"surfaces"` array of the same geometry, and it is 0-based. If one surface has no semantics, a value of `null` must be used.
220
+
221
+
222
+ > **Note:** For legacy reasons, we use `"surfaces"` to name the array of Semantic Objects. Nevertheless, this member is used for points and linestrings of `MultiPoints` and `MultiLineStrings`, as well.
223
+
224
+ {
225
+ "type": "MultiSurface",
226
+ "lod": "2",
227
+ "boundaries": \[
228
+ \[\[0, 3, 2, 1\]\],
229
+ \[\[4, 5, 6, 7\]\],
230
+ \[\[0, 1, 5, 4\]\],
231
+ \[\[0, 2, 3, 8\]\],
232
+ \[\[10, 12, 23, 48\]\]
233
+ \],
234
+ "semantics": {
235
+ "surfaces" : \[
236
+ {
237
+ "type": "WallSurface",
238
+ "slope": 33.4,
239
+ "children": \[2\]
240
+ },
241
+ {
242
+ "type": "RoofSurface",
243
+ "slope": 66.6
244
+ },
245
+ {
246
+ "type": "+PatioDoor",
247
+ "parent": 0,
248
+ "colour": "blue"
249
+ }
250
+ \],
251
+ "values": \[0, 0, null, 1, 2\]
252
+ }
253
+ }
254
+
255
+ {
256
+ "type": "CompositeSolid",
257
+ "lod": "2.2",
258
+ "boundaries": \[
259
+ \[ //-- 1st Solid
260
+ \[ \[\[0, 3, 2, 1, 22\]\], \[\[4, 5, 6, 7\]\], \[\[0, 1, 5, 4\]\], \[\[1, 2, 6, 5\]\] \]
261
+ \],
262
+ \[ //-- 2nd Solid
263
+ \[ \[\[666, 667, 668\]\], \[\[74, 75, 76\]\], \[\[880, 881, 885\]\] \]
264
+ \]
265
+ \],
266
+ "semantics": {
267
+ "surfaces" : \[
268
+ {
269
+ "type": "RoofSurface"
270
+ },
271
+ {
272
+ "type": "WallSurface"
273
+ }
274
+ \],
275
+ "values": \[
276
+ \[ //-- 1st Solid
277
+ \[0, 1, 1, null\]
278
+ \],
279
+ \[ //-- 2nd Solid get all null values
280
+ \[null, null, null\]
281
+ \]
282
+ \]
283
+ }
284
+ }
285
+
286
+ ### 3.4. Geometry templates[](#geometry-templates)
287
+
288
+ CityGML’s "ImplicitGeometries", better known in computer graphics as _templates_, are one method of compressing files since the geometries (such as benches, lamp posts, and trees) need to be defined only once. In CityJSON, they are implemented differently from what is specified in CityGML: they are defined separately in the file, and each template can be reused. By contrast, in CityGML, the geometry used for a given City Object is reused by other City Objects, there is thus no central location where all templates are stored.
289
+
290
+ The Geometry Templates are defined as a JSON object that:
291
+
292
+ * **must** have one member with the name `"templates"`. The value is an array of Geometry Objects.
293
+
294
+ * **must** have one member with the name `"vertices-templates"`. The value is an array of coordinates of each vertex of the templates (0-based indexing). The reason the vertices' indices are not global is to ensure that operations on the vertices (eg for CRS transformation, for [§ 4 Transform Object](#transform-object), or calculating the bounding box of a dataset) will not be affected by the templates (since they will often be defined locally, and translated/rotated/scaled to their final position).
295
+
296
+
297
+ Observe that the geometry of a template can have semantic surfaces, and that appearances can be assigned to it.
298
+
299
+ "geometry-templates": {
300
+ "templates": \[
301
+ {
302
+ "type": "MultiSurface",
303
+ "lod": "2.1",
304
+ "boundaries": \[
305
+ \[\[0, 3, 2, 1\]\], \[\[4, 5, 6, 7\]\], \[\[0, 1, 5, 4\]\]
306
+ \],
307
+ "semantics": {
308
+ "surfaces" : \[
309
+ {
310
+ "type": "+Skylight",
311
+ },
312
+ {
313
+ "type": "+PatioDoor",
314
+ }
315
+ \],
316
+ "values": \[0, 0, 1\]
317
+ }
318
+ },
319
+ {
320
+ "type": "MultiSurface",
321
+ "lod": "1.3",
322
+ "boundaries": \[
323
+ \[\[1, 2, 6, 5\]\], \[\[2, 3, 7, 6\]\], \[\[3, 0, 4, 7\]\]
324
+ \],
325
+ "material": {...}
326
+ }
327
+ \],
328
+ "vertices-templates": \[
329
+ \[0.0, 0.5, 0.0\],
330
+ ...
331
+ \[1.0, 1.0, 0.0\],
332
+ \[0.0, 1.0, 0.0\]
333
+ \]
334
+ }
335
+
336
+ A given template can be used as the geometry (or as one of the geometries) of a City Object. A new JSON object of type `"GeometryInstance"` is defined, and it:
337
+
338
+ * **must** have one member with the name `"template"`, whose value is the position of the template in the `"geometry-templates"` (0-indexing).
339
+
340
+ * **must** have one member with the name `"boundaries"`, whose value is an array containing only one vertex index, which refers to one vertex in the `"vertices"` member of a CityJSON file. (This is the reference point from which the transformations are applied, it is the "referencePoint" in CityGML.)
341
+
342
+ * **must** have one member with the name `"transformationMatrix"`, whose value is a 4x4 matrix (thus 16 values in an array) defining the rotation/translation/scaling of the template. Note that these 16 values are ordered row-by-row, as the example below shows.
343
+
344
+
345
+ {
346
+ "type": "SolitaryVegetationObject",
347
+ "geometry": \[
348
+ {
349
+ "type": "GeometryInstance",
350
+ "template": 0,
351
+ "boundaries": \[372\],
352
+ "transformationMatrix": \[
353
+ 2.0, 0.0, 0.0, 0.0,
354
+ 0.0, 2.0, 0.0, 0.0,
355
+ 0.0, 0.0, 2.0, 0.0,
356
+ 0.0, 0.0, 0.0, 1.0
357
+ \]
358
+ }
359
+ \]
360
+ }
361
+
362
+ > **Note:** The CityJSON website has a [page to help developers with Geometry Templates](https://www.cityjson.org/dev/geom-templates/), it contains simple examples, explains which transformations to apply to obtain world coordinates, and explains how matrices work (for instance, in the example above, a scaling of 2.0 is applied).