mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
1fe4570860
The chunk planner (Morton sort + greedy pack) and instance composition (federation × placement matrix chain + world-AABB derive) were inline helpers in ViewportWindow.cpp. Pulled both out as free-function modules so the math + lookup logic can be exercised without a Qt window or a wgpu device. ViewportWindow now delegates; InstanceLookup is a using- alias to InstanceCompose::InstanceLookup. Also added an addSubBufferForTesting / clearSubPoolsForTesting seam to BufferPool so the sub-allocator invariants can be pinned with fake WGPUBuffer handles. The fakes are never dereferenced; the guard drops the sub-pools before destructor would call wgpuBufferRelease. Three new test binaries under src/ifcviewer/tests/, 33 cases / 173 assertions: BufferPool first-fit + alignment + coalescing + multi- sub-pool isolation; ChunkPlanner Morton split / interleave / stable sort / greedy-pack monotonicity and single-mesh-oversize; InstanceCompose identity / translation / order-of-multiplication / large-placement cancellation against federation false origin / column-major writeback / findInstance lookup paths.
99 lines
4.5 KiB
C++
99 lines
4.5 KiB
C++
/********************************************************************************
|
|
* *
|
|
* This file is part of IfcOpenShell. *
|
|
* *
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* Lesser GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
* *
|
|
********************************************************************************/
|
|
|
|
#include "InstanceCompose.h"
|
|
|
|
#include <cstring>
|
|
#include <limits>
|
|
|
|
namespace InstanceCompose {
|
|
|
|
void worldAabbFromLocal(const float local_min[3], const float local_max[3],
|
|
const float M[16],
|
|
float world_min_out[3], float world_max_out[3]) {
|
|
world_min_out[0] = world_min_out[1] = world_min_out[2] =
|
|
std::numeric_limits<float>::max();
|
|
world_max_out[0] = world_max_out[1] = world_max_out[2] =
|
|
-std::numeric_limits<float>::max();
|
|
for (int c = 0; c < 8; ++c) {
|
|
const float x = (c & 1) ? local_max[0] : local_min[0];
|
|
const float y = (c & 2) ? local_max[1] : local_min[1];
|
|
const float z = (c & 4) ? local_max[2] : local_min[2];
|
|
const float wx = M[0]*x + M[4]*y + M[8] *z + M[12];
|
|
const float wy = M[1]*x + M[5]*y + M[9] *z + M[13];
|
|
const float wz = M[2]*x + M[6]*y + M[10]*z + M[14];
|
|
if (wx < world_min_out[0]) world_min_out[0] = wx;
|
|
if (wx > world_max_out[0]) world_max_out[0] = wx;
|
|
if (wy < world_min_out[1]) world_min_out[1] = wy;
|
|
if (wy > world_max_out[1]) world_max_out[1] = wy;
|
|
if (wz < world_min_out[2]) world_min_out[2] = wz;
|
|
if (wz > world_max_out[2]) world_max_out[2] = wz;
|
|
}
|
|
}
|
|
|
|
void composeInstance(
|
|
const double placement_col_major[16],
|
|
const Eigen::Matrix4d& federated_false_origin,
|
|
const Eigen::Matrix4d& model_transformation,
|
|
const Eigen::Matrix4d& coordinate_operation,
|
|
const float local_aabb_min[3], const float local_aabb_max[3],
|
|
float transform_col_major_out[16],
|
|
float world_aabb_min_out[3], float world_aabb_max_out[3]) {
|
|
using Mat4dCol = Eigen::Matrix<double, 4, 4, Eigen::ColMajor>;
|
|
using Mat4fCol = Eigen::Matrix<float, 4, 4, Eigen::ColMajor>;
|
|
|
|
const Eigen::Matrix4d P =
|
|
Eigen::Map<const Mat4dCol>(placement_col_major);
|
|
const Eigen::Matrix4d composed =
|
|
federated_false_origin *
|
|
model_transformation *
|
|
coordinate_operation *
|
|
P;
|
|
|
|
Eigen::Map<Mat4fCol> T_f(transform_col_major_out);
|
|
T_f = composed.cast<float>();
|
|
|
|
worldAabbFromLocal(local_aabb_min, local_aabb_max,
|
|
transform_col_major_out,
|
|
world_aabb_min_out, world_aabb_max_out);
|
|
}
|
|
|
|
bool findInstanceInModels(
|
|
uint32_t object_id,
|
|
const std::unordered_map<uint32_t, ModelGpuData>& models,
|
|
InstanceLookup& out) {
|
|
if (object_id == 0) return false;
|
|
for (const auto& [mid, m] : models) {
|
|
auto it = m.object_id_to_instance.find(object_id);
|
|
if (it == m.object_id_to_instance.end()) continue;
|
|
const uint32_t inst_idx = it->second;
|
|
if (inst_idx >= m.instances.size()) continue;
|
|
const InstanceCpu& inst = m.instances[inst_idx];
|
|
out.model_id = mid;
|
|
out.mesh_id = inst.mesh_id;
|
|
std::memcpy(out.placement_transformation,
|
|
inst.placement_transformation,
|
|
sizeof(out.placement_transformation));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace InstanceCompose
|