Data Acquisition

We will use the Overpass API and cpr to query OpenStreetMap for all the available tree data within the specified bounding box (bbox):

std::string query =
    "[out:json]; (node(" + bbox + ")[\"natural\"=\"tree\"];); out;";
    std::cout << "Query: " << query << std::endl;

cpr::Response r = cpr::Post(
    cpr::Url{"http://overpass-api.de/api/interpreter"}, cpr::Body{query},
    cpr::Header{{"Content-Type", "application/x-www-form-urlencoded"}},
    cpr::Timeout{10000} // Set a timeout of 10 seconds
);

The http://overpass-api.de/api/interpreter endpoint interprets and executes the Overpass QL queries, retrieving specific parts of the OpenStreetMap data. In this case, the query fetches all nodes within the given bounding box tagged as natural=tree.

If the query is not successful, a cpr.log file will be generated to store the error message. Otherwise, the data will be stored in a .json file.

A config.json file is available for the user to specify the area of interest and other parameters:

{
  "bbox": "48.5748, 7.7383,48.5918, 7.7610",
  "LOD": 0,
  "default_height_range": [3, 6],
  "input_building_mesh": "mesh_lod1.msh",
  "output_name": "stars_city",
  "output_format": "msh",
  "verbose": false,
  "autorefine": true
}

Where :

  • bbox: is the bounding box for the query in the format: (SW latitude, SW longitude, NE latitude, NE longitude)

  • LOD: is the level of details of the meshes (0, 1, 2 or 3)

  • default_height_range: is a range used to randomly assign a height to trees that do not have one.

  • input_building_mesh: is the name of the input file representing the terrain mesh.

  • output_name: is the name of the output file.

  • output_format: is the format of the output file (msh, stl, off).

  • verbose: is a boolean to enable or disable the verbose mode.

  • autorefine: is a boolean to enable or disable the automatic refinement of the tree meshes.

The data will be stored in query_result.json file in the root directory of the project.

Here is an example of the query result for one tree:

{
    "type": "node",
    "id": 10162018740,
    "lat": 48.5850910,
    "lon": 7.7502624,
    "tags": {
        "circumference": "1.47655",
        "diameter_crown": "5",
        "genus": "Platanus",
        "height": "6",
        "leaf_cycle": "deciduous",
        "leaf_type": "broadleaved",
        "natural": "tree",
        "ref": "16401",
        "source": "data.strasbourg.eu - patrimoine_arbore",
        "source:date": "2022-01-02",
        "species": "Platanus acerifolia x",
        "species:wikidata": "Q24853030"
    }
}

Sometimes, multiple tags can be missing, as shown here:

{
    "type": "node",
    "id": 4439566691,
    "lat": 48.5839128,
    "lon": 7.7487125,
    "tags": {
      "natural": "tree"
    }
}

We will primarily use the tree’s GPS position (latitude and longitude), its height, its trunk’s circumference, and its crown’s diameter.

References