Primitives are validated hierarchically
The methodology to validate the five different 3D primitives, as defined in the previous section, follows the methodology described in Ledoux [19] for single Solids, and extends it so that MultiSolids and CompositeSolids are handled.
The methodology uses many of the internals of the CGAL libraryFootnote 5 to represent and validate the 3D primitives, and uses existing methods to validate the 2D primitives. Because the geometric types and modules of CGAL do not follow the definitions of ISO19107, the geometric types available in different packages were modified and combined. One example is that a Solid is represented by a list of Shells (which are CGAL::Polyhedron_3), and the interactions between the different shells are validated with my own code using the Boolean operations in CGAL::Nef_polyhedron_3.
As Fig. 2 shows for one CompositeSolid, the 3D primitives are validated hierarchically:
-
the lower-dimensionality primitives (the LinearRings and Polygons) are validated by first projecting them to a 2D plane (obtained with least-square adjustment), and then using 2D validation methods;
-
then these are assembled into Shells and/or surfaces, and their validity is analysed;
-
then the Solids are validated (e.g. the interactions between different Shells, the orientation of the normals, etc.)
-
finally, for CompositeSolids, the interactions between the Solids are analysed.
This means that if one Polygon forming a CompositeSolid is not valid, the validator will report that error but will not continue the validation at the next level (to avoid “cascading” errors); all the primitives at one level are however validated.
At each level, the validator can report different error codes. As Fig. 3 shows, there are in total 32 different codes. Notice also that there are other errors:
-
errors related to specific City Objects in the CityGML data model [11, 23]. Currently these are only for CityGML Buildings, but they will be in the future extended to other classes if there is a need from practitioners. And also other standards will be included, e.g. IndoorGML is currently under development.
-
input errors, e.g. with files that do not respect the schema. These are common in practice, and can influence the validation process [24, 30].
A fast C++ implementation
The source code of val3dity is freely available under the GNU General Public License v3.0. Compiling binaries for macOS, Linux, and Windows is easy; for Windows executables are even offered. It is written in C++ and uses these two open-source libraries: (1) CGAL library to represent some 3D primitives (as explained above); (2) GEOSFootnote 6 is used to perform the validation of the 2D primitives, the error codes (eventually) thrown by GEOS are mapped to the error codes of val3dity.
CGAL was chosen because it contains several of the building blocks required to implement a validator, and because it offers the possibility to use exact arithmetic for all the packages [31]. Besides the basic components of CGAL, the following packages are used:
-
2D Polygons: used to represent each ring of a Polygons;
-
2D Triangulation: in val3dity all the surfaces are triangulated with a constrained Delaunay triangulation [7], which allows us to support interior rings in Polygons and helps in catching complex cases of planarity [13];
-
3D Polyhedral Surfaces: used to represent one Shell;
-
3D Boolean Operations on Nef Polyhedra: used to represent one Solid and to model and verify the interactions between the Shells, but also the interactions between the different Solids of a CompositeSolid and the different parts of a Building;
-
3D Minkowski Sum of Polyhedra: used when a tolerance is used to validate CompositeSolids and BuildingParts (see the section below);
How to use it. val3dity is a command-line program only, there is no graphical interface (see Fig. 4). Several parameters can be set by the users, these are mostly related to the tolerances that val3dity uses. Indeed, while both ISO19017 and CityGML mention that each Polygon must be planar, the concept of tolerance is not mentioned. Tolerances for the following can be defined:
-
planarity of Polygons: the tolerances used have been agreed upon by the community in the OGC Quality Interoperability Experiments [24];
-
snapping between vertices: since in many formats, e.g. GML, the same vertex needs to have its coordinates listed for each Polygon, a tolerance must be used to identified if they are the same;
-
overlap between Solids or BuildingParts, as explained below.
As an alternative to the command-line interface, one can use the web-application of val3dity (see Fig. 5), which is freely available to everyone (there is however a maximum file size that can be uploaded).
Input formats. The following formats can be used as input: CityGML, CityJSONFootnote 7, GML file of any flavour, OBJFootnote 8, and OFFFootnote 9. For CityGML and CityJSON files, all the City Objects (e.g. Building or Bridge) are processed and all their 3D primitives are validated. Other GML files are simply scanned and their 3D primitives are validated according to the rules in ISO19107, all the rest is ignored. For OBJ and OFF files (formats without semantics and used mostly for visualisation), each primitive will be validated according to the ISO19107 rules, therefore one must specify how the primitive(s) should be validated (as MultiSurface, CompositeSurface, or Solid).
Interactions between solids are validated with a tolerance
A CompositeSolid, formed for instance by the SolidsA and B, should fulfil the 2 assertions defined in the ‘Background’ section. While these can be verified with Boolean operations, in practice we often encounter datasets where two Solids overlap (or are disjoint) by a very small amount, e.g. the overlapping volume would be around 10cm 3 for a Building. While the overlap is an error, in practice reporting this as an error can be a nuisance for the user.
val3dity therefore uses the concept of an overlap tolerance to validate CompositeSolids. This can be seen as a generalisation to 3D of the tolerance used for the 2D validation of polygon, see for example van Oosterom et al. [25]. As shown in Fig. 6, the mathematical morphology theory in 3D [27] is used to erode and dilate Solids by a user-defined parameter. Erosion is performed when the overlap between Solids is verified (Ao∩Bo=∅), and dilation when disjointness is verified (A∪B= one Solid). These operations are realised by a series of operators that uses the Minkowski sum of a Solid with a structuring element (a cube or dodecahedron in this case); as shown in Boeters et al. [6] and Donkers [10] the shape of the element will influence the resulting shape and thus the results. The perfect structuring element would be a sphere (would not yield errors, as an approximation by a dodecahedron does), however the closer the structuring element approximates a sphere the more computation time will be necessary.
Buildings having one or more BuildingParts can also be validated with an overlap tolerance. However, only the overlap assertion is verified, since BuildingParts are allowed to be disjoint; the CityGML standard is not clear about this, but this was confirmed as the intended behaviour [17].
It should be noticed that using an overlap tolerance when validating slows down the process since the implementation of the Minkowski sum in CGAL runs in O(n3 m3) time in the worst case [12], where n and m are the number of primitives (of any dimensionality) in the input (the Solid and the structuring element). This can be observed in the experiments with real-world datasets in the next section.
Reporting errors to the user
Some validators, in 2D and 3D, report only the first error encountered, and then stop. This can be frustrating and time-consuming for the user because she needs to fix the error and rerun the validation again. val3dity was designed to avoid this, and aims at validating as many parts of a 3D primitive as possible, but stops to avoid so-called ‘cascading errors’, i.e. errors that do not exist but are cause by another error. This is why a hierarchical validation is used, as previously explained. For each error, extra information is usually given, for instance: (i) if a Shell contains a hole, its location is provided; (ii) if a Polygon forming a Solid is invalid, then its identifier is reported (and if it does not have one then its position in the input file is reported); (iii) if two Solids in a CompositeSolid overlap, the identifiers of the Solids are reported, etc. val3dity outputs a validation report, in JSON format, where for each (CityGML) object and 3D primitive the validation errors are listed. The report is both human- and machine-readable. As shown in Fig. 7, it is also possible to navigate this report with an interactive HTML viewer containing a summary and a list of detailed errors for each primitive and object.