Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 51 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Repair of non-manifold and self-intersecting roof junctions during arrangement snapping. This prevents certain geometric errors like non-watertight meshes, and highly non-planar faces that could prevriously happen in complex roof arrangements. See #168.
- Repair of non-manifold and self-intersecting roof junctions during arrangement snapping. This prevents certain geometric errors like non-watertight meshes, and highly non-planar faces that could previously happen in complex roof arrangements. See #168.
- Optional per-tile triangulated terrain output as CityJSON `TINRelief` features, see the `--terrain` option.
- A new `max-nodata-fraction` configuration option to control the maximum fraction of nodata pixels in a building polygon that is allowed before a building pointcloud is considered insufficient.
- A descriptor-backed `roofer::reconstruction::ReconstructionConfig` that contains the configuration for every reconstruction stage. Field declarations are now the single source for defaults, descriptions, validation, nested TOML parsing, generated documentation, and Python bindings.
- A nested C++ `ReconstructOptions` API and corresponding `reconstruct` overload. The nested reconstruction configuration is also available from Python, including each component configuration that exposes public parameters.

## Fixed
### Fixed
- More robust handling of OGC WKT payloads in LAS/LAZ files.
- Prevent roof-ground bow-ties by clipping roof faces against the terrain before extrusion.
- Correct squared-distance tolerance comparisons during extrusion.
- Reject TOML integer values outside the supported `int` range instead of silently narrowing them.

## Changed
### Changed
- The pointcloud-insufficient test is now an absolute per-building density floor (`min-building-density`, points/m²) instead of a tile-relative `mean - 2·std` outlier test. The old test depended the entire tile that was being processed, so the same building could be flagged differently between runs with different tiling — potentially skipping point-rich buildings and leaving them without geometry. The decision is now deterministic and depends only on the building's own data.
- Region growing no longer uses a wall-clock time limit, which could make a building reconstruct with success on one run and fall back to LoD 1.1 on the next given identical input due to resource starvation with multithreading. The deterministic plane-count limit (`lod11-fallback-planes`) is now the sole reconstruction-complexity cutoff. The `lod11-fallback-time` parameter is deprecated and removed.
- Use mesh centroid for volume calculation
- Region growing no longer uses a wall-clock time limit, which could make a building reconstruct with success on one run and fall back to LoD 1.1 on the next given identical input due to resource starvation with multithreading. The deterministic plane-count limit (`lod11-fallback-planes`) is now the sole reconstruction-complexity cutoff. The `lod11-fallback-time` behavior is removed; its CLI flag and root configuration key are accepted but ignored with a deprecation warning during 1.x compatibility.
- Reconstruction configuration now uses nested TOML tables such as `[reconstruction.plane-detector]` and `[reconstruction.arrangement-optimiser]`. Core reconstruction stages receive their component configuration aggregates; pipeline-derived settings such as requested LoD and terrain availability are overlaid on local copies.
- Reconstruction parameter descriptions now state physical and angular units where applicable; counts remain unit-free.
- All canonical reconstruction angle parameters now use degrees.
Plane-detection normal, horizontal, and wall thresholds are expressed
directly as angles instead of dot products, and the line-regularisation
angle is no longer in radians. The legacy `plane-detect-normal-angle` alias
and compatibility API properties retain their 1.x dot-product semantics.
- Reconstruction snapping and duplicate-vertex tolerances now use distances
in metres instead of base-10 exponents. Existing defaults retain their
previous effective distances.
- Added global `unit-scale` (metres per input coordinate unit) to convert
metre-based reconstruction, crop, and output parameters for input data that
uses another unit.
- Set the default cityjson scale in the transform object to 0.0001. This helps with improving geometric validity. The previous 0.001 setting regurlarly caused validity issues due to the relatively large quatisation error.
- Descriptor-generated TOML documentation and Python bindings omit reconstruction components that have no public parameters.
- `complexity-factor` now directly controls the optimiser energy balance: the data term is weighted by `complexity-factor` and the smoothness term by `1 - complexity-factor`. The independent `data_multiplier` and `smoothness_multiplier` component options were removed.
- The flattened C++ `roofer::ReconstructionConfig` remains as a 1.x compatibility adapter, while its `reconstruct` overloads are deprecated. Its defaults and validation delegate to the nested configuration.
- Low-level C++ component configuration member names were normalised to `snake_case`, and obsolete members were removed. This is a source-breaking change for code that uses the component configuration structs directly; the flattened `roofer::ReconstructionConfig` adapter does not cover those direct uses.
- Legacy root-level reconstruction TOML keys remain accepted during 1.x, emit a destination-specific deprecation warning, and are applied before nested TOML values. CLI arguments retain the highest precedence. The `--lod12`, `--lod13`, `--lod22`, `--clip-terrain`, and `--complexity-factor` flags remain supported without deprecation warnings. Other supported legacy reconstruction CLI flags remain accepted with deprecation warnings; several older names remain root-TOML-only aliases and are not accepted as CLI flags.
- Use mesh centroid for volume calculation.

