spatial hierarchy: storey elevation + Long Name column + resizable layout

- helpers/placement: port get_storey_elevation (placement Z, falling back
  to the Elevation attribute), matching ifcopenshell.util.placement.
- Add a secondary column: the storey elevation for IfcBuildingStorey,
  otherwise the LongName when filled. Elevations are right-aligned.
- Columns: Name is drag-resizable (interactive) and defaults to 20% of the
  width, Long Name stretches to fill the rest, and the eye is pinned to the
  right at a fixed width. Header shown so the divider can be grabbed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-07-08 20:33:29 +10:00
parent 90196dd51d
commit 4afb3892a2
6 changed files with 95 additions and 11 deletions
+41
View File
@@ -20,8 +20,11 @@
#include "placement.h"
#include "../ifcparse/exception.h"
#include "../ifcparse/instance_data.h"
#include "../ifcparse/schema.h"
#include "schema_dispatch.i"
#include <cstddef>
#include <type_traits>
#include <vector>
@@ -125,6 +128,31 @@ Eigen::Matrix4d get_local_placement_s(const express::Base& placement) {
return get_axis2_placement_s<Schema>(placement);
}
// ifcopenshell.util.placement.get_storey_elevation: the Z of the storey's
// placement in project units, falling back to the Elevation attribute.
template <typename Schema>
double get_storey_elevation_s(const express::Base& storey) {
const auto typed = storey.template as<typename Schema::IfcBuildingStorey>();
if (!typed) {
return 0.0;
}
if (const auto placement = typed.ObjectPlacement()) {
return get_local_placement_s<Schema>(placement)(2, 3);
}
// Fallback: the optional Elevation attribute (read by name).
const ifcopenshell::entity* declaration = storey.declaration().as_entity();
if (declaration != nullptr) {
const std::ptrdiff_t index = declaration->attribute_index("Elevation");
if (index >= 0) {
const attribute_value value = storey.get_attribute_value(static_cast<std::size_t>(index));
if (!value.isNull() && value.type() == ifcopenshell::Argument_DOUBLE) {
return static_cast<double>(value);
}
}
}
return 0.0;
}
} // namespace
Eigen::Matrix4d axes_to_placement(const Eigen::Vector3d& origin,
@@ -167,3 +195,16 @@ Eigen::Matrix4d get_local_placement(const express::Base& placement) {
#undef IFCOPENSHELL_DISPATCH
unsupported_schema(name);
}
double get_storey_elevation(const express::Base& storey) {
if (!storey) {
return 0.0;
}
const auto name = storey.declaration().schema()->name();
#define IFCOPENSHELL_DISPATCH(Schema, Identifier) \
if (name == Identifier) \
return get_storey_elevation_s<Schema>(storey);
IFCOPENSHELL_HELPER_FOR_EACH_SCHEMA(IFCOPENSHELL_DISPATCH)
#undef IFCOPENSHELL_DISPATCH
unsupported_schema(name);
}