Institute of Formal Methods in Computer Science University of Stuttgart Universitätsstraße 38 D–70569 Stuttgart Bachelorarbeit Creating Assetto Corsa tracks based on OpenStreetMaps and height data Jost Malte Klink Course of Study: Informatik Examiner: Prof. Dr. Stefan Funke Supervisor: Felix Weitbrecht, M.Sc. Commenced: April 10, 2024 Completed: October 10, 2024 Abstract Over the years many government initiatives got formed for creating digital models of the landscape, using among other things aerial LiDAR scans. Those sometimes being available under an open license allows for using those models, with high accuracy, in many applications. This research work aims at developing an application for using DTMs (Digital Terrain Models), obtained by aerial scans, for creating game maps used in simulation games, especially the popular racing simulator Assetto Corsa. For determining the driveable road surface, path data from OSM (OpenStreetMap) is used. The path points get interpolated using a Catmull-Rom-Spline and then connected to a road mesh. From the DTM a terrain mesh is generated and simplified using an edge collapse algorithm. Finally, both meshes get combined and exported to be used in the racing simulation game or, for further detailing work, in a 3D modeling software. This work produced an open source C++ web application for uploading DTM files, selecting a path, and generating a basic driveable game map from it. Kurzfassung Über die Jahre haben sich viele Regierungsinitiativen gebildet, die als Ziel haben digitale Land- schaftsmodelle des eigenen Landes zu erstellen, unteranderem durch Techniken wie LiDAR Scans, aufgenommen aus der Luft. Diese hoch detaillierten Datensätze sind teilweise öffentlich zugänglich und können damit in verschiedenen Anwendungen genutzt werden. Ziel dieser Arbeit ist es eine Anwendung zu entwickeln, die digitale Geländemodelle (DGM) nutzt zur Erstellung von digitalen Rennstrecken, nutzbar in Rennsimulationsspielen, wie dem populärem Computerspiel Assetto Corsa. Zur Bestimmung der befahrbaren Straßen, wurden Datenpunkte des OSM (OpenStreetMap) Projects genutzt. Diese Wegpunkte wurden dann mit einer Catmull-Rom-Spline interpoliert und anschließend zu einem Polygonnetz verbunden, welches die Straßenoberfläche bildet. Von den Höhendaten aus dem DGM wird ein Gelände-Polygonnetz erstellt, welches mithilfe eines Kantenkontraktions- Algorithmus vereinfacht wird. Zuletzt werden beide Polygonnetze in einer 3D Szene kombiniert und exportiert, bereit für den Import ins Spiel oder in eine 3D Modellierungssoftware zur weiteren Bearbeitung. Im Rahmen dieser Arbeit einstand eine Open Source C++ Web-Anwendung zum Hochladen von DGM Dateien, auswählen der gewünschten Straßen, und anschließender Erstellung einer funktionalen befahrbaren Spielwelt. 3 Contents 1 Introduction 15 1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.2 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2 Background 17 2.1 Geospatial Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.2 Assetto Corsa Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.3 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3 Implementation 25 3.1 Application Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 Web Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3 Main Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4 Results 33 4.1 Neuffen - Germany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.2 Albula Pass - Switzerland . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 5 Conclusion and Outlook 37 Bibliography 39 A Comparison between edge collapse policies 43 B Images of the track Neuffen 45 C Images of the track Albula Pass 47 5 List of Figures 2.1 The difference between DTM and DSM (Graphic inspired by plex earth1) . . . . 17 2.2 Minimal folder structure of an Assetto Corsa track mod . . . . . . . . . . . . . . 20 2.3 A track loaded inside ksEditor, on the left an example of the naming convention for the different meshes can be seen . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.1 Folder structure of the developed application . . . . . . . . . . . . . . . . . . . 25 3.2 The web interface of the app running in the Chromium based Brave browser . . . 27 4.1 The track Neuffen in the 3D modeling software Blender . . . . . . . . . . . . . . 33 4.2 Two problems with the generated track Neuffen . . . . . . . . . . . . . . . . . . 34 4.3 The web interface with the input for the Albula Pass in Switzerland . . . . . . . . 35 4.4 Gaps between tiles because of the edge collapse algorithm . . . . . . . . . . . . 35 B.1 The starting position of the track Neuffen in the game Assetto Corsa . . . . . . . 45 B.2 Right after the second hairpin turn of the track Neuffen in the game Assetto Corsa 45 C.1 Looking south up the mountain of Albula Pass in the game Assetto Corsa . . . . 47 C.2 Looking west wards down into the valley of Albula Pass in the game Assetto Corsa 47 7 List of Listings 2.1 Route for requesting the node index of the closest node to a position on the globe 23 9 List of Algorithms 3.1 The processing steps of a raster file to a terrain mesh in pseudocode . . . . . . . 29 3.2 The processing steps of an OSM path to a road mesh in pseudocode . . . . . . . 30 11 Acronyms 2D two dimensional. 18 3D three dimensional. 18 API application programming interface. 22 CGAL Computational Geometry Algorithms Library. 22 DEM Digital Elevation Model. 17 DSM Digital Surface Model. 17 DTM Digital Terrain Model. 3, 15 GDAL Geospatial Data Abstraction Library. 22 GeoTIFF Geographic Tagged Image File Format. 18 JSON JavaScript Object Notation. 22 LiDAR light detection and ranging. 17 OGC Open Geospatial Consortium. 18 OSGeo The Open Source Geospatial Foundation. 22 OSM OpenStreetMap. 3, 15 TIFF Tagged Image File Format. 18 WKT well known text. 28 13 1 Introduction With the development of self driving cars, the need for realistic and accurate simulation data becomes increasingly important. Accurate high quality data however is costly to gather and therefore was previously only available to big companies and organizations that had the necessary monetary resources. On the other hand there exist government incentives to map the geological features of their country for scientific surveys, e.g. for finding resource deposits or for flood simulations to ensure public safety1. And with the rise of initiatives to make this data publicly available2it is possible to repurpose this data for driving and racing simulations, which was previously not possible without significant monetary investments. Furthermore, initiatives like the INSPIRE Directive3 by the European Union help making data from different countries compatible and further expand the availability of high quality datasets. Making it viable for a wide range of people to use real world data in their projects. 1.1 Motivation This work looks at using freely available geographic terrain data, namely elevation data, to generate a basic working track usable in the racing simulator game Assetto Corsa4. The racing simulator from 2013 was chosen because of its extensive modding support and long standing modding community [luc21]. Every car enthusiast probably once had the experience of driving a particular interesting road, maybe a windy mountain pass or beautiful forest road and had the dream of having the chance to experience the thrill of racing on it. Racing simulator games allow for having those experiences, however most of the time only well know race tracks are available as playable maps in the games. Given the modding support of Assetto Corsa one can overcome this problem by creating these tracks themselves. The problem then becomes a task of manually recreating real life locations, which is a very time consuming process, with many sub tasks [Nes23]. However, with the previously mentioned rise in freely available high quality geological data the aim of this work was to streamline the first steps of creating a map based on a real world location. The application developed in this work allows to read-in height data in form of DTMs (Digital Terrain Models) and transform it into meshes usable in the game. Furthermore, it allows to select paths on an OSM (OpenStreetMap) powered web interface for defining the driveable road surface used in the game. Together this allows for easily creating a basic functional Assetto Corsa racing map, that serves as a basis for further manually refinements. Those could for example be adding buildings, vegetation, or street barriers in a 3D modeling software of choice. 1https://experience.arcgis.com/experience/753ad2ebd3554fa696885b8c366c3049 2https://www.bmi.bund.de/DE/themen/moderne-verwaltung/open-government/open-data/open-data-node.html 3https://knowledge-base.inspire.ec.europa.eu/overview_en 4https://assettocorsa.gg 15 https://experience.arcgis.com/experience/753ad2ebd3554fa696885b8c366c3049 https://www.bmi.bund.de/DE/themen/moderne-verwaltung/open-government/open-data/open-data-node.html https://knowledge-base.inspire.ec.europa.eu/overview_en https://assettocorsa.gg 1 Introduction 1.2 Structure This thesis is organized into six chapters. Starting with the current Chapter 1 for introducing the thematic, stating the motivation for this topic as well as mentioning some related work. Afterwards a description and explanation of relevant data structures and used algorithms is given in Chapter 2 on the facing page. Chapter 3 on page 25 gives an overview of the implementation and highlights solutions for encountered problems. In Chapter 4 on page 33 some examples produced with the developed application are shown and evaluated. Finally, Chapter 5 on page 37 gives a summary of this work and names possible future improvement. 16 2 Background This chapter will introduce and explain the information needed for understanding the topics this paper deals with. The first section covers necessary information about geospatial data. After that a section about how game maps in Assetto Corsa work follows. And the last section of this chapter highlights the tools and libraries used by the developed application. 2.1 Geospatial Data This work uses two types of real world data to generate the game map. For generating the terrain of the map, height data in form of raster-files is used. Secondly for generating the road mesh of the game map, path points from OSM are utilized. 2.1.1 Height Data Height data can be obtained by many methods. On a global scale there is data from satellite missions with a resolution down to one arc sec which is approximately a distance of 30 meters between data points [Hir14; Jha18]. For finer scale data which is needed to create realistic roads, LiDAR (light detection and ranging) scans are an option. These can be performed from the air using airplanes or on the ground [Liu08]. The data used in this work was obtained using aerial LiDAR scans. Landscape DTM DSM Figure 2.1: The difference between DTM and DSM (Graphic inspired by plex earth1) These data surveys are often performed by an aircraft and are commissioned by the government. LiDAR scans produce two types of DEMs (Digital Elevation Models). One representing the top most points, called DSM (Digital Surface Model), which contains besides points reflected by the ground also vegetation as well as artificial object points (e.g. from buildings). And secondly one only containing the true ground points, which is called DTM [Hir14]. The difference between the two models is visualized in Figure 2.1. For clas- sification of the LiDAR data many algorithms exist, for example based on returned intensity [YGC+08] or based on multi-spectral scans [EGF17]. DTMs are the datasets used in this work because the true ground height is needed for generating the terrain and later placing the road on it. Buildings 1Elevation Modeling - the differences between DTM, DSM & DEM https://support.plexearth.com/hc/en-us/ articles/4642425453201-Elevation-Modeling-the-differences-between-DTM-DSM-DEM 17 https://support.plexearth.com/hc/en-us/articles/4642425453201-Elevation-Modeling-the-differences-between-DTM-DSM-DEM https://support.plexearth.com/hc/en-us/articles/4642425453201-Elevation-Modeling-the-differences-between-DTM-DSM-DEM 2 Background and vegetation are considered decorations and additional content, not generated by the developed program. At the time of writing, most of the freely available aerial datasets have a resolution of 1-2 meters. The raw point cloud generated by a LiDAR scan is for the purposes of this work not suitable, as it can contain holes or outliers from e.g. points reflected by birds [Liu08]. Fortunately, the data released by the surveys most of the time is already preprocessed and published as an uniform grid of data points. Formats used in this work are data grids in form of GeoTiff raster images (.tif file ending) or directly as point grids in the .xyz file format (see Section 2.1.1 on the next page). Projections This is a shallow excursion, sufficient for this work, into the world of map projections. Representing real world 3D (three dimensional) data on a greater scale using a 2D (two dimensional) planar map or image raster comes with some challenges. A sphere cannot be flattened into a 2D plane without distorting some of its features [Sny87]. Common attributes of maps are representation of area, shape, scale, and direction. While a projection can preserve some attributes it can only do so by distorting others, therefore choosing a fitting projection depends strongly on the application of the derived map [RM17; Sny87]. Fortunately projections for specific location, like a country, can be chosen to have the content at the center of projection where distortion is most often minimal [RM17]. GeoTIFF Files GeoTIFF (Geographic Tagged Image File Format) files are defined in the OGC GeoTIFF standard [DHH+19] maintained by the OGC (Open Geospatial Consortium). Based on the raster image file format TIFF (Tagged Image File Format) developed by Aldus Corporation, a GeoTIFF file is defined as “a valid TIFF 6.0 file” [DHH+19]. The flexible raster format of TIFF files [Des92] is used to store, in case of DTMs, height data instead of colour data in the pixels, but can be used to store all sort of sensory data (e.g. infrared data bands from satellite imagery [Hyy21]). Furthermore the extensible build in tag format [Des92] is utilizing to store relevant geographic tagging information, which is a major benefits of using GeoTIFF for distributing the data of DTMs. Relevant geographic data used by the developed application is limited to the coordinate transformation matrix, and the projection description. The first one describes how pixel coordinates get mapped to points in the used projection. Which in turn is described by the second one, the projection description string, defining how points on the globe get mapped to a plane, which is needed to represent earth based coordinates on an raster (see Section 2.1.1). XYZ Files The XYZ file is a simple ASCII text based format structured with three values per line. Based on the Cartesian coordinate system the three values per line represent a point in space defined by its x, y, and z coordinates [24h]. In the context of geospatial data, the positive x-axis is commonly mapped to the direction east, positive y-axis to the direction north, and the z-axis is interpreted as height 18 2.2 Assetto Corsa Maps information [24g; Phi97]. If the spacing between points is constant then the XYZ file is considered a so called “gridded XYZ raster datasets”[24g]. A drawback of the simplicity of XYZ files is, that they do not support auxiliary data in the file, therefore needed information, e.g. used projection, needs to be supplied externally to the application. List of Data Sources A short list of DTM data sources commonly used during the development of the application (a more comprehensive list of freely available sources can be found at https://www.opendem.info/ opendemsearcher.html): • Baden-Württemberg, Germany: https://opengeodata.lgl-bw.de/#/(sidenav:product/3) DTM 1m resolution, 2km tile size (License: dl-de/by-2-0) • England: https://environment.data.gov.uk/survey DTM 1m resolution, 5km tile size (License: OGLv3.0) • Switzerland: https://www.swisstopo.admin.ch/de/hoehenmodell-swissalti3d DTM 0.5m resolution, 1km tile size (License: terms of use) 2.1.2 Path Data The second type of geospatial data the application uses is coordinates of way-points along a real world road for creating the driveable in-game road surface. These points are taken from an OSM street graph and are selected using the integrated web interface. For simplicity reasons, a custom graph representation of the OSM data was chosen. This graph format was developed by the institute that supervised this work and comes with an existing tool for creating the graph files [22a]. The custom file format, with the file ending .fmi after the name of the institute, is text based [22b]. It consists of two header lines for defining the node and edge count. Afterwards each node gets defined one per line, followed by all of the edges, also defined one per line. A node entry consists of a node id followed by the original OSM id, its latitude, its longitude, and an elevation that can be zero. Edge entries consist of a source node id, a target node id, a weight, a type, and optionally a value for the speed limit in 𝑘𝑚/ℎ. The weight can either be distance, travel time based on edge type, or travel time based on speed limit [22a]. The type is a mapping from the highway OSM key2 to an arbitrary integer id defined using a config file. 2.2 Assetto Corsa Maps Exporting mods for Assetto Corsa happens through the ksEditor that is distributed together with the game (a screenshot of the editor can be seen in Figure 2.3 on page 21). This editor can open FBX files using the FBX-SDK-2014.13 and exports tracks in the game native .kn5 file format. Adding 2https://wiki.openstreetmap.org/wiki/Key:highway 3https://aps.autodesk.com/developer/overview/fbx-sdk 19 https://www.opendem.info/opendemsearcher.html https://www.opendem.info/opendemsearcher.html https://opengeodata.lgl-bw.de/#/(sidenav:product/3) https://www.govdata.de/dl-de/by-2-0 https://environment.data.gov.uk/survey https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/ https://www.swisstopo.admin.ch/de/hoehenmodell-swissalti3d https://www.swisstopo.admin.ch/de/nutzungsbedingungen-kostenlose-geodaten-und-geodienste https://wiki.openstreetmap.org/wiki/Key:highway https://aps.autodesk.com/developer/overview/fbx-sdk 2 Background mods to the game happens by drag-and-dropping an, optionally compressed, mod folder onto the community developed content manager4 or by manually copying the folder into the game files to assettocorsa/content/tracks/. 2.2.1 Mod folder The following paragraph is heavily cited from [luc21]. The minimal folder structure for a mod to be loaded into the game can be seen in Figure 2.2. The root folder should have the name of the track, which can be a maximum of 32 character and comprised only of ASCII characters, digits and underscores. Right under the root folder there is the track_name.kn5 file exported by the ksEditor. Next to this file there is at least one folder named ui. In there should be a json file called ui_track.json that defines metadata like the name and the country of the track. Also in the ui folder an preview image and an image of the track outline, both displayed in the track selection menu, can be supplied, called preview.png and outline.png respectively. Additionally the data folder can be added with files that define further functionality, like surfaces.ini that defines surfaces and sets their properties. Or ideal_line.ai used for displaying the ideal driving line, which can be a copy of fast_lane.ai in the ai folder. The ai files can be generated in the game by driving and recording the desired path using an in-game plugin5. track_name ai fast_lane.ai data ideal_line.ai surfaces.ini ui outline.png preview.png ui_track.json...........................Track metadata track_name.kn5.............................Track game file (files in bold are required) Figure 2.2: Minimal folder structure of an Assetto Corsa track mod 2.2.2 Track file The objects in the FBX file (see Section 2.3.3 on page 22) loaded for conversion into ksEditor need to follow a specific naming convention to be processed correctly. An example of the naming convention applied can be seen in Figure 2.3 on the facing page. 4https://acstuff.ru/app/ 5https://assettocorsamods.net/threads/how-can-i-make-ai-path.234/ 20 https://acstuff.ru/app/ https://assettocorsamods.net/threads/how-can-i-make-ai-path.234/ 2.2 Assetto Corsa Maps The following paragraph is heavily cited from [luc21]. Each object in the scene that should be considered by the physics engine needs to have a name following the schema . For object that should have physical properties the id in the name needs to be unique and greater than zero. For purely visual assets the id can be omitted or set to zero. The id is followed by a name defining the physical properties and an optional suffix, which gets ignored by the game. Predefined names are ROAD, GRASS, KERB, and SAND for defining how the mesh should behave as driveable surface. Custom surfaces can be defined in the data/surfaces.ini file of the mod6. Additionally the predefined name WALL exist for marking objects, like barriers, buildings, or signs, as obstacles. Besides visual and physical objects there also exist objects for marking special positions. One of these special positions is the AC_PIT_0 and AC_PIT_1 object for defining the position and orientation of the car spawns, further there exists AC_START_0 and AC_START_1 for defining the spawn position at the starting line. Beside spawn position also time taking positions can be defined using AC_TIME_0_L and AC_TIME_0_R for circuit type tracks. Respectively there exists AC_AB_START_L, AC_AB_START_R, AC_AB_FINISH_L, and AC_AB_FINISH_R for A-to-B type stages. Figure 2.3: A track loaded inside ksEditor, on the left an example of the naming convention for the different meshes can be seen 6https://assettocorsamods.net/threads/build-your-first-track-basic-guide.12/#post-25 21 https://assettocorsamods.net/threads/build-your-first-track-basic-guide.12/#post-25 2 Background 2.3 Tools 2.3.1 GDAL & PROJ GDAL (Geospatial Data Abstraction Library) is “a translator library for raster and vector geospatial data formats” [GDA24] developed by the OSGeo (The Open Source Geospatial Foundation). This work uses the library for its abstract raster data model, to allow working with multiple available geospatial data file formats, e.g. GeoTiff (Section 2.1.1) and XYZ (Section 2.1.1). However, for XYZ files only gridded XYZ raster files (Section 2.1.1 on page 18) are supported [24g]. Furthermore, it comes with the PROJ library, which is also an OSGeo project, and allows for transforming coordinates between a multitude of projections [PRO24]. 2.3.2 CGAL CGAL (Computational Geometry Algorithms Library) is an open source C++ library for “efficient and reliable geometric algorithms” [The24]. This work uses the mesh simplification algorithms to reduce the generated high detail grid mesh, to be handled by the game engine. The library uses an edge collapse algorithm together with an edge heuristic to determine which edge to collapse next [CRŞK24]. Multiple heuristics are available that all try to keep the original shape of the mesh, by prioritizing edges in regions with low frequent changes. 2.3.3 FBX SDK FBX is a proprietary file format for exchanging 3D assets, developed by Autodesk7 [20]. The file can be exported in text as well as in binary format using the FBX SDK binaries distributed on their website8. Inside the file a scene tree is stored, consisting out of multiple nodes. Each node has a name and transformation data that defines the local translation, rotation, and scale relative to its parent node [24e]. Additionally, nodes can have attributes assigned to them to define their type. Attributes used by the developed applications are limited to the mesh attribute, besides that light, camera, and more attributes exist. Furthermore nodes can also store references to materials created in that scene, those are in turn referenced by the mesh attribute [24d]. 2.3.4 Crow Crow is an header only open source C++ library for creating web services [24a]. Besides automatic serving of static web pages it also allows for defining custom routes with URL parameter support, which allows for a quick setup of an web API (application programming interface). Furthermore it has built in support for JSON (JavaScript Object Notation) creation and parsing [24b]. In Listing 2.1 on the facing page a function from the developed application is shown as an example on how to define API interfaces with Crow. Using the macro CROW_ROUTE(CrowApp, url) the route to the API interface is defined together with its parameters [24f]. The function executed when a request for 7https://www.autodesk.com/company 8https://aps.autodesk.com/developer/overview/fbx-sdk 22 https://www.autodesk.com/company https://aps.autodesk.com/developer/overview/fbx-sdk 2.3 Tools Listing 2.1 Route for requesting the node index of the closest node to a position on the globe CROW_ROUTE(pImpl->app, "/api/get_node//") ([&grid = pImpl->mGrid](const double lat, const double lon) { const int closestNode = grid.GetClosestNode({lat, lon}); crow::json::wvalue x; x["nodeId"] = closestNode; return x; }); this route is processed gets defined using a Lambda expression9. URL parameters are passed to the Lambda function as arguments, already parsed to the correct type. The last three lines of the example show how the build in JSON API can be used to create a response to the request. Map Viewer For the web frontend the open-source interactive map library Leaflet10 was used. Leaflet offers a tile layer for displaying OSM map tiles as well as a vector layer for adding paths, polygons, and markers onto the map [24c]. 9https://en.cppreference.com/w/cpp/language/lambda 10https://leafletjs.com 23 https://en.cppreference.com/w/cpp/language/lambda https://leafletjs.com 3 Implementation This chapter highlights the structure of the developed applications and explains how the different components interact with each other as well as giving some implementation details of solutions for encountered problems. 3.1 Application Structure track-mapper data ...................................Data files for testing . . . experiments....................Test apps for specific topics fbx-export gdal-info mesh-simplification point-projection road-creation spline-sampling src.............................................Source files app.................................Console application graph .....................................Graph library mesh.......................................Mesh library scene.................................FBX scene library web.....................................Web application static...............................Static web files ( https://github.com/JostMK/track-mapper ) Figure 3.1: Folder structure of the developed application The developed application is available as an open source repository on GitHub1 at https: //github.com/JostMK/track-mapper. The repository is structured into three top-level folders: data, experiments, and src (see Figure 3.1). Source files of the application are located in the src folder, which is divided into modules. The app module contains a console application for creating tracks on the command line. The graph module contains the BasicGraph class for storing a road network, that can be created from an fmi file (Section 2.1.2 on page 19) using the FMIGraphReader. Additionally, a grid class for efficiently retrieving nearest points as well as a Dijkstra shortest 1https://github.com 25 https://github.com/JostMK/track-mapper https://github.com/JostMK/track-mapper https://github.com/JostMK/track-mapper https://github.com 3 Implementation path algorithm [Dij59] are available. The mesh module contains functions for reading raster files (Section 2.1.1 on page 17), creating and converting meshes, interpolating paths, and the gdal_wrapper. To avoid needing to link every class against GDAL, a wrapper was written that uses opaque pointers as well as automatic resource clean up following the C++ RAII principle2. Implementing automatic resource clean up was needed because GDAL uses an outdated approach using global creator and destroyer functions for creating objects3. The scene module contains the TrackScene class that abstracts the FBX scene creation containing the track mod. Furthermore, the TrackCreator class exists that fully abstracts the creation of the track mod using the aforementioned TrackScene. This creator class is used by the web application for creating the track based on the user input. The web module contains the main application with a web interface for user input and uses the advanced TrackCreator class for track creation. However, the main content of the web module is the BasicWebApp class that uses the Crow library (Section 2.3.4 on page 22) for creating the web interface together with the static containing the web files for the interface. When building the project, the static folder needs to be copied next to the application executable file for Crow to find the files. In the data folder, some example files for testing purposes are given together with the sources for the files. The experiments folder contains small project most often containing only a single source that were created for experimenting and testing with used libraries. The fbx-export folder contains three applications, one for creating a FBX file containing a flat plane, one for printing some information about a FBX file, taken from the official documentation4, and one for converting a FBX file to ASCII or binary format. The last one was often used during development to validate the created output in the open source software blender5, which can only read the binary format, while on the other hand the ksEditor (Section 2.2 on page 19), because of the use of an outdated FBX SDK, could only open the ASCII format. In gdal-info folder a small application for printing relevant information about a raster file (Section 2.1.1 on page 17) can be found. The mesh-simplification folder contains an application that simplifies a mesh using all the available simplification algorithms of CGAL, to comparing the results and choosing one used in the main project. In point-projection are the final results of experimenting on how to get OSM points (Section 2.1.2 on page 19) and raster coordinates into the same reference system (Section 2.1.1 on page 18). The road-creation folder contains the first prototype on how to make the road by extending the mesh sideways using the halfway vector between the vector to the previous point of the path and the vector to the next point. The spline-sampling folder contains code for path interpolation using B-Splines and Catmull-Rom-Splines and was used for comparing the results and complexity to implement the methods. 2https://en.cppreference.com/w/cpp/language/raii 3Note the pairs of “GDALCreate. . .” and “GDALDestroy. . .” functions https://gdal.org/en/latest/api/gdal_alg. html#gdal-alg-h-gdal-algorithms-c-api 4https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_getting_started_your_first_fbx_ sdk_program_html 5https://www.blender.org 26 https://en.cppreference.com/w/cpp/language/raii https://gdal.org/en/latest/api/gdal_alg.html#gdal-alg-h-gdal-algorithms-c-api https://gdal.org/en/latest/api/gdal_alg.html#gdal-alg-h-gdal-algorithms-c-api https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_getting_started_your_first_fbx_sdk_program_html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_getting_started_your_first_fbx_sdk_program_html https://www.blender.org 3.2 Web Application 3.2 Web Application User interaction with the developed application happens through a web interface running on a local web server created by the application. The Crow library (Section 2.3.4 on page 22) was used for creating the web server because of its ease of use and it being open source. When starting the executable, the user gets prompted for the path to an fmi file (Section 2.1.2 on page 19) containing the graph of a road network. After submitting a valid file path, and loading of the graph was successful, the web server starts, and the application automatically opens the web interface in the default browser of the system. A screenshot of the web interface can be seen in Figure 3.2. Figure 3.2: The web interface of the app running in the Chromium based Brave browser On the right of the web page a form for creating the track is placed, the first text input field is the name of the track. Below that the button for adding raster files is placed, which prompts the user to input a file path to the raster file. If the file path points to a valid geospatial dataset file, like a GeoTIFF or XYZ file, the dataset gets loaded and the outline of the raster gets displayed on the map (the green rectangles in Figure 3.2). The map is created using the open source Leaflet (Section 2.3.4 on page 23) framework using tiles from the OSM tile service6. In case of an XYZ file and an empty Projection input field, an error is shown to the user, informing him to first define the projection used by the dataset, because it is not contained in the file (see Section 2.1.1 on page 18). All the added raster files are show in a list below the button and can be removed by pressing the bin icon to the right of the entry. Paths can be added using the Add Path button, which starts the path creation mode. In this mode, clicking on the map adds a way point marker to the map. After placing the first marker all the once following will be connected using the shortest path to the previously placed one, creating the path. The finished path can be submitted by pressing the Finish button, that appeared in place of the Add Path button after starting the path creation mode. Multiple paths are supported 6https://wiki.openstreetmap.org/wiki/Raster_tile_providers 27 https://wiki.openstreetmap.org/wiki/Raster_tile_providers 3 Implementation but will exist as separate meshes which can lead to overlapping with other road meshes. Like as for raster files, paths can be removed using the bin icon. The final step is to specify an output location for the to be generated FBX file and pressing the Create Track button, which opens a progress dialog on the page. At this point the web interface is no longer needed and the browser tab can be closed. Progress updates will also be printed to the console of the application, however if invalid data gets parsed while creating the track the process is canceled and an error message would be shown on the web page. Further, if the browser tab was not yet closed, the progress dialog is hidden again allowing to edit the previously submitted data, to correct possible invalid inputs and submit again. 3.2.1 Backend The Crow web server (Section 2.3.4 on page 22) automatically serves the content in the static folder (see Figure 3.1 on page 25), that create the aforementioned web interface and has additionally six API endpoints defined. The first four endpoints are for getting information to be displayed on the web interface. This includes /api/get_node// for getting the id of the closest available node in the loaded road network to a given position on the map, used when the user creates a path. In the background a regular grid based on the latitude and longitude value is used to speed up the query. Because of the geometry of the earth, the lines of constant longitude, also called meridians, intersect at the poles [Sny87]. This has the effect that the width and thereby the area of the grid cells approaches zero the closer to the poles the cell is. Therefore the grid is arbitrarily chosen to end at 89° and −89° latitude and it is advised to not use the application near the polar regions. It was decided that this is not a real limitation since most of the use cases of this application, being mountain passes and paved roads, are not in the polar regions. The next API endpoint is /api/get_location/ for getting a JSON object containing the latitude and longitude of a node given by its id, for which only the road graph is needed. For getting the shortest path between to nodes of the road graph the /api/get_path// endpoint is available. By passing the node id of the start node and the node id of the target node in the URL a Dijkstra shortest path query is performed [Dij59]. The returned value is a JSON object containing the total distance and an array of all the nodes on the shortest path. The final of the four endpoints used for displaying is /api/get_raster_extend/ for getting the outline of a raster file (Section 2.1.1 on page 17). To avoid sending the contents of files between the web interface and the server only the file path is send. However file paths can contain characters that are not supported in URL parameters, therefore the string send to the API is base64 encoded. Besides these API endpoints for getting data meant for displaying, there is also one end- point for submitting the track data and starting the track creation process. It is available at /api/create_track/ and expects a JSON object containing the track name, the output path, the projection WKT (well known text), an array containing the file paths to the raster files, and an array containing the paths, that in turn are also arrays containing the node ids of the way points defined by the user. The projection WKT can be an empty string if none was supplied by the user. On calling this endpoint, the submitted data will be parsed and the track creation process will be started. After the process is started, the progress is written to a thread safe communication object and can be queried using the /api/get_progress endpoint. This endpoint returns a JSON object containing a progress message as well as a boolean for when the track creation process is finished. Besides that it optionally has an error field if one occurred. 28 3.3 Main Thread 3.3 Main Thread This section discusses the main thread of the application that is responsible for starting the web interface as well as generating the track. 3.3.1 Communication Generating the track takes some time, if the web server handling the web interface would be running in the same thread, it would appear unresponsive. To mitigate this, a split of the application into two threads was needed, the main thread and the web server thread. For communication between the two threads a state object was chosen, that will hold the necessary data and can be accessed by both threads. The state object will be created by the main thread and passed to the web server in its Start method. When the user submits the data using the create_track API endpoint (Section 3.2.1 on the facing page), the web server will parse that data and assign it to the corresponding fields on the state object. Additionally it will set the isPopulated flag using a thread safe setter function. This flag gets periodically checked by the main thread, that waits in the meantime. After the flag got set the main thread will start creating the track as well as updating a progress and error string on the state object. Those have the purpose of giving feedback to the user about the progress and give information in case of an error. They are periodically checked by the web server. To ensure thread safety the state object has two theoretical phases, first the population phase where its values only gets accessed by the web server followed by a track creation phase where only the main thread will access the values. This ensures thread safety, while only needing to secure the communication flags and progress strings, with mutual exclusion mechanisms, that are accessed by both thread at the same time. 3.3.2 Terrain creation Algorithm 3.1 The processing steps of a raster file to a terrain mesh in pseudocode procedure AddRaster(rasterfile) grid← OpenDataset(rasterfile) if not grid.valid then return end if cgalMesh← meshFromRasterData(grid) ratio← 40 × 103 / cgalMesh.vertexCount // After reduction mesh should have 40000 vertices reduceMesh(cgalMesh, ratio) sceneMesh← cgalToSceneMesh(cgalMesh) AddGrassMesh(sceneMesh) StoreGrid(grid) // Needed to later determine the height of the road end procedure The process of generating a terrain mesh from a raster file can be seen in pseudocode in Section 3.3.2. The first step is to read in the raster data using the GDALDatasetWrapper from the gdal_wrapper (Section 3.1 on page 25). If the data is invalid the function just returns, however this should never 29 3 Implementation happen since the raster file paths get validated when the user inputs them into the web application. After having a valid raster grid the points get connected to a regular grid mesh. Based on the amount of vertices the mesh then has, a reduction ratio gets calculated. Since Assetto Corsa only support meshes with up to roughly 65 thousand vertices7, the aim is to have meshes with roughly 40 thousand vertices. Using the calculated reduction ratio, the mesh gets reduced using the edge collapse algorithm provided by CGAL using the Garland Heckbert Classic plane policy8. This policy was used because of its speed benefits over the default Lindstrom Turk policy while still retained the most visual details compared to its variants, e.g. Probabilistic plane (see Appendix A on page 43). After reducing the vertex count below the constraint of the engine the mesh can be converted and added to the FBX Scene for export. The conversion takes the CGAL mesh and returns a mesh in a custom format storing only the necessary information. It also calculates the vertex Normals as well as the texture UVs for the mesh. Finally the mesh gets added to the FBX scene and additionally the original grid get stored for determining the height of road points. 3.3.3 Road creation Algorithm 3.2 The processing steps of an OSM path to a road mesh in pseudocode procedure AddRoad(points, projection, width) reprojectOSMPoints(points, projection) setHeightForPoints(points) samples← subdivideCatmullRom(points, 4) setHeightForPoints(samples) samples← interpolateCatmullRom(samples, 0.5) segments← SegmentPath(samples) for all s ∈ segments do // Each segment should create a mesh with roughly 40000 vertices cgalMesh←meshFromPath(s, width) sceneMesh← cgalToSceneMesh(cgalMesh) AddRoadMesh(sceneMesh) end for end procedure The process of generating a road mesh from the OSM path data can be seen in pseudocode in Section 3.3.3. Before working with the points the first step is to reproject them into the coordinate system used by the raster. The benefit of converting the OSM points into the system of the raster and not the other way around or into a common middle ground, is because assuming the data set is of good quality then the coordinate system is already chosen to minimize distortion in that location (Section 2.1.1 on page 18). After the points are in the same space as the raster data, they get a height assigned. Followed by two interpolation steps to better align with the terrain height as well as having a good resolution for driving. The first interpolation step subdivides each segment of the path into four. Afterwards the height of the points is set again, this is to make sure that also long straights, where OSM would only place two points for beginning and end of the straight, also sample the height sufficient enough. Finally one last interpolation is used to make the vertex density 7The vertices get probably stored in an array with max length of 216 8https://doc.cgal.org/latest/Surface_mesh_simplification/index.html 30 https://doc.cgal.org/latest/Surface_mesh_simplification/index.html 3.3 Main Thread roughly the same by approximately place one every 0.5 meters. For both interpolation methods, the application uses a Catmull-Rom-Spline. It has the benefit of automatically fitting the line through the points without needing to calculate the position of handles like for B-Splines. The next step is to segment the path into multiple one to make sure that after generating the road the vertex count constraint of Assetto Corsa are still meet. Finally for each segment a road mesh gets generated, converted to the compacted format, and added to the FBX Scene. 3.3.4 Export The application exports two FBX files, one with the name specified in the web interface and one with the suffix -raw after the name. The first file is meant to be loaded into ksEditor and the second one to be modified using a 3D modeling software for further detailing work. To be able to play the track in the game the user only needs to load the file without the suffix into ksEditor assign the textures and export it into a valid mod folder structure, like described in Section 2.2 on page 19. 31 4 Results This section is showing two example tracks created with the developed application. It will note how long each creation took to process as well as highlight some shortcomings. 4.1 Neuffen - Germany The first example is a mountain road leading up onto the Swabian Jura1, a mountain range south of Stuttgart, Germany. This particular road leads from the town of Neuffen up to the town of Hülben and is located next to the castle ruin Hohenneuffen. The generated track consists out of seven terrain tiles and three roads (two of them are just for decorative purposes) and it took 445s or 7 minutes and 25 seconds to process. The tiles are in the XYZ format (Section 2.1.1 on page 18) with each spanning an area of one square kilometer with a resolution of one meter per raster cell, which amount to one million data points per tile. A screenshot of the inputs into the web application can be seen in Figure 3.2 on page 27 and screenshots of the result in the game can be seen in Appendix B on page 45. (a) Overview of the whole track scene (b) Closeup of the vertices and edges of a terrain tile Figure 4.1: The track Neuffen in the 3D modeling software Blender In Figure 4.1 an overview of the generated track scene can be seen. Additionally a closeup op the vertices and edges of one of the terrain tiles is shown to highlight the result of the mesh simplification process performed using CGAL. One can see in Figure 4.1b how areas with low frequent changes, 1Also know as Swabian Alps https://en.wikipedia.org/wiki/Swabian_Jura 33 https://en.wikipedia.org/wiki/Swabian_Jura 4 Results e.g. flat roads or meadows, have fewer vertices than areas with high frequent changes, e.g. cliffs and small ditches. This is essential for keeping the overall shape of the landscape while still reducing computational load for the game. One problem present on all tracks is the terrain mesh visually clipping through the road mesh (see Figure 4.2a) This happens because only the point in the middle of the road gets set to the height defined by the DTM data source and the mesh then gets extended sideways without any height changes (Section 3.3.3 on page 30). Therefore if it happens that the terrain mesh is inaccurate in that location, compared to the real world, or the road is slanted in the real work, then the two meshes intersect. Inaccuracies can happen in the discretization step in the creation of the raster file, or when simplifying the mesh to adhere to the restrictions of the game (Section 3.3.3 on page 30). (a) The terrain mesh visually clipping through the road mesh (b) Deviations created by inaccuracies in the path data of OSM Figure 4.2: Two problems with the generated track Neuffen Another problem encountered with this test case, was an incorrectly placed OSM road point, which lead to a misplaced road. In Figure 4.2b one can see that following the height information of the DTM the road should be a straight leading up to the right bent at the top of the image (see the red line indicating the correct road outline). However the road mesh generated deviates to the right into the hill side, because of an OSM point places off to the right of the actual road (the blue line represents the path OSM provided). 4.2 Albula Pass - Switzerland The second example is a segment from the Albula Pass in the south east of Switzerland. The generated track consists out of six terrain tile and one road (see Figure 4.3 on the facing page) and took 1388s or 23 minutes and 8 seconds to process. The tiles are in the GeoTIFF format (Section 2.1.1 on page 18) with each spanning an area of one square kilometer with a resolution of 0.5 meter per raster cell, which amounts to four million data points per tile. Screenshots of the result in the game can be seen in Appendix C on page 47. 34 4.2 Albula Pass - Switzerland Figure 4.3: The web interface with the input for the Albula Pass in Switzerland Figure 4.4: Gaps between tiles because of the edge collapse algorithm Another problem present on all tracks is the introduction of gaps between tiles (see Figure 4.4) by the way the edge collapse algorithm works. It selects edges using a priority system using a heuristic for determining how important an edge is for the overall shape [CRŞK24]. However because the tile nor the heuristic is aware of the other tiles around the tile, currently operating on, it cannot collapse corresponding edges at the border of neighboring tiles. This lead to offsets between corresponding border vertices among the tiles, which creates the gaps. The problem is especially prominent in this example because of the step elevation changes and uneven terrain leading to bigger deviations when collapsing edges and therefore larger gaps. One trivial way of fixing this would be to combine all the raster data into one big mesh and then perform the collapse algorithm on that. Disregarding the time it takes to generate the road (which is insignificant compared to the terrain generation), simplifying a mesh with one million vertices took roughly one minute (compare Section 4.1 on page 33). On the other hand simplifying a mesh with four million vertices took roughly three to four minutes (compare Section 4.2 on the preceding page). From that it looks like the amount of vertices 2 and the amount of time it takes to reach a specific number of remaining edges are proportional to each other, meaning the combined approach is equal in this regard. However in the separate tile approach after each tile finished simplifying, its resources get released, so the memory consumption was constant and that of one tile. When combining the meshes first the memory consumption would be scaling linearly with the amount of tiles used, which is given the size of the datasets a big disadvantage. Therefore keeping the tiles separate and having the compromise of gaps was chosen, with the opportunity for improvements in future work. 2which is proportional to the amount of edges in a regular grid 35 5 Conclusion and Outlook Overall the development of an application for generating a basic functional track for the game Assetto Corsa, based on real world data was archived. Like the two examples in Chapter 4 on page 33 show, the track is driveable and the shape of the landscape is, because of the high detail geospatial height data, very accurate to that of the real world. However because of the complexity of the task there are still some areas that need improvement. Most importantly removing the terrain below the road to stop clipping. Additionally, a second road mesh below the main road mesh that extends further to the side and mimics the shape of the terrain besides the road would be beneficial. This would allow the player to leave the track, e.g. because the car loses grip and slides out of the turn, and either recover or collide with something, as opposed to falling to the purely visual terrain mesh. Further improvement to the road mesh could be adding a slight twist to the road in corners to create cambered corners that allow for higher driving speeds. On the user sides there are opportunities to allow for more customization through settings, like splitting up large raster files into smaller, or selecting the areas that should be included using a shape. Furthermore OSM has many metadata information, that could get used for improving the generation, like using the highway type to automatically determine the road width. 37 Bibliography [20] FBX SDK. Version 2020.3.7. Autodesk, 2020. url: https://aps.autodesk.com/ developer/overview/fbx-sdk (cit. on p. 22). [22a] OsmGraphCreator. 2022. url: https://github.com/fmi-alg/OsmGraphCreator (cit. on p. 19). [22b] OsmGraphCreator. 2022. url: https://fmi.uni-stuttgart.de/alg/research/stuff/ (cit. on p. 19). [24a] Crow - A Fast and Easy to use microframework for the web. Version 1.2.0. CrowCpp, 2024. url: https://crowcpp.org/master/ (cit. on p. 22). [24b] JSON. CrowCpp. 2024. url: https://crowcpp.org/master/guides/json/ (cit. on p. 22). [24c] Leaflet an open-source JavaScript library for mobile-friendly interactive maps. Ver- sion 1.9.4. Leaflet, 2024. url: https://leafletjs.com/index.html (cit. on p. 23). [24d] Meshes, Materials and Textures. Autodesk. 2024. url: https://help.autodesk.com/ view/FBX/2020/ENU/?guid=FBX_Developer_Help_meshes_materials_and_textures_ html (cit. on p. 22). [24e] Nodes and the Scene Graph. Autodesk. 2024. url: https://help.autodesk.com/ view/FBX/2020/ENU/?guid=FBX_Developer_Help_nodes_and_scene_graph_html (cit. on p. 22). [24f] Routes. CrowCpp. 2024. url: https://crowcpp.org/master/guides/routes/ (cit. on p. 22). [24g] XYZ – ASCII Gridded XYZ. The Open Source Geospatial Foundation. 2024. url: https://gdal.org/en/latest/drivers/raster/xyz.html#xyz-ascii-gridded-xyz (cit. on pp. 19, 22). [24h] XYZ Point Cloud. Library of Congress. 2024. url: https://www.loc.gov/preservati on/digital/formats/fdd/fdd000617.shtml?loclr=blogsig (cit. on p. 18). [CRŞK24] F. Cacciola, M. Rouxel-Labbé, B. Şenbaşlar, J. Komaromy. “Triangulated Surface Mesh Simplification”. In: CGAL User and Reference Manual. 6.0. CGAL Editorial Board, 2024. url: https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMes hSimplification (cit. on pp. 22, 35). [Des92] A. D. Desk. TIFF - Revision 6.0. https://www.itu.int/itudoc/itu-t/com16/tiff-fx/ docs/tiff6.pdf. Aldus Corporation. 1992. url: https://archive.org/details/TIFF6 (cit. on p. 18). [DHH+19] E. Devys, T. Habermann, C. Heazel, R. Lott, E. Rouault. OGC GeoTIFF Standard. Open Geospatial Consortium. 2019. doi: 10.62973/19-008r4. url: http://www. opengis.net/doc/IS/GeoTIFF/1.1 (cit. on p. 18). 39 https://aps.autodesk.com/developer/overview/fbx-sdk https://aps.autodesk.com/developer/overview/fbx-sdk https://github.com/fmi-alg/OsmGraphCreator https://fmi.uni-stuttgart.de/alg/research/stuff/ https://crowcpp.org/master/ https://crowcpp.org/master/guides/json/ https://leafletjs.com/index.html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_meshes_materials_and_textures_html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_meshes_materials_and_textures_html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_meshes_materials_and_textures_html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_nodes_and_scene_graph_html https://help.autodesk.com/view/FBX/2020/ENU/?guid=FBX_Developer_Help_nodes_and_scene_graph_html https://crowcpp.org/master/guides/routes/ https://gdal.org/en/latest/drivers/raster/xyz.html#xyz-ascii-gridded-xyz https://www.loc.gov/preservation/digital/formats/fdd/fdd000617.shtml?loclr=blogsig https://www.loc.gov/preservation/digital/formats/fdd/fdd000617.shtml?loclr=blogsig https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMeshSimplification https://doc.cgal.org/6.0/Manual/packages.html#PkgSurfaceMeshSimplification https://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.pdf https://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.pdf https://archive.org/details/TIFF6 https://doi.org/10.62973/19-008r4 http://www.opengis.net/doc/IS/GeoTIFF/1.1 http://www.opengis.net/doc/IS/GeoTIFF/1.1 Bibliography [Dij59] E. W. Dijkstra. “A note on two problems in connexion with graphs”. In: Numerische Mathematik 1.1 (1959), pp. 269–271. issn: 0945-3245. doi: 10.1007/BF01386390. url: https://doi.org/10.1007/BF01386390 (cit. on pp. 26, 28). [EGF17] N. Ekhtari, C. Glennie, J. C. Fernandez-Diaz. “Classification of multispectral lidar point clouds”. In: 2017 IEEE International Geoscience and Remote Sensing Symposium (IGARSS). 2017, pp. 2756–2759. doi: 10.1109/IGARSS.2017.8127568 (cit. on p. 17). [GDA24] GDAL/OGR contributors. GDAL/OGR Geospatial Data Abstraction software Library. Open Source Geospatial Foundation. 2024. doi: 10.5281/zenodo.5884351. url: https://gdal.org (cit. on p. 22). [Hir14] C. Hirt. “Digital Terrain Models”. In: Encyclopedia of Geodesy. Ed. by E. Grafarend. Cham: Springer International Publishing, 2014, pp. 1–6. isbn: 978-3-319-02370-0. doi: 10.1007/978-3-319-02370-0_31-1. url: https://doi.org/10.1007/978-3-319- 02370-0_31-1 (cit. on p. 17). [Hyy21] O. Hyytiälä. “Real-time satellite data processing platform architecture”. Master’s thesis. Helsinki: University of Helsinki, Faculty of Science, 2021. url: https: //helda.helsinki.fi/server/api/core/bitstreams/d24bf4c4-9b89-4fd9-accb- 427e736be2a3/content (cit. on p. 18). [Jha18] R. Jha. “Application of 30m Resolution SRTM DEM in Nepal”. In: Journal of the Institute of Engineering 14.1 (June 2018), pp. 235–240. doi: 10.3126/jie.v14i1.20089. url: https://www.nepjol.info/index.php/JIE/article/view/20089 (cit. on p. 17). [Liu08] X. Liu. “Airborne LiDAR for DEM generation: some critical issues”. In: Progress in Physical Geography: Earth and Environment 32.1 (Feb. 2008), pp. 31–49. doi: 10.1177/0309133308089496. url: https://doi.org/10.1177/0309133308089496 (cit. on pp. 17, 18). [luc21] luchian. Build your FIRST track - BASIC GUIDE. Assetto Corsa Mods. Dec. 10, 2021. url: https://assettocorsamods.net/threads/build-your-first-track-basic- guide.12/ (cit. on pp. 15, 20, 21). [Nes23] M. Nesvadba. “Transforming Real-World Race Course Into Racing Simulator Level”. SUPERVISOR: RNDr. David Kuťák. Master’s thesis. Brno: Masaryk University, Faculty of Informatics, 2023. url: https://theses.cz/id/fag822/ (cit. on p. 15). [Phi97] J. D. Phillips. Potential-Field Geophysical Software for the PC. USGS Numbered Series. U.S. Geological Survey, 1997. doi: 10.3133/ofr97725. url: https://doi.org/ 10.3133/ofr97725 (cit. on p. 19). [PRO24] PROJ contributors. PROJ coordinate transformation software library. Open Source Geospatial Foundation. 2024. doi: 10.5281/zenodo.5884394. url: https://proj.org/ (cit. on p. 22). [RM17] A. H. Robinson, T. C. on Map Projections. “Which Map Is Best?” In: Choosing a Map Projection. Ed. by M. Lapaine, E. L. Usery. Cham: Springer International Publishing, 2017, pp. 1–14. isbn: 978-3-319-51835-0. doi: 10.1007/978-3-319-51835-0_1. url: https://doi.org/10.1007/978-3-319-51835-0_1 (cit. on p. 18). [Sny87] J. P. Snyder. Map projections: A working manual. USGS Numbered Series. Washington, D.C.: U.S. Geological Survey, 1987. doi: 10.3133/pp1395. url: https://doi.org/10. 3133/pp1395 (cit. on pp. 18, 28). 40 https://doi.org/10.1007/BF01386390 https://doi.org/10.1007/BF01386390 https://doi.org/10.1109/IGARSS.2017.8127568 https://doi.org/10.5281/zenodo.5884351 https://gdal.org https://doi.org/10.1007/978-3-319-02370-0_31-1 https://doi.org/10.1007/978-3-319-02370-0_31-1 https://doi.org/10.1007/978-3-319-02370-0_31-1 https://helda.helsinki.fi/server/api/core/bitstreams/d24bf4c4-9b89-4fd9-accb-427e736be2a3/content https://helda.helsinki.fi/server/api/core/bitstreams/d24bf4c4-9b89-4fd9-accb-427e736be2a3/content https://helda.helsinki.fi/server/api/core/bitstreams/d24bf4c4-9b89-4fd9-accb-427e736be2a3/content https://doi.org/10.3126/jie.v14i1.20089 https://www.nepjol.info/index.php/JIE/article/view/20089 https://doi.org/10.1177/0309133308089496 https://doi.org/10.1177/0309133308089496 https://assettocorsamods.net/threads/build-your-first-track-basic-guide.12/ https://assettocorsamods.net/threads/build-your-first-track-basic-guide.12/ https://theses.cz/id/fag822/ https://doi.org/10.3133/ofr97725 https://doi.org/10.3133/ofr97725 https://doi.org/10.3133/ofr97725 https://doi.org/10.5281/zenodo.5884394 https://proj.org/ https://doi.org/10.1007/978-3-319-51835-0_1 https://doi.org/10.1007/978-3-319-51835-0_1 https://doi.org/10.3133/pp1395 https://doi.org/10.3133/pp1395 https://doi.org/10.3133/pp1395 Bibliography [The24] The CGAL Project. CGAL User and Reference Manual. 6.0. CGAL Editorial Board, 2024. url: https://doc.cgal.org/6.0/Manual/packages.html (cit. on p. 22). [YGC+08] B. Yunfei, L. Guoping, C. Cao, L. Xiaowen, H. Zhang, H. Qisheng, B. Linyan, C. Chaoyi. “Classification of Lidar Point Cloud and Generation of DTM from LiDAR Height and Intensity Data in Forested Area”. In: The International Archives of the Photogrammetry, Remote Sensing and Spatial Information Sciences 37.7 (2008), pp. 313–318. url: https://www.isprs.org/proceedings/xxxvii/congress/3b_pdf/ 63.pdf (cit. on p. 17). All links were last followed on October 9, 2024. 41 https://doc.cgal.org/6.0/Manual/packages.html https://www.isprs.org/proceedings/xxxvii/congress/3b_pdf/63.pdf https://www.isprs.org/proceedings/xxxvii/congress/3b_pdf/63.pdf A Comparison between edge collapse policies Policy name time in s result Lindstrom-Turk 59.4 Garland-Heckbert Classic-plane 47.5 43 A Comparison between edge collapse policies Garland-Heckbert Classic-triangle 47.6 Garland-Heckbert Probabilistic plane 43.7 Garland-Heckbert Probabilistic triangle 43.8 Comparison between the different policy available in CGAL for the edge collapse algorithm. The original model had one million vertices and three million edges. After the simplification each model had around 300000 edges (a reduction ratio of 0.1 was used). 44 B Images of the track Neuffen Figure B.1: The starting position of the track Neuffen in the game Assetto Corsa Figure B.2: Right after the second hairpin turn of the track Neuffen in the game Assetto Corsa 45 C Images of the track Albula Pass Figure C.1: Looking south up the mountain of Albula Pass in the game Assetto Corsa Figure C.2: Looking west wards down into the valley of Albula Pass in the game Assetto Corsa Declaration I hereby declare that the work presented in this thesis is entirely my own and that I did not use any other sources and references than the listed ones. I have marked all direct or indirect statements from other sources contained therein as quotations. Neither this work nor significant parts of it were part of another examination procedure. I have not published this work in whole or in part before. The electronic copy is consistent with all submitted copies. place, date, signature 1 Introduction 1.1 Motivation 1.2 Structure 2 Background 2.1 Geospatial Data 2.2 Assetto Corsa Maps 2.3 Tools 3 Implementation 3.1 Application Structure 3.2 Web Application 3.3 Main Thread 4 Results 4.1 Neuffen - Germany 4.2 Albula Pass - Switzerland 5 Conclusion and Outlook Bibliography A Comparison between edge collapse policies B Images of the track Neuffen C Images of the track Albula Pass