From 76d4d4db679e6efb752d4203674a31e297f2db70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:06:18 +0000 Subject: [PATCH 1/4] Initial plan From 57e07447b4528708e8c710543dcbf9d002c35e8c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:09:08 +0000 Subject: [PATCH 2/4] Remove unused tileHashes variable from OctreeTiler Co-authored-by: bertt <538812+bertt@users.noreply.github.com> --- src/b3dm.tileset/OctreeTiler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/b3dm.tileset/OctreeTiler.cs b/src/b3dm.tileset/OctreeTiler.cs index 2f0f41fc..4004b995 100644 --- a/src/b3dm.tileset/OctreeTiler.cs +++ b/src/b3dm.tileset/OctreeTiler.cs @@ -98,7 +98,6 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int { // clone processedGeometries to avoid modifying the original set in recursive calls var localProcessedGeometries = new HashSet(processedGeometries); - var tileHashes = new HashSet(); // Get the largest geometries (up to MaxFeaturesPerTile) for this tile at this level int target_srs = tilingSettings.KeepProjection ? inputTable.EPSGCode : 4978; @@ -109,7 +108,6 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int if (geometriesToProcess.Count > 0) { foreach (var geom in geometriesToProcess.Where(geom => !string.IsNullOrEmpty(geom.Hash))) { localProcessedGeometries.Add(geom.Hash); - tileHashes.Add(geom.Hash); } var file = $"{tilesetSettings.OutputSettings.ContentFolder}{Path.AltDirectorySeparatorChar}{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}.glb"; From d013a3f4b122fcccbb5d129ab0fd45d3d907742a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:14:37 +0000 Subject: [PATCH 3/4] Implement tileHashes pattern like QuadtreeTiler Co-authored-by: bertt <538812+bertt@users.noreply.github.com> --- src/b3dm.tileset/OctreeTiler.cs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/b3dm.tileset/OctreeTiler.cs b/src/b3dm.tileset/OctreeTiler.cs index 4004b995..eb9d6479 100644 --- a/src/b3dm.tileset/OctreeTiler.cs +++ b/src/b3dm.tileset/OctreeTiler.cs @@ -98,6 +98,7 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int { // clone processedGeometries to avoid modifying the original set in recursive calls var localProcessedGeometries = new HashSet(processedGeometries); + var tileHashes = new HashSet(); // Get the largest geometries (up to MaxFeaturesPerTile) for this tile at this level int target_srs = tilingSettings.KeepProjection ? inputTable.EPSGCode : 4978; @@ -108,17 +109,23 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int if (geometriesToProcess.Count > 0) { foreach (var geom in geometriesToProcess.Where(geom => !string.IsNullOrEmpty(geom.Hash))) { localProcessedGeometries.Add(geom.Hash); + tileHashes.Add(geom.Hash); } var file = $"{tilesetSettings.OutputSettings.ContentFolder}{Path.AltDirectorySeparatorChar}{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}.glb"; TileCreationHelper.WriteTileIfNeeded(geometriesToProcess, tilesetSettings.Translation, stylingSettings, tilesetSettings.Copyright, tilingSettings.CreateGltf, tilingSettings.SkipCreateTiles, file, file); + + UpdateTileBoundingBox3D(tile, tileBounds, tileHashes, where); + tile.Available = true; } tiles.Add(tile); if (tileBounds != null) { var key = $"{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}"; - tileBounds[key] = bbox; + if (!tileBounds.ContainsKey(key)) { + tileBounds[key] = bbox; + } } return localProcessedGeometries; @@ -126,6 +133,7 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int private void CreateTile3D(BoundingBox3D bbox, int level, Tile3D tile, List tiles, Dictionary tileBounds, string where, HashSet processedGeometries) { + var tileHashes = new HashSet(); int target_srs = tilingSettings.KeepProjection ? inputTable.EPSGCode : 4978; var bbox1 = new double[] { bbox.XMin, bbox.YMin, bbox.XMax, bbox.YMax, bbox.ZMin, bbox.ZMax }; @@ -134,11 +142,15 @@ private void CreateTile3D(BoundingBox3D bbox, int level, Tile3D tile, List 0) { // Collect hashes of processed geometries foreach (var geom in geometries.Where(geom => !string.IsNullOrEmpty(geom.Hash))) { + tileHashes.Add(geom.Hash); processedGeometries.Add(geom.Hash); } var file = $"{tilesetSettings.OutputSettings.ContentFolder}{Path.AltDirectorySeparatorChar}{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}.glb"; TileCreationHelper.WriteTileIfNeeded(geometries, tilesetSettings.Translation, stylingSettings, tilesetSettings.Copyright, tilingSettings.CreateGltf, tilingSettings.SkipCreateTiles, file, file); + + UpdateTileBoundingBox3D(tile, tileBounds, tileHashes, where); + tile.Available = true; } else { @@ -148,7 +160,23 @@ private void CreateTile3D(BoundingBox3D bbox, int level, Tile3D tile, List tileBounds, HashSet tileHashes, string where) + { + if (tileBounds == null || tileHashes.Count == 0) { + return; + } + + // Update bounding box based on actual geometries in the tile + var bbox_geometries = GeometryRepository.GetGeometriesBoundingBox(conn, inputTable.TableName, inputTable.GeometryColumn, inputTable.EPSGCode, null, tileHashes, where, tilingSettings.KeepProjection); + var bbox3d = new BoundingBox3D(bbox_geometries[0], bbox_geometries[1], bbox_geometries[4], bbox_geometries[2], bbox_geometries[3], bbox_geometries[5]); + + var key = $"{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}"; + tileBounds[key] = bbox3d; + } } From f3470e3b3fea83e5ef8336dfdb5e3c2d3db94051 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:44:37 +0000 Subject: [PATCH 4/4] Only call UpdateTileBoundingBox3D when not using implicit tiling Co-authored-by: bertt <538812+bertt@users.noreply.github.com> --- src/b3dm.tileset/OctreeTiler.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/b3dm.tileset/OctreeTiler.cs b/src/b3dm.tileset/OctreeTiler.cs index eb9d6479..8756356b 100644 --- a/src/b3dm.tileset/OctreeTiler.cs +++ b/src/b3dm.tileset/OctreeTiler.cs @@ -115,7 +115,9 @@ private HashSet CreateTileForLargestGeometries3D(BoundingBox3D bbox, int var file = $"{tilesetSettings.OutputSettings.ContentFolder}{Path.AltDirectorySeparatorChar}{tile.Level}_{tile.Z}_{tile.X}_{tile.Y}.glb"; TileCreationHelper.WriteTileIfNeeded(geometriesToProcess, tilesetSettings.Translation, stylingSettings, tilesetSettings.Copyright, tilingSettings.CreateGltf, tilingSettings.SkipCreateTiles, file, file); - UpdateTileBoundingBox3D(tile, tileBounds, tileHashes, where); + if (!tilingSettings.UseImplicitTiling) { + UpdateTileBoundingBox3D(tile, tileBounds, tileHashes, where); + } tile.Available = true; } @@ -149,7 +151,9 @@ private void CreateTile3D(BoundingBox3D bbox, int level, Tile3D tile, List