diff --git a/viz_3dtiles/Cesium3DTileset.py b/viz_3dtiles/Cesium3DTileset.py index cc5516f..f12c2f1 100644 --- a/viz_3dtiles/Cesium3DTileset.py +++ b/viz_3dtiles/Cesium3DTileset.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- import json +import os from pathlib import Path +from statistics import mean class Cesium3DTileset: @@ -103,3 +105,131 @@ def write_file(self): outfile.write(self.to_json()) # print("Tileset saved to " + self.get_filename()) + + def create_parent_json( + self, + json_paths=[], + save_to=None, + save_as="tileset.json", + remove_children=True + ): + """ + Merge all the tileset json files into one main tileset.json file. + + Parameters + ---------- + + json_paths : list of strings + The paths to the tileset json files to be merged + + save_to : string (optional) + Set the filepath, but not the filename or extension, of + tileset.json. If set to None, then the save_to path on the + tileset instance will be used. + + save_as : string (optional) + Set the filename of the tileset, without the extension. + Defaults to "tileset". If set to None, then the save_as string + on the tileset instance will be used. + + remove_children : bool + If True, then the children json files will be removed after + they are merged into the parent. + """ + + if save_to is None: + save_to = self.save_to + + if save_as is None: + save_as = self.save_as + + # The tileset.json should be saved at the root of this directory + parent_json_path = os.path.join(save_to, save_as + "." + self.FILE_EXT) + + tileset = { + "asset": { + "version": "0.0" + }, + "root": { + "boundingVolume": {"box": []}, + "geometricError": None, + "refine": "ADD", + "children": [] + } + } + + # Parent bounding volume is the union of all B3DM bounding volumes + all_bvs = [] + + # Parent geometric error + all_ges = [] + + # Check that all the JSON files exist + for json_path in json_paths: + + if not os.path.isfile(json_path): + raise ValueError(f"JSON file {json_path} does not exist") + + # Read in the json + with open(json_path, "r") as f: + j = json.load(f) + + # Get the bounding volume + bv = j["root"]["boundingVolume"]["box"] + # Get the geometric error + ge = j["root"]["geometricError"] + + # The URI of the B3DM file should be relative to the parent + # tileset.json file. URL in child JSON is just the filename + ext + # of the B3DM file (not the full path). Assume the child JSON is + # saved in the same directory as the child B3DM. + child_filename = j["root"]["content"]["url"] + child_fullpath = os.path.join( + os.path.dirname(json_path), child_filename) + rel_uri = os.path.relpath(child_fullpath, save_to) + + # Make the json/dict + child = { + "geometricError": ge, + "boundingVolume": {"box": bv}, + "refine": "ADD", + "content": { + "boundingVolume": {"box": bv}, + "uri": rel_uri + } + } + + # Add the child to the tileset + tileset["root"]["children"].append(child) + + # Add the bounding volume to the list of all bounding volumes + all_bvs.append(bv) + + # Add the geometric error to the list of all geometric errors + all_ges.append(ge) + + # Calculate the parent bounding volume + mid_x = mean([bv[0] for bv in all_bvs]) + mid_y = mean([bv[1] for bv in all_bvs]) + mid_z = mean([bv[2] for bv in all_bvs]) + width = sum([bv[3] for bv in all_bvs]) + length = sum([bv[7] for bv in all_bvs]) + parent_bounding_volume = [ + mid_x, mid_y, mid_z, width, + 0, 0, 0, length, 0, 0, 0, 0] + + # Calculate the parent geometric error + parent_geometric_error = sum(all_ges) + + # Update the tileset + tileset["root"]["boundingVolume"]["box"] = parent_bounding_volume + tileset["root"]["geometricError"] = parent_geometric_error + + # Write the tileset.json + with open(parent_json_path, "w") as f: + json.dump(tileset, f, indent=4) + + if remove_children: + # Remove the children + for j in json_paths: + os.remove(j) diff --git a/viz_3dtiles/__init__.py b/viz_3dtiles/__init__.py index bec16a8..2703ea8 100644 --- a/viz_3dtiles/__init__.py +++ b/viz_3dtiles/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from .Cesium3DTile import Cesium3DTile from .Cesium3DTileset import Cesium3DTileset +from .StagedTo3DConverter import StagedTo3DConverter __version__ = '0.0.1' \ No newline at end of file