{"id":36704700,"url":"https://github.com/tum-gis/citymodel-compare","last_synced_at":"2026-01-12T11:41:39.750Z","repository":{"id":181291133,"uuid":"666518715","full_name":"tum-gis/citymodel-compare","owner":"tum-gis","description":"A tool to map and match CityGML datasets, as well as interpret their changes, all by using graphs.","archived":false,"fork":false,"pushed_at":"2025-09-04T23:15:12.000Z","size":24681,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-05T01:11:42.624Z","etag":null,"topics":["citygml","database","geometry","graph-algorithms","graphs","neo4j","semantic","semantic-networks"],"latest_commit_sha":null,"homepage":"https://www.asg.ed.tum.de/en/gis/our-team/staff/son-h-nguyen/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tum-gis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-14T18:20:42.000Z","updated_at":"2025-09-04T23:13:01.000Z","dependencies_parsed_at":"2024-01-18T16:41:41.432Z","dependency_job_id":"2e2619a9-b57f-47c4-89d0-7ab46f8d2121","html_url":"https://github.com/tum-gis/citymodel-compare","commit_stats":null,"previous_names":["tum-gis/ctdiff","tum-gis/citymodel-compare"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/tum-gis/citymodel-compare","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tum-gis%2Fcitymodel-compare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tum-gis%2Fcitymodel-compare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tum-gis%2Fcitymodel-compare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tum-gis%2Fcitymodel-compare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tum-gis","download_url":"https://codeload.github.com/tum-gis/citymodel-compare/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tum-gis%2Fcitymodel-compare/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["citygml","database","geometry","graph-algorithms","graphs","neo4j","semantic","semantic-networks"],"created_at":"2026-01-12T11:41:35.591Z","updated_at":"2026-01-12T11:41:39.743Z","avatar_url":"https://github.com/tum-gis.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Logo citymodel-compare](resources/logo.jpg)\n\n# citymodel-compare\n\n## What it is\n\nA tool to map and match CityGML datasets, as well as interpret their changes, all by using graphs.\n\n+ **MAPPING**: CityGML datasets are represented as **graphs** and stored in the graph database Neo4j. The mapping\n  process is very flexible and can support both versions **2.0** and **3.0** of CityGML (as it\n  uses [citygml4j](https://github.com/citygml4j/citygml4j)).\n\n+ **MATCHING**: The graph representations of the mapped CityGML datasets are matched based on both their **semantic**\n  and\n  **geometric** properties. **Spatial indexing** (such as R-Tree) is used to accelerate matching time in massive\n  datasets.\n\n+ **INTERPRETING**: The change detection process often results in a high number of low-semantic-level changes. This\n  interpretation process **reduces this number**, while simultaneously **increasing the semantic contents** of changes.\n\nThe ultimate goal of this tool is to provide a **precise**, **expressive**, and **human-centered** interpretation of\nchanges in CityGML.\n\n## Contents\n\n+ [How to run it](#how-to-run-it)\n+ [How to test it](#how-to-test-it)\n+ [How to use my own datasets](#how-to-use-my-own-datasets)\n+ [How to define my own pattern rules](#how-to-define-my-own-pattern-rules)\n+ [What's next](#whats-next)\n+ [How to cite it](#how-to-cite-it)\n+ [License](LICENSE)\n+ [Contact](#contact)\n\n## How to run it\n\nThis tool can be used in two ways: either via Gradle or via Docker. For testing purposes, Docker is recommended.\n\nWhat is needed:\n\n+ [Docker](https://docs.docker.com/get-docker/)\n+ [Neo4j Desktop](https://neo4j.com/download/)\n\n1. Make sure Docker is up and running.\n\n2. Pull the following image from Docker Hub:\n\n   ```shell\n   docker pull tumgis/citymodel-compare:1.0.0\n   ```\n   \n   To use latest (experimental) functionalities, pull the following image instead:\n\n   ```shell\n    docker pull tumgis/citymodel-compare:1.0.0-dev\n    ```\n\n3. Run the image:\n\n   ```shell\n   # Linux \n   docker run \\\n      -it --rm \\\n      -p 7474:7474 -p 7687:7687 \\\n   tumgis/citymodel-compare:1.0.0-dev\n   ```\n   ```shell\n   # Windows\n    docker run ^\n       -it --rm ^\n       -p 7474:7474 -p 7687:7687 ^\n    tumgis/citymodel-compare:1.0.0-dev\n   ```\n\n   This will start a Neo4j instance with all necessary dependencies installed. The parameters are as follows:\n    + `-it`: Interactive mode.\n    + `--rm`: Remove the container after it exits.\n    + `-p 7474:7474`: Expose port 7474 of the container to port 7474 of the host machine. This is the port used by the\n      Neo4j browser (such as visualization and inspecting Cypher queries).\n    + `-p 7687:7687`: Expose port 7687 of the container to port 7687 of the host machine. This is the port used by the\n      Neo4j Bolt connector (such as for RESTful services).\n\n   **Notes**: To simplify the process for testing purposes, the Docker container has already been loaded with\n   a test dataset. This dataset includes an older and a newer tiled CityGML dataset of Hamburg, from 2016 and 2022,\n   respectively,\n   which are publicly available [here](https://metaver.de/trefferanzeige?docuuid=2C1F2EEC-CF9F-4D8B-ACAC-79D8C1334D5E).\n\n   **Notes**: Once started, the datasets will be automatically mapped and matched, and their changes will be interpreted\n   and stored in the graph database. All from scratch, no existing Neo4j database instance is contained in the Docker\n   container beforehand.\n   Please refer to this [section](#how-to-use-my-own-datasets) for more details on how to use your own datasets.\n\nThat's it! The old and new CityGML datasets have been mapped, matched, and interpreted. You are now ready to use the\ntool.\n\n## How to test it\n\nNow that the tool is up and running, we can test it with a few simple examples. In this section, we will use the\ndatasets already prepared and available for use in the Docker container.\n\n1. Open Neo4j Desktop, click create new **Remote Datase** and add the following connection details:\n\n   ```shell\n   neo4j://localhost:7687\n   ```\n\nIf requested, the default username and password are both `neo4j`. The following window should appear:\n\n![Neo4j Browser](resources/neo4j_browser.jpg)\n\n2. In Neo4j Browser, run the following query to count the number of nodes created for the old datasets:\n\n   ```cypher\n   MATCH (n:`__PARTITION_INDEX__0`)\n   RETURN count(n)\n   ```\n\n   ```Cypher\n   Result: 35095\n   ```\n\n   Similarly, run the following query to count the number of nodes created for the new datasets:\n\n   ```cypher\n   MATCH (n:`__PARTITION_INDEX__1`)\n   RETURN count(n)\n   ```\n\n   ```Cypher\n   Result: 35324\n   ```\n\n3. To see how many buildings the old dataset has:\n\n   ```cypher\n   MATCH (n:`__PARTITION_INDEX__0`:`org.citygml4j.model.citygml.building.Building`) \n   RETURN count(n)\n   ```\n\n   ```Cypher\n   Result: 46\n   ```\n\n   And the new dataset:\n\n   ```cypher\n   MATCH (n:`__PARTITION_INDEX__1`:`org.citygml4j.model.citygml.building.Building`)\n   RETURN count(n)\n   ```\n\n   ```Cypher\n   Result: 47\n   ```\n\n4. Now, let's see how many literal changes (i.e. on the lowest semantic level) have been detected:\n\n   ```cypher\n   MATCH (c:`jgraf.neo4j.diff.Change`)\n   WHERE NOT exists((:`jgraf.neo4j.diff.Change`)-[:AGGREGATED_TO]-\u003e(c))\n   RETURN count(c)\n   ```\n\n   ```Cypher\n   Result: 2540\n   ```\n\n   All changes are labelled with `jgraf.neo4j.diff.Change`. The second line with `WHERE` is used to filter out changes\n   on the lowest level, meaning they do not have any incoming interpretation edges from other changes.\n\n5. To count the number of interpretation nodes created from these literal changes:\n\n   ```cypher\n   MATCH (c:`jgraf.neo4j.diff.Change`)\n   WHERE exists((:`jgraf.neo4j.diff.Change`)-[:AGGREGATED_TO]-\u003e(c))\n   RETURN count(c)\n   ```\n\n   ```Cypher\n   Result: 1512\n   ```\n\n5. To see how many literal changes have been interpreted:\n\n   ```cypher\n   MATCH (c:`jgraf.neo4j.diff.Change`)\n   WHERE NOT exists((:`jgraf.neo4j.diff.Change`)-[:AGGREGATED_TO]-\u003e(c))\n   AND exists((c)-[:AGGREGATED_TO]-\u003e(:`jgraf.neo4j.diff.Change`))\n   RETURN count(c)\n   ```\n\n   ```Cypher\n   Result: 723\n   ```\n\n   This means that, of the `2540` literal changes, `723`, or `28%`, have been interpreted.\n\n6. To visualize a building and its changes:\n\n   ```cypher\n   MATCH paths=(:`__PARTITION_INDEX__0`:`org.citygml4j.model.citygml.building.Building` \n   { id:'DEHH_0681b536-7e9c-478f-b131-0f96d1bc7717' })\n   \u003c-[]-(:`jgraf.neo4j.diff.Change`)\n   RETURN paths\n   ```\n\n   The building and its directly connected changes are shown as follows:\n\n   \u003cp align=\"center\"\u003e\n   \u003cimg src=\"resources/building.svg\" alt=\"An example building and its connected changes\" style=\"width:80%;\"\u003e\n   \u003c/p\u003e\n\n---\n\nAs shown in the figure, this roofs of this building have been raised by some amount. The **pattern** includes:\n\n+ The building's `measuredHeight` has been changed by `dh_m \u003e 0`\n\n+ The building's roof surfaces have been translated by `dh_r \u003e 0`\n\n+ The building's ground surfaces have been translated by a small `dh_g` (signed, + is upwards, - is downwards)\n\n+ The building's walls have grown in height by `dh_w \u003e 0`, such that `dh_w = dh_m = dh_r + dh_g`\n\n---\n\n7. To find out how many such buildings with raised roofs have been detected:\n\n   ```cypher\n   MATCH (c:`jgraf.neo4j.diff.Change` {change_type: 'RaisedBuildingRoofs'})\n   -[]-\u003e(b:`org.citygml4j.model.citygml.building.Building`)\n   RETURN b, c\n   ```\n\n   This query returns `6` buildings:\n\n    \u003cp align=\"center\"\u003e\n    \u003cimg src=\"resources/raised_roofs.svg\" alt=\"Buildings with raised roofs\" style=\"width:80%;\"\u003e\n    \u003c/p\u003e\n\n   The raise margins `dh_m` can be queried as follows:\n\n   ```cypher\n   MATCH (c:`jgraf.neo4j.diff.Change` {change_type: 'RaisedBuildingRoofs'})\n   RETURN round(toFloat(c.RIGHT_PROPERTY_VALUE) - toFloat(c.LEFT_PROPERTY_VALUE), 3) AS dh_m\n   ORDER BY dh_m ASC\n   ```\n\n   The sorted results are as follows:\n\n| **Order** | **dh_m (m)** |\n|-----------|--------------|\n| 1         | 0.008        |\n| 2         | 0.05         |\n| 3         | 0.12         |\n| 4         | 0.188        |\n| 5         | 0.251        |\n| 6         | 1.025        |\n\n8. To list all rule nodes used for all interpretations:\n\n    ```cypher\n    MATCH (r:RULE)\n    RETURN r\n    ```\n\n   The results are as follows:\n\n   \u003cimg src=\"resources/rules.svg\" alt=\"Visualization of all rules\" style=\"width:100%;\"\u003e\n\n9. To inspect the rules specifically for raised roofs:\n\n   ```cypher\n   MATCH (p)-[]-\u003e(r:RULE {change_type:'RaisedBuildingRoofs'})\n   RETURN p, r\n   ```\n\n   In the figure below, the node in the center represents the rule `RaisedBuildingRoofs`, while the others represent:\n    + `UpdatedBuildingMeasuredHeight`\n    + `TranslatedBuildingRoofs`\n    + `SizeChangedBuildingWalls`\n    + `TranslatedBuildingGrounds`\n\n   \u003cdiv style=\"text-align: center;\"\u003e\n   \u003cimg src=\"resources/raised_roofs_rules.svg\" alt=\"Visualization of rules for raised roofs\" style=\"width:80%;\"\u003e\n   \u003c/div\u003e\n\n10. These rules are defined in Cypher. Please refer to this [Cypher file](scripts/rules_v2.cql) for more details.\n\n\u003cimg src=\"resources/line.jpg\" alt=\"Buildings with raised roofs\" style=\"width:100%;\"\u003e\n\n## How to use my own datasets\n\nThe following steps are required to use your own datasets:\n\n1. Clone this project:\n\n   ```shell\n   git clone https://github.com/tum-gis/citymodel-compare\n   cd citymodel-compare\n   ```\n\n2. Copy your datasets into the `input` directory, such as:\n\n   ```shell\n   # Copy old.gml and new.gml into the input directory\n   cp /path/to/your/datasets/old.gml input/\n   cp /path/to/your/datasets/new.gml input/\n   ```\n\n3. Edit file `citygmlv2.conf` in the `config` directory to include these datasets:\n\n   ```shell\n   # Input dataset to map onto graphs, can have multiple files/directories\n   # If a path is a directory, ALL files in that folder shall be imported as one\n   mapper.dataset.paths = [\n      \"input/old.gml\",\n      \"input/new.gml\"\n   ]\n   ```\n\n   **Notes**:\n    + The value `mapper.dataset.paths` can point to either files or directories. If the path is a directory, all files\n      in that folder shall be imported as one.\n    + The first file in the list is considered the **old** dataset, while the second is the **new** dataset.\n    + The file `citygmlv2.conf` is used for CityGML v2.0 datasets. For CityGML v3.0 datasets, edit file\n      `citygmlv3.conf` instead.\n\n4. Make sure Docker is up and running.\n\n5. Pull the following image from Docker Hub:\n\n   ```shell\n   docker pull tumgis/citymodel-compare:1.0.0-dev\n   ```\n\n6. Run the Docker container with bind mounts (make sure you are in the cloned `citymodel-compare` directory):\n\n    ```shell\n    # Linux\n    docker run \\\n        -it --rm \\\n        -p 7474:7474 -p 7687:7687 \\\n        -v \"/path/to/config:/home/gradle/src/citymodel-compare/config\" \\\n        -v \"/path/to/input:/home/gradle/src/citymodel-compare/input\" \\\n        -v \"/path/to/output:/home/gradle/src/citymodel-compare/output\" \\\n        -v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\" \\\n    tumgis/citymodel-compare:1.0.0-dev\n    ```\n\n    ```shell\n    # Windows\n    docker run ^\n        -it --rm ^\n        -p 7474:7474 -p 7687:7687 ^\n        -v \"/path/to/config:/home/gradle/src/citymodel-compare/config\" ^\n        -v \"/path/to/input:/home/gradle/src/citymodel-compare/input\" ^\n        -v \"/path/to/output:/home/gradle/src/citymodel-compare/output\" ^\n        -v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\" ^\n    tumgis/citymodel-compare:1.0.0-dev\n    ```\n\n   The parameters are as follows:\n    + `-v \"/path/to/config:/home/gradle/src/citymodel-compare/config\"`: Bind mount the `config` directory of the host\n      machine to the `config` directory of the container. This is where the configuration files are stored. Please\n      replace `/path/to/config` with the absolute path to the `config` directory of the host machine.\n    + `-v \"/path/to/input:/home/gradle/src/citymodel-compare/input\"`: Bind mount the `input` directory of the host\n      machine to the `input` directory of the container. This is where the datasets are stored. Please replace\n      `/path/to/input` with the absolute path to the `input` directory of the host machine.\n    + `-v \"/path/to/output:/home/gradle/src/citymodel-compare/output\"`: Bind mount the `output` directory of the host\n      machine to the `output` directory of the container. This is where the results are stored, including the Neo4j\n      database. Please replace `/path/to/output` with the absolute path to the `output` directory of the host machine.\n    + `-v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\"`: Bind mount the `scripts` directory of the host\n      machine to the `scripts` directory of the container. This is where the rule files and other functions are stored.\n      Please replace `/path/to/scripts` with the absolute path to the `scripts` directory of the host machine.\n\n## How to define my own pattern rules\n\nThe following steps are required to define your own pattern rules:\n\n1. Clone this project:\n\n   ```shell\n   git clone https://github.com/tum-gis/citymodel-compare\n   cd citymodel-compare\n   ```\n\n2. Edit file `scripts/rules_v2.cql` in the `scripts` directory to include your own rules. An example of the file can be\n   found [here](scripts/rules_v2.cql). The rules are defined using\n   Neo4j's [Cypher Query Language](https://neo4j.com/developer/cypher/).\n\n   The rules contain nodes and edges. The nodes are labelled with `RULE` and the edges are labelled\n   with `AGGREGATED_TO`. Each node and edge can have properties (see tables below).\n\n3. Make sure Docker is up and running.\n\n4. Pull the following image from Docker Hub:\n\n   ```shell\n   docker pull tumgis/citymodel-compare:1.0.0-dev\n   ```\n\n5. Run the Docker container with bind mounts (make sure you are in the cloned `citymodel-compare` directory):\n\n    ```shell\n    # Linux\n    docker run \\\n        -it --rm \\\n        -p 7474:7474 -p 7687:7687 \\\n        -v \"/path/to/config:/home/gradle/src/citymodel-compare/config\" \\\n        -v \"/path/to/input:/home/gradle/src/citymodel-compare/input\" \\\n        -v \"/path/to/output:/home/gradle/src/citymodel-compare/output\" \\\n        -v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\" \\\n    tumgis/citymodel-compare:1.0.0-dev\n    ```\n\n    ```shell\n    # Windows\n    docker run ^\n        -it --rm ^\n        -p 7474:7474 -p 7687:7687 ^\n        -v \"/path/to/config:/home/gradle/src/citymodel-compare/config\" ^\n        -v \"/path/to/input:/home/gradle/src/citymodel-compare/input\" ^\n        -v \"/path/to/output:/home/gradle/src/citymodel-compare/output\" ^\n        -v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\" ^\n    tumgis/citymodel-compare:1.0.0-dev\n    ```\n\n   The parameters are as follows:\n    + `-v \"/path/to/config:/home/gradle/src/citymodel-compare/config\"`: Bind mount the `config` directory of the host\n      machine to the `config` directory of the container. This is where the configuration files are stored. Please\n      replace `/path/to/config` with the absolute path to the `config` directory of the host machine.\n    + `-v \"/path/to/input:/home/gradle/src/citymodel-compare/input\"`: Bind mount the `input` directory of the host\n      machine to the `input` directory of the container. This is where the datasets are stored. Please replace\n      `/path/to/input` with the absolute path to the `input` directory of the host machine.\n    + `-v \"/path/to/output:/home/gradle/src/citymodel-compare/output\"`: Bind mount the `output` directory of the host\n      machine to the `output` directory of the container. This is where the results are stored, including the Neo4j\n      database. Please replace `/path/to/output` with the absolute path to the `output` directory of the host machine.\n    + `-v \"/path/to/scripts:/home/gradle/src/citymodel-compare/scripts\"`: Bind mount the `scripts` directory of the host\n      machine to the `scripts` directory of the container. This is where the rule files and other functions are stored.\n      Please replace `/path/to/scripts` with the absolute path to the `scripts` directory of the host machine.\n\n### Node properties\n\n| **Property**  | **Description**                                                                                                                                                                                                                                                                                                                                                                                      | **Mandatory** |\n|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|\n| `change_type` | The type of current change                                                                                                                                                                                                                                                                                                                                                                           | Yes           |\n| `calc_scope`  | Directive to calculate scope over this type of changes. For example, `calc_scope=\"p1;p2;p3\"` will calculate scope based on all changes with the same `change_type` and have the same values of `p1`, `p2`, `p3`. The current implementation allows for fuzzy comparison of numeric and date-time values. For instance, `1.0001` and  `1.000` may be considered equal for error tolerance of `0.001`. | No            |\n| `tags`        | Tags for the current change. For example, `tags=\"update;thematic;toplevel\"` will add indications to categorize this change as an update of thematic properties that belong to a top-level feature.                                                                                                                                                                                                   | No            |\n\n### Edge properties\n\n| **Property**        | **Description**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | **Mandatory** |\n|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|\n| `next_content_type` | The type of the target content node. This is used by the interpreter while navigating within the content network.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Yes           |\n| `search_length`     | Specify the maximum length the interpreter should traverse to reach target nodes of `next_content_type`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | No            |\n| `not_contains`      | Specify the content type that should not be included while travering to the target content node. If a content node of this `not_contains` is encountered, the interpreter shall exit. For example, `not_contains` can be used to distinguish changes that belong to a building part or a building.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | No            |\n| `name`              | Give a name to the current change. This is needed for joining multiple converging rule edges that are required to create the next interpreted change. The `join` conditions require ALL converging rule edges to have a unique `name`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | No            |\n| `join`              | Conditions for joining converging rule edges. Conditions are given in JavaScript syntax. For example, the join conditions `fuzzyEquals(parseFloat(rule_measured_height.RIGHT_PROPERTY_VALUE) - parseFloat(rule_measured_height.LEFT_PROPERTY_VALUE), rule_size_changed_walls.z) \u0026\u0026 fuzzyEquals(rule_translated_roofs.z, parseFloat(rule_size_changed_walls.z) + parseFloat(rule_translated_grounds.z))` takes the properties `LEFT_PROPERTY_VALUE` and `RIGHT_PROPERTY_VALUE` of change named `rule_measured_height`, as well as property `z` of `rule_translated_roofs` and `rule_size_changed_walls` and `rule_translated_grounds`. The function `fuzzyEquals(a, b)` is pre-defined and can be freely used to test whether two strings `a` and `b` are numerically equal, with error tolerance taking into account. The function `parseFloat(a)` is available in JavaScript to convert a string to a number. | No            |\n| `scope`             | Test whether the current change belong to a scoped change. There are two values: `clustered`, and `global`. If `scope` is used, `weight` can be omitted. Note: scopes are only calculated for changes that belong to top-level features.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | No            |\n| `conditions`        | Conditions for the creation of the next (interpreted) change. The conditions are given in JavaScript syntax and must be evaluated to `true` or `false`. Properties of the current change node can also be used. For instance, `PROPERTY_NAME === \"measuredHeight\" \u0026\u0026 fuzzyEquals(RIGHT_PROPERTY_VALUE - LEFT_PROPERTY_VALUE, 1.0)` can be used to determine whether the current change is an updated `measuredHeight`, and whether the new value is greater than the old value by `1.0`. The function `fuzzyEquals(a, b)` is pre-defined and can be freely used to test whether two strings `a` and `b` are numerically equal, with error tolerance taking into account.                                                                                                                                                                                                                                       | No            |\n| `propagate`         | Directive to propagate the properties of the current change to the next (interpreted) change. For instance, `propagate=\"p1;p2;p3\"` will propagate the properties `p1`, `p2`, and `p3`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | No            |\n| `weight`            | Determine the number of occurrences of the current changes required for the creation of the next interpreted change. For example, `weight=5`. If the weight value is not known beforehand, the placeholder `*` can be used, such as `weight=*`. This placeholder shall be updated with a concrete value the interpreter during runtime.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | No            |\n\n### Pre-defined functions\n\nSince `conditions` and `join` can be given in JavaScript syntax, pre-defined functions, JavaScript functions, and other\nJavaScript syntax can be used. The following pre-defined functions are available:\n\n| **Function**          | **Description**                                                                                              |\n|-----------------------|--------------------------------------------------------------------------------------------------------------|\n| `fuzzyEquals(a, b)`   | Test whether two strings `a` and `b` are numerically equal, with error tolerance taking into account.        |\n| `spatialEquals(a, b)` | Test whether two geometries `a` and `b` are spatially equivalent, with error tolerances taking into account. |\n\nOther JavaScript functions can be used as well. For example, `Math.abs(a)` can be used to get the absolute value of `a`,\nor `parseFloat(a)` can be used to convert a string `a` to a number.\n\nThe pre-defined functions are defined in JavaScript in the file [functions.js](scripts/functions.js). This file is read\nby the interpreter during runtime, thus you can define your own functions here and use them in `conditions` or `join`.\n\n## What's next\n\nThe following features will be added soon:\n\n+ The ability to **run** the mapping, matching, and interpretation processes separately.\n\n\u003cimg src=\"resources/line.jpg\" alt=\"Buildings with raised roofs\" style=\"width:100%;\"\u003e\n\n## How to cite it\n\nThis tool is part of the following publications:\n\n**Nguyen, Son H.**: [_Automatic Detection and Interpretation of Changes in Massive Semantic 3D City Models_](https://mediatum.ub.tum.de/?id=1748695).\nDissertation, Technical University of Munich, 2024.\n\n**Nguyen, Son H.; Kolbe, Thomas H.**: [_Identification and Interpretation of Change Patterns in \nSemantic 3D City Models_](https://mediatum.ub.tum.de/doc/1730733/1730733.pdf). Lecture Notes in Geoinformation and Cartography - Recent Advances in 3D Geoinformation Science - \nProceedings of the 18th 3D GeoInfo Conference, Springer, 2023.\n\n**Nguyen, Son H.; Kolbe, Thomas H.**: [_Path-tracing Semantic Networks to Interpret Changes in Semantic 3D City\nModels_](https://www.isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/X-4-W2-2022/217/2022/).\nProceedings of the 17th International 3D GeoInfo Conference 2022 (ISPRS Annals of the Photogrammetry, Remote Sensing and\nSpatial Information Sciences), ISPRS, 2022.\n\n**Nguyen, Son H.; Kolbe, Thomas H.**: [_Modelling Changes, Stakeholders and their Relations in Semantic 3D City\nModels_](https://www.isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/VIII-4-W2-2021/137/2021/).\nProceedings of the 16th International 3D GeoInfo Conference 2021 (ISPRS Annals of the Photogrammetry, Remote Sensing and\nSpatial Information Sciences), ISPRS, 2021, 137-144.\n\n**Nguyen, Son H.; Kolbe, Thomas H.**: [_A Multi-Perspective Approach to Interpreting Spatio-Semantic Changes of Large 3D\nCity\nModels in CityGML using a Graph\nDatabase_](https://www.isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/VI-4-W1-2020/143/2020/). Proceedings of the\n15th International 3D GeoInfo Conference 2020 (ISPRS\nAnnals\nof the Photogrammetry, Remote Sensing and Spatial Information Sciences), ISPRS, 2020, 143–150.\n\n**Nguyen, Son H.; Yao, Zhihang; Kolbe, Thomas H.**: [_Spatio-Semantic Comparison of Large 3D City Models in CityGML\nUsing\na Graph\nDatabase_](https://gispoint.de/artikelarchiv/gis/2018/gisscience-ausgabe-32018/4612-raeumlich-semantischer-vergleich-grosser-3d-stadtmodelle-in-citygml-unter-verwendung-einer-graph-datenbank.html).\ngis.Science (3/2018), 2018, 85-100.\n\n**Nguyen, Son H.; Yao, Zhihang; Kolbe, Thomas H.**: [_Spatio-Semantic Comparison of Large 3D City Models in CityGML\nUsing a Graph Database_](https://mediatum.ub.tum.de/doc/1425153/1425153.pdf). Proceedings of the 12th International 3D\nGeoInfo Conference 2017 (ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial Information Sciences), ISPRS,\n2017, 99-106.\n\n**Nguyen, Son H.**: [_Spatio-semantic Comparison of 3D City Models in CityGML using a Graph\nDatabase_](https://mediatum.ub.tum.de/doc/1374646/1374646.pdf). Master's thesis, Technical University of Munich, 2017.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgement\n\nThe development of these methods and implementations were supported \nand partially funded by the company [CADFEM](https://www.cadfem.net/) \nwithin a dedicated collaboration project in the context of the \n[Leonhard Obermeyer Center (LOC)](https://www.ed.tum.de/loc) \nat the [Technical University of Munich (TUM)](https://www.tum.de).\n\n## Contact\n\nIf you have any questions or suggestions, please contact:\n\n**Son H. Nguyen, M.Sc.**\n\n**_PhD Candidate, Research Associate_**\n\nChair of Geoinformatics | Department of Aerospace and Geodesy\n\nTUM School of Engineering and Design | Technical University of Munich (TUM)\n\nArcisstr. 21, 80333 Munich, Germany\n\nEmail: [son.nguyen@tum.de](mailto:son.nguyen@tum.de)\n\n[Homepage](https://www.asg.ed.tum.de/en/gis/our-team/staff/son-h-nguyen/) | [LinkedIn](https://www.linkedin.com/in/son-h-nguyen/) | [ResearchGate](https://www.researchgate.net/profile/Son-Nguyen-101)\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftum-gis%2Fcitymodel-compare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftum-gis%2Fcitymodel-compare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftum-gis%2Fcitymodel-compare/lists"}