### Reconstruction parameter mapping

Legacy root keys, and matching legacy CLI flags where available, map as follows:

| Legacy parameter | Nested TOML parameter | Notes |
|---|---|---|
| `lod12` | `[reconstruction] lod12` | CLI flag remains supported. |
| `lod13` | `[reconstruction] lod13` | CLI flag remains supported. |
| `lod22` | `[reconstruction] lod22` | CLI flag remains supported. |
| `clip-terrain` | `[reconstruction] clip-terrain` | CLI flag remains supported. |
| `lod13-step-height` | `[reconstruction] lod13-step-height` | Relocated; legacy CLI flag is deprecated. |
| `h-terrain-strategy` | `[reconstruction] h-terrain-strategy` | Relocated; legacy CLI flag is deprecated. |
| `complexity-factor` | `[reconstruction.arrangement-optimiser] complexity-factor` | CLI flag remains supported. |
| `plane-detect-k` | `[reconstruction.plane-detector] plane-neighbour-count` | Renamed; legacy CLI flag is deprecated. |
| `plane-detect-min-points` | `[reconstruction.plane-detector] min-plane-points` | Renamed; legacy CLI flag is deprecated. |
| `plane-detect-epsilon` | `[reconstruction.plane-detector] plane-epsilon` | Renamed; legacy CLI flag is deprecated. |
| `plane-detect-normal-angle` | `[reconstruction.plane-detector] normal-angle-threshold` | Renamed; root TOML alias only. Legacy values remain unitless dot products and are converted to degrees. |
| `line-detect-epsilon` | `[reconstruction.line-detector] distance-threshold` | Renamed; root TOML alias only. |
| `thres-alpha` | `[reconstruction.alpha-shaper] alpha` | Renamed; root TOML alias only. |
| `thres-reg-line-dist` | `[reconstruction.line-regulariser] distance-threshold` | Renamed; root TOML alias only. |
| `thres-reg-line-ext` | `[reconstruction.line-regulariser] extension` | Renamed; root TOML alias only. |
| `lod11-fallback-planes` | `[reconstruction.plane-detector] max-plane-count` | Renamed; deprecated legacy CLI flag and deterministic complexity cutoff. |
| `lod11-fallback-time` | `[reconstruction.plane-detector] max-plane-count` | Deprecated CLI flag and root key are accepted but ignored; `max-plane-count` is the deterministic replacement. |

## [1.0.0] - 2026-04-20

Expand Down
2 changes: 1 addition & 1 deletion apps/example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ optimisation_data_term=8.000000
plane_detect__k=15
plane_detect__epsilon=0.300000
plane_detect__min_points=15
plane_detect__normal_angle=0.750000
plane_detect__normal_angle=41.409622
thres_alpha=0.250000
thres_reg_line_dist=0.800000
thres_reg_line_ext=3.000000
Expand Down
7 changes: 4 additions & 3 deletions apps/ransac_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ float ransac_probability = 0.01;
int ransac_min_points = 15;
float ransac_epsilon = 0.2;
float ransac_cluster_epsilon = 0.5;
float ransac_normal_threshold = 0.8;
float ransac_normal_angle_threshold = 36.869896F;
bool bid_changed = true;
// int old_bid_changed;

Expand All @@ -35,7 +35,8 @@ void myCallback() {
ImGui::InputInt("min_points", &ransac_min_points);
ImGui::InputFloat("epsilon", &ransac_epsilon);
ImGui::InputFloat("cluster_epsilon", &ransac_cluster_epsilon);
ImGui::InputFloat("normal_threshold", &ransac_normal_threshold);
ImGui::InputFloat("normal_angle_threshold_degrees",
&ransac_normal_angle_threshold);

if (ImGui::Button("Do RANSAC")) {
// executes when button is pressed
Expand All @@ -44,7 +45,7 @@ void myCallback() {
roofer::vec3f normals;
auto nShapes = ShapeDetector->detectPlanes(
pc, normals, labels, ransac_probability, ransac_min_points,
ransac_epsilon, ransac_cluster_epsilon, ransac_normal_threshold);
ransac_epsilon, ransac_cluster_epsilon, ransac_normal_angle_threshold);

std::vector<std::array<double, 3>> randColor(nShapes);
randColor[0] = {{0.0f, 0.0f, 0.0f}};
Expand Down
Loading
Loading