ContextPriorities

This commit is contained in:
Thomas Krijnen
2026-07-10 16:31:35 +02:00
parent 542856fb30
commit 4f69855dc0
3 changed files with 403 additions and 11 deletions
@@ -1,5 +1,6 @@
#include <algorithm>
#include <string>
#include <vector>
#include <catch2/catch_test_macros.hpp>
@@ -68,6 +69,86 @@ std::size_t count_geo403_for_wall(hierarchy_helper<IfcSchema>& file, const IfcSc
return log.count("GEO403");
}
IfcSchema::IfcShapeRepresentation add_box_representation(
hierarchy_helper<IfcSchema>& file,
IfcSchema::IfcRepresentationContext context,
const std::string& identifier,
double size)
{
auto representation = file.create<IfcSchema::IfcShapeRepresentation>();
representation.setContextOfItems(context);
representation.setRepresentationIdentifier(identifier);
representation.setRepresentationType("SweptSolid");
representation.setItems(std::vector<IfcSchema::IfcRepresentationItem>{});
file.addBox(representation, size, size, size);
return representation;
}
IfcSchema::IfcRepresentation select_representation(
hierarchy_helper<IfcSchema>& file,
const IfcSchema::IfcWallStandardCase& wall,
const std::vector<std::string>& context_priorities)
{
ifcopenshell::geometry::Settings settings;
settings.set("context-priorities", std::vector<std::string>(context_priorities));
logger log;
log.output_format(logger::FMT_INMEMORY);
ifcopenshell::geometry::Converter converter(
ifcopenshell::geometry::kernels::construct(&file, "passthrough", settings), &file, settings, log);
auto selected = converter.mapping()->representation_of(wall).as<IfcSchema::IfcRepresentation>();
REQUIRE(selected);
return selected;
}
IfcSchema::IfcWallStandardCase add_wall_with_representations(
hierarchy_helper<IfcSchema>& file,
const std::vector<IfcSchema::IfcRepresentation>& representations)
{
auto wall = file.create<IfcSchema::IfcWallStandardCase>();
wall.setGlobalId(ifcopenshell::global_id());
file.addBuildingProduct(wall);
auto shape = file.create<IfcSchema::IfcProductDefinitionShape>();
shape.setRepresentations(representations);
wall.setRepresentation(shape);
return wall;
}
std::vector<ifcopenshell::geometry::geometry_conversion_task> representation_tasks(
hierarchy_helper<IfcSchema>& file,
const std::vector<std::string>& context_priorities)
{
ifcopenshell::geometry::Settings settings;
settings.set("context-priorities", std::vector<std::string>(context_priorities));
logger log;
log.output_format(logger::FMT_INMEMORY);
ifcopenshell::geometry::Converter converter(
ifcopenshell::geometry::kernels::construct(&file, "passthrough", settings), &file, settings, log);
std::vector<ifcopenshell::geometry::geometry_conversion_task> tasks;
std::vector<ifcopenshell::geometry::filter_t> filters;
converter.mapping()->get_representations(tasks, filters);
return tasks;
}
const ifcopenshell::geometry::geometry_conversion_task* task_for_product(
const std::vector<ifcopenshell::geometry::geometry_conversion_task>& tasks,
const express::Base& product)
{
for (const auto& task : tasks) {
if (std::any_of(task.products.begin(), task.products.end(), [&](const express::Base& task_product) {
return task_product.id() == product.id();
})) {
return &task;
}
}
return nullptr;
}
} // namespace
TEST_CASE("IfcGeom C++ fixture creates walls below and above the void limit", "[ifcgeom][voids]") {
@@ -79,3 +160,80 @@ TEST_CASE("IfcGeom C++ fixture creates walls below and above the void limit", "[
const auto above_limit_wall = create_wall_with_voids(above_limit_file, MAX_VOIDS + 1);
REQUIRE(count_geo403_for_wall(above_limit_file, above_limit_wall) == 1);
}
TEST_CASE("IfcGeom context priorities select representations by subcontext filter", "[ifcgeom][context]") {
hierarchy_helper<IfcSchema> file;
auto body_context = file.getRepresentationSubContext("Body", "Model");
auto tesselation_context = file.getRepresentationSubContext("Tesselation", "Model");
auto wall = file.create<IfcSchema::IfcWallStandardCase>();
wall.setGlobalId(ifcopenshell::global_id());
file.addBuildingProduct(wall);
const auto body_representation = add_box_representation(file, body_context, "Body", 1000.0);
const auto tesselation_representation = add_box_representation(file, tesselation_context, "Tesselation", 500.0);
REQUIRE(body_context.RepresentationsInContext().size() == 1);
REQUIRE(tesselation_context.RepresentationsInContext().size() == 1);
auto shape = file.create<IfcSchema::IfcProductDefinitionShape>();
shape.setRepresentations(
std::vector<IfcSchema::IfcRepresentation>{tesselation_representation, body_representation});
wall.setRepresentation(shape);
REQUIRE(select_representation(file, wall, {"body"}).id() == body_representation.id());
REQUIRE(select_representation(file, wall, {"tesselation"}).id() == tesselation_representation.id());
REQUIRE(
select_representation(file, wall, {"tesselation[context-identifier=Tesselation]"}).id() ==
tesselation_representation.id());
REQUIRE(
select_representation(file, wall, {"tesselation[targetview=MODEL_VIEW]"}).id() ==
tesselation_representation.id());
REQUIRE(
select_representation(file, wall, {"tesselation[target_view=MODEL_VIEW]"}).id() ==
tesselation_representation.id());
REQUIRE(
select_representation(file, wall, {"body", "tesselation[targetview=MODEL_VIEW]"}).id() ==
body_representation.id());
REQUIRE(
select_representation(file, wall, {"tesselation[targetview=MODEL_VIEW]", "body"}).id() ==
tesselation_representation.id());
}
TEST_CASE("IfcGeom context priorities create tasks from highest priority representation", "[ifcgeom][context]") {
hierarchy_helper<IfcSchema> file;
auto body_context = file.getRepresentationSubContext("Body", "Model");
auto tesselation_context = file.getRepresentationSubContext("Tesselation", "Model");
const auto body_representation = add_box_representation(file, body_context, "Body", 1000.0);
const auto tesselation_representation = add_box_representation(file, tesselation_context, "Tesselation", 500.0);
const auto body_only_representation = add_box_representation(file, body_context, "Body", 750.0);
const auto wall_with_both = add_wall_with_representations(
file,
std::vector<IfcSchema::IfcRepresentation>{body_representation, tesselation_representation});
const auto wall_with_body_only = add_wall_with_representations(
file,
std::vector<IfcSchema::IfcRepresentation>{body_only_representation});
auto tesselation_first_tasks = representation_tasks(file, {"tesselation[target_view=MODEL_VIEW]", "body"});
REQUIRE(tesselation_first_tasks.size() == 2);
REQUIRE(tesselation_first_tasks[0].representation.id() == tesselation_representation.id());
REQUIRE(tesselation_first_tasks[0].products.size() == 1);
REQUIRE(tesselation_first_tasks[0].products.front().id() == wall_with_both.id());
REQUIRE(tesselation_first_tasks[1].representation.id() == body_only_representation.id());
REQUIRE(tesselation_first_tasks[1].products.size() == 1);
REQUIRE(tesselation_first_tasks[1].products.front().id() == wall_with_body_only.id());
auto body_first_tasks = representation_tasks(file, {"body", "tesselation[targetview=MODEL_VIEW]"});
REQUIRE(body_first_tasks.size() == 2);
const auto* wall_with_both_task = task_for_product(body_first_tasks, wall_with_both);
REQUIRE(wall_with_both_task != nullptr);
REQUIRE(wall_with_both_task->representation.id() == body_representation.id());
const auto* wall_with_body_only_task = task_for_product(body_first_tasks, wall_with_body_only);
REQUIRE(wall_with_body_only_task != nullptr);
REQUIRE(wall_with_body_only_task->representation.id() == body_only_representation.id());
}